- Home /
Can you override the physics behaviour for a particular object?
I'm currently trying to make a simple pong game using the built in physics. I've made a script that changes the velocity and direction of the ball when hitting the paddle. It works as long as the ball hits the right or left side of the paddle, but when the ball hits the bottom or top of the paddle It seems like the ball recives both the instructions of my script, but also inherits the speed of the paddle and moves a lot faster than intended. So I'm wondering if there is a way to disable the normal physics of the ball when hitting the paddle so that my script is the only thing modifying the velocity. I've tried using triggers, but this only resulted in the ball flying trough the paddle when at higher speeds.
Here is my code. The OnCollisionEnter2D is the interesting part. That is where I change the direction and velocity of the ball. My idea was that depending on where you hit the paddle the ball goes in a different direction. If it hits the top half the ball goes up, if it hits the bottom part the ball goes down. I also made the ball speed up every time the ball hits the paddle.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(BoxCollider2D))]
public class Player : MonoBehaviour {
public enum Players {Player1, Player2}
public Players player = Players.Player1;
public float range = 120;
public float speed = 2;
public float speedAddition = 0.5f;
float movementInput = 0;
Rigidbody2D rb2d;
BoxCollider2D boxCollider;
void Start() {
rb2d = GetComponent<Rigidbody2D>();
boxCollider = GetComponent<BoxCollider2D>();
}
void Update () {
GetInput();
}
void FixedUpdate() {
Move();
}
void GetInput() {
movementInput = Input.GetAxisRaw("Vertical");
}
void Move() {
if(movementInput != 0)
{
float yVel = movementInput * speed;
rb2d.velocity = new Vector2(0, yVel);
} else
{
rb2d.velocity = Vector2.zero;
}
}
private void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.layer == LayerMask.NameToLayer("Ball"))
{
Rigidbody2D ball = collision.gameObject.GetComponent<Rigidbody2D>();
Vector2 dir = ball.transform.position - transform.position;
float lerpVal = 0.5f + (dir.y / transform.localScale.y);
Quaternion newDir = Quaternion.Lerp(Quaternion.Euler(0, 0, -range / 2), Quaternion.Euler(0, 0, range / 2), lerpVal);
float ballSpeed = ball.gameObject.GetComponent<Ball>().speed += speedAddition;
Vector2 newVel;
switch (player)
{
case Players.Player1:
newVel = (newDir * Vector2.right) * ballSpeed;
break;
case Players.Player2:
newVel = (newDir * Vector2.right) * ballSpeed;
newVel.x = -newVel.x;
break;
default:
newVel = Vector2.zero;
break;
}
ball.velocity = newVel;
// Do cool animation or sum ting
Debug.Log("(Player) Boing");
}
}
}
Just in case. Here is the code for the ball.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class Ball : MonoBehaviour {
public bool goRightOnStart = true;
public float speed = 1;
Vector2 direction = Vector2.right;
Rigidbody2D rb2d;
void Start() {
rb2d = GetComponent<Rigidbody2D>();
if (!goRightOnStart)
direction = Vector2.left;
}
public void Activate() {
rb2d.velocity = direction * speed;
}
private void OnCollisionEnter2D(Collision2D collision) {
if (LayerMask.NameToLayer("Deadzone") == collision.gameObject.layer)
{
// Tell Manager to start new round
Manager.EndRound(transform.position.x > 0);
Destroy(gameObject);
}
}
}
I need help to somehow get rid of this weird behaviour when hit I the ball on the top or bottom of the paddle. Any ideas?
Without code we can only guess what you're doing now, so there's not much to say that doesn't turn into writing a book on how to manage physics in Unity. $$anonymous$$y first reaction is this sounds like a contradiction. If you're using physics, you shouldn't have to do anything in code to change velocity and direction when the ball hits the paddle. The paddle should strike the ball and send it moving like...being hit by a paddle. Of all the problems we do have with any real time physics engine, PhysX does seem to do this particular thing on its own fairly well. At most we have to consider physics material settings and maybe make $$anonymous$$or adjustments in code at very low speeds/forces. Why are you coding the change in velocity and direction? HOW are you doing that (which, of course, means we need to see code here).
Thank you for replying! I updated the question with the player and ball script.
If you want to prevent contact at the top and bottom edges of your paddles, you could add invisible colliders above and below the end of the paddle. When the ball collides with these zones, the actual paddle collision script could be prevented from running, leaving the ball to continue unaffected.
The problem is that I will still be able to pinch the ball and cause weird behaviour. Although what I can do is disable the collider for the player if it hits a trigger on top or below the paddle. I'll try this and see if it works, thanks.
Turns out the ball can hit both the trigger and the collider before telling the collider to deactivate. Thus sending the ball to the other side like it would when you normally hit the paddle, but also deactivates it's own collider and can no longer hit the ball.
It was a good idea but I can't seem to get it to work.
The idea is that the ball must pass through the top or bottom trigger zones before hitting the top or bottom edge of the paddle. So in the script that bounces the ball, check whether either of those zones has been triggered. If they have, don't bounce the ball.
Answer by bennett_apps · Aug 05, 2018 at 12:09 AM
If you want to completely override physics, disable the rigidbody. Otherwise the rigidbody will affect how the ball moves
At the beginning when I started making the game I wanted to make it as simple as possible and let the rigidbody handle all the collisions with the borders. But now I've spent so much time trying to fix this problem that I might as well write my own code for colliding with the borders (unless there still is some easy solution hiding from me). The thing is that everything would work as I wanted it to if I could use triggers. BUT triggers have such a slow update rate (it seems...) that if the ball passes fast enough the trigger won't respond, thus letting the ball pass through it. Colliders seem to act differently, not allowing the ball to pass through (regardless of the speed), buuut colliders have the ability to modify the velocities of objects that bump into them, and as you can see, cause them to act in a different way than I was going for. If there is a way to have triggers respond immedietly when something enters that would make things a ton easier. But for now I haven't found a way to do so.
Are you sure you are using triggers correctly? Have you been able to make them fire at all? I am just wondering that if there is an error in your trigger script, you are diagnosing triggers as being too slow, but actually they're just not working at all. You are right that you have to make your own code for the ball direction as opposed to relying on physics. You want the ball to bounce upwards when it hits the upper part of the front of the paddle, regardless of inco$$anonymous$$g direction. Physics won't do that. So physics are only helping on your boundary bounces.
...or there is a way of just relying on physics and colliders if you set up your paddle collider like this:
This will give you the directional change across the height of the paddle you are after.