Question: How do i go about doing a equation on a c# console for where the player should be based on player input from unity.
To explain farther, the client is ran in unity and the server is a c# console application. When the player presses a movement key ex. (w, witch moves the player forward based on local position, as to always make the player move forward) it sends to the server that player pressed w, and then the sever responds and tells the client that it pressed w, changing the player w is pressed bool to true. Then the character moves.
Essentially I am trying to figure out how to make a equation that will do what unity does, but without a transform, or even how the transform works so that i can apply it to the server side.
Here is the client side code:
private void Update()
{
SendKeysToServer();
PlayerController();
PlayerPositionUpdateChecker();
}
public void PlayerController()
{
if (gameObject.name == ntwmng.Playername)
{
MovementControllerPlayer();
JumpControllerPlayer();
RotationControllerPlayer();
MovementFinalizer();
}
else
{
MovementControllerClones();
JumpControllerClones();
RotationControllerClones();
MovementFinalizerClones();
}
}
public void MovementControllerPlayer()
{
if (CharContr.isGrounded)
{
moveDirection = new Vector3(0, 0, 0);
if (wKeyDownPlayer)
{
moveDirection = moveDirection + new Vector3(0, 0, speed * Time.deltaTime);
}
if (sKeyDownPlayer)
{
moveDirection = moveDirection + new Vector3(0, 0, -speed * Time.deltaTime);
}
if (qKeyDownPlayer)
{
moveDirection = moveDirection + new Vector3(-speed * Time.deltaTime, 0, 0);
}
if (eKeyDownPlayer)
{
moveDirection = moveDirection + new Vector3(speed * Time.deltaTime, 0, 0);
}
moveDirection = transform.TransformDirection(moveDirection);
//moveDirection *= speed;
}
}
public void RotationControllerPlayer()
{
if (dKeyDownPlayer)
{
transform.Rotate(0, RotationSpeed * Time.deltaTime, 0);
}
if(aKeyDownPlayer)
{
transform.Rotate(0, -RotationSpeed * Time.deltaTime, 0);
}
}
public void JumpControllerPlayer()
{
if (CharContr.isGrounded)
{
if (SpaceKeyDownPlayer)
{
moveDirection.y = jumpSpeed * Time.deltaTime;
}
}
}
public void MovementFinalizer()
{
moveDirection.y -= gravity * Time.deltaTime;
CharContr.Move(moveDirection);
}
public void CameraAndListenerController()
{
if (gameObject.name == ntwmng.Playername)
{
if (playercam.enabled == false)
{
playercam.enabled = true;
}
if (AudioListener.enabled == false)
{
AudioListener.enabled = true;
}
}
else
{
if (playercam.enabled == true)
{
playercam.enabled = false;
}
if (AudioListener.enabled == true)
{
AudioListener.enabled = false;
}
}
}
public void SendKeysToServer()
{
NetworkStream NtwrkStrm = ServerConnection.GetStream();
IFormatter Formatter = new BinaryFormatter();
foreach (KeyCode kcode in Enum.GetValues(typeof(KeyCode)))
{
if(Input.GetKeyDown(kcode))
{
string type = "Movement Update Key Down";
string kycode = Convert.ToString(kcode);
//Debug.Log(kycode);
Formatter.Serialize(NtwrkStrm, type);
NtwrkStrm.Flush();
Formatter.Serialize(NtwrkStrm, ntwmng.Playername);
NtwrkStrm.Flush();
Formatter.Serialize(NtwrkStrm, kycode);
NtwrkStrm.Flush();
}else
if(Input.GetKeyUp(kcode))
{
string type = "Movement Update Key Up";
string kycode = Convert.ToString(kcode);
//Debug.Log(kycode);
Formatter.Serialize(NtwrkStrm, type);
NtwrkStrm.Flush();
Formatter.Serialize(NtwrkStrm, ntwmng.Playername);
NtwrkStrm.Flush();
Formatter.Serialize(NtwrkStrm, kycode);
NtwrkStrm.Flush();
}
}
}
public void MovementControllerClones()
{
if (CharContr.isGrounded)
{
moveDirection = new Vector3(0, 0, 0);
if (wKeyDownClone)
{
moveDirection = moveDirection + new Vector3(0, 0, speed * Time.deltaTime);
}
if (sKeyDownClone)
{
moveDirection = moveDirection + new Vector3(0, 0, -speed * Time.deltaTime);
}
if (qKeyDownClone)
{
moveDirection = moveDirection + new Vector3(-speed * Time.deltaTime, 0, 0);
}
if (eKeyDownClone)
{
moveDirection = moveDirection + new Vector3(speed * Time.deltaTime, 0, 0);
}
moveDirection = transform.TransformDirection(moveDirection);
//moveDirection *= speed;
}
}
public void RotationControllerClones()
{
if (dKeyDownClone)
{
transform.Rotate(0, RotationSpeed * Time.deltaTime, 0);
}
if (aKeyDownClone)
{
transform.Rotate(0, -RotationSpeed * Time.deltaTime, 0);
}
}
public void JumpControllerClones()
{
if (CharContr.isGrounded)
{
if (SpaceKeyDownClone)
{
moveDirection.y = jumpSpeed* Time.deltaTime;
}
}
}
public void MovementFinalizerClones()
{
moveDirection.y -= gravity * Time.deltaTime;
CharContr.Move(moveDirection);
}
public void CloneKeyUpdater(string type,string kcode)
{
//Debug.Log("Key " + kcode + " Clone Updating");
if (type == "Movement Update Key Down")
{
if (kcode == "W")
{
wKeyDownClone = true;
}
if (kcode == "A")
{
aKeyDownClone = true;
}
if (kcode == "D")
{
dKeyDownClone = true;
}
if (kcode == "S")
{
sKeyDownClone = true;
}
if (kcode == "Q")
{
qKeyDownClone = true;
}
if (kcode == "E")
{
eKeyDownClone = true;
}
if (kcode == "Space")
{
SpaceKeyDownClone = true;
}
}
else if (type == "Movement Update Key Up")
{
if (kcode == "W")
{
wKeyDownClone = false;
}
if (kcode == "A")
{
aKeyDownClone = false;
}
if (kcode == "D")
{
dKeyDownClone = false;
}
if (kcode == "S")
{
sKeyDownClone = false;
}
if (kcode == "Q")
{
qKeyDownClone = false;
}
if (kcode == "E")
{
eKeyDownClone = false;
}
if (kcode == "Space")
{
SpaceKeyDownClone = false;
}
}
}
public void PlayerKeyUpdater(string type, string kcode)
{
//Debug.Log("Key down " + kcode + " Updating");
if (type == "Movement Update Key Down")
{
if (kcode == "W")
{
wKeyDownPlayer = true;
}
if (kcode == "A")
{
aKeyDownPlayer = true;
}
if (kcode == "D")
{
dKeyDownPlayer = true;
}
if (kcode == "S")
{
sKeyDownPlayer = true;
}
if (kcode == "Q")
{
qKeyDownPlayer = true;
}
if (kcode == "E")
{
eKeyDownPlayer = true;
}
if (kcode == "Space")
{
SpaceKeyDownPlayer = true;
}
}
else if (type == "Movement Update Key Up")
{
if (kcode == "W")
{
wKeyDownPlayer = false;
}
if (kcode == "A")
{
aKeyDownPlayer = false;
}
if (kcode == "D")
{
dKeyDownPlayer = false;
}
if (kcode == "S")
{
sKeyDownPlayer = false;
}
if (kcode == "Q")
{
qKeyDownPlayer = false;
}
if (kcode == "E")
{
eKeyDownPlayer = false;
}
if (kcode == "Space")
{
SpaceKeyDownPlayer = false;
}
}
}
Any help will be muchly appreciated. :)
Edit:
so i have figured out a equation that i am using to try and mimic player movement, as of right now it only work between 0 and 90 degrees, just tell i get it exact. the equation comes out really close, but is just a tiny bit off. Any suggestions? Also, this is running on client side, no server influence, so that I can get the math to an exact. The math comes out about 1 unit per second slower then the players current position. Basically after pressing w for 1 second with speed = 20 the math comes out to 19 and actual position is 20.
here is code
if (CharContr.velocity != Vector3.zero)//checks if the player is moving
{
if (rotation < 90f && rotation > 0f) // makes sure the rotation is 0-90
{
percent = (100 / (90 / rotation)) / 100; // gets the percent
x = x + (percent * speed * Time.deltaTime); //adds to current position multiplied by speed and delta time
invertPercent = 1 - percent; //gets the percent for z
z = z + (invertPercent * speed * Time.deltaTime); // adds and stuff again
}
This is really complicated than you thought if you want to implement it yourself instead of using Unity's built-in NetworkTransform. Read this "Client-Side Prediction and Server Reconciliation" article. There are many parts of that article but it shows you what's going on and how this is done.
Although, Unity simplified a part of this if you are using Rigidbody by providing a new function (Physics.Simulate). You simulate all the Rigidbody on the server with the Physics.Simulate function, serialize the transform of each one and send to all the clients.
On the clients, receive the data, de-serialize them then lerp from the current transform to the received ones. You can find an example of how to use Physics.Simulate to determine the position of a Rigidbody in x second here.
Sending keycode to server and syncronize position based on bool is not best practice.
The good practice would be, sending 3 float value of x, y, and z position to the server, then broadcast it to other player.
so other player has the exact position without approximation
Sorry if i answer in wrong place, because i don't have enough rep to make comment.
so i did some searching and have come up with a solution, this is only for if the player is moving forward and the player direction is between 0 and 90. basically i have to use transform.translate instead of using a character controller. the reason i am doing this is so that when the player presses w it will send it to the server and the server can run this at the same time, then use the info to be able to tell were players should be.
if (rotation < 90f && rotation > 0f)
{
moveDirection = new Vector3(0, 0, 0);
percent = (100 / (90 / rotation)) / 100;
invertPercent = 1 - percent;
x = percent * speed;
z = invertPercent * speed;
transform.Translate(x * Time.deltaTime, 0, z * Time.deltaTime, Space.World);
newposition = newposition + new Vector3(x * Time.deltaTime, 0, z * Time.deltaTime);
}
Related
I was coding movement code for my game using this video: Movement code video.
Pardon my garbage code...
void Move(float dir,bool crouchFlag)
{
if(!crouchFlag)
{
if(Physics2D.OverlapCircle(OverheadChecker.position,CelingCirSize,gLayerMask))
{
crouchFlag = true;
}
}
Stand.enabled = !crouchFlag;
Stand2.enabled = !crouchFlag;
Croucher.enabled = crouchFlag;
#region Move & run
if (isGrounded && !crouchFlag && !isOnSlope)
{
Controller.XMove(dir,Speed,rb2d,velPower,acceleration,decceleration);
} else if (isGrounded && isOnSlope && canWalkOnSlope)
{
float TargetSpeed = -dir * Speed;
float TargetSpeedDif = TargetSpeed - rb2d.velocity.x;
float accelerRate = (Mathf.Abs(TargetSpeed) > 0.01f) ? airacceleration : airdecceleration;
float MoveDir = Mathf.Pow(Mathf.Abs(TargetSpeedDif) * accelerRate, velPower) * Mathf.Sign(TargetSpeedDif);
float MoveDirX = MoveDir * slopeNormalPerp.x * MultSlope;
float MoveDirY = MoveDir * slopeNormalPerp.y * MultSlope;
rb2d.AddForce(MoveDirX * Vector2.right);
rb2d.AddForce(MoveDirY * Vector2.up);
}
else if (!isGrounded)
{
float TargetSpeed = dir * Speed;
float TargetSpeedDif = TargetSpeed - rb2d.velocity.x;
float accelerRate = (Mathf.Abs(TargetSpeed) > 0.01f) ? airacceleration : airdecceleration;
float MoveDir = Mathf.Pow(Mathf.Abs(TargetSpeedDif) * accelerRate, velPower) * Mathf.Sign(TargetSpeedDif);
if (rb2d.velocity.y > 0 && !Input.GetButton("Jump"))
{
MoveDir = MoveDir * xJumpForce;
}
rb2d.AddForce(MoveDir * Vector2.right);
}else if (isGrounded && crouchFlag)
{
rb2d.sharedMaterial = noFriction;
float TargetSpeed = dir * CrouchSpeed;
float TargetSpeedDif = TargetSpeed - rb2d.velocity.x;
float accelerRate = (Mathf.Abs(TargetSpeed) > 0.01f) ? acceleration : Crouchdecceleration;
float MoveDir = Mathf.Pow(Mathf.Abs(TargetSpeedDif) * accelerRate, velPower) * Mathf.Sign(TargetSpeedDif);
rb2d.AddForce(MoveDir * Vector2.right);
}
if (isGrounded && Mathf.Abs(HorizontalValue) < 0.01f)
{
float amount = Mathf.Min(Mathf.Abs(rb2d.velocity.x), Mathf.Abs(fricAmount));
amount *= Mathf.Sign(rb2d.velocity.x);
rb2d.AddForce(Vector2.right * -amount, ForceMode2D.Impulse);
}
Vector3 CurrentScale = transform.localScale;
if(Right && dir > 0)
{
transform.localScale = new Vector3(1.4f, 1.4f
, 1);
Right = false;
}
else if (!Right == dir < 0)
{
transform.localScale = new Vector3(-1.4f, 1.4f, 1);
Right = true;
}
#endregion
}
Then I made slopes using a Sprite Shape Controller:
But, the character got stuck on the slopes when going up them, so I used this video for slopes:Fixing slopes video
Irrelevant code is removed:
private void SlopeCheck()
{
checkPos = transform.position - (Vector3)(new Vector2(0.0f, colliderSize.y / 2));
SlopeCheckHorizontal(checkPos);
SlopeCheckVertical(checkPos);
}
private void SlopeCheckHorizontal(Vector2 checkPos)
{
RaycastHit2D slopeHitFront = Physics2D.Raycast(checkPos, transform.right, slopeCheckDistance, gLayerMask);
RaycastHit2D slopeHitBack = Physics2D.Raycast(checkPos, -transform.right, slopeCheckDistance, gLayerMask);
if (slopeHitFront)
{
isOnSlope = true;
slopeSideAngle = Vector2.Angle(slopeHitFront.normal, Vector2.up);
}
else if (slopeHitBack)
{
isOnSlope = true;
slopeSideAngle = Vector2.Angle(slopeHitBack.normal, Vector2.up);
}
else
{
slopeSideAngle = 0.0f;
isOnSlope = false;
}
}
private void SlopeCheckVertical(Vector2 checkPos)
{
RaycastHit2D hit = Physics2D.Raycast(checkPos, Vector2.down, slopeCheckDistance, gLayerMask);
if (hit)
{
slopeNormalPerp = Vector2.Perpendicular(hit.normal).normalized;
slopeDownAngle = Vector2.Angle(hit.normal, Vector2.up);
if(slopeDownAngle != lastSlopeAngle)
{
isOnSlope = true;
}
lastSlopeAngle = slopeDownAngle;
Debug.DrawRay(hit.point, slopeNormalPerp, Color.blue);
Debug.DrawRay(hit.point, hit.normal, Color.green);
}
if (slopeDownAngle > maxSlopeAngle || slopeSideAngle > maxSlopeAngle)
{
canWalkOnSlope = false;
}
else
{
canWalkOnSlope = true;
}
if (isOnSlope && canWalkOnSlope && HorizontalValue == 0.0f)
{
rb2d.sharedMaterial = fullFriction;
}
else
{
rb2d.sharedMaterial = noFriction;
}
}
void Update()
{
if(slopeDownAngle != 0)
{
isOnSlope = true;
} else {
isOnSlope = false;
}
if (CanMove() == true){
HorizontalValue = Input.GetAxisRaw("Horizontal");
}
}
void FixedUpdate()
{
Gcheck();
Move(HorizontalValue, Crouch);
SlopeCheck();
}
Rigidbody>
Mass:0.5
BodyType: Dynamic
LinearDrag: 0
AngularDrag: 0
Gravity: 11
FreezeRotation: Only Z axis
::Friction Is Handled In The Movement Code::
But, when I finished the character got stuck again,
so I tried multiplying the slopeNormalPerp by a variable(MultSlope) and he just bounced up and down if made made it too high and if it was too low nothing happened.
I tried messing with varibles such as the ground-checking circles size, various colliders, the aforementioned MultSlope ,and slopeCheckDistance...
Nothing Helped...
I've been working on this for 7 months(with breaks working on other code) and I have improved greatly in coding, but I still can't fix it.
I tried messing with every relevant variable, watching the video many time, downloading and copy-pasting the code ,and following other tutorials of the slope code, No Dice.
I'm trying to implement a "lazy state machine" using enums for simple enemy AI but for some reason the logic doesn't work as intended.
I need my enemy to stop from time to time to be in Idle state. But when Idle switch fires, my enemy continues to move despite another state condition for moving script.
What's wrong with my script logic?
void Update()
{
Debug.Log(state);
onGround = Physics2D.Raycast(gameObject.transform.position, Vector2.down, groundLength, groundLayer);
Debug.DrawRay(gameObject.transform.position, Vector2.down * 1f, Color.red);
isAnythingThere = Physics2D.Raycast(wallDetection.position, Vector2.right * speed, 0.3f, sideInfo);
RaycastHit2D groundInfo = Physics2D.Raycast(groundDetection.position, Vector2.down, distance);
RaycastHit2D isPlayerInSight = Physics2D.Raycast(wallDetection.position, Vector2.right * speed, 3f, playerLayer);
switch (state)
{
default:
case State.patrol:
if ((groundInfo.collider == false || isAnythingThere) && !isPlayerInSight)
{
if (movingRight == true)
{
Debug.Log("Поворот");
transform.eulerAngles = new Vector3(0, -180, 0);
movingRight = false;
speed = -speed;
}
else
{
transform.eulerAngles = new Vector3(0, 0, 0);
movingRight = true;
speed = -speed;
}
}
if (isPlayerInSight)
{
state = State.attack;
}
if (enemyIdleCheck == false)
{
StartCoroutine("IfEnemyWantsToIdle");
}
break;
case State.attack:
RaycastHit2D isPlayerThere = Physics2D.Raycast(wallDetection.position, Vector2.right * speed, 3f, playerLayer);
Debug.DrawRay(wallDetection.transform.position, Vector2.right * speed * 3f, Color.red);
if (isPlayerThere)
{
attackDirection = (playerPosition.position - transform.position).normalized;
}
else
{
if (!jumpCooldown)
{
state = State.patrol;
}
}
if (jumpCooldown == false)
{
jumpTimer = Time.time + jumpCooldownInSeconds;
}
break;
case State.idle:
if (isPlayerInSight)
{
state = State.attack;
}
if (!isInIdleState)
{
StartCoroutine("IdlingTime");
}
break;
}
}
IEnumerator IfEnemyWantsToIdle()
{
enemyIdleCheck = true;
Debug.Log("Checking for idle possibility");
yield return new WaitForSeconds(2);
if (Random.Range(0, 20) > 10)
{
state = State.idle;
}
enemyIdleCheck = false;
if (isPlayerInSight)
{
state = State.attack;
enemyIdleCheck = false;
yield break;
}
}
IEnumerator IdlingTime()
{
isInIdleState = true;
while (state == State.idle)
{
yield return new WaitForSeconds(Random.Range(2, 4));
isInIdleState = false;
state = State.patrol;
}
if (isPlayerInSight)
{
isInIdleState = false;
yield break;
}
}
private void FixedUpdate()
{
if (state == State.patrol)
{
if (!enemy.isTakingDamage)
{
rb.velocity = new Vector2(movingSpeed * speed, rb.velocity.y);
}
}
if (state == State.attack)
{
if (!enemy.isTakingDamage)
{
rb.velocity = new Vector2(attackDirection.x * attackSpeed, rb.velocity.y);
}
if ((Random.Range(0, 100) > 90) && !jumpCooldown && onGround)
{
Debug.Log("Прыжок сработал");
//rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * jumpForce);
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
jumpCooldown = true;
Invoke("JumpCooldownTime", 1f);
}
}
}
Currently you are just not adding further force/velocity. The moment you enter the idle state you should make sure the Rigidbody2D is actually stopped!
IEnumerator IdlingTime()
{
isInIdleState = true;
// actually stop the movement
rb.velocity = Vector2.zero;
// you could even do
rb.isKinematic = true;
while (state == State.idle)
{
yield return new WaitForSeconds(Random.Range(2, 4));
isInIdleState = false;
rb.isKinematic = false;
state = State.patrol;
}
if (isPlayerInSight)
{
isInIdleState = false;
rb.isKinematic = false;
yield break;
}
}
or/and do it in
private void FixedUpdate()
{
switch(state)
{
case State.patrol:
if (!enemy.isTakingDamage)
{
rb.velocity = new Vector2(movingSpeed * speed, rb.velocity.y);
}
break;
case State.attack:
if (!enemy.isTakingDamage)
{
rb.velocity = new Vector2(attackDirection.x * attackSpeed, rb.velocity.y);
}
if ((Random.Range(0, 100) > 90) && !jumpCooldown && onGround)
{
Debug.Log("Прыжок сработал");
//rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * jumpForce);
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
jumpCooldown = true;
Invoke("JumpCooldownTime", 1f);
}
break;
case State.idle
rb.velocity = Vector2.zero;
break;
}
}
It started happening after I wrote the script for dashing. Now, whenever I dash into walls, my character gets stuck to that wall. If I dash towards the roof, then I can walk on the roof for example. Also, when I dash next to a wall / on the floor, it never stops dashing after a single press. Any help will be appreciated, thanks.
The code below is the dashing script, if needed I can post the variables set and my character controller script too.
void Start()
{
_rigidbody = GetComponent<Rigidbody2D>();
dashTime = baseDashTime;
}
void Update()
{
isGrounded = Physics2D.OverlapCircle(feet.position, checkRadius, checkGround);
if(isGrounded == true)
{
dashTime = baseDashTime;
}
if (direction == 0)
{
if (Input.GetKey(KeyCode.W) && (Input.GetKeyDown(KeyCode.LeftShift)))
{
direction = 1;
}
else if (Input.GetKey(KeyCode.A) && (Input.GetKeyDown(KeyCode.LeftShift)))
{
direction = 2;
}
else if (Input.GetKey(KeyCode.S) && (Input.GetKeyDown(KeyCode.LeftShift)))
{
direction = 3;
}
else if (Input.GetKey(KeyCode.D) && (Input.GetKeyDown(KeyCode.LeftShift)))
{
direction = 4;
}
}
else
{
if (dashTime <= 0)
{
direction = 0;
_rigidbody.velocity = Vector2.zero;
}
else
{
dashTime -= Time.deltaTime;
if (direction == 1)
{
_rigidbody.velocity = Vector2.up * dashSpeed;
}
else if (direction == 2)
{
_rigidbody.velocity = Vector2.left * dashSpeed;
}
else if (direction == 3)
{
_rigidbody.velocity = Vector2.down * dashSpeed;
}
else if (direction == 4)
{
_rigidbody.velocity = Vector2.right * dashSpeed;
}
}
}
}
In your code you have this statement in the update function. When you dash on the ground, im guessing IsGrounded will stay true, so the player will keep dashing forever. This is probably what causes the player to be stuck.
if(isGrounded == true)
{
dashTime = baseDashTime;
}
I am new to coding. I've been trying to Frankenstein basic tutorials into something of my own and it seems ive finally hit a wall. I'm really not sure what is causing this and would like some help to weed out the problem.
at the moment when I press the dash button (left shift) my character dashes in the direction he is facing but for a random duration. I would like it to be consistent and working properly.
Thanks in advance!
PS: Sorry for the long script, it contains everything to do with player movment.
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using UnityEngine;
public class CharacterController : MonoBehaviour
{
//Player Movement
public float speed;
public float jumpForce;
public Transform feetPos;
public float checkRadius;
public LayerMask whatIsGround;
public float dashSpeed;
public float startDashTime;
public float dashCooldownTime = 2;
private float nextFireTime = 0;
public Animator animator;
private Rigidbody2D rb;
private float moveInput;
private bool isGrounded;
private float jumpTimeCounter;
public float jumpTime;
private bool isJumping;
private float dashTime;
public int direction;
void Start()
{
animator.GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
dashTime = startDashTime;
}
void FixedUpdate()
{
moveInput = Input.GetAxisRaw("Horizontal");
if (direction < 1 )
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
}
void Update()
{
// Moving
isGrounded = Physics2D.OverlapCircle(feetPos.position, checkRadius, whatIsGround);
if (moveInput > 0)
{
transform.eulerAngles = new Vector3(0, 0, 0);
animator.SetBool("Moving", true);
}
else if (moveInput < 0)
{
transform.eulerAngles = new Vector3(0, 180, 0);
animator.SetBool("Moving", true);
}
else
{
animator.SetBool("Moving", false);
}
// Jumping
if (isGrounded == true && Input.GetKeyDown(KeyCode.Space))
{
animator.SetTrigger("IsJumping");
isJumping = true;
jumpTimeCounter = jumpTime;
rb.velocity = Vector2.up * jumpForce;
}
if (Input.GetKey(KeyCode.Space) && isJumping == true)
{
if (jumpTimeCounter > 0)
{
rb.velocity = Vector2.up * jumpForce;
jumpTimeCounter -= Time.deltaTime;
}
else
{
isJumping = false;
}
}
if (Input.GetKeyUp(KeyCode.Space))
{
isJumping = false;
}
if (isGrounded == false)
{
animator.SetBool("Grounded", false);
}
if (isGrounded == true)
{
animator.SetBool("Grounded", true);
}
// Dashing
if (Time.time > nextFireTime)
{
if (direction == 0)
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
UnityEngine.Debug.Log("beaners");
nextFireTime = Time.time + dashCooldownTime;
if ((transform.rotation.eulerAngles.y == 180))
{
Dashleft();
}
else
{
DashRight();
}
}
}
}
else
{
if(dashTime <= 0)
{
direction = 0;
dashTime = startDashTime;
}
else
{
dashTime -= Time.deltaTime;
}
}
}
void Dashleft()
{
direction = 1;
rb.velocity = Vector2.left * dashSpeed;
}
void DashRight()
{
direction = 1;
rb.velocity = Vector2.right * dashSpeed;
}
}
Random duration is because of the use of Rigidbody2D.
See in Unity Rigidbody2D is responsible for each and every single physical interaction. It mean forces from player like player movement and forces from your environment like friction and collision.
Here what is happening is that when your player is dashing there is also player movement force, which is also applied on your player's Rigidbody2d. And friction of ground on which your player is running/dashing on.
I've added a comment on parts that I've changed.
Updated part of your script:
private bool isDashing;
.
.
.
void Update()
{
//Added: putting a Condition to check if you player is not dashing, if it is then
//player won't be able to do anything, As I've scene and done in many games. if you
//don't want this remove it and see what happens, this is not tested so sorry if there
//is something that is not working as intended.
//dashing condition check
if(!isDashing)
{
// Moving
isGrounded = Physics2D.OverlapCircle(feetPos.position, checkRadius, whatIsGround);
if (moveInput > 0)
{
transform.eulerAngles = new Vector3(0, 0, 0);
animator.SetBool("Moving", true);
}
else if (moveInput < 0)
{
transform.eulerAngles = new Vector3(0, 180, 0);
animator.SetBool("Moving", true);
}
else
{
animator.SetBool("Moving", false);
}
// Jumping
if (isGrounded == true && Input.GetKeyDown(KeyCode.Space))
{
animator.SetTrigger("IsJumping");
isJumping = true;
jumpTimeCounter = jumpTime;
//Changed: use Add force method instead of changing the velocity.
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
//rb.velocity = Vector2.up * jumpForce;
}
if (Input.GetKey(KeyCode.Space) && isJumping == true)
{
if (jumpTimeCounter > 0)
{
//Changed: Same this rb.AddForce...
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
//rb.velocity = Vector2.up * jumpForce;
jumpTimeCounter -= Time.deltaTime;
}
else
{
isJumping = false;
}
}
if (Input.GetKeyUp(KeyCode.Space))
{
isJumping = false;
}
if (isGrounded == false)
{
animator.SetBool("Grounded", false);
}
if (isGrounded == true)
{
animator.SetBool("Grounded", true);
}
}
//dashing condition ends
// Dashing
if (Time.time > nextFireTime)
{
//Here your Dash timer ends.
isDashing = false;
if (direction == 0)
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
UnityEngine.Debug.Log("beaners");
nextFireTime = Time.time + dashCooldownTime;
//Here your Dash timer Starts.
isDashing = true;
if ((transform.rotation.eulerAngles.y == 180))
{
Dashleft();
}
else
{
DashRight();
}
}
}
}
else
{
if(dashTime <= 0)
{
direction = 0;
dashTime = startDashTime;
}
else
{
dashTime -= Time.deltaTime;
}
}
}
visit Unity - Scripting API: Rigidbody2D.AddForce hope it helps.
Happy Coding
I am trying to make a player spaceship move between three points when the user enters left or right on the keyboard. I would like the player to move smoothly between these points but it seems that the Lerp function is only interpolated once.
Here is the Game master script which checks for input from the user and passes it onto the Player controller which performs the Lerp:
Game master:
void Update ()
{
if (gameIsRunning)
{
if (Input.GetKeyDown(KeyCode.A))
{
//Go Left
player.MovePlayer("left");
}
else if (Input.GetKeyDown(KeyCode.D))
{
//Go Right
player.MovePlayer("right");
}
//Only run this if the game is running...
if (player.Lives <= 0)
{
gameIsRunning = false;
}
}
}
Player controller:
public void MovePlayer (string dir)
{
if (dir == "left")
{
if (currentPosition == Position.Left)
{
//Do Nothing!
return;
}
if (currentPosition == Position.Middle)
{
transform.position = Vector3.Lerp(middlePos.position, leftPos.position, .5f);
currentPosition = Position.Left;
}
if (currentPosition == Position.Right)
{
transform.position = Vector3.Lerp(rightPos.position, middlePos.position, .5f);
currentPosition = Position.Middle;
}
}
if (dir == "right")
{
if (currentPosition == Position.Right)
{
//Do Nothing!
return;
}
if (currentPosition == Position.Middle)
{
transform.position = Vector3.Lerp(transform.position, rightPos.position, .5f);
currentPosition = Position.Right;
}
if (currentPosition == Position.Left)
{
transform.position = Vector3.Lerp(transform.position, middlePos.position, .5f);
currentPosition = Position.Middle;
}
}
}
Screenshot:
Why is this happening?
lerp must be called with a changing parameter. try something like:
Player controller:
enum Direction
{
Left,
Right
}
Direction moveDir;
float progress;
public void MovePlayer (Direction dir)
{
moveDir = dir;
progress = 0.0f;
}
public void Update()
{
switch(dir)
{
case Direction.Left:
if (currentPosition == Position.Middle)
{
transform.position = Vector3.Lerp(middlePos.position, leftPos.position, progress);
if(progress >= 1.0f)
currentPosition = Position.Left;
else
progress += 0.1f; // change as necessary
}
if (currentPosition == Position.Right)
{
transform.position = Vector3.Lerp(rightPos.position, middlePos.position, progress);
if(progress >= 1.0f)
currentPosition = Position.Middle;
else
progress += 0.1f; // change as necessary
}
break;
case Direction.Right:
// ...
break;
}
}