Currently I am working on some player movements. The main idea of my player moves only horizontal and vertical, not diagonal. I couldn't find any reasonable solution for this problem. I really don't want to use rigidbody or character.controller for now. The other thing I want to achieve is, when I pressed multiple direction keys, I want my player move directly to last pressed direction. Here is my code:
using UnityEngine;
using System.Collections;
public class controller : MonoBehaviour {
public int movementspeed;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetKey (KeyCode.A)) {
//ratation
transform.localEulerAngles = new Vector3(0,270,0);
//move
transform.Translate (transform.right * movementspeed * Time.deltaTime);
}
else if(Input.GetKey (KeyCode.D)) {
//ratation
transform.localEulerAngles = new Vector3(0,90,0);
//move
transform.Translate (transform.right *(-1)* movementspeed * Time.deltaTime);
}
else if(Input.GetKey (KeyCode.S)) {
//ratation
transform.localEulerAngles = new Vector3(0,180,0);
//move
transform.Translate (transform.forward * (-1) * movementspeed * Time.deltaTime);
}
else if (Input.GetKey (KeyCode.W)) {
//ratation
transform.localEulerAngles = new Vector3(0,0,0);
//move
transform.Translate (transform.forward * movementspeed * Time.deltaTime);
}
else if (Input.GetKey (KeyCode.A)) {
//ratation
transform.localEulerAngles = new Vector3(0,270,0);
//move
transform.Translate (transform.right * movementspeed * Time.deltaTime);
}
}
}
The structure of your selection statement will not give you this functionality. As it will check the first if, then if false, it will check the next else if, and so on. So if I hold down A, no matter what I press, I will always only reach the A part of the code.
What I would do if I were you, is to add another layer on top of this. Only detect key down events, and set matching variables. When you set these, disable the others. Then use these variables for moving. Like this:
bool left, right, up, down;
void CheckInput() {
if (Input.GetKeyDown(KeyCode.W) {
up = true;
left = right = down = false;
}
if (Input.GetKeyDown(KeyCode.S) {
down = true;
left = right = up = false;
}
if (Input.GetKeyDown(KeyCode.A) {
left = true;
right = up = down = false;
}
if (Input.GetKeyDown(KeyCode.D) {
right= true;
left= up = down = false;
}
//And then do matching OnKeyUp events to set them false
}
void Update() {
CheckInput();
if (left)
//Move left
if (right)
//Move right
//etc.
}
Related
I only recently got into Unity, and I have made a character movement system; everything is working besides from sprinting. I have the user use "Left Shift" to sprint, although it seems sprinting never turns off. I'm not quite sure the reasoning as to why this happens or what part of code could be fixed to accommodate for this, as such, I have attached the source file of movement.
Here is the paste: https://pastebin.com/S1h5pEwq
In particular, this is the movement function:
void Movement()
{
Vector2 axis = new Vector2(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")) * walkSpeed;
Vector3 forward = new Vector3(-Camera.main.transform.right.z, 0.0f, Camera.main.transform.right.x);
Vector3 wishDirection = (forward * axis.x + Camera.main.transform.right * axis.y + Vector3.up * rb.velocity.y);
rb.velocity = wishDirection;
if (Input.GetKey(KeyCode.LeftShift))
{
isSprinting = true;
}
else
{
isSprinting = false;
}
if (isSprinting == true)
{
walkSpeed = 10.0f;
}
}
More specifically, my goal is to have Sprint be activated strictly while the key is pressed.
Try this:
void Movement()
{
Vector2 axis = new Vector2(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")) * walkSpeed;
Vector3 forward = new Vector3(-Camera.main.transform.right.z, 0.0f, Camera.main.transform.right.x);
Vector3 wishDirection = (forward * axis.x + Camera.main.transform.right * axis.y + Vector3.up * rb.velocity.y);
rb.velocity = wishDirection;
if (Input.GetKey(KeyCode.LeftShift))
{
isSprinting = true;
}
else
{
isSprinting = false;
}
if (isSprinting == true)
{
walkSpeed = 10.0f;
}
else
{
walkSpeed = 0.0f
}
}
The problem in your script was that you were not resetting the speed.
If(Input.GetKeyUp(KeyCode.LeftShift)){
isSprinting = false;
}
This will do, you didn't check when the player stopped pressing shift.
i've following issue. I'm trying to make game with top down view (something like first GTA game). The problem is when i press the key my player is moving, but can't stop. Here you can see my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovemenet : MonoBehaviour
{
private Rigidbody2D m_Rigidbody;
private Transform playerTransform;
public float m_Speed = 100.0f;
// Start is called before the first frame update
void Start()
{
m_Rigidbody = GetComponent<Rigidbody2D>();
playerTransform = GameObject.Find("Player").transform;
}
// Update is called once per frame
void FixedUpdate()
{
Vector3 playerPos = playerTransform.eulerAngles;
if (Input.GetKey(KeyCode.UpArrow))
{
m_Rigidbody.velocity= transform.up * Time.deltaTime * m_Speed;
}
if (Input.GetKey(KeyCode.DownArrow))
{
m_Rigidbody.velocity = transform.up * Time.deltaTime * (-m_Speed);
}
if (Input.GetKey(KeyCode.RightArrow))
{
transform.Rotate(0, 0, -1 * m_Speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.LeftArrow))
{
transform.Rotate(0, 0, 1 * m_Speed * Time.deltaTime);
}
}
}
'''
Can you please tell me how to fix it? Thanks for your answers.
Note that in general a velocity already is a value in absolute units per second and you don't want to multiply by Time.deltaTime in that case.
Also in general whenever dealing with Physics I wouldn't use transform at all but rather do everything via the Rigidbody.
And then simply when you don't press a key do
if (Input.GetKey(KeyCode.UpArrow))
{
m_Rigidbody.velocity = Quaternion.Euler(0, 0, m_Rigidbody.rotation) * Vector3.up * m_Speed;
}
else if (Input.GetKey(KeyCode.DownArrow))
{
m_Rigidbody.velocity = Quaternion.Euler(0, 0, m_Rigidbody.rotation) * Vector3.down * m_Speed;
}
else
{
m_Rigidbody.velocity = Vector2.zero;
}
For the rotation I would also rather go
m_Rigidbody.rotation += m_Speed * Time.deltaTime;
and
m_Rigidbody.rotation -= m_Speed * Time.deltaTime;
I am new to Unity so please be kind
So I want my character to move in the direction of the last key pressed. If I press W (up) and D (right) at the same time, the player will move in the direction of what came first. If I release that key and continue to hold the key that was pressed 2nd, the character doesn't change direction until you release said key and repress. This is ruining the feel of my game and I would like some help fixing this problem:)
Here is my character controller script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerController : MonoBehaviour
{
public float moveSpeed = 5f;
public Rigidbody2D rb;
public Animator anim;
Vector2 movement;
void Start()
{
anim = GetComponent<Animator>();
}
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal"); //gets axis as vector2
movement.y = Input.GetAxisRaw("Vertical");
anim.SetFloat("Horizontal", movement.x);
anim.SetFloat("Vertical", movement.y); //sets animation parameters
anim.SetFloat("Speed", movement.sqrMagnitude);
if (Input.GetAxisRaw("Horizontal") == 1 || Input.GetAxisRaw("Horizontal") == -1 || Input.GetAxisRaw("Vertical") == 1 || Input.GetAxisRaw("Vertical") == -1)
//If statement to set the correct idle animation (idle right, left, down) based off last direction.
{
anim.SetFloat("LastHorizontal", Input.GetAxisRaw("Horizontal"));
anim.SetFloat("LastVertical", Input.GetAxisRaw("Vertical"));
}
}
void FixedUpdate()
{
if (Mathf.Abs(movement.x) > Mathf.Abs(movement.y)) //if statement disables diagonal movement
{
movement.y = 0;
}
else
{
movement.x = 0;
}
rb.MovePosition(rb.position + movement.normalized * moveSpeed * Time.fixedDeltaTime); //applies movement to player
}
}
Instead of changing movement only on one axis in yout fixed update, I'd try forcing the direction vector for each key. So your code would look like this:
void FixedUpdate()
{
Vector3 movement = Vector3.zero
if (Input.GetKey(KeyCode.W))
{
movement.y = 1;
}
else if (Input.GetKey(KeyCode.S))
{
movement.y = -1;
}
else if (Input.GetKey(KeyCode.A))
{
movement.x = -1;
}
else if (Input.GetKey(KeyCode.D))
{
movement.x = 1;
}
else
{
movement = Vector3.zero
}
rb.MovePosition(rb.position + movement.normalized * moveSpeed * Time.fixedDeltaTime); //applies movement to player
}
The result of this should be your character not being able to move diagonaly
The base is a red cube.
The spaceship is moving already when the game start.
When I click/press the L button the spaceship rotates to face the base and starts moving to it but then when it's getting close to the base it's behaving unexpectedly and the spaceship starts rolling around the base nonstop.
What I want is to make the landing automatic like this youtube video of blender.
I don't want the graphics but the way it's landing.
Blender landing spaceship
And this is a short video clip showing my spaceship when it's start landing:
Landing test
This is the script i'm using for controlling the spaceship and the landing part should be automatic.
The script is attached to the spaceship.
using UnityEngine;
using System.Collections;
public class ControlShip : MonoBehaviour {
public int rotationSpeed = 75;
public int movementspeed = 10;
public int thrust = 10;
public float RotationSpeed = 5;
private bool isPKeyDown = false;
private float acceleration = .0f;
private Vector3 previousPosition = Vector3.zero;
private Rigidbody _rigidbody;
private bool landing = false;
private Vector3 originPosition;
private Vector3 lastPosition;
private const float minDistance = 0.2f;
private Transform baseTarget;
// Use this for initialization
void Start () {
baseTarget = GameObject.Find("Base").transform;
originPosition = transform.position;
_rigidbody = GetComponent<Rigidbody>();
Debug.Log("Acc Speed: " + thrust);
}
// Update is called once per frame
void Update()
{
if (landing == false)
{
var v3 = new Vector3(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0.0f);
transform.Rotate(v3 * rotationSpeed * Time.deltaTime);
transform.position += transform.forward * Time.deltaTime * movementspeed;
if (Input.GetKey(KeyCode.Z))
transform.Rotate(Vector3.forward * rotationSpeed * Time.deltaTime);
if (Input.GetKey(KeyCode.R))
transform.Rotate(Vector3.right * rotationSpeed * Time.deltaTime);
if (Input.GetKey(KeyCode.P))
{
isPKeyDown = Input.GetKey(KeyCode.P);
float distance = Vector3.Distance(previousPosition, transform.position);
acceleration = distance / Mathf.Pow(Time.deltaTime, 2);
previousPosition = transform.position;
_rigidbody.AddRelativeForce(0f, 0f, thrust, ForceMode.Acceleration);
}
}
else
{
transform.position += transform.forward * Time.deltaTime * movementspeed;
var targetRotation = Quaternion.LookRotation(baseTarget.position - transform.position);
var str = Mathf.Min(.5f * Time.deltaTime, 1);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, str);
}
if (landed == true)
TakeOff();
if (Input.GetKey(KeyCode.L))
{
landing = true;
lastPosition = transform.position;
}
}
void OnTriggerEnter(Collider other)
{
if (landing == true && other.gameObject.name == "Base")
{
StartCoroutine(Landed());
}
}
bool landed = false;
IEnumerator Landed()
{
yield return new WaitForSeconds(5);
Debug.Log("Landed");
landed = true;
}
private void TakeOff()
{
if (transform.position != originPosition)
{
_rigidbody.AddForce(transform.up * 10);
}
if ((transform.position - originPosition).sqrMagnitude <= (1f * 1f))
{
landed = false;
_rigidbody.useGravity = false;
}
}
void OnGUI()
{
if (isPKeyDown)
{
GUI.Label(new Rect(100, 100, 200, 200), "Acc Speed: " + acceleration);
}
}
}
This is the part of the landing, should be the part of the landing:
transform.position += transform.forward * Time.deltaTime * movementspeed;
var targetRotation = Quaternion.LookRotation(baseTarget.position - transform.position);
var str = Mathf.Min(.5f * Time.deltaTime, 1);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, str);
The spaceship have two components: Rigidbody, Use Gravity set to true. And a Box Collider.
The Base have a box collider component.
You appear to have a box collider on your vehicle and it looks as though it is colliding with the terrain when your code tries to bring it in for a landing. Try switching the collider to be a trigger(tick option on collider component).
Then try it again, as this will not cause physical collisions. If it works or fails for a totally different reason you know this is the cause or a contributing factor.
EDIT: It is worth also noting that when trying to achieve this kind of effect it can be much easier to trigger an animation than try to achieve it in physics based code. Unity offers some great animation controllers and you can call an animation when you need to land since you are taking control away from the player anyway.
While doing this you could turn off the collider so you don't get any strange collision then turn it on when the ship needs to take off, provided you need that of course.
Hope it helps.
I have the following script attached to my ball on a game:
public class MovePlayer : MonoBehaviour {
//public GameObject packman;
// Use this for initialization
private Vector3 currentSpeed;
void Start () {
currentSpeed = new Vector3(0.0f, 0.0f, 0.0f);
}
// Update is called once per frame
void Update () {
if (Input.GetKey(KeyCode.LeftArrow)){
currentSpeed.x = -(0.0001f);
}
else if (Input.GetKey(KeyCode.RightArrow))
{
currentSpeed.x = 0.0001f;
}
else currentSpeed.x = 0;
/*if (Input.GetKeyDown(KeyCode.UpArrow))
{
}*/
//move packman
this.transform.Translate(Time.deltaTime * currentSpeed.x, Time.deltaTime * currentSpeed.y,
Time.deltaTime * currentSpeed.z);
}
}
Then I touch left or right arrow on the game, and the ball moves really fast to one direction and never stops even if I touch the other arrow.
I found it is because I added "Physics -> character controller" to
the ball. Removing this component did the job. Why was character
controller producing the described effect? – Daniel Roca Lopez
It sounds like the Character Controller you had added accidentally, had pre-written values for how the Object behaved.
So on top of your MovePlayer script, you also got the Movement from CharacterController.
use FixedUpdate() like this
public class MovePlayer : MonoBehaviour {
//public GameObject packman;
// Use this for initialization
private Vector3 currentSpeed;
void Start () {
currentSpeed = new Vector3(0.0f, 0.0f, 0.0f);
}
// Update is called once every 1/60th second
void FixedUpdate () {
if (Input.GetKey(KeyCode.LeftArrow)){
currentSpeed.x = -(0.0001f);
}
else if (Input.GetKey(KeyCode.RightArrow))
{
currentSpeed.x = 0.0001f;
}
else currentSpeed.x = 0;
/*if (Input.GetKeyDown(KeyCode.UpArrow))
{
}*/
//move packman
this.transform.Translate(Time.deltaTime * currentSpeed.x, Time.deltaTime *
currentSpeed.y, Time.deltaTime * currentSpeed.z);
}
}