I am learning game development and I want to replicate an “air hockey” game like this one:
https://store.steampowered.com/app/750330/Air_Hockey/
I want to control the disk with the mouse and with the disk, I can collide with the puck to score a goal.
My issue is that sometimes the puck goes through the wall like in the following picture (the puck is the yellow game object and the black game object is the disk):
This happens in the corner of the table or when there is a high velocity.
Another example where the puck is completely inside the walls:
I would like to use Unity physics to learn how to develop this game so I created the following game objects:
the table: collider
4 borders: collider
the disk: collider + rigidbody with collision detection “continuous”
the puck: collider + kinematic rigidbody + collision detection “continuous” with the following script:
void FixedUpdate()
{
Vector3 m_Input = new Vector3(Input.GetAxis("Mouse X"), 0, Input.GetAxis("Mouse Y"));
playerRigidbody.MovePosition(transform.position + m_Input * Time.deltaTime * moveSpeed);
}
How can I prevent the disk to go through the wall? Why is this happening?
I also changed various settings in Edit --> project settings --> physics --> Default max depenetration velocity
I am following the best way to develop this kind of game (having a kinematic disk controlled with the script I write before)?
Any suggestion is welcome.
Thank you
A kinematic rigidbody will not be affected by collisions with other physics objects (such as the walls in your game). As mentioned in the Unity documentation:
If isKinematic is enabled, [...] collisions [...] will not affect the rigidbody anymore.
Because of this, you can't rely on the physics simulation to handle this interaction. One strategy you can use here is to define bounds within which the player disc is allowed to move, then use Mathf.Clamp to constrain the position of the disc to prevent it from moving out of them.
So with a few additions, your code might become:
public Vector3 minBounds;
public Vector3 maxBounds;
public float discRadius;
void Awake(){
minBounds = new Vector3(minBounds.x + discRadius, 0, minBounds.z + discRadius);
maxBounds = new Vector3(maxBounds.x - discRadius, 0, maxBounds.z - discRadius);
}
void FixedUpdate()
{
Vector3 m_Input = new Vector3(Input.GetAxis("Mouse X"), 0, Input.GetAxis("Mouse Y"));
Vector3 newPosition = transform.position + m_Input * Time.deltaTime * moveSpeed;
Vector3 clampedPosition = new Vector3(
Mathf.Clamp(newPosition.x, minBounds.x, maxBounds.x),
newPosition.y,
Mathf.Clamp(newPosition.z, minBounds.z, maxBounds.z));
playerRigidbody.MovePosition(clampedPosition);
}