A Flash Developer Resource Site

Page 1 of 2 12 LastLast
Results 1 to 20 of 29

Thread: Ball inside Ball collision - stop bouncing

  1. #1
    bibuti. nolen's Avatar
    Join Date
    Sep 2002
    Location
    az.
    Posts
    191

    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(10x000000);
    bigBall.graphics.drawCircle(00120);
    bigBall.stage.stageWidth/2;
    bigBall.stage.stageHeight/2;
    addChild(bigBall);
    // smaller ball
    smallBall.graphics.beginFill(0xFF0000);
    smallBall.graphics.drawCircle(0,040);
    smallBall.graphics.endFill();
    smallBall.stage.stageWidth/50;
    smallBall.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_FRAMEonFrame);

    // enterframe function
    function onFrame(e:Event):void
    {
        
    movement.+= 0.8;
        
        
    ballDist.bigBall.smallBall.x;
        
    ballDist.bigBall.smallBall.y;
        
        
    // if the smaller ball is outside the bigger ball
        // perform reaction
        
    if(ballDist.len+smallBall.width/bigBall.width 2)
        {    
            var 
    wall:Vector2D ballDist.leftNormal;
            var 
    dp:Number dot(movementwall.normal);
            var 
    dp2:Number dot(movementwall.leftNormal.normal);
            
    projection.dp*wall.normal.x;
            
    projection.dp*wall.normal.y;
            
    proj2.dp2*(wall.leftNormal.x/wall.len);
            
    proj2.dp2*(wall.leftNormal.y/wall.len);
            
    proj2.*= -1;
            
    proj2.*= -1;
            
    movement.projection.proj2.x;
            
    movement.projection.proj2.y;
            
    movement.*= 0.5;
            
    movement.*= 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:Vector2Dv2:Vector2D):Number
    {
        return (
    v1.x*v2.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=0y: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/__len;
                        
    __normal.__y/__len;
                    } else
                    {
                        
    __normal.0;
                        
    __normal.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.

  2. #2
    Funkalicious TOdorus's Avatar
    Join Date
    Nov 2006
    Location
    Nijmegen, Netherlands
    Posts
    697
    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 

  3. #3
    bibuti. nolen's Avatar
    Join Date
    Sep 2002
    Location
    az.
    Posts
    191
    Quote Originally Posted by TOdorus View Post
    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.

  4. #4
    bibuti. nolen's Avatar
    Join Date
    Sep 2002
    Location
    az.
    Posts
    191
    Bump for the "morning" crew.
    i'm obsessed with video games.

  5. #5
    Professional Air Guitarist Frag's Avatar
    Join Date
    Dec 2002
    Location
    Brain, Body, Clothes, Computer Chair, Room, House, Neighborhood, City, State, Country, Continent, World, Galaxy, Universe, and on?
    Posts
    811
    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

  6. #6
    bibuti. nolen's Avatar
    Join Date
    Sep 2002
    Location
    az.
    Posts
    191
    Quote Originally Posted by Frag View Post
    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.

  7. #7
    Senior Member realMakc's Avatar
    Join Date
    Oct 2002
    Posts
    921
    Quote Originally Posted by nolen View Post
    You can paste this into any version of Flash CS3 or greater.
    and it will not compile because...
    Quote Originally Posted by nolen View Post
    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.
    who is this? a word of friendly advice: FFS stop using AS2

  8. #8
    Senior Member realMakc's Avatar
    Join Date
    Oct 2002
    Posts
    921
    bah, TOdorus already said that.
    who is this? a word of friendly advice: FFS stop using AS2

  9. #9
    bibuti. nolen's Avatar
    Join Date
    Sep 2002
    Location
    az.
    Posts
    191
    Quote Originally Posted by realMakc View Post
    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.

  10. #10
    bibuti. nolen's Avatar
    Join Date
    Sep 2002
    Location
    az.
    Posts
    191
    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.

  11. #11
    Senior Member Pazil's Avatar
    Join Date
    Sep 2006
    Location
    Ontario, Canada
    Posts
    913
    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!

  12. #12
    Funkalicious TOdorus's Avatar
    Join Date
    Nov 2006
    Location
    Nijmegen, Netherlands
    Posts
    697
    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

  13. #13
    Senior Member Pazil's Avatar
    Join Date
    Sep 2006
    Location
    Ontario, Canada
    Posts
    913
    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!

  14. #14
    bibuti. nolen's Avatar
    Join Date
    Sep 2002
    Location
    az.
    Posts
    191
    Quote Originally Posted by Pazil View Post
    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.

  15. #15
    Senior Member Pazil's Avatar
    Join Date
    Sep 2006
    Location
    Ontario, Canada
    Posts
    913
    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!

  16. #16
    Funkalicious TOdorus's Avatar
    Join Date
    Nov 2006
    Location
    Nijmegen, Netherlands
    Posts
    697
    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.

  17. #17
    bibuti. nolen's Avatar
    Join Date
    Sep 2002
    Location
    az.
    Posts
    191
    Quote Originally Posted by TOdorus View Post
    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.

  18. #18
    Funkalicious TOdorus's Avatar
    Join Date
    Nov 2006
    Location
    Nijmegen, Netherlands
    Posts
    697
    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.+= 0.8
         
        
    ballDist.bigBall.smallBall.x
        
    ballDist.bigBall.smallBall.y
         
        
    // if the smaller ball is outside the bigger ball 
        // perform reaction 
        
    if(ballDist.len+smallBall.width/bigBall.width 2
        {     
            (....)
            
    //Friction is applied
            
    movement.*= 0.5;
            
    movement.*= 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.*= 0.95;
             
    movement.*= 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.

  19. #19
    bibuti. nolen's Avatar
    Join Date
    Sep 2002
    Location
    az.
    Posts
    191
    Quote Originally Posted by TOdorus View Post
    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.+= 0.8
         
        
    ballDist.bigBall.smallBall.x
        
    ballDist.bigBall.smallBall.y
         
        
    // if the smaller ball is outside the bigger ball 
        // perform reaction 
        
    if(ballDist.len+smallBall.width/bigBall.width 2
        {     
            (....)
            
    //Friction is applied
            
    movement.*= 0.5;
            
    movement.*= 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.*= 0.95;
             
    movement.*= 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.

  20. #20
    bibuti. nolen's Avatar
    Join Date
    Sep 2002
    Location
    az.
    Posts
    191
    PHP Code:
    import com.nolentabner.Vector2D;

    var 
    gravity:Vector2D = new Vector2D(00.8);
    var 
    mass:Number 5;

    // initialization of the balls
    var smallBall:Sprite = new Sprite();
    var 
    bigBall:Sprite = new Sprite();
    // bigger ball
    bigBall.graphics.lineStyle(10x000000);
    bigBall.graphics.drawCircle(00120);
    bigBall.stage.stageWidth/2;
    bigBall.stage.stageHeight/2;
    addChild(bigBall);
    // smaller ball
    smallBall.graphics.beginFill(0xFF0000);
    smallBall.graphics.drawCircle(0,060);
    smallBall.graphics.endFill();
    smallBall.stage.stageWidth/50;
    smallBall.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_FRAMEonFrame);

    stage.addEventListener(MouseEvent.CLICKonClick);

    var 
    i:int 0;

    function 
    onClick(e:MouseEvent):void
    {
        switch(
    i)
        {
            case 
    0:
                
    gravity.= -0.8;
                
    gravity.0;
            break;
            
            case 
    1:
                
    gravity.0;
                
    gravity.= -0.8;
            break;
            
            case 
    2:
                
    gravity.0.8;
                
    gravity.0;
            break;
            
            case 
    3:
                
    gravity.0;
                
    gravity.0.8;
            break;
        }
        
    i++
        if(
    i>3)
        {
            
    0;
        }
    }

    // enterframe function
    function onFrame(e:Event):void
    {
        
    movement.+= mass*gravity.x;
        
    movement.+= mass*gravity.y;
        
        
    ballDist.bigBall.smallBall.x;
        
    ballDist.bigBall.smallBall.y;
        
        
    // if the smaller ball is outside the bigger ball
        // perform reaction
        
    if(ballDist.len+smallBall.width/bigBall.width 2)
        {    
            var 
    wall:Vector2D ballDist.leftNormal;
            var 
    dp:Number dot(movementwall.normal);
            var 
    dp2:Number dot(movementwall.leftNormal.normal);
            
    projection.dp*wall.normal.x;
            
    projection.dp*wall.normal.y;
            
    proj2.dp2*(wall.leftNormal.x/wall.len);
            
    proj2.dp2*(wall.leftNormal.y/wall.len);
            
    proj2.*= -1;
            
    proj2.*= -1;
            
    movement.= (projection.proj2.x);
            
    movement.= (projection.proj2.y);
            
    movement.*= 0.3;
            
    movement.*= 0.3;
            
        }
        else { 
             
    //Friction is applied 
             
    movement.*= 0.95
             
    movement.*= 0.95
        }
        
        
        
    smallBall.x+=movement.x;
        
    smallBall.y+=movement.y;
    }
    // finds the dot product between two vectors
    function dot(v1:Vector2Dv2:Vector2D):Number
    {
        return (
    v1.x*v2.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
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center