Unity3D C# direction change while running don't work - c#

I'm currently working on a 2D game in Unity as a beginner in Unity and C#.
My character should walk left and right with axis horizontal, this works perfectly. But now I want, that my character runs, when I press additionally "Fire1". This works partly too, but when I change the direction while pressing "Fire1" the character stops. Without pressing "Fire1" the direction change works. It seems the script don't get the horizontal change, because the debug.log says "0" when "Fire1" is pressed while direction change.
if (onPlatform) {
activeMoveSpeed = moveSpeed * onPlatformSpeedModifier;
} else if(Input.GetButton("Fire1")) {
activeMoveSpeed = moveSpeed * sprintSpeedModifier;
} else {
activeMoveSpeed = moveSpeed;
}
Debug.Log (Input.GetAxisRaw ("Horizontal"));
//Player go left and right
if (Input.GetAxisRaw ("Horizontal") > 0f) {
myRigidbody.velocity = new Vector3 (activeMoveSpeed, myRigidbody.velocity.y, 0f);
transform.localScale = new Vector3 (1f, 1f, 1f);
} else if (Input.GetAxisRaw ("Horizontal") < 0f) {
myRigidbody.velocity = new Vector3 (-activeMoveSpeed, myRigidbody.velocity.y, 0f);
transform.localScale = new Vector3 (-1f, 1f, 1f);
} else {
myRigidbody.velocity = new Vector3(0f, myRigidbody.velocity.y, 0f);
}

You could try to multiply each moveSpeed by Time.deltaTime. I had an issue that seems pretty similar to this one and it helped.

Related

Unity 3D instantly rotate in the direction of movement

I have a somewhat similar question to this one, I'm trying to rotate in the direction of movement but the issue is that I want to maintain my position and just instantly rotate because I have a procedural maze and there's not enough space to gradually swing around in the direction of movement in a wide turn. I'll post code attempts at the bottom, attempt two gives the error: viewing vector is zero.
If you look at all four of these screenshots, when the y-axis is rotated, the x-axis and z-axis jump to a new position. When I'm moving this ends up looking like I'm teleporting around the maze. Anyone know how to rotate while remaining in the same position?
Here's right:
Here's forward:
Here's left:
Here's back:
here's code attempt 1:
public void playerMovement()
{
float horizontalInput = Input.GetAxis("Horizontal");
float verticalInput = Input.GetAxis("Vertical");
Vector3 movementx = new Vector3(horizontalInput, 0f, 0f);
Vector3 movementy = new Vector3(0f, 0f, verticalInput);
movementy = transform.forward * verticalInput;
movementx = transform.right * horizontalInput;
if (horizontalInput > 0)
{
transform.eulerAngles = new Vector3(0f, 90f, 0f);
transform.Translate(-movementx.normalized * 0.1f, Space.Self);
}
if (horizontalInput < 0)
{
transform.eulerAngles = new Vector3(0f, 270f, 0f);
transform.Translate(-movementx.normalized * 0.1f, Space.Self);
}
if (verticalInput < 0)
{
transform.eulerAngles = new Vector3(0f, 180f, 0f);
transform.Translate(movementy.normalized * 0.1f, Space.Self);
}
if (verticalInput > 0)
{
transform.eulerAngles = new Vector3(0f, 0f, 0f);
transform.Translate(movementy.normalized * 0.1f, Space.Self);
}
}
Here's code attempt 2:
public void playerMovement2()
{
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
movement = transform.TransformDirection(movement);
transform.Translate(movement.normalized * 0.1f, Space.Self);
transform.rotation = Quaternion.LookRotation(movement);
}
I took your second attempt and modified it:
This way you will walk and look in the direction you
void Update()
{
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
transform.Translate(movement.normalized * 0.1f, Space.World);
transform.rotation = Quaternion.LookRotation(movement, Vector3.up);
}
However then the character will always "flip" back to forward
-> you can solve that by only moving when new input is given
For example like this:
void Update()
{
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
if (movement.magnitude > 0f)
{
transform.Translate(movement.normalized * 0.1f, Space.World);
transform.rotation = Quaternion.LookRotation(movement, Vector3.up);
}
}

