PDA

View Full Version : collision detction bug


ianE
11-01-2007, 10:28 AM
I am trying to make a mini golf game and have been using "flash mx game design demystified" to help me. Currently I have a ball which you can fire around the screen and also some walls which the ball will bounce off just fine, exactly what I want.

The problem occurs when the ball is close to the wall but not actually touching it. If you then shoot the ball away from the ball it bounces back and through the wall.

I think the problem lies with the collision detection script, the ball thinking it has hit the wall and then bouncing back though it.

However, I've been trying for three days now to fix this problem with no luck and was hoping someone else could shed some light on the solution or suggest a work around.(I was wanting to use frame independent detection but am now considering the good old hitTest).

I you can see the problem in action here (http://www.ianellisdesign.co.uk/misc/golf10b.swf)

and here is the code, all on frame 1:

ball = {};
ball.clip = _root.pb;
ball.x = ball.clip._x;
ball.y = ball.clip._y;
ball.radius = ball.clip._width/2;
ball.xmov = 0;
ball.ymov = 0;
airDecay = .95;
gravity = .99;
depth = 100;
lineArray = [];
function createLine(x, y, angle, length) {
if (angle == 0) {
angle = .000001;
}
if (angle == 90) {
angle = 89.999999;
}
if (angle == 180) {
angle = 179.999999;
}
if (angle == 270) {
angle = 269.999999;
}
if (angle == -90) {
angle = -89.999999;
}
if (angle == -180) {
angle = -179.999999;
}
if (angle == -270) {
angle = -269.999999;
}
lineDepth = ++depth;
name = "line"+lineDepth;
clipName = "line_clip"+lineDepth;
this.attachMovie("bank", clipName, lineDepth);
this[name] = {};
ob = this[name];
ob.lineDecay = .5;
ob.length = length;
ob.realAngle = angle;
ob.angle = ob.realAngle*Math.PI/180;
ob.clip = this[clipName];
ob.clip._x = x;
ob.clip._y = y;
ob.clip._rotation = ob.realAngle;
ob.slope = Math.tan(ob.angle);
ob.sinAngle = Math.sin(ob.angle);
ob.cosAngle = Math.cos(ob.angle);
ob.x = ob.clip._x;
ob.y = ob.clip._y;
ob.b = ob.y-ob.slope*ob.x;
ob.clip.lineStyle(0, 0x000000, 100);
ob.clip.lineTo(ob.length, 0);
ob.x1 = ob.x;
ob.y1 = ob.y;
ob.x2 = ob.x+ob.length*ob.cosAngle;
ob.y2 = ob.y+ob.length*ob.sinAngle;
lineArray.push(ob);
return ob;
}
l = createLine(400, 100, 90, 200);
l = createLine(400, 300, 0, 200);
l = createLine(600, 300, 270, 200);
l = createLine(600,100,180,200);


function getFrames(tempLine, point) {
//Step 1
var slope2 = point.ymov/point.xmov;
if (slope2 == Number.POSITIVE_INFINITY) {
var slope2 = 1000000;
} else if (slope2 == Number.NEGATIVE_INFINITY) {
var slope2 = -1000000;
}
//The y intercept of the ball trajectory
var b2 = point.y-slope2*point.x;
//intersection point
var x = (b2-tempLine.b)/(tempLine.slope-slope2);
var y = tempLine.slope*x+tempLine.b;
//Step 2
//The angle that the ball is moving
var theta = Math.atan2(point.ymov, point.xmov);
//The difference between the angle of the line and of the ball trajectory
var gamma = theta-tempLine.angle;
//modify x and y
var sinGamma = Math.sin(gamma);
var r = (point.radius+0.000001)/sinGamma;
//The ball's position at point of contact
var x = x-r*Math.cos(theta);
var y = y-r*Math.sin(theta);
//Step 4
//Now find how long it will take to get to the point of contact
var dis = Math.sqrt((x-point.x)*(x-point.x)+(y-point.y)*(y-point.y));
var vel = Math.sqrt(point.xmov*point.xmov+point.ymov*point.y mov);
var frames = dis/vel;
//Step 3
//now check to see if point of contact is on the line segment
var slope2a = -1/tempLine.slope;
var b2a = y-slope2a*x;
//point of contact
var xa = (tempLine.b-b2a)/(slope2a-tempLine.slope);
var ya = slope2a*xa+b2a;
if ((xa>tempLine.x1 && xa<tempLine.x2) || (xa<tempLine.x1 && xa>tempLine.x2) || ((ya>tempLine.y1 && ya<tempLine.y2) || (ya<tempLine.y1 && ya>tempLine.y2))) {
//within segment boundaries
} else {
//not within segment boundaries
//set frame1 high
var frames = 1000;
}
if (frames>0 && frames<=1) {
ballLineReaction(tempLine, point, x, y);
}
}
function ballLineReaction(tempLine, point, x, y) {
var lineDecay = tempLine.lineDecay;
var alpha = tempLine.angle;
var cosAlpha = math.cos(alpha);
var sinAlpha = math.sin(alpha);
//get the x and y velocities of the ball
var vyi = point.ymov;
var vxi = point.xmov;
//project the x and y velocities onto the line of action
var vyip = vyi*cosAlpha-vxi*sinAlpha;
//project the x and y velocities onto the line
var vxip = vxi*cosAlpha+vyi*sinAlpha;
//reverse the velocity along the line of action
var vyfp = -vyip*lineDecay;
var vxfp = vxip;
//translate back to Flash's x and y axes
var vyf = vyfp*cosAlpha+vxfp*sinAlpha;
var vxf = vxfp*cosAlpha-vyfp*sinAlpha;
//set the velocities of the ball based from the results
point.xmov = vxf;
point.ymov = vyf;
point.tempx = point.x+point.xmov;
point.tempy = point.y+point.ymov;
}
function getTempPositions() {
ball.ymov *= airDecay;
ball.xmov *= airDecay;
//ball.ymov += gravity;

ball.tempx = ball.x+ball.xmov;
ball.tempy = ball.y+ball.ymov;
}
function bankCollisionDetect() {
for (var i = 0; i<lineArray.length; ++i) {
getFrames(lineArray[i], ball);
}
}
function render() {
ball.x = ball.tempx;
ball.y = ball.tempy;
ball.clip._x = ball.x;
ball.clip._y = ball.y;
}
_root.onEnterFrame = function() {
//now=getTimer();
getTempPositions();
bankCollisionDetect();
render();
//trace(getTimer()-now);
};
onMouseDown =function(){

distFromX = _xmouse - ball.x;
distFromY = _ymouse - ball.y;


angle = rotation(distFromX,distFromY)+180;
ball.clip._rotation = angle;
tempXmov = (distFromX*-1)/5;
tempYmov = (distFromY*-1)/5;


ball.xmov = tempXmov;
ball.ymov = tempYmov;
}
function calcRads(angle){
rads = angle*Math.PI/180;
return rads;
}

Again if anyone could help me with this I would be very grateful, thanks.

scarce
12-20-2007, 08:08 PM
I am trying to make a mini golf game and have been using "flash mx game design demystified" to help me. Currently I have a ball which you can fire around the screen and also some walls which the ball will bounce off just fine, exactly what I want.

The problem occurs when the ball is close to the wall but not actually touching it. If you then shoot the ball away from the ball it bounces back and through the wall.

I think the problem lies with the collision detection script, the ball thinking it has hit the wall and then bouncing back though it.

However, I've been trying for three days now to fix this problem with no luck and was hoping someone else could shed some light on the solution or suggest a work around.(I was wanting to use frame independent detection but am now considering the good old hitTest).

I you can see the problem in action here (http://www.ianellisdesign.co.uk/misc/golf10b.swf)

and here is the code, all on frame 1:

ball = {};
ball.clip = _root.pb;
ball.x = ball.clip._x;
ball.y = ball.clip._y;
ball.radius = ball.clip._width/2;
ball.xmov = 0;
ball.ymov = 0;
airDecay = .95;
gravity = .99;
depth = 100;
lineArray = [];
function createLine(x, y, angle, length) {
if (angle == 0) {
angle = .000001;
}
if (angle == 90) {
angle = 89.999999;
}
if (angle == 180) {
angle = 179.999999;
}
if (angle == 270) {
angle = 269.999999;
}
if (angle == -90) {
angle = -89.999999;
}
if (angle == -180) {
angle = -179.999999;
}
if (angle == -270) {
angle = -269.999999;
}
lineDepth = ++depth;
name = "line"+lineDepth;
clipName = "line_clip"+lineDepth;
this.attachMovie("bank", clipName, lineDepth);
this[name] = {};
ob = this[name];
ob.lineDecay = .5;
ob.length = length;
ob.realAngle = angle;
ob.angle = ob.realAngle*Math.PI/180;
ob.clip = this[clipName];
ob.clip._x = x;
ob.clip._y = y;
ob.clip._rotation = ob.realAngle;
ob.slope = Math.tan(ob.angle);
ob.sinAngle = Math.sin(ob.angle);
ob.cosAngle = Math.cos(ob.angle);
ob.x = ob.clip._x;
ob.y = ob.clip._y;
ob.b = ob.y-ob.slope*ob.x;
ob.clip.lineStyle(0, 0x000000, 100);
ob.clip.lineTo(ob.length, 0);
ob.x1 = ob.x;
ob.y1 = ob.y;
ob.x2 = ob.x+ob.length*ob.cosAngle;
ob.y2 = ob.y+ob.length*ob.sinAngle;
lineArray.push(ob);
return ob;
}
l = createLine(400, 100, 90, 200);
l = createLine(400, 300, 0, 200);
l = createLine(600, 300, 270, 200);
l = createLine(600,100,180,200);


function getFrames(tempLine, point) {
//Step 1
var slope2 = point.ymov/point.xmov;
if (slope2 == Number.POSITIVE_INFINITY) {
var slope2 = 1000000;
} else if (slope2 == Number.NEGATIVE_INFINITY) {
var slope2 = -1000000;
}
//The y intercept of the ball trajectory
var b2 = point.y-slope2*point.x;
//intersection point
var x = (b2-tempLine.b)/(tempLine.slope-slope2);
var y = tempLine.slope*x+tempLine.b;
//Step 2
//The angle that the ball is moving
var theta = Math.atan2(point.ymov, point.xmov);
//The difference between the angle of the line and of the ball trajectory
var gamma = theta-tempLine.angle;
//modify x and y
var sinGamma = Math.sin(gamma);
var r = (point.radius+0.000001)/sinGamma;
//The ball's position at point of contact
var x = x-r*Math.cos(theta);
var y = y-r*Math.sin(theta);
//Step 4
//Now find how long it will take to get to the point of contact
var dis = Math.sqrt((x-point.x)*(x-point.x)+(y-point.y)*(y-point.y));
var vel = Math.sqrt(point.xmov*point.xmov+point.ymov*point.y mov);
var frames = dis/vel;
//Step 3
//now check to see if point of contact is on the line segment
var slope2a = -1/tempLine.slope;
var b2a = y-slope2a*x;
//point of contact
var xa = (tempLine.b-b2a)/(slope2a-tempLine.slope);
var ya = slope2a*xa+b2a;
if ((xa>tempLine.x1 && xa<tempLine.x2) || (xa<tempLine.x1 && xa>tempLine.x2) || ((ya>tempLine.y1 && ya<tempLine.y2) || (ya<tempLine.y1 && ya>tempLine.y2))) {
//within segment boundaries
} else {
//not within segment boundaries
//set frame1 high
var frames = 1000;
}
if (frames>0 && frames<=1) {
ballLineReaction(tempLine, point, x, y);
}
}
function ballLineReaction(tempLine, point, x, y) {
var lineDecay = tempLine.lineDecay;
var alpha = tempLine.angle;
var cosAlpha = math.cos(alpha);
var sinAlpha = math.sin(alpha);
//get the x and y velocities of the ball
var vyi = point.ymov;
var vxi = point.xmov;
//project the x and y velocities onto the line of action
var vyip = vyi*cosAlpha-vxi*sinAlpha;
//project the x and y velocities onto the line
var vxip = vxi*cosAlpha+vyi*sinAlpha;
//reverse the velocity along the line of action
var vyfp = -vyip*lineDecay;
var vxfp = vxip;
//translate back to Flash's x and y axes
var vyf = vyfp*cosAlpha+vxfp*sinAlpha;
var vxf = vxfp*cosAlpha-vyfp*sinAlpha;
//set the velocities of the ball based from the results
point.xmov = vxf;
point.ymov = vyf;
point.tempx = point.x+point.xmov;
point.tempy = point.y+point.ymov;
}
function getTempPositions() {
ball.ymov *= airDecay;
ball.xmov *= airDecay;
//ball.ymov += gravity;

ball.tempx = ball.x+ball.xmov;
ball.tempy = ball.y+ball.ymov;
}
function bankCollisionDetect() {
for (var i = 0; i<lineArray.length; ++i) {
getFrames(lineArray[i], ball);
}
}
function render() {
ball.x = ball.tempx;
ball.y = ball.tempy;
ball.clip._x = ball.x;
ball.clip._y = ball.y;
}
_root.onEnterFrame = function() {
//now=getTimer();
getTempPositions();
bankCollisionDetect();
render();
//trace(getTimer()-now);
};
onMouseDown =function(){

distFromX = _xmouse - ball.x;
distFromY = _ymouse - ball.y;


angle = rotation(distFromX,distFromY)+180;
ball.clip._rotation = angle;
tempXmov = (distFromX*-1)/5;
tempYmov = (distFromY*-1)/5;


ball.xmov = tempXmov;
ball.ymov = tempYmov;
}
function calcRads(angle){
rads = angle*Math.PI/180;
return rads;
}

Again if anyone could help me with this I would be very grateful, thanks.


alright, lets try to approach this from a simple stand point first...try making your walls thicker...it's possible that the line is to thin that it's reading passed the line when it's close to it, thus making your ball go passed it cause it isn't detecting the object it needs to justify it's distance.