I am pretty new to Unity so how I did it may not be the best way, but when the character jumps it is inconsistent.
Some bounces are a lot further than others and I am not sure why this is happening.
Also if I press the up arrow really quickly the cube jumps really far but if I wait a couple seconds it bounce like normal.
Here is my code:
using UnityEngine;
using System.Collections;
public class MovePlayer : MonoBehaviour
{
Vector3 endPos;
int numBackwards = 0;
bool jumping = false;
public Rigidbody rigidBody;
//public Collider theCollider;
void Start()
{
rigidBody = GetComponent<Rigidbody> ();
}
// Update is called once per frame
void Update()
{
rigidBody.freezeRotation = true;
endPos = gameObject.transform.position;
if (!jumping)
{
if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
if (numBackwards < 0)
{
numBackwards++;
}
else
{
UpdateScore.score++;
}
transform.Translate(Vector3.up * 50 * Time.deltaTime, Space.World);
transform.Translate(Vector3.forward * 110 * Time.deltaTime, Space.World);
}
else if (Input.GetButtonDown("down") && gameObject.transform.position == endPos)
{
transform.Translate(Vector3.up * 50 * Time.deltaTime, Space.World);
transform.Translate(-Vector3.forward * 110 * Time.deltaTime, Space.World);
numBackwards--;
}
else if (Input.GetButtonDown("left") && gameObject.transform.position == endPos)
{
transform.Translate(Vector3.up * 50 * Time.deltaTime, Space.World);
transform.Translate(Vector3.left * 110 * Time.deltaTime, Space.World);
}
else if (Input.GetButtonDown("right") && gameObject.transform.position == endPos)
{
transform.Translate(Vector3.up * 50 * Time.deltaTime, Space.World);
transform.Translate(Vector3.right * 110 * Time.deltaTime, Space.World);
}
}
}
void OnCollisionEnter(Collision other)
{
if (other.gameObject.CompareTag("Ground"))
jumping = false;
}
void OnCollisionExit(Collision other)
{
if (other.gameObject.CompareTag("Ground"))
jumping = true;
}
}
Instead of translate the object, make use of the rigidbodys ability to add a force to it. I also replaced the collision events with a simpler way. It checks the distance between the objects center and the ground. (You can still use your way obviously). The FixedUpdate insure that the code will be called regularly instead of depending on the frame speed. (More on that topic Here)
//PUBLIC
public float distance;
public float fspeed;
public float uspeed;
//PRIVATE
private Rigidbody rigidBody;
void Awake()
{
rigidBody = GetComponent<Rigidbody>();
rigidBody.freezeRotation = true;
}
void FixedUpdate()
{
if (Physics.Raycast(transform.position, -Vector3.up, distance + 0.1F))
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
rigidBody.AddForce(new Vector3(0, uspeed, fspeed));
}
if (Input.GetKeyDown(KeyCode.DownArrow))
{
rigidBody.AddForce(new Vector3(0, uspeed, -fspeed));
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
rigidBody.AddForce(new Vector3(fspeed, uspeed, 0));
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
rigidBody.AddForce(new Vector3(-fspeed, uspeed, 0));
}
}
}
public float distance
Is the min distance to the ground until you can jump again
public float fspeed
Is the forward or side speed (jump distance)
public float uspeed
Is the upwards speed (jump height)
Related
I'm trying to make my player dash at where he's looking. The code below works but it gives 2 different result.
If the player dash and move at the same time, the player gets pushed a few units.
If the player dash only, the player gets pushed 4/5 times the one above.
How do I get result 1 for both of them whether they are moving or standing still.
private void Start() {
rb = GetComponent<Rigidbody>();
}
private void Update()
{
horizontalInput = Input.GetAxisRaw("Horizontal");
verticalInput = Input.GetAxisRaw("Vertical");
direction = new Vector3(horizontalInput, 0f, verticalInput).normalized;
if(Input.GetKeyDown(KeyCode.Space)){
isDashing = true;
}
}
private void FixedUpdate() {
Move();
if(isDashing){
Dash();
}
}
void Move()
{
if(direction.magnitude >= 0.1f)
{
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + camera.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, 0.1f);
transform.rotation = Quaternion.Euler(0f, angle, 0f);
Vector3 moveDirection = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
moveDirection.y = rb.velocity.y;
rb.velocity = moveDirection * currentSpeed * Time.deltaTime;
}
}
void Dash()
{
rb.AddForce(transform.forward * dashForce, ForceMode.Impulse);
isDashing = false;
}
I am trying to add gravity to my "residents" of a town builder game. Basically the residents just walk around to a random location, wait 2 seconds then do it again. I am trying to add gravity to them so they don't float.
controller = GetComponent<CharacterController>();
moveDirection = Vector3.zero;
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
These four lines are the gravity lines I tried added and very weird things happen such as the resident teleporting up if it touches anything, even the ground. What can I do? I basically just want the residents not to float above the ground and follow the slopes of the land like regular walking.
Below is the whole code if its needed to help solve my problem.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resident : MonoBehaviour
{
private Vector3 location;
private Quaternion rotation;
private int speed;
private Vector3 moveDirection = Vector3.zero;
private bool canRotate = true;
Vector3 moveVector;
CharacterController controller;
// Start is called before the first frame update
void Start()
{
transform.rotation *= Quaternion.Euler(-90, 0, 0);
controller = GetComponent<CharacterController>();
speed = 5;
SetRandomPos();
StartCoroutine(ExampleCoroutine());
}
void Update()
{
int gravity = 20;
moveDirection = Vector3.zero;
//Check if cjharacter is grounded
moveDirection.y -= gravity * Time.deltaTime;
// Move the controller
controller.Move(moveDirection * Time.deltaTime);
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, location, step);
if (canRotate)
{
transform.LookAt(location);
transform.rotation *= Quaternion.Euler(-90, 90, 0);
canRotate = false;
}
if (transform.position == location)
{
StartCoroutine(ExampleCoroutine());
}
}
void SetRandomPos()
{
location = new Vector3(Random.Range(transform.position.x - 10f, transform.position.x + 10f), transform.position.y, Random.Range(transform.position.z - 10f, transform.position.z + 10f));
canRotate = true;
}
IEnumerator ExampleCoroutine()
{
//yield on a new YieldInstruction that waits for 5 seconds.
yield return new WaitForSeconds(2);
//After we have waited 5 seconds print the time again.
if (transform.position == location)
{
SetRandomPos();
}
}
}
I am not exactly clear what you intend to do, but saw a few issues with the code and tried to fix them. The snippet is untested, I just added what I believe to be the correction that should fix your issues.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
private Vector3 location;
private Coroutine changeMovement = null;
private float speed;
private Vector3 playerVelocity = Vector3.zero;
CharacterController controller;
// Start is called before the first frame update
void Start()
{
controller = GetComponent<CharacterController>();
speed = 5;
SetRandomPos();
}
void Update()
{
bool groundedPlayer = controller.isGrounded;
if (groundedPlayer && playerVelocity.y < 0)
{
playerVelocity.y = 0f;
}
Vector3 move = (transform.position - location).normalized;
controller.Move(move * Time.deltaTime * speed);
if (move != Vector3.zero)
{
gameObject.transform.forward = move;
}
// check if we are close to our goal, then change the goal
if (changeMovement == null && Vector3.Distance(transform.position,location) < 0.1f)
{
changeMovement = StartCoroutine(ExampleCoroutine());
}
playerVelocity.y += gravityValue * Time.deltaTime;
controller.Move(playerVelocity * Time.deltaTime);
}
void SetRandomPos()
{
location = new Vector3(Random.Range(transform.position.x - 10f, transform.position.x + 10f), transform.position.y, Random.Range(transform.position.z - 10f, transform.position.z + 10f));
}
IEnumerator ExampleCoroutine()
{
//yield on a new YieldInstruction that waits for 5 seconds.
yield return new WaitForSeconds(2);
SetRandomPos();
changeMovement = null;
}
Edit: I changed the code and used the CharacterController.Move as a base.
When my player jumps and lands on something it always shakes around like that.
Also, sometimes when I jump a few times in a row (about 10 times) it would go through the ground and just fall down.
I tried using a collider and I don't see anything in the movement script that may cause this. I'm currently using Unity 2018.4.20f1 and Visual Studio c#.
Any solutions?
Player Movement script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public static int movespeed = 6;
public Vector3 userDirection = Vector3.right;
public Rigidbody rb;
public bool isGrounded;
Vector3 jumpMovement;
bool jump = false;
[SerializeField]
float jumpHeight = 1.8f, jumpSpeed = 8f;
void Start()
{
rb = GetComponent<Rigidbody>(); }
void OnCollisionStay()
{
isGrounded = true;
}
public float fallMultiplier = 3.5f;
public float lowJumpMultiplier = 2f;
void Update()
{
//movement
transform.Translate(userDirection * movespeed * Time.deltaTime);
if (Input.GetButton("Jump") && !jump)
StartCoroutine(Jump());
}
IEnumerator Jump()
{
float originalHeight = transform.position.y;
float maxHeight = originalHeight + jumpHeight;
jump = true;
yield return null;
while (transform.position.y < maxHeight)
{
transform.position += transform.up * Time.deltaTime * jumpSpeed;
yield return null;
}
while (transform.position.y > originalHeight)
{
transform.position -= transform.up * Time.deltaTime * jumpSpeed;
yield return null;
}
rb.useGravity = true;
jump = false;
yield return null;
}
}
Edit: I didn't notice the link.
You are forcing it to go down to originalHeight, without checking if there is an object higher than that. You can remove
while (transform.position.y > originalHeight)
{
transform.position -= transform.up * Time.deltaTime * jumpSpeed;
yield return null;
}
and let the rigidbody control gravity (by setting rb.useGravity = true; as you did).
Original answer:
You are probably going below the ground when calling transform.position -= transform.up * Time.deltaTime * jumpSpeed;. Try adding
if (transform.position.y < originalHeight)
transform.position = new Vector3(transform.position.x, originalHeight, transform.position.z)
after it.
I have a cube that is on the scene and when you press one of the arrow keys it moves up and in the direction of the arrow key. When you click while the cube is already in the air it jumps again before it gets back to the ground. How do I make it so that the cube can't jump again until it is back on the ground? This is my code so far:
public class MovePlayer : MonoBehaviour {
Vector3 endPos;
Vector3 startPos;
bool jumping = false;
// Update is called once per frame
void Update () {
endPos = gameObject.transform.position;
startPos = gameObject.transform.position;
if (Input.GetButtonDown ("up") && gameObject.transform.position == endPos) {
transform.Translate(Vector3.up * 50 * Time.deltaTime, Space.World);
transform.Translate(Vector3.forward * 50 * Time.deltaTime, Space.World);
}
else if (Input.GetButtonDown ("down") && gameObject.transform.position == endPos) {
transform.Translate(Vector3.up * 50 * Time.deltaTime, Space.World);
transform.Translate(-Vector3.forward * 50 * Time.deltaTime, Space.World);
}
else if (Input.GetButtonDown ("left") && gameObject.transform.position == endPos) {
transform.Translate(Vector3.up * 50 * Time.deltaTime, Space.World);
transform.Translate(Vector3.left * 50 * Time.deltaTime, Space.World);
}
else if (Input.GetButtonDown ("right") && gameObject.transform.position == endPos) {
transform.Translate(Vector3.up * 50 * Time.deltaTime, Space.World);
transform.Translate(Vector3.right * 50 * Time.deltaTime, Space.World);
}
}
}
Make the Boolean jumping false if the player is in contact/colliding with the ground. If not make it true. Then add and check it with the jump input condition so true will not let jump and false will let jump.
For detecting ground use some code like below. Tag the ground as you want. Both player and ground will need collider component and at least one of them will need Rigidbody component attached.
void OnCollisionEnter (Collision other)
{
if (other.collider.tag == "ground_tag")
{
Jumping = false;
}
}
void OnCollisionExit (Collision other)
{
if (other.collider.tag == "ground_tag")
{
Jumping = true;
}
}
You may use raycast from your character's feet to the ground. And if that ray hits something - you are on the ground.
var origin = transform.position;
var onGround = Raycast(origin, Vector3.down, 1f);
Note that you need to cast a ray from your feet, so you will probably need to change origin value.
That approach is good as you can use layer masks, and a lot of other options.
I'm learning C# while programming my game, I'm stuck doing the movement. I want my character to move continuously by pressing 'D' or 'A' once. Then, after colliding with an invisible wall while going to the right, go backwards until it hits another invisible wall and stop.
I managed to make my GameObject move, but when it collides with the wall, nothing happens. Both objects have a rigidbody2D, the same z-coordinates, and correct tags.
public class SquadMovement : MonoBehaviour {
float speed;
bool collisionRightWall = false;
// Update is called once per frame
void Update () {
if (Input.GetKeyDown (KeyCode.D)) {
CancelInvoke ();
InvokeRepeating ("RightMovement", Time.deltaTime, Time.deltaTime);
}
if (Input.GetKeyDown (KeyCode.A)) {
CancelInvoke ();
InvokeRepeating ("LeftMovement", Time.deltaTime, Time.deltaTime);
}
}
void RightMovement () {
speed = 10f;
transform.Translate (speed * Time.deltaTime, 0, 0);
}
void LeftMovement () {
speed = -7f;
transform.Translate (speed * Time.deltaTime, 0, 0);
}
void OnCollisionWallR (Collider2D colR) {
if (colR.gameObject.tag == "invisibleWallRight") {
collisionRightWall = true;
Debug.Log (collisionRightWall);
}
}
}
I'm using invisible walls because I don't know how to use x-coordinates, There HAS to be a more efficient way but I want to know first why this don't work. I would be glad if someone could teach me that too.
using UnityEngine;
using System.Collections;
public class SquadMovement : MonoBehaviour {
float constantspeed = 3;
float speed;
//Key inputs
void Update () {
transform.Translate (constantspeed * Time.deltaTime, 0, 0);
if (Input.GetKeyDown (KeyCode.D)) {
StopAllCoroutines ();
StartCoroutine (RightMovement(0f));
}
if (Input.GetKeyDown (KeyCode.A)) {
StopAllCoroutines ();
StartCoroutine (LeftMovement(0f));
}
}
//Movement itself (Right, Left)
IEnumerator RightMovement (float Rloop) {
while (transform.position.x < Time.time * constantspeed + 6) {
speed = 10f;
transform.Translate (speed * Time.deltaTime, 0, 0);
yield return new WaitForSeconds (Rloop);
}
if (transform.position.x > Time.time * constantspeed + 5.9) {
StopAllCoroutines ();
StartCoroutine (LeftMovement (0f));
}
}
IEnumerator LeftMovement (float Lloop) {
while (transform.position.x > Time.time * constantspeed -8) {
speed = -7f;
transform.Translate (speed * Time.deltaTime, 0, 0);
yield return new WaitForSeconds (Lloop);
}
}
}