9

In unity, i have a racket which is supposed to hit a ball, and the racket is controlled directly by the mouse, i.e the bat is being moved by the mouse using mouse axes and the using transform.translate() function to move the racket.

I expected that Unity3d's physics will not properly translate the racket's movement directly by mouse and impact the ball accordingly, and i would have to write something custom, and it turned out to be true.

But the ball's collision is not being detected properly when the racket is moving. When it is still, everything is fine, and the ball behaves as i like.

Now i went as far as writing a custom physics script (i use C# for scripting) in which i attached 4 raycasts of length 0.6F to the ball, and after doing some complex vector calculations, calculate the velocity of the ball after hitting the racket, and apply it directly to the velocity of the ball using rigidbody.velocity = calculateVelocity(). Now it is again working fine when the racket is not moving, but not when i move the racket. The exact (symptoms of the) problem is:

Using built-in Physics and collision detection: When the racket is moving, the ball sometimes pass straight through the racket, and sometimes, it slows down (to unbelievable levels).

Using my script to calculate velocity: The problem is the same, but it lets me identify what is wrong when i print the normal of the collider (the racket). It sometimes give the right normal, and sometime gives the negative of the normal vector, which means that it is going straight through the top surface and detecting the hit with the bottom side of the collider (racket).

The things i have tried:

  1. Increasing the size of the collider (it works with the wider box collider on the racket, but then obviously the ball moves from quite a distance away from the racket, and my own script works here, default physics give strange results when racket is moved), in short i don't get the reality that i want.

  2. Decreasing the fixed timestamp to 0.001, which significantly improved things, but still very very far away from the result i want, and the ball is again quite often picking the wrong side of the ball.

  3. Changing collision detection to continuous dynamic. Which didn't improve things either.

And in addition to the wrong side picked at collision, another problem i have observed is that after bouncing off the racket, the ball is moves but the racket is moved faster, it instead of moving in a complete arc or line, somehow appears in front of the ball, resulting in two hits. It is a conjecture based on what is visible.

Also it is clear that the "movement" aspect of the racket is not being read by Unity3d's built in physics, resulting in strange behavior when racket is moving using mouse hits the ball.

I am stuck, i have no idea where to move from here. Please tell me what is it that i am doing wrong.

SpeedBirdNine
  • 4,610
  • 11
  • 49
  • 67

5 Answers5

8

As others have pointed out, the problem is that the ball goes from being on a side of the pad in one frame to being on the other side in the next. Fast moving objects tend to do that if the barriers are too slim.

There are three very simple solutions for this problem:

  • Increase the size of the pad or the ball, which is what happened when you changed the collider size.
  • Establish a maximum speed for the ball, so that it can never move fast enough to go through the pads.
  • Increase the frequency with which Unity makes its physics calculations. It can be changed in Time Manager, reducing the value of Fixed Timestep. Beware of reducing this too much, or the physics engine will be unable to finish a call before the next round is supposed to start and it will never be able to catch up with the game.

Setting a maximum speed for moving objects is something that must always be done. You cannot risk having an important object skyrocket during the game and leave everything in an uncontrolled state.

Elideb
  • 11,660
  • 1
  • 16
  • 16
  • I have tried setting maximum speed for both the racket and the ball, i can maybe increase the size of the whole environment, maybe this might give better chance of detecting the right side of the collider. I'll implement both the solution given by Justin808 and increase the size of everything. – SpeedBirdNine Sep 10 '11 at 19:27
  • This thing worked so brilliantly, i doubled the size of everything, and now it is not missing a collision. I still have the other problem which Justin808 talked about, that the racket at one moment is in front of the ball and the next frame it is behind the ball, but at least i am seeing two distinct collisions, which can be handled with code! Thanks a lot! It took me only 2 min to do. Now i am going to implement Justin's solution to solve two collisions. By this time if someone has other explanation, please share it too! – SpeedBirdNine Sep 15 '11 at 21:19
  • Ok problem solved, i didn't have to place a raycast between previous and next position of the ball as now the collider of the racket is not missing the ball. Other thing is that racket movement through mouse doesn't translate to additional force applied to the ball. I had to write this part myself, and set istrigger as true for racket collider so that the original physics do not interfere. But now there was a problem of hitting multiple times, i solved it by using a flag, which becomes false when hit first time, and true again after 1 second, or when the ball hits another object. This works! – SpeedBirdNine Sep 16 '11 at 00:56
5

What I think is happening is that each interval that happens the ball/racquet are moved and then checked for a collision. The issue is that the ball/racquet move to far in a single interval and miss the collision.

1) Ball before racquet 
2) Ball after racquet 

