- Home /
Touch does not work with fast moving object
Hi everyone,
I have a 2D Ball with a circle collider moving and hitting walls with a box collider 2d. The user should touch (mobile device) the ball, when the ball is slow seems to be ok but when the ball is fast the script I made doesn’t detect the “collision”, the only way to touch the ball is predict the ball movement and touch just where the ball is going. I have two script, the first one moves the ball using the rigidbody’s velocity. I set the velocity in Start and in OnCollisionEnter2D.
The other script detects user input, in Update I check for Touch and if found I set true a boolean and in FixedUpdate a Physics2D.OverlapCircle checks whether the touch hit the ball. Before I was using a Physics2D.Raycast. Checking out answer in internet seems that movement should go in fixed update, basically handled in a physical manner, I use velocity and I’ve tried to use AddForce.
I tried to put the raycast/overlapCircle in Update and in FixedUpdate.
The ball’s rigidbody is set to Collision Detection: Continuous.
I tried to set a lower value for Maximum Allowed Timestep but it didn’t work too.
private bool startTouchCheck;
private Vector2 position;
void Update ()
{
//I want to take just one touch and the touch must be in TouchPhase.began.
//Then I save the position and set startTouchCheck to true.
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
startTouchCheck = true;
position = touch.position;
}
}
}
private void FixedUpdate()
{
if (startTouchCheck)
{
Vector2 touchWorldPos = Camera.main.ScreenToWorldPoint(position);
//The ball layer, I want only to detect the ball
string[] masks = new string[1];
masks[0] = "ball";
//I tried Physics2D.Raycast too
if (Physics2D.OverlapCircle(touchWorldPos, 0.3f, LayerMask.GetMask(masks), -1f, 1f))
{
//Another script handle the ball clicked "event"
gameManager.Clicked();
}
startTouchCheck = false;
position = Vector3.zero;
}
}
This is just a guess, but maybe the ball is not at the position it is rendered at when it is moving fast due to the different rate of Update()
and FixedUpdate()
. That is, the order of the events might be 1) touch and record its position in Update()
, 2) the physics engine updates the ball position an unknown number of times, and then 3) FixedUpdate()
gets called to check the touch position.
If this is the issue, the solution could be to check for collision in a capsule shape.
Can you explain how should I use a capsule shape? If the order of the events is that, if I check touch position in 1) I should get the real position I think, but it's not the case.
This has always been a problem with fast moving objects. The root cause is that collisions are calculated by the physics engine in one frame before the obstacle, and then, when they are again calculated in the next frame, the collider has moved beyond the obstacle, so, it never actual touches the obstacle .
Just google something like "Unity fast moving objects". There are many topics on workarounds.
EDIT:
Just remembered there's a wiki script that might help you: http://wiki.unity3d.com/index.php/DontGoThroughThings
I'm not sure I understand. $$anonymous$$y object don't go through things
I have a 2D Ball with a circle collider moving and hitting walls with a box collider 2d
When the ball hits the wall it is actually stopped by the collider of the wall, so the ball would automatically bounce off the wall. So, If the The Physics Engine didn't detect the collider of the wall touching the ball's collider (for any reason), three things would happen: a. the ball would go through the wall, b. The Physics Engine would not raise any collision/trigger events, and c. The Physics Engine would not detect that the wall's collider is inside the range of Physics2D.OverlapCircle
.
I suspect you are not using the Physics Engine for bouncing the ball off the wall. No problem with that, because when I said "goes through the wall" I was assu$$anonymous$$g that you are using the Physics Engine for that. However, what I said holds true, as far as the Physics2D.OverlapCircle
not detecting the wall collider within its radius. i.e. when Physics2D.OverlapCircle
runs, the wall's collider is either before or after the range of the circle due to fast speed.
Answer by JVene · Jul 18, 2018 at 11:48 AM
This reminded me of a movie trailer from many years ago, a character says (perhaps slightly paraphrased from memory), "He said cheer up, it could be worse. He was right. I cheered up, and it got worse."
There is a wide difference in touch response from all the various devices an app like this can run on, so it can be worse.
To figure out how to proceed, I'd suggest adding some code to help measure what is happening. During the check for overlapped, when the test fails, create a log of data showing where the ball was, and where the touch was, when the presumed intersection fails. This will give you some measurement of how far off the tracking is.
Another way of measuring what's happening is to draw a kind of reticule, just a circle around the point of touch as it is being processed so you might see how the intersection is being missed. A pattern might emerge that suggests what can be done to help.
I think you'll have to consider checking the ball velocity to artificially expand the "size of the touch" that should intersect when the ball is fast. A study of the data I propose would give some idea of the formula(s) to use to expand this intersection of touch to make things work out.
While expanding size might work, you may prefer to refine the concept in a way that anticipates the actions as the proceed. For example, record some short history of the touch and the ball's path and fashion tests to sense if the user is "chasing the ball", is close, and should therefore (on a fast moving ball) be given a larger "size" to the touch, but if the user isn't moving in the path of the ball (inferring they're not trying and are not close), don't give them a larger touch size.
This kind of approach, adjusting behaviors based on speed, can come up outside the domain of touch. I had a "bouncing ball problem" in a simulation of a real world game (used more like a tool than an entertainment app), where I had to get the ball's bounce and roll to match as closely as possible to data collected from measuring response of the real ball on the real materials used in the actual tournaments of a contest. Getting that right simply couldn't rely upon adjustments to the physics engine's parameters. One setting would make part of the simulation work (the initial bounce), but subsequent bounces would either stop way too soon, or continue way too long. I had to use script on the ball to measure velocity, check what materials or objects were being "bounced upon", and adjust the ball's behavior for various key contexts to get it to work just right.
This is something a bit similar in that in the intersection between hardware, the simulation of physics, the animation of artwork and the cycle of the game engine there are a lot of variables and parameters we just have to "fudge" to get right.
I'll try your hints, I think you're right and I have to workaround the problem. Expanding size is a good idea but actually hard to implement, I should consider another case where the user is chasing the ball but eventually he touches too much ahed of the rendered ball causing to make the game think he actually touched the ball. But I'll try this way too. Thanks.