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!