i am trying to make a 2D unity platformer that shoots projectiles to the mouse direction.
so, i was trying to make the player move. but, there is a problem. it does not jump as i expected. when i pressed the jump key, sometimes, it jumps, but sometimes, it doesn't. and i think the jump doesn't usualy work while moving but i don't know how to fix this.
i tried putting the jump function into the if statement,changed variables, but it still doesn't work as i thought.
i used the sprite render to flip the sprite so the child objects does not flip with the player later in the game progress(because when i did it by vector and rotation at my first try, it didn't ended well)
public class playerMovement : MonoBehaviour
{
//movement variables
public float speed;
private float moveInput;
//player components
private Rigidbody2D rb;
private SpriteRenderer spriteRender;
//jump variables
private float jumpInput;
public float jumpForce;
//ground variables
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
spriteRender = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void FixedUpdate()
{
moving();
jumping();
}
//move left & right function
void moving()
{
moveInput = Input.GetAxis("Horizontal");
if (moveInput > 0)
{
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
spriteRender.flipX = false;
}
else if (moveInput < 0)
{
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
spriteRender.flipX = true;
}
}
//jump function
void jumping()
{
//this input is what i tried for the jump function at the first
//jumpInput = Input.GetAxis("Jump");
//rb.velocity = new Vector2(rb.velocity.x, jumpInput * jumpForce);
//but it fell down slowly so i made this line of code
if (Input.GetButtonDown("Jump"))
{
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
}
}
}
He I had the same mistake. You just have to put "jumping()" in "Update()"!
Because if it is in the Fixedupdate it will only allow you to jump every second or something like that.
https://docs.unity3d.com/ScriptReference/Rigidbody2D.AddForce.html
Alternatively, you could use rb.AddForce to make the character jump.
Related
I'm making a 2D game where the player moves left and right while dodging falling objects, I put triggers so it doesn't leave the screen but sometimes when it collides with these triggers it passes this collider. I sent an image of the colliders, the Player inspector and also a collider.
Here my Player code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Ball : MonoBehaviour
{
public bool isRight;
public float speed;
public Transform pointR;
public Transform pointL;
Rigidbody2D rb;
private SpriteRenderer sprite;
private float maxSpeed;
[Header("PowerUps")]
public float force;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
sprite = GetComponent<SpriteRenderer>();
maxSpeed = 600f;
}
void Update()
{
if(Input.GetMouseButtonDown(0))
{
isRight = !isRight;
}
}
void FixedUpdate()
{
if(isRight)
{
rb.velocity = new Vector2(speed, 0);
rb.AddForce(rb.velocity,ForceMode2D.Force );
sprite.flipX = true;
if(rb.velocity.x >= maxSpeed)
{
rb.velocity = new Vector2(maxSpeed, 0);
}
}
else
{
rb.velocity = new Vector2(-speed, 0 );
rb.AddForce(rb.velocity, ForceMode2D.Force );
sprite.flipX = false;
}
}
void OnTriggerEnter2D(Collider2D collider)
{
if(collider.gameObject.tag =="ColliderL")
{
isRight = !isRight;
}
if(collider.gameObject.tag == "ColliderR")
{
isRight = !isRight;
}
// For PowerUps
if(collider.gameObject.tag == "SpeedUp")
{
StartCoroutine(Seconds());
}
}
IEnumerator Seconds()
{
rb.AddForce(rb.velocity * force);
yield return new WaitForSeconds(5f);
rb.AddForce(rb.velocity * -force);
}
}
I would ideally need to see your scene setup to further pinpoint your mistakes. But these are a few common mistakes that are made:
Tags are case-sensitive. Also, make sure to assign them.
Your collider on one of the object is not 2D; There is Collider, then there is Collider2D.
Your collider is not marked as trigger.
Though there are a few non-related problems with your setup:
rb.velocity.collider doesn't exist. You are looking for rb.velocity.
Ideally you want to set physics changes (velocity, in your case) to FixedUpdate() instead.
If you do want to get colliders from RigidBody, use GetAttachedColliders.
Assuming you are setting up a border which the player can never pass through, you should use a full collider instead of a trigger. This uses OnCollisionEnter2D.
new Vector2(speed, 0* Time.deltaTime);
0 * Time.deltaTime does nothing, since you are multiplying by 0.
What you are looking for is probably new Vector2(speed * Time.deltaTime, 0);. But you don't need to multiply the speed by deltaTime since you are not moving the ball manually via it's Transform.
rb.velocity = new Vector2(speed, 0); should be your result.
I have a physics enabled sphere in my scene and a character that i can move around using WASD. now what i want is that as soon as player hits the ball it should not be physics enabled anymore and move along with player as like the player is holding it in the hands.
What i have tried so far:
i was able to do it but not at all perfect how i want it to be. i tried OnCollisionEnter to detect the collision, i made the sphere a child of the player, i used isKinematic = true as soon as collision is detected and i used Vector3.MoveTowards for the object to follow the position as the player.
I have attached two reference videos below
Reference Clip(The style i am aiming for):https://www.youtube.com/watch?v=fi-GB0RwLr0
MyVersion(This is what i am able to do):https://www.youtube.com/watch?v=JtV11KHY4pU
overall, if you watch the clips you can see how my version is very rigid, stucky, buggy, not so light weight feeling at all. Cut me a slack as well if i did anything way wrong, i started unity like just in the previous month.
This is my Player script through which i am controlling it all
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Player : MonoBehaviour
{
public float MoveSpeed;
[SerializeField]private Rigidbody playerRig;
[SerializeField] private Rigidbody ballRig;
[SerializeField] private GameObject Ball;
[SerializeField] private GameObject heldObj;
private bool isTouching = false;
private Vector3 offset = new Vector3(0, 1, 3);
private Vector3 force;
public float jump;
private bool isGrounded = true;
private void Start()
{
Ball = GameObject.FindGameObjectWithTag("Ball");
ballRig.GetComponent<Rigidbody>();
playerRig.GetComponent<Rigidbody>();
}
void Update()
{
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
playerRig.velocity = new Vector3(x*MoveSpeed, playerRig.velocity.y,z*MoveSpeed);
Vector3 vel = playerRig.velocity;
vel.y = 0;
if (vel.x != 0 || vel.z != 0)
{
transform.forward = vel;
}
if(transform.position.y < -10)
{
GameOver();
}
ReleaseTheBall();
if (isTouching == true)
{
ballRig.transform.position = Vector3.MoveTowards(ballRig.transform.position, playerRig.transform.position, 5f);
}
}
void Jump()
{
force = new Vector3(0, jump, 0);
if (Input.GetKeyDown(KeyCode.Space) && isGrounded == true)
{
isGrounded = false;
playerRig.AddForce(force, ForceMode.Impulse);
}
}
private void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.tag == "Ball" && heldObj == null)
{
ballRig.isKinematic = true;
// ballRig.constraints = RigidbodyConstraints.FreezeRotation;
ballRig.transform.parent = playerRig.transform;
isTouching = true;
Debug.Log(" BALL PICKED UP AND MOVING ");
heldObj = Ball;
}
}
public void ReleaseTheBall()
{
if (Input.GetKeyDown(KeyCode.Space) && heldObj != null)
{
isTouching = false;
heldObj = null;
ballRig.transform.parent = null;
//ballRig.constraints = RigidbodyConstraints.None;
ballRig.isKinematic = false;
//Vector3 forceDirection = new Vector3(playerRig.transform.position.x, 0, playerRig.transform.position.z);
Vector3 rotationDirection = new Vector3(playerRig.transform.rotation.x, playerRig.transform.rotation.y, playerRig.transform.rotation.z);
ballRig.AddForce(new Vector3(transform.position.x,0,transform.position.z) * 5, ForceMode.Impulse);
ballRig.AddTorque(rotationDirection * 1);
Debug.Log("BALL RELEASED");
}
}
public void GameOver()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
i know there could be some very inefficient lines of code here, feel free to call out those lines as well.
So, basically what i want is that i want my player to pick up the ball as soon as it hits it and the ball should move exactly like player as if he is holding the ball in his hands and when i hit the spacebar i want the ball to be released into the direction i am looking(this part is also very tricky for me), what i am trying to do is i want to do exactly like in the refrence clip. Thanks a lot in advance.
one more thing, when i stop pressing any key to move(WASD), my player transform keeps changing values up and down and it slightly starts moving. i mean when i dont press any key, it still kinda moves.
First of all, you have indeed quite a lot of lines that aren't useful in here and that could be optimized.
Anyway, I hope this will do what you want it to do:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
[RequireComponent(typeof(Rigidbody))]
public class Player : MonoBehaviour {
[Header("Movement Setup")]
[Tooltip("Translation speed in m/s")]
[SerializeField] float _TranslationSpeed;
[Tooltip("Rotation speed in °/s")]
[SerializeField] float _RotationSpeed;
[Tooltip("Interpolation speed [0;1]")]
[SerializeField] float _InterpolationSpeed;
[Tooltip("Strength for jumps")]
[SerializeField] float _JumpingStrength;
[Tooltip("Strength for shoots")]
[SerializeField] float _ShootingStrength;
[Header("Other Settings")]
[Tooltip("Where the helded item will be placed")]
[SerializeField] Transform _ContactPoint;
[Tooltip("Which layers should be considered as ground")]
[SerializeField] LayerMask _GroundLayer;
// The player's rigid body
Rigidbody _Rigidbody;
// Is the player on the ground
bool _IsGrounded;
// Rigidbody of what's the player is helding. Null if the player isn't holding anything
Rigidbody _HeldedItemRigidbody;
// Getter to _IsGrounded, return true if the player is grounded
public bool IsGrounded { get { return _IsGrounded; } }
private void Start() {
_Rigidbody = GetComponent<Rigidbody>(); // The player's rigidbody could be serialized
}
void FixedUpdate() {
float horizontalInput, verticalInput;
// Getting axis
horizontalInput = Input.GetAxis("Horizontal");
verticalInput = Input.GetAxis("Vertical");
// Moving toward the x
Vector3 moveVect = transform.forward * _TranslationSpeed * Time.fixedDeltaTime * verticalInput;
_Rigidbody.MovePosition(_Rigidbody.position + moveVect);
// Rotating the player based on the horizontal input
float rotAngle = horizontalInput * _RotationSpeed * Time.fixedDeltaTime;
Quaternion qRot = Quaternion.AngleAxis(rotAngle, transform.up);
Quaternion qRotUpRight = Quaternion.FromToRotation(transform.up, Vector3.up);
Quaternion qOrientationUpRightTarget = qRotUpRight * _Rigidbody.rotation;
Quaternion qNewUpRightOrientation = Quaternion.Slerp(_Rigidbody.rotation, qOrientationUpRightTarget, Time.fixedDeltaTime * _InterpolationSpeed); // We're using a slerp for a smooth movement
_Rigidbody.MoveRotation(qRot * qNewUpRightOrientation);
// This prevents the player from falling/keep moving if there is no input
if (_IsGrounded) _Rigidbody.velocity = Vector3.zero;
_Rigidbody.angularVelocity = Vector3.zero;
if (transform.position.y < -10) GameOver();
if (Input.GetKey(KeyCode.Mouse0) && _HeldedItemRigidbody != null) ShootTheBall();
if (!_IsGrounded) return; // What's below this won't be executed while jumping
if (Input.GetKey(KeyCode.Space)) Jump();
}
void Jump() {
_IsGrounded = false;
_Rigidbody.AddForce(_JumpingStrength * transform.up, ForceMode.Impulse);
}
private void OnCollisionEnter(Collision collision) {
// Checking if the player encountered a ground object
if ((_GroundLayer & (1 << collision.gameObject.layer)) > 0) _IsGrounded = true;
if (collision.gameObject.tag == "Ball") { // this can be improved as tags are error prone
// Setting the item position to contact point
collision.gameObject.transform.position = _ContactPoint.position;
// Getting the rigidbody
_HeldedItemRigidbody = collision.gameObject.GetComponent<Rigidbody>();
// Setting the parent
_HeldedItemRigidbody.transform.parent = transform;
// Setting the body to be kinematic
_HeldedItemRigidbody.isKinematic = true;
// Stopping any movement or rotation
_HeldedItemRigidbody.velocity = Vector3.zero;
_HeldedItemRigidbody.angularVelocity = Vector3.zero;
}
}
public void ShootTheBall() {
// Reverting what's done in OnCollisionEnter
_HeldedItemRigidbody.transform.parent = null;
_HeldedItemRigidbody.isKinematic = false;
// Adding force for the shoot
_HeldedItemRigidbody.AddForce(transform.forward * _ShootingStrength, ForceMode.Impulse);
// Resetting helding item to null
_HeldedItemRigidbody = null;
}
public void GameOver() {
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
You have to add a layer, and set the ground to this new layer.
Set up the variable as you like, don't hesitate to mess up with it a little bit to find what suits you (and don't forget to set up the player's mass (in rigidbody) as well!!)
Exemple of setup for the player script
Last things, you have to add an empty game object to your player which will be where the ball will be placed. I know it's a little bit dirty but place it a bit far from the player (more than the ball's radius) or it will bug. We could do something programatically to fix the ball at a spot and adapt this spot to the ball's radius.
This is an example of player
As you can see, I have the empty "player" gameobject which has the rigidbody, the collider and the player script.
The GFX item which is just the capsule.
If you don't know about this: the player game object is actually on the floor (at the player's feet) so it's better for movements. If you do this, don't forget to adjust the player's capsule collider to fit the GFX.
I also have the contact point.
Forget about the nose stuff, it's just a way to see where the player is facing when you just have a capsule.
If you have any question, feel free to ask.
I'm making a unity game based off of TierZoo, and while testing a movement script, i crashed into one of the rigidbody trees for fun... and that made the player prefab stop moving forward, and it started moving in odd directions Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewPlayerController : MonoBehaviour
{
private Rigidbody rb;
public GameObject player;
public float thrust = 1.0f;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.W))
{
rb.AddRelativeForce(player.transform.right * thrust * 2.5f);
}
if (Input.GetKey(KeyCode.A)) { player.transform.Rotate(0, -1, 0); }
if (Input.GetKey(KeyCode.D)) { player.transform.Rotate(0, 1, 0); }
if (Input.GetKey(KeyCode.S))
{
rb.AddRelativeForce(player.transform.right * thrust * -2.5f);
}
}
}
If you can find a way to fix this, let me know.
You could fix the rotation also in Y direction by keeping track of it and setting it hard in FixedUpdate.
In general as said in the comments:
Whenever a Rigidbody is involved you should not
do movements through the transform component
do movements in Update
both breaks the physics engine and you might get strange and unexpected movements or simply no collisions working etc.
Rather do
- go through the Rigidbody component e.g. using MovePosition and MoveRotation
- do these in FixedUpdate
these keeps the physics intact and moves your Rigidbody only e.g. until it collides meanwhile.
Then for the rotation you have framerate-dependent values Rotate(0, -1, 0)! You rather want to use Time.deltaTime in order to get smooth framerate-independent rotation speed - not in 1 degree per frame but rather e.g. 45 degrees per second.
You script could look like
public class NewPlayerController : MonoBehaviour
{
// already reference this via the Inspector
[SerializeField] private Rigidbody rb;
public GameObject player;
public float thrust = 1.0f;
private void Awake()
{
// as fallback get it on runtime
if(!rb) rb = GetComponent<Rigidbody>();
}
bool moveLeft;
bool moveRight;
bool rotateLeft;
bool rotateRight;
private float angle;
void Update()
{
// Get User input here
// (in your case it would be also fine to do it in FixedUpdate.
// What doesn't work in FixedUpdate are mainly the one-time events like GetKeyDown)
moveRight = Input.GetKey(KeyCode.W);
rotateLeft = Input.GetKey(KeyCode.A);
rotateRight = Input.GetKey(KeyCode.D);
moveLeft = Input.GetKey(KeyCode.S);
}
private void FixedUpdate()
{
if(moveRight) rb.AddRelativeForce(rb.rotation * Vector3.right * thrust * 2.5f);
if(moveLeft) rb.AddRelativeForce(rb.rotation * Vector3.right * thrust * -2.5f);
// Now for the rotations keep track of what you rotated already
// and overwrite the rotation with the fix value:
if(rotateLeft)
{
// e.g. for rotating 45°/second
angle -= -45 * Time.deltaTime;
rb.MoveRotation(Quaternion.Euler(0, angle, 0));
}
if(rotateRight)
{
angle += 45 * Time.deltaTime;
rb.MoveRotation(Quaternion.Euler(0, angle, 0));
}
}
}
I am developing a 3D game like "Stairs By Ketchapp" in Unity.
I am moving the stairs backward instead of moving the player forward by using "transform.Translate" and I am making the player(which is a ball) jump whenever it hit the ground.
The player can only move on the X-axis, Y-axis and I have frozen the Z coordinates for the player so that it cannot move forward or backward by hitting the edge of a stair. Whenever the player hits the ground it jumps back.
The problem is with the landing of the player.
I want the player to land right in the middle of the next stair regardless of its position on the X-axis. so that it can look like it traveled the distance of one stair in one jump.
Here is the stair script
public class Stairmovement : MonoBehaviour {
public float speed;
Vector3 destroyPos;
private void Start()
{
destroyPos = new Vector3(0, -0.5f, -2f);
}
// Update is called once per frame
void Update () {
transform.Translate(new Vector3(0, -0.5f, -2f) * Time.deltaTime * speed);
if(transform.position.z <= destroyPos.z)
{
//transform.position = new Vector3(0, 4f, 16);
transform.position = new Vector3(0, transform.position.y + 4.5f, transform.position.z + 18f);
}
}
}
And this is my player script
public class Player : MonoBehaviour {
private Rigidbody myRigidbody;
public bool grounded;
public float jumpSpeed;
public float forwardSpeed;
public float fallMultiplier;
// Use this for initialization
void Start () {
myRigidbody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update () {
if (grounded)
{
myRigidbody.velocity = new Vector3(myRigidbody.velocity.x, jumpSpeed, forwardSpeed);
grounded = false;
}
if (this.gameObject.transform.position.y > 1f)
{
myRigidbody.velocity += Vector3.up * Physics.gravity.y * (fallMultiplier) * Time.deltaTime;
}
}
private void OnCollisionEnter(Collision other)
{
if (other.transform.tag == "Ground")
{
Debug.Log("Grounded");
grounded = true;
}
}
}
I need your help guys, I hope you guys can understand the problem, if not then please do let me know. I'll try to explain it better. I'll appreciate any kind of help, Thank you.
This is an image showing the difference between jumping position and landing position. [Note: please keep it in mind that I am moving the stairs.]
![Image]: https://i.stack.imgur.com/VW9FK.png
The idea is you need to play with the stair's backward movement speed so that each stair will only move "1 stair length" through the duration of time that ball is on air. So lets say if each stair's movement taking 1 second, then the ball should also be on air exaclty 1 second and land on the stair.
I'm working on a 2D game (for smartphone) which is automatically jumping, and I want to give a player movement (accelerometer) (a similar principle as doodle jump). How to make automatically jumping of 2D sprite? I tried to create an animation but it will not move using the accelerometer. So I coded script for automatically jump but it's not working. any help? (automatically jump means when player hits ground, jump again)
public float speed = 6.0F;
public float jumpSpeed = 8.0F;
public float gravity = 20.0F;
private Vector3 moveDirection = Vector3.zero;
Rigidbody2D coll;
void Start(){
coll = GetComponent<Rigidbody2D>();
}
void Update() {
if (coll.gameObject.tag == "Ground") {
moveDirection = Vector3.zero;
moveDirection.x = 1;
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
}
}
}
So can someone give me script when player hit ground, player will jump? I want to move up and to the right.
Player object should have collider2D and rigidbody2D. Ground object should have collider2D and "Ground" tag. This code must be on player object.
public int power;
void Update()
{
transform.position = new Vector3(transform.position.x + Input.acceleration.x, transform.position.y, transform.position.z);
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.collider.gameObject.tag.Equals("Ground"))
{
rigidbody2D.AddForce(Vector2.up * power);
}
}
I hope it works.