Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411588 Posts in 69386 Topics- by 58443 Members - Latest Member: Mansreign

May 06, 2024, 02:30:36 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Help with circular collision reactions (Flash)
Pages: [1]
Print
Author Topic: Help with circular collision reactions (Flash)  (Read 2984 times)
Problem Machine
Level 8
***

It's Not a Disaster


View Profile WWW
« on: November 30, 2008, 08:12:58 PM »

Okay, I've been banging my head against this problem for a few days now, and I'm hoping someone here can help me out because this is starting to get pretty frustrating.
I've been putting together a framework to make a series of small-medium sized Flash games built around a similar theme. I've decided that, for the purposes of this project, circular collision detection is perfectly satisfying, and I've been building on that. The actual detection is a pretty simple test, but I need some degree of physical interaction. Basically, I'm looking to have a system which integrates mass (and potentially at some point accurate bounce). Basically I can break this down into two connected problems:
a) Move the objects apart so that they aren't overlapping at the end of the frame
b) Modify the velocity as appropriate for the collision
So, I thought I had both of these solved at one point.
Code:
var _TempEntity:Entity = c.getEntity();
if (!(_TempEntity is PhysicsEntity))
continue;

var _That:PhysicsEntity = _TempEntity as PhysicsEntity;

var _X0:Number = 0, Y0:Number = 0;
var _X1:Number = _That.getLocationX() - this.mLocation.x;
var _Y1:Number = _That.getLocationY() - this.mLocation.y;

var _Angle:Number = Math.atan2(_Y1, _X1);
var _Sine:Number = Math.sin(_Angle);
var _Cosine:Number = Math.cos(_Angle);

var _VelocityX0:Number = mVelocity.x * _Cosine + mVelocity.y * _Sine;
var _VelocityY0:Number = mVelocity.y * _Cosine - mVelocity.x * _Sine;

var _VelocityX1:Number = _That.getVelocity().x * _Cosine + _That.getVelocity().y * _Sine;
var _VelocityY1:Number = _That.getVelocity().y * _Cosine - _That.getVelocity().x * _Sine;

var _VelocityXTotal:Number = _VelocityX0 - _VelocityX1;
_VelocityX0 = ((mMass - _That.getMass()) * _VelocityX0 + (2 * _That.getMass() * _VelocityX1))
/ (mMass + _That.getMass());
_VelocityX1 = _VelocityXTotal + _VelocityX0;

var _FinalVelocity0:Point = new Point( _VelocityX0 * _Cosine - _VelocityY0 * _Sine,
_VelocityY0 * _Cosine + _VelocityX0 * _Sine);
var _FinalVelocity1:Point = new Point( _VelocityX1 * _Cosine - _VelocityY1 * _Sine,
_VelocityY1 * _Cosine + _VelocityX1 * _Sine);


var _DistanceToOffset:Number = c.getOverlap() / 2;
var _ThatMassRatio:Number = this.mMass / _That.mMass;
mLocation = mLocation.add(new Point(-(_DistanceToOffset * _Cosine) * (1 - _ThatMassRatio), -(_DistanceToOffset * _Sine) * (1 - _ThatMassRatio)));
_That.mLocation = _That.mLocation.add(new Point(_DistanceToOffset * _Cosine * _ThatMassRatio, _DistanceToOffset * _Sine * _ThatMassRatio));

mDeltaVelocity = mDeltaVelocity.add(_FinalVelocity0.subtract(this.mVelocity));
_That.mDeltaVelocity = _That.mDeltaVelocity.add(_FinalVelocity1.subtract(_That.mVelocity));

_That.removeCollisionWith(this);

This version worked really well for that demonstration. Occasional minor twitching glitches were visible, but it didn't SEEM like a big deal at the time. Unfortunately, I found out differently later. After getting projectiles implemented, I discovered that the twitching was MUCH more exaggerated when dealing with small, fast-moving objects. Well, to make a long story short (too late!), I spent forever trying to find an equation that would work for both of these situations. I kept on running into situations where the overlap-correction segment wasn't keeping them properly separated, and they'd start flying all over the screen like crazy. But I realized, after spending way more time than it should take me to realize something like this; WHY would they start flying all over the screen just because my offset equations aren't right? The offset equations don't deal with force at all, just with moving the objects to the appropriate position to keep them from overlapping. So I FINALLY went ahead and compared the force before collision to the force after, and found that they were not the same. This, as I understand it, is a bad thing.

So now I'm doubting that that first solution, (which I got from this book), was ever all that great; but then I tried implementing ANOTHER solution which I found on Gamasutra (here) only to find that it gives me much the same results. Here's my implementation of that solution:
Code:
var _That:PhysicsEntity = _TempEntity as PhysicsEntity;

