Velocity of Collision2D collider/rigidbody doesn't have velocity? - c#

To start off I'm a beginner just trying to learn Unity, I'm just trying to create a Pong game.
Trying to access the velocity of a moving player object when the ball collides with the player. Tried to pass in the actual player object as a RigidBody2D and as it's BoxCollider but keep getting just empty velocities with the player movement being as below:
void Update()
{
if(Input.GetKey(MoveUp)) {
var move = new Vector2(0, 1) * Speed;
rb.velocity = move;
}
else if (Input.GetKey(MoveDown))
{
var move = new Vector2(0, -1) * Speed;
rb.velocity = move;
}
else
{
var move = new Vector2(0, -1) * 0;
rb.velocity = move;
}
}
And the collision being handled as below:
void OnCollisionEnter2D(Collision2D collision)
{
rb = GetComponent<Rigidbody2D>();
if (collision.collider.tag == "Player")
{
var playerVel = collision.rigidbody.velocity;
var playerColVel = collision.collider.attachedRigidbody.velocity;
}
}
Both these velocity variables return (0,0) along with their magnitude also being (0,0).
I am trying to follow a tutorial, but the tutorial is years old and I'm wondering has something changed to how to setup velocity or am I missing something?

The way of collision detection has changed a little in the latest version of unity. Here is the code that I use -
public PlayerMovement movement;
public GAME_MANAGER GameManager;
private void OnCollisionEnter(Collision collisionInfo)
{
if (collisionInfo.collider.tag == "Obstalce")
{
// you need to make the ball bounce like velocity += 2f;
}
if (collisionInfo.collider.tag == "Side Obstacles")
{
// here also you have to write what will be the action after the ball hit the paddle
FindObjectOfType<GAME_MANAGER>().IncreaseRightScore();
}
}
If you want more in-depth information, you can follow this tutorial - https://www.youtube.com/watch?v=gAB64vfbrhI

Managed to fix this via removing the stop and separating out the code for when the button is released. This causes the player to have it's y velocity properly.

Related

Unity3D: How to move an object in relation to another object?

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.

How to make a sprite slower when it moves over a sprite?

I have a game object called "Player" and my map is made up of short grasses and long grasses. If my player is on the long grass, I want it to slow down. One additional problem is that there are multiple Long grasses game objects in my game. Here is a screenshot of them :
https://imgur.com/hUq4baV
This is what my current movement code looks like :
public class PlayerMovement : MonoBehaviour
{
public Sprite Up;
public Sprite Down;
public Sprite Right;
public Sprite Left;
public float speed;
private SpriteRenderer sr;
// Update is called once per frame
void Update()
{
Vector3 move;
if (Input.GetKey(KeyCode.W))
{
GetComponent<SpriteRenderer>().sprite = Up;
move = new Vector2(0, speed * Time.deltaTime);
transform.position += move;
}
if (Input.GetKey(KeyCode.A))
{
GetComponent<SpriteRenderer>().sprite = Left;
move = new Vector2(speed * Time.deltaTime, 0);
transform.position -= move;
}
if (Input.GetKey(KeyCode.D))
{
GetComponent<SpriteRenderer>().sprite = Right;
move = new Vector2(speed * Time.deltaTime, 0);
transform.position += move;
}
if (Input.GetKey(KeyCode.S))
{
GetComponent<SpriteRenderer>().sprite = Down;
move = new Vector2(0,speed * Time.deltaTime);
transform.position -= move;
}
}
}
// All my code does is that on each WASD, it changes to a different sprite and moves it.
An explanation would be appreciated because I'm a beginner to this.
use colliders, eg. boxcolliders to detect if player is touching the grass.
Use a tag on you player
use the oncollisionenter2d() method on the grass
void OnCollisionEnter2D(Collision2D col) {
if(col.tag == "PlayerTag") {
playerScriptWhereSpeedIsLocated.speed = 1 //the speed you want
} }
One solution to this would be to use 2D Trigger Colliders.
Assuming your player has some sort of 2D collider attached to it, you may attach trigger colliders to your grass objects which can then send a message to the PlayerMovement script when the player enters/leaves the trigger by adding the OnTriggerEnter2D and OnTriggerExit2D methods to your PlayerMovement class. Here's an example of how this might work:
void OnTriggerEnter2D(Collider2D col)
{
// You can use gameObject.tag to determine what type of object we're colliding with
if(col.gameObject.tag == "LongGrass"){
speed = .8f;
}
}
void OnTriggerExit2D(Collider2D col)
{
if(col.gameObject.tag == "LongGrass"){
speed = 1f;
}
}
I would encourage you to look into the Collision action matrix if you are having
trouble detecting collisions in this way. You'll also make sure you tag your grass correctly for this method to work.

