-
bibuti.
Ball inside Ball collision - stop bouncing
I'm currently wrapping my head around vectors and have tried my hand at ball vs ball collisions.
My problem comes when the ball has bounced enough and should finally be coming to rest.
Code below:
PHP Code:
import com.nolentabner.Vector2D;
// initialization of the balls
var smallBall:Sprite = new Sprite();
var bigBall:Sprite = new Sprite();
// bigger ball
bigBall.graphics.lineStyle(1, 0x000000);
bigBall.graphics.drawCircle(0, 0, 120);
bigBall.x = stage.stageWidth/2;
bigBall.y = stage.stageHeight/2;
addChild(bigBall);
// smaller ball
smallBall.graphics.beginFill(0xFF0000);
smallBall.graphics.drawCircle(0,0, 40);
smallBall.graphics.endFill();
smallBall.x = stage.stageWidth/2 - 50;
smallBall.y = stage.stageHeight/2;
addChild(smallBall);
// initialization of the vectors
// main movement vector for smallBall
var movement:Vector2D = new Vector2D(0, -2);
// vector between ball centers
var ballDist:Vector2D = new Vector2D(0,0);
// used for collision reaction
var projection:Vector2D = new Vector2D(0,0);
var proj2:Vector2D = new Vector2D(0,0);
// step per frame. will eventually be replaced with a timer
stage.addEventListener(Event.ENTER_FRAME, onFrame);
// enterframe function
function onFrame(e:Event):void
{
movement.y += 0.8;
ballDist.x = bigBall.x - smallBall.x;
ballDist.y = bigBall.y - smallBall.y;
// if the smaller ball is outside the bigger ball
// perform reaction
if(ballDist.len+smallBall.width/2 > bigBall.width / 2)
{
var wall:Vector2D = ballDist.leftNormal;
var dp:Number = dot(movement, wall.normal);
var dp2:Number = dot(movement, wall.leftNormal.normal);
projection.x = dp*wall.normal.x;
projection.y = dp*wall.normal.y;
proj2.x = dp2*(wall.leftNormal.x/wall.len);
proj2.y = dp2*(wall.leftNormal.y/wall.len);
proj2.x *= -1;
proj2.y *= -1;
movement.x = projection.x + proj2.x;
movement.y = projection.y + proj2.y;
movement.x *= 0.5;
movement.y *= 0.5;
/*if(movement.len < 0.4)
{
movement.x = 0;
movement.y = 0;
}*/
}
smallBall.x+=movement.x;
smallBall.y+=movement.y;
}
// finds the dot product between two vectors
function dot(v1:Vector2D, v2:Vector2D):Number
{
return (v1.x*v2.x + v1.y*v2.y);
}
PHP Code:
package com.nolentabner
{
public class Vector2D extends Object
{
// x
private var __x:Number;
// y
private var __y:Number;
// length of our vector
private var __len:Number;
// our normal
private var __normal:Vector2D;
// our lefthand normal
private var __leftNormal:Vector2D;
// our righthand normal
private var __rightNormal:Vector2D;
// tracking variables
private var lenUndefined:Boolean;
public function Vector2D(x:Number=0, y:Number=0)
{
this.__x = x;
this.__y = y;
lenUndefined = true;
}
/*** GETTERS/SETTERS ***/
// x
public function get x():Number
{
return __x;
}
public function set x(num:Number):void
{
__x = num;
}
// y
public function get y():Number
{
return __y;
}
public function set y(num:Number):void
{
__y = num;
}
// length (read only)
public function get len():Number
{
__len = Math.sqrt(__x * __x + __y * __y);
return __len;
}
// normal (read only)
public function get normal():Vector2D
{
if(!__normal)
{
//normalized unit-sized vector
__normal = new Vector2D();
if (this.len>0)
{
__normal.x = __x/__len;
__normal.y = __y/__len;
} else
{
__normal.x = 0;
__normal.y = 0;
}
}
return __normal;
}
// left hand normal (read only)
public function get leftNormal():Vector2D
{
return new Vector2D(__y, __x * -1);
}
// right hand normal (read only)
public function get rightNormal():Vector2D
{
return new Vector2D(__y * -1, __x);
}
/*** UTILITIES ***/
public function normalize():void
{
if (this.len == 0)
{
__x = 0;
__y = 0;
}
else
{
__x /= this.len;
__y /= this.len;
}
}
public function toString():String
{
var st:String = "Vector2D: x=" + __x.toString() + " y=" + __y.toString();
st += " length="+len.toString();
return st;
}
}
}
You can paste this into any version of Flash CS3 or greater.
edit: I posted the Vector2D class as well. It's nothing amazing but works for now.
You can see where i commented out a check where if the length of the movement vector is less than a specific amount, to set the x/y properties of the vector to 0. It somewhat worked but it didn't look natural.
Can anyone take a look at this and help point me in the right direction? I just want a mostly-realistic collision reaction between two balls where one is inside the other.
Here is an example of what happens for those who don't want to create their own .swf. I know how lazy some of you are out there .
http://www.nolentabner.com/projects/ball/test.swf
Thanks!
Last edited by nolen; 03-02-2009 at 06:40 PM.
i'm obsessed with video games.
-
Funkalicious
PHP Code:
function updateVelocity(){
//Applying acceleration
VelocityVector += AccelerationVector //Can be any number, so you can use 0 when no acceleration
//Applying friction
VelocityVector.length * 0.8 //Or any number between 0 and 1
}
So I think in your example you keep Velocity at a certain value and after a while when you want to stop it apply friction. To actually have balls of different weight you should also add a Force vector and acceleration should be:
PHP Code:
AccelerationVector += ForceVector / Mass
-
bibuti.
Originally Posted by TOdorus
PHP Code:
function updateVelocity(){
//Applying acceleration
VelocityVector += AccelerationVector //Can be any number, so you can use 0 when no acceleration
//Applying friction
VelocityVector.length * 0.8 //Or any number between 0 and 1
}
So I think in your example you keep Velocity at a certain value and after a while when you want to stop it apply friction. To actually have balls of different weight you should also add a Force vector and acceleration should be:
PHP Code:
AccelerationVector += ForceVector / Mass
When you refer to Velocity, are you meaning the vector I named 'movement'? That one seems to change as gravity is applied and it bounces off the other circle. I think I'm still a bit confused.
i'm obsessed with video games.
-
bibuti.
Bump for the "morning" crew.
i'm obsessed with video games.
-
Professional Air Guitarist
I couldn't tell by glancing from your code, but this may be a similar problem to one I had. I was working on collision with a point and a line and I had this infinite bouncing dilemma as well. I finally realized that it was my gravity that kept adding energy to the system every frame and so the point (ball in your case) would never come to rest because that downward vector was being redirected upward based on the angle of the line (or circle). I think I abandoned that project after that but at least this may have helped you find your problem? Or maybe I'm the only one with that issue =p
-
bibuti.
Originally Posted by Frag
I couldn't tell by glancing from your code, but this may be a similar problem to one I had. I was working on collision with a point and a line and I had this infinite bouncing dilemma as well. I finally realized that it was my gravity that kept adding energy to the system every frame and so the point (ball in your case) would never come to rest because that downward vector was being redirected upward based on the angle of the line (or circle). I think I abandoned that project after that but at least this may have helped you find your problem? Or maybe I'm the only one with that issue =p
Yeah, I can see that it's the gravity that's making it "shiver". My issue comes from knowing when to make the gravity stop affecting the ball.
When I turn it off too early, it stops the ball on the side of the larger ball, thus giving an unrealistic feel.
I'll keep playing around with the code, but hopefully someone can hop in and say, "hey dude, you're doing it wrong. try this". Haha.
i'm obsessed with video games.
-
Senior Member
Originally Posted by nolen
You can paste this into any version of Flash CS3 or greater.
and it will not compile because...
Originally Posted by nolen
the Vector2D class is just a small class I came up with to simplify things. I don't think it's relevant to post it.
yeah well I don't think it's relevant for me to re-write it to get your code to compile :P
My issue comes from knowing when to make the gravity stop affecting the ball.
you dont need to turn it off, instead you need to multiply your ball velocity by something smaller than 1 (like 0.98) - this will eventually stop it.
-
Senior Member
bah, TOdorus already said that.
-
bibuti.
Originally Posted by realMakc
and it will not compile because...yeah well I don't think it's relevant for me to re-write it to get your code to compile :Pyou dont need to turn it off, instead you need to multiply your ball velocity by something smaller than 1 (like 0.98) - this will eventually stop it.
Oh poop. You're totally right. I'll upload a copy of the class when I'm home from the office tonight.
So right now I'm adding gravity to the velocity (that's the 0.8 at the beginning of the frame loop, and if there is a collision I am multiplying the velocity by 0.5 (that's at the end of the loop). You're saying I need to multiply it by yet another number?
Sorry to be so dense. It was a long weekend.
i'm obsessed with video games.
-
bibuti.
Alright, I've updated the first post with the code for the Vector2D class in case anyone else wanted to compile the example and whatnot.
I appreciate all the help so far. Thanks!
i'm obsessed with video games.
-
Senior Member
I'd say just check at what speed the ball is traveling at, and if yspeed is 0 (or very VERY close to zero), then set the yspeed to 0, and if xspeed is VERY close to zero, set that to zero too. That way, when you multiply your speeds by the gravity, it doesn't have anything to multiply by...
Not sure, but at first thought, it should work...
P.
WIP-ZOMBIES
I love vegetarians! More meat for the rest of us!
-
Funkalicious
Allright, please read up on mechanics. A force creates acceleration which gives something velocity. Something with velocity generates friction with the stuff surrounding it.
So in mechanical terms multiplying something by .xx is friction. Gravity is not friction, it is a constant acceleration downward. So when a ball is thrown it moves at a pretty much constant speed in the horizontal vector (slight friction and only little time in the air) and a constant acceleration towards the earth in the vertical vector, because of gravity. Example
-
Senior Member
I know, but sometimes it's easier to simply multiply something by a number rather than adding it, solely for the behavour of multiplication versus addition.
I can only suggest what I've found to work in most cases, though of course, it doesn't reflect real life at all...something I should work on, since I like precise math anyway. Anyways, I'm paying attention to this thread...
P.
WIP-ZOMBIES
I love vegetarians! More meat for the rest of us!
-
bibuti.
Originally Posted by Pazil
I'd say just check at what speed the ball is traveling at, and if yspeed is 0 (or very VERY close to zero), then set the yspeed to 0, and if xspeed is VERY close to zero, set that to zero too. That way, when you multiply your speeds by the gravity, it doesn't have anything to multiply by...
Not sure, but at first thought, it should work...
P.
I just tried that and it stops the ball unnaturally on either side, instead of in the middle. There has to be something simple that I'm missing.
i'm obsessed with video games.
-
Senior Member
hmmm...
Well, I've never used physics like yours before...I've only used shortcuts, and that was a long time ago too...
I'll try to read up on some physics, see if I find anything...
P.
WIP-ZOMBIES
I love vegetarians! More meat for the rest of us!
-
Funkalicious
So your code in your first post is still the code your using for your onEnterFrame function? Because there's still no friction in there, only when the small ball it hits the big ball.
-
bibuti.
Originally Posted by TOdorus
So your code in your first post is still the code your using for your onEnterFrame function? Because there's still no friction in there, only when the small ball it hits the big ball.
So the "if(ballDist.len+smallBall.width/2 > bigBall.width / 2)" statement, I should multiply the movement vector by something like 0.5? That seems to slow the whole thing down and still cause a wiggle.
I think vectors and I aren't meant to be friends.
i'm obsessed with video games.
-
Funkalicious
Not vector but physics really. You seem to understand vectors just fine, it's just that if an object doesn't generate any friction it will never stop. Well here we go:
PHP Code:
// enterframe function
function onFrame(e:Event):void
{
movement.y += 0.8;
ballDist.x = bigBall.x - smallBall.x;
ballDist.y = bigBall.y - smallBall.y;
// if the smaller ball is outside the bigger ball
// perform reaction
if(ballDist.len+smallBall.width/2 > bigBall.width / 2)
{
(....)
//Friction is applied
movement.x *= 0.5;
movement.y *= 0.5;
/*if(movement.len < 0.4) //This is still quite a big number. I'd go with a value like < 0.000001
{
movement.x = 0;
movement.y = 0;
}*/
} else {
//Friction is applied
movement.x *= 0.95;
movement.y *= 0.95;
}
smallBall.x+=movement.x;
smallBall.y+=movement.y;
}
Unless the ball is in a vacuum, it generates friction by rubbing against the air or whatever gas it is in. This is considerably less friction then rubbing against a solid wall, but friction none the less.
-
bibuti.
Originally Posted by TOdorus
Not vector but physics really. You seem to understand vectors just fine, it's just that if an object doesn't generate any friction it will never stop. Well here we go:
PHP Code:
// enterframe function function onFrame(e:Event):void { movement.y += 0.8; ballDist.x = bigBall.x - smallBall.x; ballDist.y = bigBall.y - smallBall.y; // if the smaller ball is outside the bigger ball // perform reaction if(ballDist.len+smallBall.width/2 > bigBall.width / 2) { (....) //Friction is applied movement.x *= 0.5; movement.y *= 0.5; /*if(movement.len < 0.4) //This is still quite a big number. I'd go with a value like < 0.000001 { movement.x = 0; movement.y = 0; }*/ } else { //Friction is applied movement.x *= 0.95; movement.y *= 0.95; } smallBall.x+=movement.x; smallBall.y+=movement.y; }
Unless the ball is in a vacuum, it generates friction by rubbing against the air or whatever gas it is in. This is considerably less friction then rubbing against a solid wall, but friction none the less.
OH. I see what you mean.
What I've done is tried something similar to what you've just posted and then also putting the smaller ball to sleep if the velocity is less than a certain amount. It seems to do the trick well enough for what I'm trying to accomplish.
Unless the ball is much smaller, then it sticks to the sides :/.
Thanks TOdorus. You're helping a lot.
i'm obsessed with video games.
-
bibuti.
PHP Code:
import com.nolentabner.Vector2D;
var gravity:Vector2D = new Vector2D(0, 0.8);
var mass:Number = 5;
// initialization of the balls
var smallBall:Sprite = new Sprite();
var bigBall:Sprite = new Sprite();
// bigger ball
bigBall.graphics.lineStyle(1, 0x000000);
bigBall.graphics.drawCircle(0, 0, 120);
bigBall.x = stage.stageWidth/2;
bigBall.y = stage.stageHeight/2;
addChild(bigBall);
// smaller ball
smallBall.graphics.beginFill(0xFF0000);
smallBall.graphics.drawCircle(0,0, 60);
smallBall.graphics.endFill();
smallBall.x = stage.stageWidth/2 - 50;
smallBall.y = stage.stageHeight/2;
addChild(smallBall);
// initialization of the vectors
// main movement vector for smallBall
var movement:Vector2D = new Vector2D(0, -2);
// vector between ball centers
var ballDist:Vector2D = new Vector2D(0,0);
// used for collision reaction
var projection:Vector2D = new Vector2D(0,0);
var proj2:Vector2D = new Vector2D(0,0);
// step per frame. will eventually be replaced with a timer
stage.addEventListener(Event.ENTER_FRAME, onFrame);
stage.addEventListener(MouseEvent.CLICK, onClick);
var i:int = 0;
function onClick(e:MouseEvent):void
{
switch(i)
{
case 0:
gravity.x = -0.8;
gravity.y = 0;
break;
case 1:
gravity.x = 0;
gravity.y = -0.8;
break;
case 2:
gravity.x = 0.8;
gravity.y = 0;
break;
case 3:
gravity.x = 0;
gravity.y = 0.8;
break;
}
i++
if(i>3)
{
i = 0;
}
}
// enterframe function
function onFrame(e:Event):void
{
movement.x += mass*gravity.x;
movement.y += mass*gravity.y;
ballDist.x = bigBall.x - smallBall.x;
ballDist.y = bigBall.y - smallBall.y;
// if the smaller ball is outside the bigger ball
// perform reaction
if(ballDist.len+smallBall.width/2 > bigBall.width / 2)
{
var wall:Vector2D = ballDist.leftNormal;
var dp:Number = dot(movement, wall.normal);
var dp2:Number = dot(movement, wall.leftNormal.normal);
projection.x = dp*wall.normal.x;
projection.y = dp*wall.normal.y;
proj2.x = dp2*(wall.leftNormal.x/wall.len);
proj2.y = dp2*(wall.leftNormal.y/wall.len);
proj2.x *= -1;
proj2.y *= -1;
movement.x = (projection.x + proj2.x);
movement.y = (projection.y + proj2.y);
movement.x *= 0.3;
movement.y *= 0.3;
}
else {
//Friction is applied
movement.x *= 0.95;
movement.y *= 0.95;
}
smallBall.x+=movement.x;
smallBall.y+=movement.y;
}
// finds the dot product between two vectors
function dot(v1:Vector2D, v2:Vector2D):Number
{
return (v1.x*v2.x + v1.y*v2.y);
}
Here is the updated version. I added a mouse click listener to change the gravity clockwise. You can see that if you click fast, the ball goes all crazy and outside the larger ball.
I think something bigger is wrong with my code. Haha.
i'm obsessed with video games.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|