trace("BEFORE::: FORCE = " + ((mVelocity.length * mMass) + (_That.getVelocity().length * _That.mMass)));

var _N:Point = mLocation.subtract(_That.mLocation);
_N.normalize(1);

var _A1:Number = mLocation.x * _N.x + mLocation.y * _N.y;
var _A2:Number = _That.mLocation.x * _N.x + _That.mLocation.y * _N.y;

var _OptimizedP:Number = (2 * (_A1 - _A2)) / (mMass + _That.mMass);

var _V1:Point = new Point();
_V1.x = mVelocity.x - _OptimizedP * _That.mMass * _N.x;
_V1.y = mVelocity.y - _OptimizedP * _That.mMass * _N.y;

var _V2:Point = new Point();
_V2.x = _That.mVelocity.x + _OptimizedP * mMass * _N.x;
_V2.y = _That.mVelocity.y + _OptimizedP * mMass * _N.y;

trace("AFTER--- FORCE = " + ((_V1.length * mMass) + (_V2.length * _That.mMass)));

mDeltaVelocity = mDeltaVelocity.add(_V1.subtract(this.mVelocity));
_That.mDeltaVelocity = _That.mDeltaVelocity.add(_V2.subtract(_That.mVelocity));
Does anyone have an idea what I'm doing wrong here? I'm stumped ;_;
Logged

Alex May
...is probably drunk right now.
Level 10
*


hen hao wan


View Profile WWW
« Reply #1 on: November 30, 2008, 10:15:03 PM »

I was going to link you to pool hall lessons. I've implemented it before so it should work fine.

Another option is Box2D for AS3 which also works extremely well.
Logged

Problem Machine
Level 8
***

It's Not a Disaster


View Profile WWW
« Reply #2 on: November 30, 2008, 10:20:38 PM »

Well... if it worked fine for you, do you have any idea what I might be doing wrong here?  Undecided
Logged

Alex May
...is probably drunk right now.
Level 10
*


hen hao wan


View Profile WWW
« Reply #3 on: November 30, 2008, 10:33:10 PM »

Well I never did anything like bullets with it. Consider doing multiple updates with smaller time steps for the small and fast-moving physics entities.
Logged

Problem Machine
Level 8
***

It's Not a Disaster


View Profile WWW
« Reply #4 on: November 30, 2008, 10:37:55 PM »

Agh, but I haven't even gotten to that part yet, I can't even get the basic physics simulation I have up above with this solution  Cry
Oh well, I'll take another run at it tomorrow night, I'm tired of looking at it for today.
Logged

JLJac
Level 10
*****



View Profile
« Reply #5 on: November 30, 2008, 11:09:04 PM »

I know very little actionscript, so what you have posted tells me nothing. I'll try to help anyways.

First thing you need to know is exactly when the two circles collide. If you know that you can put them in that position by multiplying their movement vectors with that time. A good way to know if you have gotten it right is to check if the distance between their centers is exactly the sum of their radius, like it should be if they are just touching each others surfaces. There are several good formulas for this on the net, you don't really have to understand it, just use it.

The next step I do like this:

I calculate the values for a line pointing from the center of one circle to the center of the other one. The direction of this line we call DIRECTION. This means that DIRECTION is a direction vector with a length of 1.0 pointing from the center of circle1 to the center of circle2. We will use this later.

Then I calculate the values for a line perpendicular to the first one. Let's call this one LINE. I have marked this with red color.

I calculate the distance from the circles movement vectors to LINE. Let's call this COLLISIONSPEED. If they are moving inwards, their COLLISIONSPEED is positive, if they are moving outwards, it is negative. I have marked their COLLISIONSPEED with blue.

Now add the COLLISIONSPEEDS togheter. If their sum is negative, the circles move away from each other, and no collision should be calculated. If the sum is positive, a collision is present. Let's call this sum COLLISIONSUM.



BOUNCE is the average of the two circles bouncyness. If 0.00 they  will lose all their momentum in the bouncing direction, if 1.00 they will maintain all their speed.

I now set a variable that we'll call REPULSIONSPEED. This variable is set to

REPULSIONSPEED = COLLISIONSUM + (COLLISIONSUM*BOUNCE)

MASSFAC is local variable calculated like this:

MASSFAC = CIRCLE1MASS/(CIRCLE1MASS+CIRCLE2MASS)
Meaning that if circle1 weights 75 and circle2 only 25 the MASSFAC will be 0.75.

So, you add this to circle1:s velocity:
C1SPEED = C1SPEED + (-1*DIRECTION*(REPULSIONSPEED*(1.0-MASSFAC)))

And circle2:
C2SPEED = C2SPEED + (DIRECTION*(REPULSIONSPEED*MASSFAC))

