Air Hockey Game - Player flies the puck if moving too fast

I am currently developing an Air hockey game in Unity3d. The problem that I encounter is that when a player tries to hit the puck too quickly, the player enters through the puck and therefore no collision occurs. The game works perfectly as expected if the player remains stationary and the puck hits the player or if the player scores the puck at a slow pace.

The player has a rigid body using continuous collision detection using the capsule collider. The puck also has a rigid body with continuous dynamic collision detection and a mesh collider with a convex.

I tried to set a fixed time interval to 0.01, but this did not affect. Here is the script for player movement:

void ObjectFollowCursor() { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); Vector3 point = ray.origin + (ray.direction * distance); Vector3 temp = point; temp.y = 0.2f; // limits player on y axis cursorObject.position = temp; } 

and here is the puck code when it collides with the player:

 // If puck hits player if(collision.gameObject.tag == "Player") { Vector3 forceVec = this.GetComponent<Rigidbody>().velocity.normalized * hitForce; rb.AddForce(forceVec, ForceMode.Impulse); Debug.Log ("Player Hit"); } 

Any help would be greatly appreciated. Thank you

+6
source share
2 answers

You were right to try Continuous Collision Detection (CCD). There are some limitations (especially in this case when you want to use CCD with two moving objects, and not with one moving object and one static object), but it is intended for such a scenario. Rigidbody documentation covers the following restrictions:

Set the collision detection mode to Continuous to prevent a solid body passing through any static (i.e. non-rigid body) MeshColliders. Set Continuous Dynamic to Rigid through any other supported rigid bodies with collision detection set to Continuous or Continuous Dynamic. Continuous collision detection is supported for Box-, Sphere-, and CapsuleColliders.

To summarize, both washers and paddles must be installed in Continuous Dynamic, and both must be Box-, Sphere-, or Capsule Colliders. If you can make these restrictions work for your game, you can get continuous collision detection without recording them yourself.


A note on CCD Unity that repeats:

Note that continuous collision detection is intended as a protective grid to catch collisions in cases where objects would otherwise pass through each other but would not deliver physically accurate collisions of results, so you can still consider reducing a fixed time step value in the TimeManager inspector to make the simulation more accurate if you encounter problems with fast-moving objects.

But since you manually specify a reaction to a collision, this may not be a problem.

+2
source

The problem you are causing is called tunneling.

This is because your subject is moving at high speed, and no collision has been detected in this particular frame. In frame n ball is located directly in front of the bat, but when frame n+1 calculated, the ball moves behind the bat, so the collision is “completely absent”.

This is a common problem, but there are solutions.

I recommend that you study this script and try to implement it in your game.

This is not my code: SOURCE: http://wiki.unity3d.com/index.php?title=DontGoThroughThings

 using UnityEngine; using System.Collections; public class DontGoThroughThings : MonoBehaviour { // Careful when setting this to true - it might cause double // events to be fired - but it won't pass through the trigger public bool sendTriggerMessage = false; public LayerMask layerMask = -1; //make sure we aren't in this layer public float skinWidth = 0.1f; //probably doesn't need to be changed private float minimumExtent; private float partialExtent; private float sqrMinimumExtent; private Vector3 previousPosition; private Rigidbody myRigidbody; private Collider myCollider; //initialize values void Start() { myRigidbody = GetComponent<Rigidbody>(); myCollider = GetComponent<Collider>(); previousPosition = myRigidbody.position; minimumExtent = Mathf.Min(Mathf.Min(myCollider.bounds.extents.x, myCollider.bounds.extents.y), myCollider.bounds.extents.z); partialExtent = minimumExtent * (1.0f - skinWidth); sqrMinimumExtent = minimumExtent * minimumExtent; } void FixedUpdate() { //have we moved more than our minimum extent? Vector3 movementThisStep = myRigidbody.position - previousPosition; float movementSqrMagnitude = movementThisStep.sqrMagnitude; if (movementSqrMagnitude > sqrMinimumExtent) { float movementMagnitude = Mathf.Sqrt(movementSqrMagnitude); RaycastHit hitInfo; //check for obstructions we might have missed if (Physics.Raycast(previousPosition, movementThisStep, out hitInfo, movementMagnitude, layerMask.value)) { if (!hitInfo.collider) return; if (hitInfo.collider.isTrigger) hitInfo.collider.SendMessage("OnTriggerEnter", myCollider); if (!hitInfo.collider.isTrigger) myRigidbody.position = hitInfo.point - (movementThisStep / movementMagnitude) * partialExtent; } } previousPosition = myRigidbody.position; } } 
+5
source

All Articles