using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
CharacterController characterController;
[SerializeField] private float speed = 5.0f;
public float jumpSpeed = 8.0f;
public float gravity = 20.0f;
private Vector3 moveDirection = Vector3.zero;
private void Start()
{
characterController = GetComponent<CharacterController>();
}
private void Update()
{
var horizontal = Input.GetAxis("Horizontal");
var vertical = Input.GetAxis("Vertical");
transform.Translate(new Vector3(horizontal, 0, vertical) * (speed * Time.deltaTime));
if (characterController.isGrounded)
{
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("vertical"));
moveDirection *= speed;
if (Input.GetButton("Jump"))
{
moveDirection.y = jumpSpeed;
}
}
moveDirection.y -= gravity * Time.deltaTime;
characterController.Move(moveDirection * Time.deltaTime);
}
}
I was new in game development when I am making an game but I got the problem that the character is not able to jump and when I try to move the character it keeps floating on the air.
This code here works for me
if (Input.GetButtonDown("Jump"))
{
rb.velocity = new Vector3(rb.velocity.x, jumpHeight, 0);
//jumpheight is set at 14, and my gravity scale is at 4
}
you will have to reference your 'rb' like:
public Rigidbody2D rb;
then drag your players rigidbody into the new Rb that shows up on the script.
rb.velocity adds a velocity of the original x velocity and sets the y velocity to 14, and z velocity = 0.
Hope this answers your question
Related
the problem I am having is when I run full speed (i.e. pressing a and w and looking 45 degrees to the right it doesn't use .normalized on purpose) into a wall or anything else it allows the player to go through it, so my code is
Vector3 m_Input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
Vector3 moveDirection = m_Input;
moveDirection = transform.TransformDirection(moveDirection);
rb.MovePosition(transform.position + moveDirection * moveSpeed);
and moveSpeed is set to 0.2. I have checked and all of the colliders are not triggers. any help would be greatly appreciated
First off do double check
All your colliders & rigidbody are 3d
Everything is on the same layer (or your layers are set to interact with each other)
Your rigidbody is attached to the same game object as your collider
However, it seems that your issue is that your rigidbody is set to be kinematic (as Rigidbody.MovePosition is intended to be used by kinematic rigidbody's only)
If your rigidbody is set to kinematic then no forces (such as collider normal forces) will be applied to your object, so it will be able to pass through walls.
Solution
The easiest way to avoid this is by making sure your rigidbody is set to non-kinematic, and moving it via Rigidbody.velocity.
Something similar to:
Vector3 m_Input = new Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical"));
Vector3 moveDirection = m_Input;
moveDirection = transform.TransformDirection(moveDirection);
rb.velocity = (moveDirection * moveSpeed);
This should move your character according to physics and allow for the correct interactions with colliders.
Also, you should be aware if you ever do want to move a rigidbody like that, you should be sure to do so in FixedUpdate and scale movement by Time.FixedDeltaTime.
now the jump is broken this is the full script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FPSMovement : MonoBehaviour
{
public Rigidbody rb;
public GameObject cam;
Vector2 rotation = Vector2.zero;
public float sensitivity = 10f;
public string xAxis = "Mouse X";
public string yAxis = "Mouse Y";
public float OmoveSpeed;
public float SprintSpeed;
public float moveSpeed;
public float jumpVar;
public bool Grounded = false;
public Vector3 slideScale;
public Vector3 normalScale;
public Vector3 dir;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
moveSpeed = OmoveSpeed;
slideScale = new Vector3(1, 0.5f, 1);
normalScale = new Vector3(1, 1, 1);
}
// Update is called once per frame
void FixedUpdate()
{
dir = rb.velocity;
// Should be cross platform movement
Vector3 m_Input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
Vector3 moveDirection = m_Input;
moveDirection = transform.TransformDirection(moveDirection);
rb.velocity = (moveDirection * moveSpeed);
// Sprinting
if (Input.GetKey(KeyCode.LeftControl))
{
moveSpeed = SprintSpeed;
}
else
{
moveSpeed = OmoveSpeed;
}
// Jumping
if (Input.GetKey(KeyCode.Space))
{
if (Grounded)
{
rb.velocity += new Vector3(0, jumpVar, 0);
Grounded = false;
}
}
// TO-DO: Sliding
// Camera Rotation
rotation.x += Input.GetAxis(xAxis) * sensitivity;
rotation.y += Input.GetAxis(yAxis) * sensitivity;
rotation.y = Mathf.Clamp(rotation.y, -90, 90);
var xQuat = Quaternion.AngleAxis(rotation.x, Vector3.up);
var yQuat = Quaternion.AngleAxis(rotation.y, Vector3.left);
transform.localRotation = xQuat;
cam.transform.localRotation = yQuat;
}
private void OnCollisionEnter(Collision collision)
{
if (collision.transform.tag == "Ground")
{
Grounded = true;
}
}
private void OnCollisionExit(Collision collision)
{
Grounded = false;
}
}
My question might sound confusing but I want to make my code so when my character doesn't move, he looks directly towards the closest enemy. The problem is that when I stop moving my character, it only does the command once and doesn't redirect to the enemy's new position. I tested out many things like making it so when i move, it looks at the enemy and it seems to work but whenever I set it to not move, it doesn't work.
using System.Collections.Generic;
using UnityEngine;
namespace work.working.worked
{
public class Movement : MonoBehaviour
{
public float moveSpeed;
public float rotationSpeed;
public static bool ismoving;
public Rigidbody2D rb;
Vector2 movement;
// Update is called once per frame
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
if (Input.anyKey)
{
ismoving = true;
}
else
{
ismoving = false;
}
if (ismoving == true)
{
Vector2 direction = new Vector2(movement.x, movement.y);
direction.Normalize();
if (direction != Vector2.zero)
{
Quaternion toRotation = Quaternion.LookRotation(Vector3.forward, direction);
transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotationSpeed * Time.deltaTime);
}
}
if (ismoving == false)
{
Vector3 direction = FindClosest.closestEnemy.position - transform.position;
direction.Normalize();
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg - 85f;
rb.rotation = angle;
}
}
}
}
Instead of Input.anyKey you could check that the magnitude of movement vector to see if character is moving.
ismoving = movement.magnitude > 0.0f;
using System.Collections.Generic;
using UnityEngine;
namespace work.working.worked
{
public class Movement : MonoBehaviour
{
public float moveSpeed;
public float rotationSpeed;
public bool ismoving;
public Rigidbody2D rb;
Vector2 movement;
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
ismoving = movement.magnitude > 0.0f;
if (ismoving)
{
Vector2 direction = new Vector2(movement.x, movement.y);
direction.Normalize();
if (direction != Vector2.zero)
{
Quaternion toRotation = Quaternion.LookRotation(Vector3.forward, direction);
transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotationSpeed * Time.deltaTime);
}
}
else
{
Vector3 direction = FindClosest.closestEnemy.position - transform.position;
direction.Normalize();
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg - 85f;
rb.rotation = angle;
}
}
}
Also don't make ismoving variable static or it gets set by every active Movement component in loaded scenes which can lead to unexpected behavior down the line. If its public, you can see it's state in Unity inspector by selecting the GameObject with Movement component.
This is weird.
I've been learning more in depth about Rigidbody, and I can't for the life of me, make it jump. I'm copying exactly what I see on youtube tutorials, and it works for the youtubers, but not for me.
In more C# english - I was trying to .AddForce(ForceMode.TriedEverything) on the y axis, via user Input. It won't work consistently. sometimes it's higher, sometimes lower, most times nothing at all. this is weird. and I didn't even put isGrounded or any other limitation. Simply "addforce if user input". This is case no 1
Case 2 is much simpler, and NEVER works: it's based on setting the velocity to a new vector with only the y axis manipulated. I'll sharethe code. the “jumpForce” is set to 12, but i've tried 500 too. no difference. This case does have a “grounded” condition, but it didn't work without it as well. Anyway, both print statements get executed.
Both cases were tested in Update and in FixedUpdate, no differences.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMotor : MonoBehaviour
{
public LayerMask layerMask = default;
public bool grounded;
[SerializeField] float moveSpeed = 7f;
[SerializeField] float jumpForce = 12f;
Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
float x = Input.GetAxisRaw("Horizontal") * moveSpeed;
float y = Input.GetAxisRaw("Vertical") * moveSpeed;
Vector3 movePosition = transform.right * x + transform.forward * y;
Vector3 newPosition = new Vector3(movePosition.x, rb.velocity.y, movePosition.z);
grounded = Physics.CheckSphere(new Vector3(transform.position.x, transform.position.y - 1, transform.position.z), 0.4f, layerMask);
if (Input.GetKeyDown(KeyCode.Space)&& grounded)
{
print("reached if statement");
rb.velocity = new Vector3(rb.velocity.x, jumpForce, rb.velocity.z);
print("jumpingjumping");
}
rb.velocity = newPosition;
}
void FixedUpdate()
{
}
}
Thanks folks.
The problem is the order of your code. You are setting the newPosition variable before the jump statement so the y velocity is 0, then you are setting the y velocity to the jump velocity but after that you set the velocity to the newPosition which still has a velocity of 0 because it was set before the jump statement. Here is the working code:
public LayerMask layerMask = default;
public bool grounded;
[SerializeField] float moveSpeed = 7f;
[SerializeField] float jumpForce = 12f;
Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
float x = Input.GetAxisRaw("Horizontal") * moveSpeed;
float y = Input.GetAxisRaw("Vertical") * moveSpeed;
Vector3 movePosition = transform.right * x + transform.forward * y;
grounded = Physics.CheckSphere(new Vector3(transform.position.x, transform.position.y - 1, transform.position.z), 0.4f, layerMask);
if (Input.GetKeyDown(KeyCode.Space) && grounded)
{
print("reached if statement");
rb.velocity = new Vector3(rb.velocity.x, jumpForce, rb.velocity.z);
print("jumpingjumping");
}
Vector3 newPosition = new Vector3(movePosition.x, rb.velocity.y, movePosition.z);
rb.velocity = newPosition;
}
void FixedUpdate()
{
}
Hope this helped you!
Hi I am very new to Unity and only got basic knowledge. I created a player who can move and also a camera which follows the player and according to the mouseX and mouseY acis the camera rotates.
Now I want the camera rotation angle to be the forward position.
If the player press w he moves along x acis but if the camera angle change and the player press w it should move into this direction.
player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DoublePlayer : MonoBehaviour
{
private CharacterController _controller;
public float _jumpHeight = 3f;
[SerializeField]
private float _moveSpeed = 5f;
[SerializeField]
private float _gravity = 9.81f;
private float _directionY;
void Start()
{
_controller = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
float horizontalInput = Input.GetAxis("Horizontal");
float verticalInput = Input.GetAxis("Vertical");
Vector3 direction = new Vector3(horizontalInput, 0, verticalInput);
// set gravity
_directionY -= _gravity * Time.deltaTime;
direction.y = _directionY;
_controller.Move(direction * _moveSpeed * Time.deltaTime);
}
}
camera.cs
public class CameraController : MonoBehaviour
{
public float RotationSpeed = 1;
public Transform Target, Player;
float mouseX, mouseY;
void Start()
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void LateUpdate()
{
CamControl();
}
void CamControl()
{
mouseX += Input.GetAxis("Mouse X") * RotationSpeed;
mouseY += Input.GetAxis("Mouse Y") * RotationSpeed;
mouseY = Mathf.Clamp(mouseY, -35, 60);
transform.LookAt(Target);
Target.rotation = Quaternion.Euler(mouseY, mouseX, 0);
Player.rotation = Quaternion.Euler(0, mouseX, 0);
}
}
For Target and Player variable I selected the player object.
Do someone has a simple solution I can understand?
You could simply take the direction and rotate it along with the object that component is attached to using Quaternion * Vector3 operator
var rotatedDirection = transform.rotation * direction;
Or if you rather need the orientation of the other script attached to a different object then do e.g.
// link your camera or whatever shall be used for the orientation via the Inspector
[SerializeField] private Transform directionProvider;
and then
var rotatedDirection = directionProvider.rotation * direction;
Since you're getting the rotation directly from a Transform, you could use Transform.TransformDirection:
Vector3 rotatedDirection = transform.TransformDirection(direction);
Here's my code. Currently, the player moves forwards relative to a fix plane. Rotating the player/camera has no affect on which direction they travel when I press the "go forward" key.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MainController : MonoBehaviour
{
public float speed;
float jumpSpeed = 0.5f;
bool isGrounded;
private Rigidbody rb;
public GameObject player;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
if (Input.GetButtonDown("Jump") || Input.GetAxis("Right Trigger") > 0f && isGrounded)
{
rb.AddForce(Vector3.up * jumpSpeed, ForceMode.Impulse);
isGrounded = false;
}
if (isGrounded)
{
rb.AddForce(movement * speed * Time.deltaTime);
}
else
{
rb.AddForce((movement/4) * speed * Time.deltaTime);
}
}
void OnCollisionStay()
{
isGrounded = true;
}
void OnCollisionExit()
{
isGrounded = false;
}
}
How do I make it so that the player moves relative to the camera's direction?
It's because RigidBody.AddForce() adds force in absolute direction, no matter which direction the gameobject is looking.
You should try using RigidBody.AddRelativeForce(), like:
if (isGrounded)
{
rb.AddRelativeForce(movement * speed * Time.deltaTime);
}
I think there is a better way to do this, but see if it results in the expected behavior:
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 looking = (transform.rotation * Vector3.forward).normalized;
Vector3 perpendicular = Vector2.Perpendicular(new Vector2(looking.x, looking.z));
perpendicular.z = perpendicular.y;
perpendicular.y = looking.y;
Vector3 vertical = moveVertical * looking;
Vector3 horizontal = moveHorizontal * perpendicular;
Vector3 movement = vertical - horizontal;
...
}