Meaning that the circles will be thrown away from each other at speeds matching their mass, the small circle will take 75% of the blow, the big one only
25%.

I doubt that this is at all correct physics, but it's how I do it and it works fine for me. Don't hesitate to ask further questions Smiley
Logged
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #6 on: December 01, 2008, 02:52:33 AM »

I haven't checked the maths of your code, but I'm guessing that the problem is you are adjusting the velocity of the two circles, but not their positions, so they collide immediately in the next frame, with odd effects. I've got no idea what you are attempting with your traces, those values are gibberish. If you are trying to check for conservation of momentum, then you need to do it as a vector equation, i.e. that both the following remain unchanged:
Code:
v1.x*m1+v2.x*m2
v1.y*m1+v2.y*m2

JLJac's solution is nice, as it calculates exact times of collisions, and thus everything else exactly too. But you can find that, depending on your game, this will cause your game to slow to a crawl, as it is only advancing each time by the next collision, rather than 1/30 seconds.

I once laboured with getting collisions nice for a long time, like you are, and it's very fun and a good way to learn. You evidently have a lot still to learn about physics and vector maths, so that's fine.
But for an actual game, you shouldn't re-invent the wheel. So I'm going to go with seconding Box2DAS3 (full disclosure: I do some dev work for this).

Box2D solves the tunnelling problem with a method called Conservative Advancement, which works similarly to JLJac's solution. But it splits it up per "island", i.e. block of interacting shapes, so it doesn't cause the whole simulation to stop and start. It's the only flash engine to do this.

It does tons of other useful things too, but not ones relevant to the discussion  Huh?
Logged
Problem Machine
Level 8
***

It's Not a Disaster


View Profile WWW
« Reply #7 on: December 01, 2008, 09:12:48 AM »

Quote
I haven't checked the maths of your code, but I'm guessing that the problem is you are adjusting the velocity of the two circles, but not their positions, so they collide immediately in the next frame, with odd effects.
I was working on solving that problem when I noticed that the objects had a net gain in velocity. No matter HOW often they collide, that shouldn't be happening (except perhaps in some small floating point precision error kinds of ways).
Quote
I've got no idea what you are attempting with your traces, those values are gibberish.
It's the magnitude of the vector times the mass of the object. Basically the same thing as in your quote, but not broken into components. The sum should be equal before and after the collision, correct?

I've looked at Box2d before, but that'd be way overkill for what I'm looking to do here.
Logged

BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #8 on: December 01, 2008, 09:34:36 AM »

It's the magnitude of the vector times the mass of the object. Basically the same thing as in your quote, but not broken into components. The sum should be equal before and after the collision, correct?
No, you cannot take the magnitude and compare, it doesn't work that way. If you work through the maths, you'll see why they are not equivalent (reminder, length = sqrt(x*x+y*y) ). I think you are conflating conservation of momentum (sum of v*m as vectors) with conservation of kinetic energy (sum of 0.5*v.v*m as scalars; only for elastic collisions).

You need to do it as I said, a vector equation. And relabel it properly, as (linear) momentum, while you are at it.
Logged
Problem Machine
Level 8
***

It's Not a Disaster


View Profile WWW
« Reply #9 on: December 01, 2008, 09:40:31 AM »

Gah, this is what I get for trying to copy solutions from books instead of trying to make my own  :D

edit: Ah, just realized that made it sound like I was blaming other formulas for my failure. I just meant that if I'd had to work through all this myself I wouldn't have made such misleading fuckups, heh.
« Last Edit: December 01, 2008, 09:48:53 AM by Kobel » Logged

Ivan
Owl Country
Level 10
*


alright, let's see what we can see


View Profile
« Reply #10 on: December 01, 2008, 11:33:22 AM »

http://www.harveycartel.org/metanet/tutorials/tutorialA.html
Logged

http://polycode.org/ - Free, cross-platform, open-source engine.
Problem Machine
Level 8
***

It's Not a Disaster


View Profile WWW
« Reply #11 on: December 16, 2008, 03:10:35 AM »

Quote
var _A1:Number = mLocation.x * _N.x + mLocation.y * _N.y;
var _A2:Number = _That.mLocation.x * _N.x + _That.mLocation.y * _N.y;

OH MY GOD HOW DID IT TAKE ME THIS LONG TO NOTICE THIS?  Cry
Logged

Alex May
...is probably drunk right now.
Level 10
*


hen hao wan


View Profile WWW
« Reply #12 on: December 16, 2008, 03:25:01 AM »

What's wrong with it?
Logged

BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #13 on: December 16, 2008, 04:04:40 AM »

In the original code it was with velocity, not position. Tsk, tsk.
Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic