How can I make this unity movement script work? - c#

How can I make this script work, or another alternative player movement script? This basic movement script in Unity doesn't do anything when i press WASD for some reason. I am a beginner at C# and unity and I kind of need an alternative player movement script that actually works.
void Update()
{
if (Input.GetKeyDown(KeyCode.W))
transform.Translate(Vector3.forward);
if (Input.GetKeyDown(KeyCode.S))
transform.Translate(Vector3.back);
if (Input.GetKeyDown(KeyCode.A))
transform.Translate(Vector3.left);
if (Input.GetKeyDown(KeyCode.D))
transform.Translate(Vector3.right);

I recommend using the GetAxis("Horizontal") and GetAxis("Vertical") methods which maps wasd and arrow keys by default to help slim down your big if tree.
Below is a small example from an old unversity project of mine.
Note: the "* speed * Time.deltaTime" as this is used to help translate as time/frames move on, speed is just a multiplier in this case.
public float speed = 10.0f;
private float translation;
private float straffe;
// Use this for initialization
void Start()
{
// turn off the cursor
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
// Input.GetAxis() is used to get the user's input
// You can further set it on Unity. (Edit, Project Settings, Input)
translation = Input.GetAxis("Vertical") * speed * Time.deltaTime;
straffe = Input.GetAxis("Horizontal") * speed * Time.deltaTime;
transform.Translate(straffe, 0, translation);
if (Input.GetKeyDown("escape"))
{
// turn on the cursor
Cursor.lockState = CursorLockMode.None;
}
}

Input.GetKeyDown checks if you pressed the w key on that frame. You need Input.GetKey. That checks if you are holding

You should use GetAxis("Horizontal") & GetAxis("Vertical");
Here is my basic code for my projects default movement:
//movement
Rigidbody rb;
float xInput;
float yInput;
public float speed;
public float defSpeed;
public float sprint;
public bool isGrounded = true;
public float jump;
// Start is called before the first frame update
private void Awake()
{
rb = GetComponent<Rigidbody>();
}
void Start()
{
}
// Update is called once per frame
void Update()
{
xInput = Input.GetAxis("Horizontal");
yInput = Input.GetAxis("Vertical");
//Things is still can't understand
Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
float cameraRot = Camera.main.transform.rotation.eulerAngles.y;
rb.position += Quaternion.Euler(0, cameraRot, 0) * input * speed * Time.deltaTime;
//sprint
if (Input.GetKeyDown(KeyCode.LeftShift))
{
speed = sprint;
}
else if (Input.GetKeyUp(KeyCode.LeftShift))
{
speed = defSpeed;
}
//jump
if (Input.GetKeyDown(KeyCode.Space) && isGrounded == true)
{
rb.AddForce(0, jump, 0);
//Debug.Log("Jump!");
}
Hope this helps:)

Related

Unity: "NotImplementedException: The method or operation is not implemented". Animation logic within Unity

My problem is two-fold. Animation and a GameObject jumping off during Play. I don't know the exact phrases of what happens, I'll try to explain best I can.
I want to increase a float upon movement, which should trigger animation for my character. It is the SpeedBlend in image below. It's between 0 and 1.
The movement works fine and debugging works fine. But I cannot get the SpeedBlend to increase.
Here are the issues:
It says "NullReferenceException: Object reference not set to an instance of an object" when I press Play. I narrowed it down to the GameObject jumping off the public Animator when i press Play. I don't know the exact wording of what happens, but the "Animation (Animator)" is no longer attached to the Scripts' Animator. Does that make sense?
See below.
The "Animation (Animator)" jumps off on Play. If I declare the animator in Start function, it jumps off. If I don't declare it, it stays on during Play. See below.
private void Start()
{
Cursor.lockState = CursorLockMode.Locked;
controller = GetComponent<CharacterController>();
animator = GetComponentInChildren<Animator>();
}
If I re-apply the "Animation (Animator)" to the Scripts' Animator during Play, it changes the problem to
"NotImplementedException: The method or operation is not implemented."
My current solution for animating my character is:
//animation
if (direction != Vector3.zero)
{
animator.SetFloat("SpeedBlend", 0.5f);
Debug.Log("moving works fine");
}
The debugging works fine.
So my questions are two-fold:
Why is the "Animation (Animator)" no longer attached to the Script during Play?
My solution animator.SetFloat("SpeedBlend", 0.5f); doesn't work. Why not?
Just in case you want the read the entire code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThirdPersonMovement : MonoBehaviour
{
public CharacterController controller;
public Transform cam;
//moving
public float speed = 6f;
public float turnSmoothTime = 0.1f;
float turnSmoothVelocity;
//https://www.youtube.com/watch?v=_QajrabyTJc&ab_channel=Brackeys
//gravity + jumping
public float gravity = -9.81f;
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
public float jumpHeight = 3f;
Vector3 velocity;
bool isGrounded;
//Animation
public Animator animator;
// Start is called before the first frame update
private void Start()
{
Cursor.lockState = CursorLockMode.Locked;
controller = GetComponent<CharacterController>();
animator = GetComponentInChildren<Animator>();
}
// Update is called once per frame
void Update()
{
Move();
/*
Idle();
*/
Run();
}
void Move()
{
//isgrounded
isGrounded = Physics.CheckSphere(transform.position, groundDistance, groundMask);
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
//moving or walking
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
Vector3 direction = new Vector3(horizontal, 0f, vertical).normalized;
if (direction.magnitude >= 0.1f)
{
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cam.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
transform.rotation = Quaternion.Euler(0f, angle, 0f);
Vector3 moveDirection = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
controller.Move(moveDirection.normalized * speed * Time.deltaTime);
}
//gravity
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
//jumping
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
//animation
if (direction != Vector3.zero)
{
animator.SetFloat("SpeedBlend", 0.5f);
Debug.Log("moving works fine");
}
}
/*
void Idle()
{
animator.SetFloat("SpeedBlend", 0);
}
*/
void Run()
{
//running
if (Input.GetKey(KeyCode.LeftShift))
{
speed = 12f;
Debug.Log("left shift presseed");
/*
animator.SetFloat("SpeedBlend", 1f);
*/
}
else
{
speed = 6f;
}
}
}
I tried changing movement scripts, changing animation types. Instead of the current Blend Tree, I tried using a bool parameter "isWalking". None of it works, and I can't for the love of me grasp why. If I manually increase the SpeedBlend during Play, the animation changes as it should.
If you cannot run your app in debug mode (which would show you the exception and its StackTrace):
Add a try-catch to your code
try
{
// the code that throws
}
catch (Exception ex)
{
// Set a break point or log the exception and its StackTrace.
Console.WriteLine(ex.ToString());
}
Try to log the StackTrace for example to a file or to the console (if you have no logging set up). That will show you what method throws the exception.
You can also get the whole exception as a string, with inner exception and all StackTraces via ex.ToString() and log that (instead of the StackTrace property only). See the code example above.
In case of the NotImplementedException: probably a base class has a virtual or abstract method that that you need to override.

bike movement feels like the bike's on ice when turning

whenever I turn my bike it feels like it's sliding. Here's the script
[SerializeField] float turn;
[SerializeField] float maxSpeed;
[SerializeField] GameObject bikeParts;
[SerializeField] float tilt = 20f;
Rigidbody rb;
float lastY;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
float straightMov = Input.GetAxis("Vertical");
float horizontalMov = Input.GetAxis("Horizontal");
ControlStraightMov(straightMov);
ControlWeightTurning(horizontalMov);
lastY = transform.position.y;
}
private void ControlWeightTurning(float horizontalMov)
{
Vector3 bikePartsRot = bikeParts.transform.eulerAngles;
bikePartsRot.x = tilt * horizontalMov;
bikeParts.transform.eulerAngles = bikePartsRot;
transform.Rotate(0f, (turn * Time.deltaTime) * horizontalMov, 0f);
}
private void ControlStraightMov(float straightMov)
{
if (straightMov > 0)
{
rb.AddRelativeForce((accel * Time.deltaTime) * -straightMov, 0f, 0f);
}
else if (straightMov < 0)
{
rb.AddRelativeForce(((accel / 1.3f * Time.deltaTime) * -straightMov), 0f, 0f);
}
}
Whenever the bike picks up speed, it becomes very difficult to turn the bike because the force that was added keeps moving the bike in a different direction than the direction the bike's facing, how do I apply that force it was facing before on the direction it is facing now so that it doesn't feel like sliding?
I have tried fixing this problem but i just can't because i am pretty new to unity.
how do I apply that force it was facing before on the direction it is facing now
Not sure if this would feel right but you could probably do it like e.g.
private void Update ()
{
...
rb.velocity = transform.forward * rb.velocity.magnitude;
}
Which will keep the current speed and just redirect it into the new forward direction.
In general note: Whenever there is a Rigidbody involved you don't want to set any manipulation through the Transform component but only via the Rigidbody.
So you should not do
bikeParts.transform.eulerAngles = bikePartsRot;
transform.Rotate(0f, (turn * Time.deltaTime) * horizontalMov, 0f);
but both times rather calculate the target rotation and go through e.g. rb.MoveRotation in FixedUpdate.
Which might look somewhat like
float horizontalMove;
void Update()
{
var straightMove = Input.GetAxis("Vertical");
// Get and store the input in Update
horizontalMove = Input.GetAxis("Horizontal");
ControlStraightMov(straightMove);
lastY = transform.position.y;
}
private void FixedUpdate ()
{
// Handle it in FixedUpdate
ControlWeightTurning(horizontalMove);
}
private void ControlWeightTurning(float horizontalMove)
{
var bikePartsRot = bikeParts.transform.eulerAngles;
bikePartsRot.x = tilt * horizontalMove;
// Calculate the new final rotation
var newRotation = Quaternion.Euler(bikePartsRot) * Quaternion.Euler(Vector3.up * (turn * Time.deltaTime) * horizontalMove));
// Apply it only via the Rigidbody
rb.MoveRotation(newRotation);
}

