Adding force to LineRenderer relative to the length of the line? - c#

I've lurked around here for ages and found a lot of help through other people's questions. But after extensive searching, I couldn't find a post to help me find a solution to a problem that I'm having, so I decided to post my own question here so if it gets answered, it might help someone else in a similar fashion!
I'm having some issues with adding force to my linerenderer. The basic idea is that I have an object that I shoot forward by dragging a line in the opposite direction. Now all that is missing is for the shot to have force that is relative to the length of the "dragline", as in how "strong" the object is pulled. I'm having some trouble with that so I thought I'd ask someone smarter and more experienced than me!
Here is my script to draw the dragline:
public class DragIndicatorScript : MonoBehaviour
{
Vector3 startPos;
Vector3 endPos;
Camera camera;
LineRenderer lineRenderer;
Vector3 camOffset = new Vector3(0, 0, 10);
[SerializeField] AnimationCurve animCurve;
// Start is called before the first frame update
void Start()
{
camera = Camera.main;
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (lineRenderer == null)
{
lineRenderer = gameObject.AddComponent<LineRenderer>();
}
lineRenderer.enabled = true;
lineRenderer.positionCount = 2;
startPos = camera.ScreenToWorldPoint(Input.mousePosition) + camOffset;
lineRenderer.SetPosition(0, startPos);
lineRenderer.useWorldSpace = true;
lineRenderer.widthCurve = animCurve;
lineRenderer.numCapVertices = 10;
lineRenderer.material = new Material(Shader.Find("Hidden/Internal-Colored"));
lineRenderer.startColor = Color.magenta;
lineRenderer.endColor = Color.cyan;
}
if (Input.GetMouseButton(0))
{
endPos = camera.ScreenToWorldPoint(Input.mousePosition) + camOffset;
lineRenderer.SetPosition(1, endPos);
}
if (Input.GetMouseButtonUp(0))
{
lineRenderer.enabled = false;
}
}
}
and here is my script to control the shooting of the object:
public class Shoot : MonoBehaviour
{
Rigidbody2D rigidigidy;
Vector2 startpos;
Vector2 endpos;
[SerializeField] float power = 10f;
void Start()
{
rigidigidy = GetComponent<Rigidbody2D>();
}
void Update()
{
if (Input.GetMouseButtonUp(0))
{
endpos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Launch();
}
}
void OnMouseDown()
{
startpos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
void Launch()
{
Vector2 direction = (startpos - endpos).normalized;
rigidigidy.AddForce(direction * power, ForceMode2D.Impulse);
}
}
Thanks in advance! I have used Google for hours on end and written several lines of code and I feel like I just can't find what I'm looking for.
EXTRA QUESTION 1)
How do I clamp the linerenderer to always be where the pullable object is? I wish to make it so that the player can drag anywhere on the playable area, but the linerenderer always instantiates on the object in question (it is always the same object, as in it is the "player model").
EXTRA QUESTION 2)
I know how to change the material of the linerenderer inside the script, but I haven't really found a proper way to call the material from my assets (I made a material that I would like to use as the dragline), so as a placeholder I am just using:
Material(Shader.Find("Hidden/Internal-Colored"));
lineRenderer.startColor = Color.magenta;
lineRenderer.endColor = Color.cyan;
since I wanted to have something there that is even a little more pleasing to the eye than just the default pink one.

