So I have successfully built a script that can determine the physics for a ball reflecting linearly off of walls, similar to pong, while the ball is using a kinematic rigidbody. The issue is when the ball hits the wall and the OnCollisionEnter2D is called, the ball has had it's position adjusted based on it's velocity such that it is phased inside the wall a tiny amount. My understanding is that this is necessary in order for the engine to recognize the collision. The ball seemingly reflects like normal, but in the uncommon event that the reflected angle allows the ball to travel while still having it's collider phased inside the wall, and the ball impacts a different surface of the wall, this 2nd impact will not result in the OnCollisionEnter2D call and the reflecting result, since technically the collider never left the wall in this time. This causes the ball to fly past the wall and off-screen.
I've tried many solutions to fix this, mainly making it so that before the bounce occurs but in the collision event, I would move the ball back to the precise location where the edge of the ball hit the edge of the wall. This would mean that the collider of the ball is in-bounds at all times and therefore no odd behavior as a result of overlapping would occur. I've yet to find a good method to do this, and I'm wondering if there is one that could be suggested to me or if there's a different solution entirely (which doesn't involve changing the ball's rigidbody from kinematic).
Below is the appropriate parts of the script I have written currently, as well as an image of what the game view looks like for visualization.
public class sword : MonoBehaviour {
public Rigidbody2D rb;
public CircleCollider2D coll;
public float speed;
public Vector2 trajectory;
public GameObject Player;
// Use this for initialization
void Start () {
speed = 0.0f;
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "player")
{
transform.position = new Vector2(-1000, -1000);
Player.GetComponent<movement>().equipped = true;
}
if (collision.gameObject.tag == "solid")
{
ContactPoint2D otherObject = collision.contacts[0];
Vector2 normal = otherObject.normal;
trajectory = Vector2.Reflect(trajectory, normal);
}
}
private void FixedUpdate()
{
//constantly calculating new velocity
rb.velocity = speed * trajectory;
speed = speed * 0.93f; //drag
if (speed < 0.0001f)
{
speed = 0.0f;
}
if (speed > 1)
{
Physics2D.IgnoreCollision(Player.GetComponent<CircleCollider2D>(), coll, true);
}
else
{
Physics2D.IgnoreCollision(Player.GetComponent<CircleCollider2D>(), coll, false);
}
}
}
More Details: The sword in this image is what acts like the ball. My speed variable is set from a separate script. Everything is on the default layer. The Rigidbody for the ball it is kinematic, and for the walls it is static. Trajectory is a Vector2 that corresponds with the angular direction of the ball.