unity player moving on the x axis with the finger does not work

Hey I'm developing an android game with unity its in 3d and the main point is that you are a square which you have to move on the x-Axis. I want that the player can place his finger wherever he wants and swipe left or right (still touching the display) and the distance between the positions where he starts touching and where he is now the square should move right or left. When the player is not touching it should not move at the x-Axis. I did this but my code has a problem when I release my finger and touch again without moving right or left the square deflects to one side very fast. Of course when the finger not move the square shouldn't move.
Picture for better understand
// My Code
public class PlayerMovement : MonoBehaviour
{
void FixedUpdate()
{
// move the player constantly forward
transform.position += Vector3.forward * Time.deltaTime * speed;
if (Input.touchCount > 0)
{
touch = Input.GetTouch(0);
// the current finger position
touchedPosMoved = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 10));
switch (touch.phase)
{
case TouchPhase.Began:
// get finger position when touch start
touchedPosBegan = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 10));
startX = transform.position.x;
break;
case TouchPhase.Moved:
// claculate the distance between start and curent position of the finger
differenz = Mathf.Abs(touchedPosBegan.x - touchedPosMoved.x);
if (touchedPosBegan.x > touchedPosMoved.x)
{
differenz = differenz * -1;
}
break;
}
// Move player at the X-axis
Vector3 idk = new Vector3((startX + differenz) * 8, transform.position.y, transform.position.z);
gameObjectStart = new Vector3(startX, transform.position.y, transform.position.z);
transform.position = Vector3.Lerp(gameObjectStart, idk, Time.deltaTime * 2);
}
}
}
Does anyone know the problem or has another solution for my to move the player as described above
Here I find a better code without these problems I hope this can help other programmers ;)
private void FixedUpdate()
{
transform.position += Vector3.forward * Time.deltaTime * speed;
if (Input.touchCount > 0)
{
touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Moved)
{
transform.position = new Vector3(
transform.position.x + touch.deltaPosition.x * multiplier,
transform.position.y,
transform.position.z + touch.deltaPosition.y * multiplier);
}
}
}

Dash against slopes using physics in Unity 2D