The main question is a bit unclear to me. You already have the startpos-endpos. Wouldn't this already be the vector including the magnitude you are looking for?
I would probably rather combine your two scripts and not let them handle input and positions independently.
I would let your Shoot handle the input and only forward it to the DragIndicatorScript since as the name suggests: It shall only be an indicator and should not be the component deciding the final shoot strength.
So the Shoot should rather calculate the input vector, clamp it and only pass this to the indicator which then can update its end position based on the anchor (see below) and the vector.
EXTRA QUESTION 1:
I would simply remember the offset between the anchor and the startPos. Then you can later calculate back the endPoint by simply taking this offset into account.
For being able to drag anywhere on the screen you should not use OnMouseDown which only works if the mouse is actually over your collider but rather go the way you did in DragIndicatorScript and use GetMouseButtonDown(0).
It sounds like you additionally also want a maximum length for the line and use this maximum length also as maximum shoot power. One argument more as said before why I would let shoot control it all.
EXTRA QUESTION 2:
You can simply reference your material in a slot in the Inspector. In general however I would suggest to rather add the LineRenderer already beforehand and completely set it up. Then you don't even need to do it via code!
So it might look somewhat like
public class Shoot : MonoBehaviour
{
[SerializeField] private DragIndicatorScript _dragIndicator;
[SerializeField] private Rigidbody2D _rigidBody;
[SerializeField] private float power = 10f;
[SerializeField] private Camera _camera;
// This script should clamp the input
[SerializeField] private float maxLength;
private Vector2 inputStartPosition;
private void Awake()
{
if(!_rigidBody) _rigidBody = GetComponent<Rigidbody2D>();
if(!_camera) _camera = Camera.main;
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
// store the initial input position
inputStartPosition = camera.ScreenToWorldPoint(Input.mousePosition);
// Enable the indicator and for now set the endpoint also on the anchor since there wasn't any input yet
_dragIndicator.SetIndicator(Vector2.zero);
}
if (Input.GetMouseButton(0))
{
// Get the current position
Vector2 inputCurrentPosition = camera.ScreenToWorldPoint(Input.mousePosition);
// Get the input delta between the current and initial position
var input = inputCurrentPosition - inputStartPosition;
// Now clamp this vector to the max length
input = Vector2.ClampMagnitude(input, maxLength);
_dragIndicator.SetIndicator(input);
}
if (Input.GetMouseButtonUp(0))
{
// Just to be sure recalculate from the current position
Vector2 inputCurrentPosition = camera.ScreenToWorldPoint(Input.mousePosition);
var input = inputCurrentPosition - inputStartPosition;
// Now clamp this to the max length
input = Vector2.ClampMagnitude(input, maxLength);
_dragIndicator.HideIndicator();
// Directly pass in the final input vector, this way you don't need to store it in a field
Launch(input);
}
}
private void Launch(Vector2 input)
{
// Input already contains the direction and magnitude of the user input
_rigidBody.AddForce(-input * power, ForceMode2D.Impulse);
}
}
and the DragIndicatorScript only receives these commands:
public class DragIndicatorScript : MonoBehaviour
{
[SerializeField] private LineRenderer _lineRenderer;
// For the EXTRA QUESTION 1
[SerializeField] private Transform _lineAnchor;
// For EXTRA QUESTION 2
[SerializeField] private Material _lineMaterial;
[SerializeField] private AnimationCurve animCurve;
private void Awake()
{
if(!TryGetComponent<LineRenderer>(out _lineRenderer))
{
_lineRenderer = gameObject.AddComponent<LineRenderer>();
}
// Setup your Line ONCE
_lineRenderer.positionCount = 2;
_lineRenderer.useWorldSpace = true;
_lineRenderer.widthCurve = animCurve;
_lineRenderer.numCapVertices = 10;
_lineRenderer.material = _lineMaterial;
_lineRenderer.startColor = Color.magenta;
_lineRenderer.endColor = Color.cyan;
_lineRenderer.SetPosition(0, _lineAnchor.position);
_lineRenderer.enabled = false;
}
public void HideIndicator()
{
_lineRenderer.enabled = false;
}
public void SetIndicator(Vector3 input)
{
lineRenderer.SetPosition(1, _lineAnchor.position + input);
_lineRenderer.enabled = true;
}
}

Related

EnemyAI script not moving the Enemy

