I have been having great trouble getting my sprite to jump. So far I have a section of code which with a single tap of "W" will send the sprite in a constant velocity upwards. I need to be able to make my sprite come back down to the ground a certain time or height after begining the jump. There is also a constant pull of velocity 2 on the sprite to simulate some kind of gravity.
// Walking = true when there is collision detected between the sprite and ground
if (Walking == true)
if (keystate.IsKeyDown(Keys.W))
{
Jumping = true;
}
if (Jumping == true)
{
spritePosition.Y -= 10;
}
Any ideas and help would be appreciated but I'd prefer a modified version of my code posted if at all possible.
You need to apply an impulse to your sprite as opposed to a constant velocity of 10 like you are doing.
There is a good tutorial here for what you are trying to do.
public class Player
{
private Vector2 Velocity, Position;
private bool is_jumping;
private const float LandPosition = 500f;
public Player(Vector2 Position)
{
this.Position = new Vector2(Position.X, LandPosition);
Velocity = Vector2.Zero;
is_jumping = false;
}
public void UpdatePlayer(Gametime gametime, KeyboardState keystate, KeyboardState previousKeyBoardState)
{
if (!is_jumping)
if (keystate.isKeyDown(Keys.Space) && previousKeyBoardState.isKeyUp(Keys.Space))
do_jump(10f);
else
{
Velocity.Y++;
if (Position.Y >= LandPosition)
is_jumping = false;
}
Position += Velocity;
}
private void do_jump(float speed)
{
is_jumping = true;
Velocity = new Vector2(Velocity.X, -speed);
}
}
fun little mix of psuedocode and some real code, just add the variables that I didn't include at the top.
Also check out Stack Overflow Physics ;) Good luck with your game.
edit: that should be complete, let me know how things go.
I would do something like this...
const float jumpHeight = 60F; //arbitrary jump height, change this as needed
const float jumpHeightChangePerFrame = 10F; //again, change this as desired
const float gravity = 2F;
float jumpCeiling;
bool jumping = false;
if (Walking == true)
{
if (keystate.IsKeyDown(Keys.W))
{
jumping = true;
jumpCeiling = (spritePosition - jumpHeight);
}
}
if (jumping == true)
{
spritePosition -= jumpHeightChangePerFrame;
}
//constant gravity of 2 when in the air
if (Walking == false)
{
spritePosition += gravity;
}
if (spritePosition < jumpCeiling)
{
spritePosition = jumpCeiling; //we don't want the jump to go any further than the maximum jump height
jumping = false; //once they have reached the jump height we want to stop them going up and let gravity take over
}
Related
I'm making a game in which the player controls two different characters (each one has its own empty object with a camera as child), and switchs one or another by pressing the control key. The thing is, I'm trying to make a little transition between both characters cameras by using another camera, so it doesn't just teleports between one and another but I can't seem to do it. I tried with lerp but I don't know if I got it right, so I read and tried Vector3.MoveTowards but still couldn't do it. This is my code so far (the while is because a last-moment-braindead I had):
public class CameraController : MonoBehaviour
{
public Camera cam1;
public Camera cam2;
public Camera movingCamera;
public bool isCurrentPlayer;
public Transform target1;
public Transform target2;
public float speed = 0.2f;
void FixedUpdate()
{
float step = speed * Time.deltaTime;
if (Input.GetButtonDown("Control"))
{
if (isCurrentPlayer)
{
movingCamera.enabled = true;
cam2.enabled = false;
while (transform.position != target1.position)
{
transform.position = Vector3.MoveTowards(transform.position, target1.position, step);
}
if (transform.position == target1.transform.position)
{
movingCamera.enabled = false;
cam1.enabled = true;
}
isCurrentPlayer = false;
}
else if (!isCurrentPlayer)
{
movingCamera.enabled = true;
cam1.enabled = false;
while (transform.position != target2.position)
{
transform.position = Vector3.MoveTowards(transform.position, target2.position, step);
}
if (transform.position == target2.transform.position)
{
movingCamera.enabled = false;
cam2.enabled = true;
}
isCurrentPlayer = true;
}
}
}
I'm curious about two things. Why did you use FixedUpdate to manage your updates? This isn't physics code. Is there a particular reason you are using multiple cameras? If I may, I propose the following changes.
You can simply make use of the main camera instead of multiple cameras. Additionally, you can increase the number of player objects you can toggle through by using an array of player GameObjects, and by changing the input parameters to left control and right control, you can toggle between next player and previous player to navigate bi-directionally through the array of players.
Here's my example code that implements these changes (tested and works, though improvements can be made.)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// Attached to Main Camera
public class CameraController : MonoBehaviour {
// set manually in inspector
public GameObject[] players;
public float movementSpeed = 1.0f;
public float rotationSpeed = 1.0f;
private int currentPlayer;
private float startTime;
private float distanceToPlayer;
private Vector3 startPosition;
private Quaternion startOrientation;
// Use this for initialization
void Start () {
currentPlayer = 0;
ResetCamera();
}
// Update is called once per frame
void Update () {
float distanceCovered;
float rotationCovered;
float fractionTraveled;
// switch to previous
if (Input.GetButtonDown("left ctrl")) {
if (currentPlayer == 0) currentPlayer = players.Length - 1;
else currentPlayer--;
ResetCamera();
}
// switch to nextPlayer
if (Input.GetButtonDown("right ctrl")) {
if (currentPlayer == players.Length - 1) currentPlayer = 0;
else currentPlayer++;
ResetCamera();
}
// Keep moving camera
if (transform.position != players[currentPlayer].transform.position)
{
distanceCovered = (Time.time - startTime) * movementSpeed;
fractionTraveled = distanceCovered / distanceToPlayer;
rotationCovered = (Time.time - startTime) * rotationSpeed;
// Lerp to player position
transform.position = Vector3.Lerp(
startPosition,
players[currentPlayer].transform.position,
fractionTraveled
);
// match player orientation
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
players[currentPlayer].transform.rotation,
rotationCovered
);
// Stop moving camera
} else {
// Match orientation
if (transform.rotation != players[currentPlayer].transform.rotation)
transform.rotation = players[currentPlayer].transform.rotation;
// Set parent transform to current player
transform.parent = players[currentPlayer].transform;
}
}
void ResetCamera() {
transform.parent = null;
startTime = Time.time;
startPosition = transform.position;
startOrientation = transform.rotation;
distanceToPlayer = Vector3.Distance(
transform.position,
players[currentPlayer].transform.position
);
}
}
Obviously the values would need to be tweaked, and the movement algorithm is pretty basic. Crude but function. You can also add player movement code into the camera, just make sure it points to players[currentPlayer] and it will work for each of your player objects without having to use additional scripts unless there is a reason to do so.
Feel free to use this code. Like I said, it works. However, should you choose to do so, it can easily be modified to function like your original code simply by removing the array and reinstating the individual GameObjects.
transform.position points to the position of CameraController game object. If you want to move movingCamera you probably want to use movingCamera.transform.position. Also keep in mind that in your script the MoveTowards() would only fire when you are pressing your "Control" button.
As memBrain said it would be the best practice to use only one camera for this - visually it would look the same.
The script should look something like this:
// Assuming target1 is player 1 and target2 is player 2
private float snapThreshold = 0.1f;
private Vector3 movingCameraDestination = Vector3.zero;
void FixedUpdate()
{
if(Input.GetButtonDown("Control"))
{
if(isCurrentPlayer)
{
//Set position of transition camera to player 1 and set it's destination to player's 2 position
movingCamera.transform.position = player1.position;
movingCameraDestination = player2.position;
//Disable player 1 camera and enable transition camera
cam1.enabled = false;
movingCamera.enabled = true;
}
else
{
//Set position of transition camera to player 21 and set it's destination to player's 1 position
movingCamera.transform.position = player2.position;
movingCameraDestination = player1.position;
//Disable player 1 camera and enable transition camera
cam2.enabled = false;
movingCamera.enabled = true;
}
}
//If transition camera is enabled and its destination is not Vector3.zero - move it
if(movingCameraDestination != Vector3.zero && movingCamera.enabled)
{
movingCamera.transform.position = Vector3.Lerp(movingCamera.transform.position, movingCameraDestination, speed * Time.deltaTime);
//If the distance between transition camera and it's destination is smaller or equal to threshold - snap it to destination position
if(Vector3.Distance(movingCamera.transform.position, movingCameraDestination) <= snapThreshold)
{
movingCamera.transform.position = movingCameraDestination;
}
//If transition camera reached it's destination set it's destination to Vector3.zero and disable it
if(movingCamera.transform.position == movingCameraDestination)
{
movingCameraDestination = Vector3.zero;
movingCamera.enabled = false;
}
}
}
Looking at help forums on Unity, I figured out quickly that the syntax I was looking at was really outdated (Same thing on here: Unity Doublejump in C#).
Here's the article I was talking about:
http://answers.unity3d.com/questions/753238/restrict-number-of-double-jumps.html
For instance, in the void Awake(), in the current version of Unity I'm using, it says that rigidbody2D.fixedAngle = true; was no longer supported, and I needed to use constraints on the gameObject I was trying to program (what axis should I use... the x,y or z?). After doing some editing and after looking up the error messages, I was able to change all of the rigidbody2D.velocity into the updated syntax, which was GetComponent ().velocity .
Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour {
public float speed = 6.0f;
//public float j
Transform groundCheck;
//private float overlapRadius = 0.2f;
public LayerMask whatisGround;
private bool grounded = false;
private bool jump = false;
public float jumpForce = 700f;
private bool doubleJump = false;
public int dJumpLimit = 5;
void Start()
{
groundCheck = transform.Find ("groundcheck");
PlayerPrefs.SetInt ("doublejumps", dJumpLimit);
}
void Update()
{
if (Input.GetKey(KeyCode.Space))
{
jump = true;
}
//perhaps put A and D here?
}
void FixedUpdate()
{
//to check if Mario is on the ground
//overlap collider replace Overlap Circle???
//overlap point??
//grounded = GetComponent<Rigidbody2D> ().OverlapCollision(groundCheck.position, overlapRadius, whatisGround);
if (grounded)
doubleJump = false;
if (dJumpLimit < 1)
doubleJump = true;
bool canJump = (grounded || !doubleJump);
if (jump && canJump) {
GetComponent<Rigidbody2D> ().velocity = new Vector2 (GetComponent<Rigidbody2D> ().velocity.x, 0);
GetComponent<Rigidbody2D> ().AddForce (new Vector2 (0, jumpForce));
if (!doubleJump && !grounded) {
doubleJump = true;
dJumpLimit--;
}
}
jump = false;
//code that will work with the limits?
//GetComponent<Rigidbody2D>().velocity = new Vector2(speed,GetComponent<Rigidbody2D>().velocity.y);
//this will make it stack?
//GetComponent<Rigidbody2D>().velocity = new Vector2(speed,GetComponent<Rigidbody2D>().velocity.x);
//GetComponent<Rigidbody2D>().velocity = new Vector2(speed,GetComponent<Rigidbody2D>().velocity.y);
}
}
Good thing is that it was able to compile in the end. But I still don't know how the constraints work (they resist motion on the x,y,z axis right?). The jumps still don't have a capstone, and the variable dJumpLimit doesn't seem to stop all the jumping! I had also lot of trouble trying to decipher what the booleans were trying to accomplish, and it would help a lot if you tell me what the outdated code was trying to do, and what I failed doing so. That would help me a lot.Thanks so much for helping!!!
I have added the same code with some additional comments to help you.
The basic idea is to allow jumping under certain conditions, and allow double jumping under certain other conditions,
Try to think about it logically, Mario can only jump when he is on the ground, so we need to check that every frame. If he is grounded, and the player presses space, we make him jump.
Now, we want Mario to be able to double-jump but only if he is already in the air (otherwise it's just a regular jump) and only if he has not already double-jumped in this "current" jump.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour {
public float speed = 6.0f;
//public float j
Transform groundCheck; // For checking if grounded
//private float overlapRadius = 0.2f; // For checking if grounded
public LayerMask whatisGround; // A layer mask to distinguish what is considered as ground
private bool grounded = false; // True when Mario is touching ground
private bool jump = false; // Flag to check when player intends to jump
public float jumpForce = 700f; // How much force we will apply to our jump
private bool doubleJump = false; // This becomes true once we have double-jumped
public int dJumpLimit = 5; // A limit to prevent too many jumps happening
void Start()
{
// Find the Transform called "groundcheck"
groundCheck = transform.Find ("groundcheck");
// Set the PlayerPrefs integer called "doublejumps" to the value of dJumpLimit
PlayerPrefs.SetInt ("doublejumps", dJumpLimit);
}
void Update()
{
// If Space is being pressed...
if (Input.GetKey(KeyCode.Space))
{
jump = true; // Set jump bool to true to indicate our intention to jump
}
//perhaps put A and D here?
}
void FixedUpdate()
{
//to check if Mario is on the ground - this is necessary so we can't jump forever
//overlap collider replace Overlap Circle???
//overlap point??
//grounded = GetComponent<Rigidbody2D> ().OverlapCollision(groundCheck.position, overlapRadius, whatisGround);
// If Mario is touching ground...
if (grounded)
doubleJump = false; // Make sure that as we are grounded we are not allowed to "jump again"
if (dJumpLimit < 1)
doubleJump = true;
// Set a new bool to true if grounded is true OR doubleJump is false
bool canJump = (grounded || !doubleJump);
// If the player pressed space AND we are allowed to jump...
if (jump && canJump) {
// Apply existing x velocity to the x direction
GetComponent<Rigidbody2D> ().velocity = new Vector2 (GetComponent<Rigidbody2D> ().velocity.x, 0);
// Apply our jump force to the y direction
GetComponent<Rigidbody2D> ().AddForce (new Vector2 (0, jumpForce));
// If doubleJump is false AND we are not grounded...
if (!doubleJump && !grounded) {
doubleJump = true; // We have double jumped so set to true
dJumpLimit--; // Decrement one from dJumpLimit
}
}
jump = false; // Reset the jump bool to false
//code that will work with the limits?
//GetComponent<Rigidbody2D>().velocity = new Vector2(speed,GetComponent<Rigidbody2D>().velocity.y);
//this will make it stack?
//GetComponent<Rigidbody2D>().velocity = new Vector2(speed,GetComponent<Rigidbody2D>().velocity.x);
//GetComponent<Rigidbody2D>().velocity = new Vector2(speed,GetComponent<Rigidbody2D>().velocity.y);
}
}
I would like to make a smooth jump towards the nearest cube. I already have a script to detect the closest cube. I want that the X-axis is locked, so only the Y-axis and the Z-axis change when jumping. I would like to use a Jump animation when jumping. I already tried to use Vector3MoveTowards, but that didn't really work well, maybe I didn't use it properly.
Detect nearest cube where the player should jump to (C#)
void Update()
{
FindClosestCube ();
GameObject closestCube = FindClosestCube ();
Debug.Log (closestCube);
}
GameObject FindClosestCube() {
GameObject[] gos;
gos = GameObject.FindGameObjectsWithTag("cube");
GameObject closest = null;
float distance = Mathf.Infinity;
float position = transform.position.z;
foreach (GameObject go in gos) {
float diff = go.transform.position.z - position;
float curDistance = diff;
if (curDistance < distance) {
closest = go;
distance = curDistance;
}
}
return closest;
}
The tricky part is that at some cubes you have to jump up (y+1), with some cubes you jump towards the same Y (y+0) and with some cubes you jump down (y-1).
How do I do this?
Image of how it looks like:
EDIT: I have this code right now:
----------------C#-----------------
Rigidbody rb;
public int clicks = 0;
Vector3 target;
public Animation jumpAnimation;
bool jump = false;
float cubeDiffY;
bool movePlayer;
public float smoothTime = 0.3f;
public float yVelocity = 0.0f;
void Start()
{
rb = GetComponent<Rigidbody> ();
}
void Update ()
{
FindClosestCube ();
GameObject closestCube = FindClosestCube ();
Debug.Log ("Closestcube = " + closestCube);
target = closestCube.transform.position + new Vector3 (0f, 0.7f, 0f);
cubeDiffY = target.y - transform.position.y;
movePlayer = true;
Debug.Log("Cube Difference Y-axis = " + Mathf.Round(cubeDiffY));
if (Input.GetMouseButtonDown (0))
{
clicks += 1;
jump = true;
jumpAnimation = gameObject.GetComponent<Animation>();
//jumpAnimation.Play ();
}
if (jump == true)
{
Jump ();
}
}
void Jump()
{
float newPosition = Mathf.SmoothDamp (transform.position.y, target.y, ref yVelocity, smoothTime);
transform.position = new Vector3 (0, newPosition, transform.position.z);
}
I calculated the difference in Y-axis between the cube where the player is standing on and the closestCube. But the Jump() doesn't work. How do I fix that?
Okay I set up a quick version of your game and got what you wanted to work, it is not exactly a quick solution, because what your doing doesn't have built in functionality for other than using animations.
Here is the character script that has all the code you need and commented thoroughly so it should explain itself.
using UnityEngine;
public class Character : MonoBehaviour
{
//the collider for the player
private new BoxCollider collider;
//the jump box collider on a empty game object that is a child to the player object
public BoxCollider JumpBox;
//the offset of the cube so it doesn't stop inside of it
public Vector3 cubeOffset;
//how high the jump will be
public float JumpHeight;
//how fast the jump will be
public float JumpSpeed;
//holds the change in position the jump will produce
private Vector3 jumpDelta;
//holds the destination cube the jump is attempting to hit
private Cube destinationCube;
//true if a jumping animation is currently playing
private bool jumping = false;
//used to swap the jump direction from up to down
private bool jumpDirection = true;
//used to hold the position of the jump so it knows when to stop
private float jumpPosition = 0;
// Use this for initialization
void Start()
{
collider = GetComponent<BoxCollider>();
}
// Update is called once per frame
void Update()
{
if(jumping)
{
//move straight towards the cube
transform.position = transform.position + (JumpSpeed * jumpDelta);
//move up and down to simulate a jump
//check the current move direction
if (jumpDirection)
{
//add to the jump position twice product of the JumpHeight the JumpSpeed so that it will
//rise and fall the same amount of time it takes to move to the destination
jumpPosition += JumpHeight * JumpSpeed * 2;
//if it has passed the jump height reverse the jump direction
if (jumpPosition >= JumpHeight)
jumpDirection = !jumpDirection;
transform.position += transform.up * JumpHeight * JumpSpeed * 2;
}
//the jump direction is going down
else
{
jumpPosition -= JumpHeight * JumpSpeed * 2;
transform.position -= transform.up * JumpHeight * JumpSpeed * 2;
}
//check if the character collider intersects witht he cubes collider
//if it has then stop jumping and set the final position as the destination position
if (collider.bounds.Intersects(destinationCube.BoxCollider.bounds))
{
jumping = false;
transform.position = destinationCube.transform.position + cubeOffset;
}
}
//detect a jump
if (Input.GetKeyDown(KeyCode.Space))
{
//detect all hits on the jump box
Collider[] hits = Physics.OverlapBox(JumpBox.center, JumpBox.size * 0.5f);
//get the closest collider with the right tag
Collider result = GetClosestColliderWithTag(hits, "Cube");
//if we have a result then begin the jumping animation
if(result != null)
{
//gets the destination cubes cube component(the custom class you have on your cubes)
destinationCube = result.gameObject.GetComponent<Cube>();
//calculate the jump delta
jumpDelta = (result.transform.position + cubeOffset) - transform.position;
//remove the left and right components so the jumping doesnt move to the left or right of the player
Vector3 component = Vector3.Project(jumpDelta, -transform.right);
jumpDelta -= component;
component = Vector3.Project(jumpDelta, transform.right);
jumpDelta -= component;
//setup the jump animation control fields to the initial values
jumpPosition = 0;
jumpDirection = true;
jumping = true;
}
}
}
private Collider GetClosestColliderWithTag(Collider[] colliders, string tag)
{
//just gets the closest collider
float distance = float.MaxValue;
int result = -1;
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].tag == tag)
{
float distanceTemp = Vector3.Distance(transform.position, colliders[i].transform.position);
if (distanceTemp < distance)
{
distance = distanceTemp;
result = i;
}
}
}
if (result != -1)
return colliders[result];
else return null;
}
}
And here is my cube script which has some things you will need to add
using UnityEngine;
public class Cube : MonoBehaviour {
//these arent important just fields I used to set up a quick version of your game
public GameObject StartPoint;
public GameObject EndPoint;
public float Speed;
private Vector3 directionVector;
private bool direction;
//YOU WILL NEED THIS!!
[HideInInspector]
public BoxCollider BoxCollider;
// Use this for initialization
void Start() {
//not important
directionVector = EndPoint.transform.position - StartPoint.transform.position;
directionVector.Normalize();
//DONT FORGET TO SET YOUR BOX COLLIDER
BoxCollider = GetComponent<BoxCollider>();
}
// Update is called once per frame
void Update()
{
float distance = 0;
if (direction)
{
distance = Vector3.Distance(EndPoint.transform.position, transform.position);
transform.position += directionVector * Speed;
if (distance < Vector3.Distance(EndPoint.transform.position, transform.position))
direction = !direction;
}
else
{
distance = Vector3.Distance(StartPoint.transform.position, transform.position);
transform.position -= directionVector * Speed;
if (distance < Vector3.Distance(StartPoint.transform.position, transform.position))
direction = !direction;
}
}
}
Previous Answer
I would say you need to calculate the perceived position of the object in the future.
Vector3 futurePos = cubePos + (cubeMoveDirection * cubeMoveSpeed);
Once you have the future position, even if it is not exact, you should aim your animation towards that position. To do this I would have the animation change a speed vector instead of an actual transforms position that way we can rotate this speed vector in any direction you want while keeping the orientation of the block. Otherwise you have to rotate the entire block to point towards the direction you want. If this is what you want then put your block under a empty gameobject, rotate the empty gameobject to point to where you want and do the speed calculations only.
Next your animation should have a net move vector which should be pre-calculated and scaled down or up to meet the distance to the future position. It will look something like this(note this is not tested)
//class fields
Vector3 AnimatedSpeed;
Vector3 AnimationDelta;
//basic calculation
//get the direction vector from the players current position to the future
block position
Vector3 dirVector = futurePos - transform.position;
//find the rotation from the current orientation to the direction vector
Quaternion rotation = Quaternion.FromToRotation(transform.forward, dirVector);
//calculate the distance from you to the cube and scale it with the magnitude of the AnimationDelta
float result = Vector3.Distance(transform.position, futurePos);
result = result / animationDelta.magnitude;
//finally rotate the forward vector by the rotation and multiply it by the
//animation speed and the result to get the step by step movement as
//the animation plays. NOTE: The animation should be based on forward direction
transform.position += (AnimationSpeed * rotation) * result * Time.deltaTime;
Hopefully this does it, like I said I haven't tested it at all so you may have to do some tweaking based on your particular case as this is essentially psuedo-code.
Good luck! I'm off to bed I'll check back when I wake up.
I am trying to achieve basic racing game. Infinite racing game, movement method like a subway surfers. I have a problem about changing lane. I dont want to teleport to other lane, I want to smoothly. I am newbee in unity, I have try Lerp method but it is not working.
using UnityEngine;
using System.Collections;
public class VehicleController : MonoBehaviour
{
public float drift;
public Vector3 positionA;
public Vector3 positionB;
public Vector3 positionC;
public Vector3 positionD;
private Transform tf;
private Rigidbody rb;
private Vector3 vehiclePos;
void Awake()
{
//rb = GetComponent<Rigidbody> ();
tf = transform;
}
void Update()
{
vehiclePos = tf.position;
if (Input.GetKey( KeyCode.Space ))
DecreaseSpeed ();
else
IncreaseSpeed ();
if (Input.GetKeyDown (KeyCode.A))
{
MoveToRight ();
Debug.Log( "Move to Right!" );
}
if (Input.GetKeyDown (KeyCode.D))
{
MoveToLeft ();
Debug.Log( "Move to Left!" );
}
}
void FixedUpdate()
{
tf.Translate (Vector3.forward * speed * Time.deltaTime);//My Movement Method.
}
void MoveToLeft()
{
if (vehiclePos.position.x == positionA.x)
vehiclePos = Vector3.Lerp (vehiclePos.position, positionB, Time.deltaTime * drift);
}
void MoveToRight()
{
if (vehiclePos.position.x == positionB.x)
vehiclePos = Vector3.Lerp (vehiclePos.position, positionA, Time.deltaTime * drift);
}
}
First: Don't use == for position.x, since it's a floating-point (decimals) value and in this case it would be very rare for it to return "true". Here's some info about comparing floats.
Second: It doesn't look like you're connecting your actual position with vehiclePos anywhere. transform.position is what you want there.
Third: Input.GetAxis() is a cleaner way to deal with direction input. Instead of specifically calling out each button you can deal with just one float value between -1 and 1. It will also let you reconfigure the keys easily.
Fourth: In an infinite runner it is better to have the world move towards your character and camera than to have the character and camera actually move forward. Floating point numbers get less precise as you move further away from zero, so you should have your action take place relatively close to the world origin (0,0,0) point if you can.
If you want to press the button once to change lanes, you should keep an integer variable that saves which lane you're currently in. If you press LEFT you subtract one, and if you press RIGHT you add one. You should also add a check to make sure it stays within the desired range.
Then in Update() you just need to ALWAYS Lerp towards that X value. You can use Mathf.Lerp to lerp only one variable at a time if you want.
public int laneNumber = 0;
public int lanesCount = 4;
bool didChangeLastFrame = false;
public float laneDistance = 2;
public float firstLaneXPos = 0;
public float deadZone = 0.1f;
public float sideSpeed = 5;
void Update() {
//"Horizontal" is a default input axis set to arrow keys and A/D
//We want to check whether it is less than the deadZone instead of whether it's equal to zero
float input = Input.GetAxis("Horizontal");
if(Mathf.Abs(input) > deadZone) {
if(!didChangeLastFrame) {
didChangeLastFrame = true; //Prevent overshooting lanes
laneNumber += Mathf.roundToInt(Mathf.Sign(input));
if(laneNumber < 0) laneNumber = 0;
else if(laneNumber >= lanesCount) laneNumber = lanesCount - 1;
}
} else {
didChangeLastFrame = false;
//The user hasn't pressed a direction this frame, so allow changing directions next frame.
}
Vector3 pos = transform.position;
pos.x = Mathf.Lerp(pos.x, firstLandXPos + laneDistance * laneNumber, Time.deltaTime * sideSpeed);
transform.position = pos;
}
You could likely just use this code as-is, but I suggest you look it over and try to figure out an understanding of how and why it works. A newbie today who always seeks to improve their skill can do something amazing next week. Hope this helps. :)
Hi there fellow Overflowers!
I have recently dived into C# in Unity, because I believe that it has more functionality than UnityScript, and I come from a C++ background. Referencing some code from a 2D script in the Sample Assets, I have tried to create my own. The code is below:
using UnityEngine;
public class PlayerControl : MonoBehaviour {
//Variables
[HideInInspector]
public bool facingForward = true; //for Flip() Function
bool isGround = true; //for Grounded() Function
public float maxSpeed = 5.0f; //Terminal sideways velocity
public float HorizonAxis; //Checks for a/d movement
public float jumpFloat = 1000.0f; //Modular, use Unity Editor
public float moveFloat = 400.0f; // " "
void Start() {
//transform.position(0,0,0);
}
void Flip() {
facingForward = !facingForward; //switches boolean
Vector3 theScale = transform.localScale; //assigns vector to localscale of Player
theScale.x *= -1; //if x = 1, position becomes -1 and thus flips
transform.localScale = theScale; //reassigns the localscale to update theScale
}
bool Grounded() {
if (transform.position.y > 1) { //if position of gameObject is greater that 1, not grounded
isGround = false;
} else {
isGround = true;
}
return isGround; //function returns true or false for isGround
}
void Update() {
HorizonAxis = /*UnityEngine.*/Input.GetAxis ("Horizontal"); //assigns HorizonAxis to a/d movement from UnityEngine.Input
if (HorizonAxis * rigidbody2D.velocity.x > maxSpeed) { // if Input a/d by current x velocity of gameObject is greater than maxSpeed
rigidbody2D.velocity = new Vector2 (Mathf.Sign (rigidbody2D.velocity.x) * maxSpeed, rigidbody2D.velocity.y); //1 or -1 times the max speed, depending on direction
}
else if (HorizonAxis * rigidbody2D.velocity.x < maxSpeed) { //if Input a/d is less than terminal velocity
rigidbody2D.AddForce(Vector2.right * HorizonAxis * moveFloat); //add force to the right equivilant to Input by scalar moveFloat
}
if (Input.GetButtonDown ("Jump")) { //If Space
if(isGround) { //and isGround returns true
rigidbody2D.AddForce(new Vector2(0.0f, jumpFloat)); //add upwards force to bottom of rigidbody2D
isGround = false; //Resets isGround value
}
}
if (HorizonAxis > 0 && !facingForward) {//if UnityEngine.Input is to the right and facing left
Flip (); //execute
}
else if (HorizonAxis < 0 && facingForward) { //else
Flip (); //execute
}
}
}
Unfortunately, the code just doesn't work. I get no compile errors, but any Input does not effect the current position of the character. Should I be using transform.Translate to change the position, or stick with AddForce to a Vector2 until the character hits a maxSpeed?
Thanks heaps :)
I (kinda) fixed the jerky jumping issue, basically you look for the input in the Update() function which switches a Bool in FixedUpdate()
void Update () {
if (Input.GetKeyDown (KeyCode.Space) && playerGrounded) {
playerJumped = true;
}
}
Then in FixedUpdate() I looked for this Bool and did my AddForce
void FixedUpdate () {
if (playerJumped) {
playerJumped = false;
rigidbody2D.AddForce (new Vector2 (0, jumpForce),ForceMode2D.Impulse);
playerGrounded = false;
}
}
Setting playerJumped to false makes sure it doesn't run several times and the player can't jump again because I also set the grounded to false. grounded gets set back to true when the player collides with things tagged "ground".
I'm still new to Unity and C# overall so I can't guarantee this is the best (or even a good) way. Hope I could help somehow though ;)