I'm working on a 2D project in Unity.
The character controller is physics based, so I use rigidbody to move the player. Everything is working fine except when I try to apply a high speed movement to the character, like a dash.
This is how the code looks like.
I just check if the player is dashing, so I increase the Vector2 movement in a certain amount.
private void DashMovement() {
if (isDashing) {
movement.x *= dashFactor;
}
}
I'm also calculating the ground angle, so I set the movement vector to follow the ground inclination.
private void OnSlopeMovement() {
if (isGrounded && !isJumping) {
float moveDistance = Mathf.Abs(movement.x);
float horizontalOnSlope = Mathf.Cos(groundAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign(movement.x);
float verticalOnSlope = Mathf.Sin(groundAngle * Mathf.Deg2Rad) * moveDistance;
if (horizontalOnSlope != 0)
movement.x = horizontalOnSlope;
if (isGrounded && verticalOnSlope != 0)
movement.y = verticalOnSlope;
}
SetMaxFallVelocity();
}
So I set the rigidbody velocity for making it move.
private void Move() {
movement.x *= Time.fixedDeltaTime;
if(isGrounded && !isJumping) movement.y *= Time.fixedDeltaTime;
Vector3 targetVelocity = new Vector2(movement.x, movement.y);
PlayerController.rb2d.velocity = Vector3.SmoothDamp(PlayerController.rb2d.velocity, targetVelocity, ref velocity, movementSmoothing);
}
The problem appears when I apply a speed high enough. I understand this issue is because of physics.
I think the ray that checks the ground and is used to calculate the groundAngle doesn't work fast enough to keep track of that movement, so I can not keep the player fixed on the ground.
I would like to find a solution without making the player kinematic, or stopping the dash on slopes.
This is how it looks ingame.
And this is how the rigidbody movement remain right over the ground, following the slopes angle.
EDIT:
This is how I get the ground angle:
private void GroundAngle() {
Vector2 rayOrigin = feetCollider.bounds.center;
rayOrigin.y += 0.1f;
Vector2 rayDirection = (Input.GetAxisRaw("Horizontal") == 0) ? Vector2.right : new Vector2(Input.GetAxisRaw("Horizontal"), 0);
int groundCollisions = Physics2D.RaycastNonAlloc(rayOrigin, Vector2.down, groundResults, Mathf.Infinity, groundMask);
if (groundCollisions > 0) {
groundAngle = Vector2.Angle(groundResults[0].normal, rayDirection) - 90f;
//Debug.DrawRay(rayOrigin, Vector2.down, Color.green);
if (groundAngle > 0 && !isDashing) {
rayOrigin.x += Input.GetAxisRaw("Horizontal") * .125f;
Physics2D.RaycastNonAlloc(rayOrigin, Vector2.down, groundResults, Mathf.Infinity, groundMask);
groundAngle = Vector2.Angle(groundResults[0].normal, rayDirection) - 90f;
//Debug.DrawRay(rayOrigin, Vector2.down, Color.blue);
}
}
}
Thanks to #Ruzhim for the help. I just post a first "solution" for the problem.
According to Ruzhim advises, I've used him code this way.
private void SetPositionAfterTick() {
if (isDashMovement) {
Vector2 currentPosition = new Vector2(transform.position.x, transform.position.y);
currentPosition.y = feetCollider.bounds.min.y;
Vector2 feetPosAfterTick = currentPosition + PlayerController.rb2d.velocity * Time.deltaTime;
float maxFloorCheckDist = .1f;
RaycastHit2D groundCheckAfterTick = Physics2D.Raycast(feetPosAfterTick + Vector2.up * maxFloorCheckDist, Vector2.down, maxFloorCheckDist * 5f);
if (groundCheckAfterTick) {
Vector2 wantedFeetPosAfterTick = groundCheckAfterTick.point;
if (wantedFeetPosAfterTick != feetPosAfterTick) {
//PlayerController.rb2d.transform.position = (wantedFeetPosAfterTick + new Vector2(0f, feetCollider.bounds.min.y - PlayerController.rb2d.position.y));
PlayerController.rb2d.velocity = Vector2.zero;
}
}
}
}
This is how it looks like.
This is good enough to continue polishing that mechanic. I still need to set the position in some way. The rigidbody's position calculation is not working as it
is raised right now, as the condition (wantedFeetPosAfterTick != feetPosAfterTick) is always true, so the character goes throw the floor and fall.
As you can see, I also need to control the down slopes movement, as it uses the slopes movement sometimes, and dash straight forward others.
This is how asker Rubzero implemented the below code to work for them:
private void SetPositionAfterTick() {
if (isDashMovement) {
Vector2 currentPosition = new Vector2(transform.position.x, transform.position.y);
currentPosition.y = feetCollider.bounds.min.y;
Vector2 feetPosAfterTick = currentPosition + PlayerController.rb2d.velocity * Time.deltaTime;
float maxFloorCheckDist = .1f;
RaycastHit2D groundCheckAfterTick = Physics2D.Raycast(feetPosAfterTick + Vector2.up * maxFloorCheckDist,
Vector2.down, maxFloorCheckDist * 5f);
if (groundCheckAfterTick) {
Vector2 wantedFeetPosAfterTick = groundCheckAfterTick.point;
if (wantedFeetPosAfterTick != feetPosAfterTick) {
//PlayerController.rb2d.transform.position = (wantedFeetPosAfterTick + new Vector2(0f, feetCollider.bounds.min.y -
PlayerController.rb2d.position.y));
PlayerController.rb2d.velocity = Vector2.zero;
}
}
}
}
This is how it looks like.
This is good enough to continue polishing that mechanic. I still need
to set the position in some way. The rigidbody's position calculation
is not working as it is raised right now, as the condition
(wantedFeetPosAfterTick != feetPosAfterTick) is always true, so the
character goes throw the floor and fall.
As you can see, I need to control the down slopes movement, as it uses
the slopes movement sometimes, and dash straight forward others.
I agree with AresCaelum; using physics to do slope movement is pretty much the opposite of what you want to be doing if you don't want to preserve momentum when you're done going up/down the slope. Specifically, your problem is here:
float moveDistance = Mathf.Abs(movement.x);
float horizontalOnSlope = Mathf.Cos(groundAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign(movement.x);
float verticalOnSlope = Mathf.Sin(groundAngle * Mathf.Deg2Rad) * moveDistance;
This is a problem because the more the player moves horizontally in a frame, the more they will move vertically based on the slope of the ramp they are on. However, this assumption doesn't hold if they should only be traveling up the ramp during only part of the movement during the frame. So, you need a way to handle that situation.
One solution is to use a raycast from where the player would be then if it's above the floor, alter the vertical velocity so that it would place them at that floor's position instead.
First, determine if slope movement has occurred in a physics frame...
private bool slopeMovementOccurred = false;
void FixedUpdate() {
slopeMovementOccurred = false;
// ...
}
private void OnSlopeMovement() {
if (isGrounded && !isJumping) {
slopeMovementOccurred = true;
// ...
}
SetMaxFallVelocity();
}
... and if it has, determine where the player is going to be after the physics update. Then do a physics2d raycast from above that position (by some amount) downward (double the previous amount) to find where the player's position should be, and then change the rb2d.velocity such that it will place the player exactly at the height they should be at.
Assuming you can calculate some kind of Vector2 feetOffset that has the local position of the player's feet:
void FixedUpdate() {
// ...
StickToSlopeLanding();
}
void StickToSlopeLanding() {
if (slopeMovementOccurred) {
Vector2 curVelocity = PlayerController.rb2d.velocity;
Vector2 feetPosAfterTick = PlayerController.transform.position
+ PlayerController.feetOffset
+ curVelocity * Time.deltaTime;
float maxFloorCheckDist = 1.0f;
// determine where the player should "land" after this frame
RaycastHit2D groundCheckAfterTick = Physics2D.Raycast(
feetPosAfterTick + Vector2.up * maxFloorCheckDist,
-Vector2.up, maxFloorCheckDist * 2f);
if (groundCheckAfterTick.collider != null) {
Vector2 wantedFeetPosAfterTick = groundCheckAfterTick.point;
// if basic physics won't take them to landing position
if (wantedFeetPosAfterTick != feetPosAfterTick) {
Vector2 wantedVelocity = curVelocity
+ Vector2.up
* ((wantedFeetPosAfterTick.y - feetPosAfterTick.y)
/ Time.deltaTime);
// adjust velocity so that physics will take them to landing position
PlayerController.rb2d.velocity = wantedVelocity;
// optionally, set a flag so that next frame
// it knows the player should be grounded
}
}
}
}
Hopefully this gets you towards a solution that will work.
Note: you may need to also move the rigidbody so that it doesn't try to clip through the corner at the top of the ramp, and you can determine where to put the rigidbody using another raycast, setting the velocity from that point to be horizontal:
void StickToSlopeLanding() {
if (slopeMovementOccurred) {
Vector2 curVelocity = PlayerController.rb2d.velocity;
Vector2 feetPosAfterTick = PlayerController.transform.position
+ PlayerController.feetOffset
+ curVelocity * Time.deltaTime;
float maxFloorCheckDist = 1.0f;
// determine where the player should "land" after this frame
RaycastHit2D groundCheckAfterTick = Physics2D.Raycast(
feetPosAfterTick + Vector2.up * maxFloorCheckDist,
-Vector2.up, maxFloorCheckDist * 2f);
if (groundCheckAfterTick.collider != null) {
Vector2 wantedFeetPosAfterTick = groundCheckAfterTick.point;
// if basic physics won't take them to landing position
if (wantedFeetPosAfterTick != feetPosAfterTick) {
// look for corner of ramp+landing.
// Offsets ensure we don't raycast from inside/above it
float floorCheckOffsetHeight = 0.01f;
float floorCheckOffsetWidth = 0.5f;
RaycastHit2D rampCornerCheck = Physics2D.Raycast(
wantedFeetPosAfterTick
- floorCheckOffsetHeight * Vector2.up
- floorCheckOffsetWidth * Mathf.Sign(movement.x) * Vector2.right,
Mathf.Sign(movement.x) * Vector2.right);
if (rampCornerCheck.collider != null) {
// put feet at x=corner position
Vector2 cornerPos = Vector2(rampCornerCheck.point.x,
wantedFeetPosAfterTick.y);
PlayerController.rb2d.position = cornerPos
- PlayerController.feetOffset;
// adjust velocity so that physics will take them from corner
// to landing position
Vector2 wantedVelocity = (wantedFeetPosAfterTick - cornerPos)
/ Time.deltaTime;
PlayerController.rb2d.velocity = wantedVelocity;
// optionally, set a flag so that next frame
// it knows the player should be grounded
}
}
}
}
}

Unity C# - Move character while jumping

My character moves great, and jumps great. But when jumping he just moves straight in the direction he came from and you can't rotate or move him while in the air. How can that be done?
From the Update Function:
if (controller.isGrounded)
{
moveD = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
moveD = transform.TransformDirection(moveD.normalized) * speed;
moveDA = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
if (moveDA.magnitude > 0)
{
gameObject.transform.GetChild(0).LookAt(gameObject.transform.position + moveDA, Vector3.up);
}
if (Input.GetButton("Jump"))
{
moveD.y = jumpSpeed;
}
}
moveD.y = moveD.y - (gravity * Time.deltaTime);
controller.Move(moveD * Time.deltaTime);
controller.isGrounded Is only true if the last time you called controller.Move() the bottom of the object's collider is touching a surface, so in your case once you jump, you cannot move until you hit the ground again.
You can solve this by separating your movement code and jumping code like so:
moveD = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
moveD = transform.TransformDirection(moveD.normalized) * speed;
moveDA = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
if (moveDA.magnitude > 0)
{
gameObject.transform.GetChild(0).LookAt(gameObject.transform.position + moveDA, Vector3.up);
}
if (controller.isGrounded)
{
if (Input.GetButton("Jump"))
{
moveD.y = jumpSpeed;
}
}
moveD.y = moveD.y - (gravity * Time.deltaTime);
controller.Move(moveD * Time.deltaTime);

C# Instantiate Prefab with Rotation

I have a little problem with this code:
private void Update()
{
if (Input.GetMouseButtonDown(0) && canClick)
{
Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mouseWorldPosition.z = player.transform.position.z;
directionVector = player.transform.position - mouseWorldPosition;
player.GetComponent<Rigidbody2D>().AddForce(directionVector.normalized * speed);
Quaternion InstanceRotation = Quaternion.Euler(mouseWorldPosition.x - 90f, 0f, 0f);
GameObject effect = Instantiate(SteamFx, mouseWorldPosition, InstanceRotation);
effect.transform.LookAt(directionVector);
}
}
The problem is that when instantiating the object, it has a z rotation. So I have an effect that when I click on the screen, it should instantiate, and blow in the player direction. It has different rotation, how to make the rotation correct.
Thks!!!

Categories