I am making my first foray into AI, specifically AI that will follow the player.
I am using the A* Path finding project scripts, but used the Brackeys tutorial for the code
https://www.youtube.com/watch?v=jvtFUfJ6CP8
Source in case needed.
Here's the code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;
public class EnemyAI : MonoBehaviour
{
public Transform Target;
public float speed = 200f;
public float NextWayPointDistance = 3f;
Path path;
int currentWaypoint = 0;
bool ReachedEndOfpath = false;
Seeker seeker;
Rigidbody2D rb;
public Transform EnemyGraphics;
// Start is called before the first frame update
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
InvokeRepeating("UpdatePath", 0f, 1f);
}
void UpdatePath()
{
if (seeker.IsDone())
seeker.StartPath(rb.position, Target.position, OnPathComplete);
}
void OnPathComplete(Path p)
{
if (!p.error)
{
path = p;
currentWaypoint = 0;
}
}
// Update is called once per frame
void fixedUpdate()
{
if(path == null)
return;
if(currentWaypoint >= path.vectorPath.Count)
{
ReachedEndOfpath = true;
return;
}
else
{
ReachedEndOfpath = false;
}
Vector2 Direction = ((Vector2)path.vectorPath[currentWaypoint] - rb.position).normalized;
Vector2 Force = Direction * speed * Time.fixedDeltaTime;
rb.AddForce(Force);
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if(distance < NextWayPointDistance)
{
currentWaypoint++;
}
if(rb.velocity.x >= 0.01f)
{
EnemyGraphics.localScale = new Vector3(-1f, 1f, 1f);
}else if(rb.velocity.x <= 0.01f)
{
EnemyGraphics.localScale = new Vector3(1f, 1f, 1f);
}
}
}
How I tried to fix the issue:
I thought it could've been a problem with the speed so I increased it to 10000000, and still nothing
Next I thought it was a problem with the Rigidbody2d so I check there, found the gravity scale was set at 0, so I increased it to 1. It made my enemy fall to the ground but still no movement.
I thought it could've been a problem with the mass and drag, so I set Linear drag and Angular drag to 0, and also set mass to 1. Still nothing.
I set the body type to kinematic, pressed run, nothing. Set the body type to static, pressed run, nothing. Set the body type to Dynamic, pressed run, still nothing.
I tried to make a new target for the enemy to follow, dragged the empty game object i nto the target, pressed run and still didn't move.
I am at a loss on how to fix this.
Please help?
Looks like maybe a typo? You have:
// Update is called once per frame
void fixedUpdate()
{
but the method is called FixedUpdate(), with a big F in front. You have fixedUpdate, which is NOT the same.

ROBLOX Like Camera Controls C#

I have looked over the internet for a Camera Script like the one in ROBLOX. But i can't seem to find one. Can anyone help me with this?
Btw i'm using Unity 2017.3
Welcome to Stack Overflow.
I will try to help you out. Please keep in mind though:
Generally questions like this will receive negative feedback as the question isn't specific enough and you haven't provided any attempts or code for us to work with.
People sometimes see this as a "can you do my work for me" scenario.
You are new so I want to take a stab at helping you out regardless.
I hope this helps you and potentially others.
I've included code comments for clarity.
TO USE THIS YOU MUST
create a new script in unity (C#) and attach it to your 'Player' GameObject
edit the script, and paste the below code into the editor
save the script and return to the editor, new settings will appear for the script
modify the settings to your liking and DRAG in the camera to the "The Camera" field
[Edit]
Probably worth mentioning, I also added a pause function to unlock the cursor and return control to the mouse, this can be built upon or removed as needed.
The script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThirdPersonCamera : MonoBehaviour {
//define some constants
private const float LOW_LIMIT = 0.0f;
private const float HIGH_LIMIT = 85.0f;
//these will be available in the editor
public GameObject theCamera;
public float followDistance = 5.0f;
public float mouseSensitivityX = 4.0f;
public float mouseSensitivityY = 2.0f;
public float heightOffset = 0.5f;
//private variables are hidden in editor
private bool isPaused = false;
// Use this for initialization
void Start () {
//place the camera and set the forward vector to match player
theCamera.transform.forward = gameObject.transform.forward;
//hide the cursor and lock the cursor to center
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update () {
//if escape key (default) is pressed, pause the game (feel free to change this)
if (Input.GetButton("Cancel"))
{
//flip the isPaused state, hide/unhide the cursor, flip the lock state
isPaused = !isPaused;
Cursor.visible = !Cursor.visible;
Cursor.lockState = Cursor.lockState == CursorLockMode.Locked ?
CursorLockMode.None : CursorLockMode.Locked;
System.Threading.Thread.Sleep(200);
}
if(!isPaused)
{
//if we are not paused, get the mouse movement and adjust the camera
//position and rotation to reflect this movement around player
Vector2 cameraMovement = new Vector2(Input.GetAxis("Mouse X"),Input.GetAxis("Mouse Y"));
//first we place the camera at the position of the player + height offset
theCamera.transform.position = gameObject.transform.position + new Vector3(0,heightOffset,0);
//next we adjust the rotation based on the captured mouse movement
//we clamp the pitch (X angle) of the camera to avoid flipping
//we also adjust the values to account for mouse sensitivity settings
theCamera.transform.eulerAngles = new Vector3(
Mathf.Clamp(theCamera.transform.eulerAngles.x + cameraMovement.y * mouseSensitivityY, LOW_LIMIT, HIGH_LIMIT),
theCamera.transform.eulerAngles.y + cameraMovement.x * mouseSensitivityX, 0);
//then we move out to the desired follow distance
theCamera.transform.position -= theCamera.transform.forward * followDistance;
}
}
}
This may be inactive, but here is one that moves on right click:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCamera : MonoBehaviour
{
private const float LOW_LIMIT = 0.0f;
private const float HIGH_LIMIT = 85.0f;
public GameObject theCamera;
public float followDistance = 5.0f;
public float mouseSensitivityX = 4.0f;
public float mouseSensitivityY = 2.0f;
public float heightOffset = 0.5f;
void Start()
{
theCamera.transform.forward = gameObject.transform.forward;
Cursor.visible = true;
Cursor.lockState = CursorLockMode.None;
}
void Update()
{
if (Input.GetMouseButton(1))
{
Vector2 cameraMovement = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
theCamera.transform.position = gameObject.transform.position + new Vector3(0, heightOffset, 0);
theCamera.transform.eulerAngles = new Vector3(
Mathf.Clamp(theCamera.transform.eulerAngles.x + cameraMovement.y * mouseSensitivityY, LOW_LIMIT, HIGH_LIMIT),
theCamera.transform.eulerAngles.y + cameraMovement.x * mouseSensitivityX, 0);
theCamera.transform.position -= theCamera.transform.forward * followDistance;
}
}
}

Switching between two or more cameras unity3D

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;
}
}
}