not

1) Ball before racquet 
2) Ball touching racquet 

So what you have to do is in your FixedUpdate() method of your ball GameObject is cast a ray from the current ball location to the previous ball location. If there is anything between those two points that should have been hit (ie the racquet) move the ball back to the reported hit point on the ray. This will trigger your existing collision detection stuff.

The reason increasing the size of the collider works as well is because the ball isn't skipping the lager collider. This has the drawbacks you mentioned in your question. The ray casting avoids this issue and allows the ball/racquet to move as fast or slow as they need to.

Justin808
  • 20,859
  • 46
  • 160
  • 265
3

This is not a complete answer, but I remember dealing with a problem like this many years ago on slower machines.

The problem was using sprite-based collision detection; relying on pixels for the sprite and obstacle being rendered at the same coordinates. If the frame rate is so low that the sprite moves more than the obstacle's size in one frame, you will get into situations where it is (for example) left of the obstacle in one frame and right of the obstacle in the next frame without ever occupying the same pixels.

In this case sprite-based collisions do not work, you have to base collisions on vectors. Instead of checking each sprite pixel for collisions, record the position and convex hull of the sprite. After each frame, calculate a vector from the old position to the new position and intersect it with the convex hull of each obstacle.

There are multiple shortcuts you can make, like comparing only against bounding boxes at first and calculating the hull only if the vector intersects a bounding box, but this is the basic idea. Good luck.

Dour High Arch
  • 21,513
  • 29
  • 75
  • 90
  • 1
    The idea seems a good starting point, but any idea how to implement it in Unity3d using as much of the built in stuff as possible (at it is optimized). And about slow machines, i have tested it on a core i7 machine with 6 GB DDR3 RAM and 1 GB ATi Radeon HD5890 graphics card, and FPS never drops below 70. And please explain what are sprite based collision detection and is this what Unity3d uses? Since i am using Unity3d, i don't think i'll be able to control the specifics of collision detection mechanism to this extent – SpeedBirdNine Sep 09 '11 at 17:15
  • 1
    Sorry, haven't used Unity. Sprite-based graphics use the actual frame buffer for calculations; if you are using OpenGL or ActiveX you are probably not using sprites. However, the notion of checking vectors against convex hulls for collisions are applicable to retained mode graphics. I imagine Unity has a way of seeing if a vector intersects a hull. – Dour High Arch Sep 09 '11 at 17:26
  • 2
    This approach is not possible when using 3d elements in Unity, as collisions are calculated with its internal engine [PhysX](http://en.wikipedia.org/wiki/PhysX). But it is a good system, already implemented in most physics engines. – Elideb Sep 10 '11 at 17:04
0

I have been working on a 3d pong game as well, and have run into the exact same problems. I'm going to try enlarging everything like you guys did. As for the paddle adding speed and spin to the ball, I was baffled by this until I realized that changing the position of the paddle does not change its velocity. If the paddle was at zero velocity before it was moved, it will be at zero when the physics engine looks at it next frame. Un checking is kenimatic and controlling the paddle directly through the velocity property fixed the problem. It caused the paddle to jitter when hitting walls, but I fixed that by removing the walls from the paddle layer and handling boundaries manually in LateUpdate. Also, when you update the velocity, first store the new desired velocity in Update so that the controls work smoothly, then commit the changes in FixedUpdate.

0

You need a variable to debounce the collision between ball and racket. Initialize the variable to true. Set the variable to false and disable racket collider on 1st collision against the racket. Then set it to true and enable racket collider when ball collides against something other than that racket. Ignore any ball racket collisions when variable is false. This will avoid multiple successive collisions on the opposite surfaces of the racket's collider.

Vikram Kapoor
  • 41
  • 1
  • 5