How to land the player right in the middle of the next stair

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.

Detect collision between player and ground Unity3D

I'm still learning Unity and right now I'm trying to make my player able to jump. Of course I don't want my player to be able to jump on forever, so my idea was to only enable jumping when the player is in contact with a floor object. This is the code I have so far:
public class PlayerController : NetworkBehaviour
{
public float speed; // Player movement speed
private bool grounded = true; // Contact with floor
private Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Show a different color for local player to recognise its character
public override void OnStartLocalPlayer()
{
GetComponent<MeshRenderer>().material.color = Color.red;
}
// Detect collision with floor
void OnCollisionEnter(Collision hit)
{
if (hit.gameObject.tag == "Ground")
{
grounded = true;
}
}
// Detect collision exit with floor
void OnCollisionExit(Collision hit)
{
if (hit.gameObject.tag == "Ground")
{
grounded = false;
}
}
void FixedUpdate()
{
// Make sure only local player can control the character
if (!isLocalPlayer)
return;
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
rb.AddForce(movement * speed);
// Detect space key press and allow jump if collision with ground is true
if (Input.GetKey("space") && grounded == true)
{
rb.AddForce(new Vector3(0, 1.0f, 0), ForceMode.Impulse);
}
}
}
But it seems OnCollisionEnter and OnCollisionExit never trigger. So the player is still able to jump whenever he wants. Am I doing something wrong?
Edit: It seems OnCollisionEnter and OnCollisionExit are triggered perfectly fine. It's just the if statements returning false. I have no idea why though.
if (GameObject.Find("Ground") != null) returned true.
Edit 2: Strangely enough both of these return Untagged:
Debug.Log(hit.gameObject.tag);
Debug.Log(hit.collider.tag);
Please give us more information
Please tell me which version of unity you are using?
Have you updated the project to some other latest version of unity?
Also give a screen shot of your 'tag' array.

how to enable and disable mouse dragging to avoid collison in unity 3d using c#

I have walls that block player movement in the scene. I want to drag the player when the path is free and disable when the player hits the wall. I can enable and disable with mouseButtonDown(). This enable only when the mouse is pressed. I dont want this.
if (Input.GetMouseButtonDown(0))
{
if (enableDrag ==false)
enableDrag = true;
}
OnMouseDrag()
{
if(enableDrag== true)
{
....
}
}
.....
void OnCollisionEnter2D (Collision2D coll)
{
if (coll.gameObject.tag == "Walls")
{
enableDrag= false;
}
}
Also I dont need unstable motion of the player when it collides with the wall.
Any comment from your experience is heplful.
Why don't you change the logic up. It sounds like you want a constant drag unless colliding with a wall. So you could in that case say:
Pseudo:
Inside your Update()
If (not colliding with walls)
DragObject()
This would require you to know when you are no longer colliding. Perhaps using OnCollisionExit.
Eventhough it is too late to answer, here is how I solved the problem.With this approach you can drag the player continously as far it is not colliding with obstacles.
void OnMouseOver ()
{
Vector2 mousePos;
Vector3 mousePosWorld = Camera.main.ScreenToWorldPoint (Input.mousePosition);
mousePos.x = mousePosWorld.x;
mousePos.y = mousePosWorld.y;
this.transform.position = Vector3.MoveTowards (transform.position, new Vector3 (mousePosWorld.x, mousePosWorld.y, 0), speed * Time.deltaTime);
if (enableDrag) {
Vector3 cursorPoint = new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 0);
Vector3 cursorPosition = Camera.main.ScreenToWorldPoint (cursorPoint) + offset;
transform.position = new Vector3 (cursorPosition.x, cursorPosition.y, 0);
}
If void OnCollisionEnter2D (Collision2D coll)
{
if (coll.gameObject.tag == "Obstacle")
{
enableDrag= false;
}
}

Categories

Resources