Unity 5 - edit the camera2DFollow script

I'm using the standard camera2DFollow script that comes with Unity 5. But I have a problem with the position of the camera. I've rotated my main camera and it looks like this now.
You see that my player is on top of the screen instead of the middle.
This is the default script in C# for the people who don't have it.
using System;
using UnityEngine;
namespace UnityStandardAssets._2D
{
public class Camera2DFollow : MonoBehaviour
{
public Transform target;
public float damping = 1;
public float lookAheadFactor = 3;
public float lookAheadReturnSpeed = 0.5f;
public float lookAheadMoveThreshold = 0.1f;
private float m_OffsetZ;
private Vector3 m_LastTargetPosition;
private Vector3 m_CurrentVelocity;
private Vector3 m_LookAheadPos;
// Use this for initialization
private void Start()
{
m_LastTargetPosition = target.position;
m_OffsetZ = (transform.position - target.position).z;
transform.parent = null;
}
// Update is called once per frame
private void Update()
{
// only update lookahead pos if accelerating or changed direction
float xMoveDelta = (target.position - m_LastTargetPosition).x;
bool updateLookAheadTarget = Mathf.Abs(xMoveDelta) > lookAheadMoveThreshold;
if (updateLookAheadTarget)
{
m_LookAheadPos = lookAheadFactor*Vector3.right*Mathf.Sign(xMoveDelta);
}
else
{
m_LookAheadPos = Vector3.MoveTowards(m_LookAheadPos, Vector3.zero, Time.deltaTime*lookAheadReturnSpeed);
}
Vector3 aheadTargetPos = target.position + m_LookAheadPos + Vector3.forward*m_OffsetZ;
Vector3 newPos = Vector3.SmoothDamp(transform.position, aheadTargetPos, ref m_CurrentVelocity, damping);
transform.position = newPos;
m_LastTargetPosition = target.position;
}
}
}
I want to change the Y to a +3 of the current position. So if my camera is on Y 2 than put it on Y 5. (This makes it so the player is in the middle and not on the top).
Thanks for the help!
You can do this by adding 3 to the camera's position at the end of each frame but I recommend against it.
What I would do, is create an empty object, name it "PlayerCameraCenter" and make the player parent to this object; then place the camera center wherever you want relative to the player, like y = 3, and make the camera follow this object instead of the player.
This way you can easily change the position of the camera, through the editor without fiddling with code.

How to change lane smoothly

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. :)

Categories