I'm trying to make the code so the cube (which is a 2d object) jump if its on the ground here's the code do u know how I tried other ways but they didn't work
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playercontroler : MonoBehaviour
{
public int thrust = 5;
public bool OnGround;
Rigidbody2D Rigidbody;
public float Speed = 7;
void Start()
{
Rigidbody = GetComponent<Rigidbody2D>();
}
void Update()
{
if (Input.GetKey(KeyCode.D))
{
this.transform.position += Vector3.right * Speed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.A))
{
this.transform.position += Vector3.left * Speed * Time.deltaTime;
}
if (Input.GetKeyDown(KeyCode.Space))
{
Rigidbody.velocity = transform.up * thrust;
}
}
}
If you hit space, Add this line for a jump:
Rigidbody.AddForce(new Vector3(0, 50, 0), ForceMode.Impulse);
For your information, I use this line of code :
Rigidbody.AddForce(transform.up * yourValue);
Related
I am making a script that allows the payer to move and jump. Moving with the WASD keys is fine but when I press the space bar to jump, but the console says NaN and the gravity in the game stops working I've looked at my player motor script and my input manager script, but I can't find any errors.
player motor script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMotor : MonoBehaviour
{
private CharacterController controller;
private Vector3 PlayerVelocity;
private bool isGrounded;
public float speed = 5f;
public float gravity = -9.8f;
public float jumpHeight = -3f;
// Start is called before the first frame update
void Start()
{
controller = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
isGrounded = controller.isGrounded;
}
public void ProcessMove(Vector2 input)
{
Vector3 moveDirection = Vector3.zero;
moveDirection.x = input.x;
moveDirection.z = input.y;
controller.Move(transform.TransformDirection(moveDirection) * speed * Time.deltaTime);
PlayerVelocity.y += gravity * Time.deltaTime;
if (isGrounded && PlayerVelocity.y < 0)
PlayerVelocity.y = -2f;
controller.Move(PlayerVelocity * Time.deltaTime);
Debug.Log(PlayerVelocity.y);
}
public void Jump()
{
if (isGrounded)
{
PlayerVelocity.y = Mathf.Sqrt(jumpHeight * -3.0f * gravity);
}
}
}
input manager script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class InputManager : MonoBehaviour
{
private PlayerInput playerInput;
private PlayerInput.OnFootActions onFoot;
private PlayerMotor motor;
// Start is called before the first frame update
void Awake()
{
playerInput = new PlayerInput();
onFoot = playerInput.OnFoot;
motor = GetComponent<PlayerMotor>();
onFoot.Jump.performed += ctx => motor.Jump();
}
// Update is called once per frame
void FixedUpdate()
{
// tell the playermotor to move using the value from our movement action
motor.ProcessMove(onFoot.Movement.ReadValue<Vector2>());
}
private void OnEnable()
{
onFoot.Enable();
}
private void OnDisable()
{
onFoot.Disable();
}
}
In this line it seems you are trying to get the square root of a negative number? PlayerVelocity.y = Mathf.Sqrt(jumpHeight * -3.0f * gravity);
Gravity and jumpheight are negative, multiplied with -3.0 that results in a negative number.
A quick test in Unity reveals that Mathf.Sqrt doesn't throw an error on negatives and instead returns NaN.
so I am trying to make a shooting machine that shoots bullet and bullet gets back from the same way it went through when hitting the wall without speeding up and without changing angle (just the opposite way)
i added force and tried many ways but nothing works , please help
here is my code (the last one) even though i normalized the force but i still feel like its speeding up
public Rigidbody2D rb;
private float bulletForce = 20f;
private bool collided;
Vector2 dir;
private void Awake()
{
instance = this;
rb = gameObject.GetComponent<Rigidbody2D>();
dir = transform.up;
}
void Update()
{
rb.AddForce(dir.normalized * bulletForce * Time.deltaTime, ForceMode2D.Impulse);
}
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Edge"))
{
dir = Vector2.Reflect(rb.position, other.contacts[0].normal);
rb.velocity = dir.normalized * bulletForce;
transform.up = dir.normalized;
}
}
this is wanted results explanation
this is current results explanation
If you just want to exactly invert the direction than
rb.velocity = -rb.velocity;
transform.up = rb.velocity;
and of course it is speeding up since you constantly add force in
void Update()
{
rb.AddForce(dir.normalized * bulletForce * Time.deltaTime, ForceMode2D.Impulse);
}
why don't you just disable any friction for this bullet and set an initial velocity once?
public class CollideReflector : MonoBehaviour
{
[SerializeField] Rigidbody2D rb;
[SerializeField] Vector2 direction;
[SerializeField] float bulletForce = 20f;
[SerializeField]float smooth;
private bool collided;
// STARTER
private void Awake()
{
instance = this;
rb = gameObject.GetComponent<Rigidbody2D>();
direction = transform.up;
}
void Update()
{
rb.AddForce(direction.normalized * bulletForce * Time.deltaTime, ForceMode2D.Impulse);
}
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Edge"))
{
var x = Quaternion.Euler(transform.eulerAngles.x, transform.eulerAngles.y, transform.eulerAngles.z);
Quaternion target = -x;
transform.rotation = Quaternion.Slerp(transform.rotation, x, Time.deltaTime * smooth);
rb.AddForce(-direction.normalized * bulletForce * Time.deltaTime, ForceMode2D.Impulse);
}
}
}
I want to press the key once
My cube moves to the right and rotates 90 degrees
The rotation is well done
But it does not move well
using UnityEngine;
using System.Collections;
public class Player : MonoBehaviour
{
public float speed;
public float time;
public GameObject contactPoint;
private Rigidbody rig;
private void Start()
{
rig = GetComponent<Rigidbody>();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.D))
{
StartCoroutine(RotatePlayer(Vector3.forward * 90, Vector3.right, time));
}
if (Input.GetKeyDown(KeyCode.A))
{
StartCoroutine(RotatePlayer(Vector3.back * 90, Vector3.left, time));
}
}
private IEnumerator RotatePlayer(Vector3 byAngle, Vector3 dir, float inTime)
{
Quaternion fromAngle = contactPoint.transform.rotation;
Quaternion toAngle = Quaternion.Euler(transform.eulerAngles - byAngle);
for (float t = 0; t < 1; t += Time.deltaTime / inTime)
{
rig.MovePosition(transform.position + (dir * speed * Time.deltaTime));
rig.MoveRotation(Quaternion.Slerp(fromAngle, toAngle, t));
yield return null;
}
}
}
Your main issue is: You should do Physics related things like movement of a Rigidbody only in FixedUpdate.
For Coroutines Unity provides WaitForFixedUpdate which does exactly what the name says, making sure the code after it is executed in a FixedUpdate physics call.
private IEnumerator RotatePlayer(Vector3 byAngle, Vector3 dir, float inTime)
{
yield return new WaitForFixedUpdate();
// here I would also use "rig" instead of "transform"
Quaternion fromAngle = contactPoint.transform.rotation;
Quaternion toAngle = Quaternion.Euler(rig.eulerAngles - byAngle);
for (float t = 0; t < 1; t += Time.deltaTime / inTime)
{
yield return new WaitForFixedUpdate();
// here I would also use "rig" instead of "transform"
rig.MovePosition(rig.position + (dir * speed * Time.deltaTime));
rig.MoveRotation(Quaternion.Slerp(fromAngle, toAngle, t));
}
}
beyond that it is a bit unclear what exactly you define as not move well. You also should somehow make sure that only one routine is running at a time. Either by terminating already running routines like
private void Update()
{
if (Input.GetKeyDown(KeyCode.D))
{
StopAllCoroutines();
StartCoroutine(RotatePlayer(Vector3.forward * 90, Vector3.right, time));
}
if (Input.GetKeyDown(KeyCode.A))
{
StopAllCoroutines();
StartCoroutine(RotatePlayer(Vector3.back * 90, Vector3.left, time));
}
}
or preventing new routines from starting until the current one is finished using a flag like
private bool alreadyRotating;
private IEnumerator RotatePlayer(Vector3 byAngle, Vector3 dir, float inTime)
{
if(alreadyRotating) yield break;
alreadyRotating = true;
......
alreadyRotating = false;
}
I'm making an isometric 3d game like Brawl Stars, and I'm trying to get the same movement, but I have some troubles. My player moves without a fixed speed,but it seem to be increased. How can solve it? The first script if of the virtual joystick and the second one is of the player movement.
Could be a problem of mass?
Joystick script:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;
public class VirtualJoystick : MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler
{
private Image bgImg;
private Image joystickImg;
private Vector3 inputVector;
private void Start()
{
bgImg = GetComponent<Image>();
joystickImg = transform.GetChild(0).GetComponent<Image>();
}
public virtual void OnDrag(PointerEventData ped)
{
Vector2 pos;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(bgImg.rectTransform, ped.position, ped.pressEventCamera, out pos))
{
pos.x = (pos.x / bgImg.rectTransform.sizeDelta.x);
pos.y = (pos.y / bgImg.rectTransform.sizeDelta.x);
inputVector = new Vector3(pos.x * 2 + 1, 0, pos.y * 2 - 1);
inputVector = (inputVector.magnitude > 1.0f) ? inputVector.normalized : inputVector;
// Move joystickImg
joystickImg.rectTransform.anchoredPosition =
new Vector3(inputVector.x * bgImg.rectTransform.sizeDelta.x / 3
, inputVector.z * (bgImg.rectTransform.sizeDelta.y / 3));
}
}
public virtual void OnPointerDown(PointerEventData ped)
{
OnDrag(ped);
}
public virtual void OnPointerUp(PointerEventData ped)
{
inputVector = Vector3.zero;
joystickImg.rectTransform.anchoredPosition = Vector3.zero;
}
public float Horizontal()
{
if (inputVector.x != 0)
return inputVector.x;
else
return Input.GetAxis("Horizontal");
}
public float Vertical()
{
if (inputVector.x != 0)
return inputVector.z;
else
return Input.GetAxis("Vertical");
}
}
Player movement's script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour
{
public float moveSpeed = 20f;
public VirtualJoystick moveJoystick;
public Rigidbody rb;
private Vector3 dir = Vector3.zero;
private bool wasMoving = false;
private void Update()
{
dir.x = moveJoystick.Horizontal();
dir.z = moveJoystick.Vertical();
if (dir.magnitude > 0)
{
wasMoving = true;
}
}
private void FixedUpdate()
{
if (wasMoving && dir.magnitude == 0f)
{
wasMoving = false;
rb.Sleep();
}
rb.AddForce(dir * moveSpeed);
}
}
How to handle character movement in Unity:
Your character is affected by physics? Use Rigidbody as you have, and use Vector3.ClampMagnitude to ensure you don't pass terminal velocity.
Your character isn't affected by physics, but affects other physical objects? Use a kinematic Rigidbody and use RigidBody.MovePosition to move.
Your character has no physics at all? Directly move it via Transform
So in your case, I'm guessing solutions 1 or 2 will work for you.
If you intend on adding force to your rb you'll have to manually limit the maximum speed your character is allowed to achieve, otherwise it will increase indefinitely or until drag is too high. Easiest way is using rb.velocity.magnitude to set a limit and only if your character is below that limit you add force.
Edit, in order to change directions:
rb.AddForce(dir * moveSpeed);
if(rigidbody.velocity.magnitude > maxSpeed){
rigidbody.velocity = Vector3.ClampMagnitude(rigidbody.velocity, maxSpeed);
}
This clamps the maximum velocity of the rigidbody after applying a force, this way you will change directions but not speed up.
Also be aware that using the joystick directions like you are doing might make your character move faster when moving diagonally.
I solved by myself changing "rb.AddForce(dir * moveSpeed);" to "rb.position+= dir*(moveSpeed/10);"
I am new to unity and don't know a lot of stuff. I've been watching tutorials and I saw one in which the guy created a replica of famous 'Chilly Snow'. The game is complete but the movement of ball isn't like the one in chilly snow. The ball starts orbiting continuously when I press mouse button. I wanted to know how to create that kind of movement, so that the ball turns left and right in a curve but doesn't go in to an orbit. I googled a lot but wasn't able to find my required result. I would really appreciate if anyone could point me in the right direction. Images are attached.Chilly Snow | Movement of my ball
public class movement : MonoBehaviour {
private float points;
public float playerSpeed;
private float rotationSpeed;
public Text score;
private bool isMovingLeft;
public GameObject player;
public bool isDead;
void Start () {
Time.timeScale = 0;
isDead = false;
isMovingLeft = true;
points = 0;
}
void Update ()
{
if (isDead == false)
{
points += Time.deltaTime;
}
transform.Translate (Vector3.down * playerSpeed * Time.deltaTime);
if (Input.GetMouseButtonDown (0))
{
Time.timeScale = 1;
isMovingLeft = !isMovingLeft;
rotationSpeed += 0.5f * Time.deltaTime;
}
if (Input.GetMouseButton (0))
{
rotationSpeed = 1f;
}
if (isMovingLeft) {
rotationSpeed += 1.5f * Time.deltaTime;
transform.Rotate(0,0,rotationSpeed);
} else
transform.Rotate(0,0, - rotationSpeed);
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Obstacle") {
Die ();
}
}
public void Die()
{
playerSpeed = 0f;
isDead = true;
Invoke ("Restart", 2f);
}
void Restart(){
SceneManager.LoadScene ("Ski_scene_1");
}
void FixedUpdate()
{
score.GetComponent<Text>().text = points.ToString("0");
}
}
Here is how I would approach it without doing a rotation... using your code.
public class movement : MonoBehaviour {
private float points;
public Text score;
public GameObject player;
public bool isDead;
private float currentXSpeed;
private float targetSpeed;
public float maxXSpeed;
public float speedChange;
void Start () {
Time.timeScale = 0;
isDead = false;
isMovingLeft = true;
points = 0;
targetSpeed = maxXSpeed;
}
void Update ()
{
if (isDead == false)
{
points += Time.deltaTime;
}
if(Input.GetMouseButtonDown(0))
{
Time.timeScale = 1;
targetSpeed = -targetSpeed;
}
currentSpeed = mathf.MoveTowards(currentSpeed, targetSpeed, speedChange * Time.deltaTime);
Vector3 movementDirection = new Vector3(currentSpeed, Vector3.down.y * playerSpeed, 0.0f);
transform.Translate (movementDirection * Time.deltaTime);
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Obstacle") {
Die ();
}
}
public void Die()
{
playerSpeed = 0f;
isDead = true;
Invoke ("Restart", 2f);
}
void Restart(){
SceneManager.LoadScene ("Ski_scene_1");
}
void FixedUpdate()
{
score.GetComponent<Text>().text = points.ToString("0");
}
}
You need something like sinusoidal movement or any other graph you fancy.
An example would be for this is like;
gameObject.transform.Translate(Vector3.right * Time.deltaTime*cubeSpeed);
gameObject.transform.position += transform.up * Mathf.Sin (Time.fixedTime * 3.0f ) * 0.1f;
Above pseudo is for 2D graph simulation, can be adapted to your situation.
The object is always moving to right and going up and down while making a sinusoidal movement. Because the up and down speed is not fixed hence you get the sinusoidal or like sinusoidal movement.
In your case, while the object is always going down it will make the sinusoidal movement to left and right.
Your movement is based on the rotation so, if you give this sinusoidal speed as your rotation speed, you can achieve this.
Another aproach can be lerp or slerp
Lerp allows you to make kinda smooth transactions between 2 vectors.
Like moving from pointA to pointB in X seconds.
For rotation you will need Quaternion.Lerp There is a great answer on Unity Answers you can check that if you haven't before.
Hope this helps! Cheers!