Problem with Jumping with Translate function [Unity 2D]

Soo, I'm trying to code a simple Platformer as a work for class, and I'm having problems with the jumping, the character actually jumps but it seems as a teleport since it instantly reaches the peak of the jump and then gradually falls, I'd like to make it smoother.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerMovement : MonoBehaviour {
public float speed;
public float jumpForce;
public bool grounded;
public Transform groundCheck;
private Rigidbody2D rb2d;
// Use this for initialization
void Start () {
rb2d = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update () {
}
private void FixedUpdate()
{
float moveVertical = 0;
float moveHorizontal = Input.GetAxis("Horizontal") * speed;
moveHorizontal *= Time.deltaTime;
grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
if (grounded && Input.GetKeyDown("space"))
{
moveVertical = Input.GetAxis("Jump") * jumpForce;
moveVertical *= Time.deltaTime;
}
Vector2 move = new Vector2(moveHorizontal, moveVertical);
transform.Translate(move);
}
}
The answer to the question is below, however, for future questions related to Unity ask on the Unity forum. You will get a better answer quicker as more people are focused on Unity itself.
To fix your jump, rather split your vertical and horizontal movement in two parts and use your rigidbody you assigned in in your Start() function to handle jumping. Use ForceMode.Impulse to get an instant burst of speed/acceleration.
private void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal") * speed;
moveHorizontal *= Time.deltaTime;
grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
if (grounded && Input.GetKeyDown("space"))
{
rb2d.AddForce(transform.up * jumpForce, ForceMode.Impulse);
}
Vector2 move = new Vector2(moveHorizontal, 0);
transform.Translate(move);
}
Instead of setting the position when you jump, add a vertical impulse to the character's rigidbody with:
if (grounded && Input.GetKeyDown("space"))
{
moveVertical = Input.GetAxis("Jump") * jumpForce;
moveVertical *= Time.fixedDeltaTime;
rb2d.AddForce(moveVertical, ForceMode.Impulse);
}
Vector2 move = new Vector2(moveHorizontal, 0f);
This will let Rigidbody2D handle the work of altering the vertical velocity on each frame.
Also, since you are doing all of these calculations in FixedUpdate, instead of Update, there is no sense in using Time.deltaTime. You should be using Time.fixedDeltaTime instead.

Moving cube back to its original postion

When I use transform.Translate on my cube's x and z axis it moves according to pressing keys. But I want the cube to move back slowly to it's original position when user stops pressing keys and default axis are x=0 ,z=0.
public float move = 1f;
void Update ()
{
this.transform.Translate (Input.GetAxis ("Horizontal") / move, 0f, Input.GetAxis ("Vertical") / move);
}
So your best bet is to store the original position
private Vector3 _intialPosition;
private float _duration = 0.4f;
private float _startTime;
void Awake()
{
_initialPosition = transform.position;
}
void Start() {
_startTime = Time.time;
}
And then check if the key has been pressed, and if not, have it move back towards the initial position
void Update()
{
if(Input.GetAxis("Horizontal") != 0 || Input.GetAxis("Vertical") != 0)
{
//Logic here to move via arrows...
}
else
{
transform.position = Vector3.Lerp(transform.position, _initialPosition, (Time.time - _startTime ) / _duration);
}
}
Unity Documentation
Lerp
You could use Vector3.MoveTowards to slowly move your current transform to a target or original transform position.
private Transform original;
public float speed = 0.5f;
void Awake()
{
original = transform;
}
void Update() {
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, original.position, step);
}
Unity3d documention - Vector3.MoveTowards

Make ball Jumping

I am trying to make a script where i can move a ball, horizontal and vertical. I managed to get that working.
But now I want to make my ball "jump". I ended with script below, but now my ball just get launched like a rocket xD
Can anyone help me out
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour
{
public float speed;
public float jumpSpeed;
public GUIText countText;
public GUIText winText;
private int count;
void Start()
{
count = 0;
SetCountText();
winText.text = " ";
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0, moveVertical);
Vector3 jump = new Vector3 (0, jumpSpeed, 0);
GetComponent<Rigidbody>().AddForce (movement * speed * Time.deltaTime);
if (Input.GetButtonDown ("Jump"));
GetComponent<Rigidbody>().AddForce (jump * jumpSpeed * Time.deltaTime);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "PickUp") {
other.gameObject.SetActive(false);
count = count +1;
SetCountText();
}
}
void SetCountText()
{
countText.text = "Count: " + count.ToString();
if (count >= 10)
{
winText.text = "YOU WIN!";
}
}
}
Jumping does not work with adding a continuous force on an object. You will have to apply a single impulse to the object once when the jump button is first pressed. This impulse will also not include a time factor, because it is applied only once. So you would get something like this:
bool jumping;
if (Input.GetButtonDown ("Jump") && !this.jumping);
{
GetComponent<Rigidbody>().AddForce (jumpForce * new Vector3(0,1,0));
this.jumping = true;
}
Also note that in your example you are multiplying the upward unit vector by the jumpspeed twice. Once in the jump vector initialization and then once in the AddForce method.
Of course, you will also have to make sure that gravity applies to pull the object back down (and if the object hits the ground, reset the jump bool.
In general, depending on what kind of game you are making, it is easier to just set the velocity of the object yourself and don't work with the Unity physics engine to do some simple moving around.
There is an error in your code in the function FixedUpdate:
if (Input.GetButtonDown ("Jump"));
in that way you are applying a force on your object at every frame because the semicolon is excluding the row below from the condition. By removing the semicolon you will have a correct if implementation in case of a jump, as long as on your RigidBody component UseGravity is enabled.
if (Input.GetButtonDown ("Jump"))
GetComponent<Rigidbody>().AddForce (jump * jumpSpeed * Time.deltaTime);
Hope it helps.
Thanks everyone, it was a great help. I now have a jumping character. One who can only jump when grounded.
public bool IsGrounded;
void OnCollisionStay (Collision collisionInfo)
{
IsGrounded = true;
}
void OnCollisionExit (Collision collisionInfo)
{
IsGrounded = false;
}
if (Input.GetButtonDown ("Jump") && IsGrounded)
{
GetComponent<Rigidbody>().velocity = new Vector3(0, 10, 0);
}

Categories

Resources