PDA

View Full Version : Some angle help


coreys
10-28-2007, 10:42 PM
I'm working on some fairly basic object physics on Maloria, where hitting an object will make it move. I'm at the part where I need it to kind of bounce off a wall when it collides with it a bit, but I'm having trouble figuring out how I would do that. Here's what I have:

function onCreated() {
if (!("function_domove" in this.joinedclasses))
join("function_domove");
this.moving = false;
this.canhurt = false;
this.distgone = 0;
this.lastpos = {this.x, this.y};
}
function onActionHit(damage, accuracy, effects, acc, px, py) {
this.dist = 0;
this.distgone = 0;
this.speed = 0;
this.canhurt = false;
this.angle = getangle(px - this.x, py - this.y);
if (this.angle > degtorad(180))
this.angle -= degtorad(180);
else this.angle += degtorad(180);
this += degtorad(int(random(-10, 11)));
temp.friction = this.weight / damage;
if (temp.friction >= 1) this.dist = 0;
else this.dist = .75 / temp.friction;
this.moving = true;
this.speed = damage/5;
if (this.speed > 5) this.canhurt = true;
onTimeOut();
}
function onTimeOut() {
if (this.moving) {
if (this.distgone < this.dist) {
temp.dir = getDir(this.lastpos[0]-this.x,this.lastpos[1]-this.y);
this.dir = temp.dir;
this.lastpos = {this.x, this.y};
temp.move = doMove(this.angle, this.dist/this.speed);
if (temp.move) this.distgone += this.dist/this.speed;
else {
//collision stuff here
}
if (this.canhurt)
triggeraction(this.x+1+vecx(temp.dir)*(this.dist/this.speed), this.y+1+vecy(temp.dir)*(temp.dist/this.speed),"Hit",this.dist/2,40);
setTimer(0.05);
}
else this.moving = false;
}
}
The class function_domove would be Zero's movement system. ("doMove(angle, speed)")...I need it to move "this.dist/this.speed" distance...but the problem if figuring out how to get the angle at which it would bounce off...

Tolnaftate2004
10-28-2007, 10:58 PM
I'll assume that anything this object is going to hit will be a horizontal or vertical line.

If it hits a horizontal line, the angle becomes 180-angle.
If it hits a vertical line, the angle becomes -angle.

coreys
10-28-2007, 11:02 PM
It's always become a 180 angle when it hits a horizontal line...? o_O
That doesn't seem right...

But also, part of the problem is figuring out if it's hitting a horizontal line or a vertical line...doMove() returns true or false, telling you whether it can move there or no (if it will run into a wall), but the problem is figuring out if it's hitting a horizontal wall or a vertical wall, since the object doesn't just move straight left, right, up, or down, it moves at angles.

Tolnaftate2004
10-28-2007, 11:08 PM
180 minus the angle.

Those work for all angles.

coreys
10-28-2007, 11:22 PM
Apparently I'm doing something wrong, since doMove() isn't returning false unless it's stuck in a corner, most of the time. And when it returns false properly, moving it at the angle 180 - the original angle doesn't work.

Tolnaftate2004
10-29-2007, 12:18 AM
I hope you're not using 180 - this.angle. It should certainly be pi - this.angle. I was hoping to simplify it a bit in my first post, sorry.

coreys
10-29-2007, 01:28 AM
I actually used degtorad(180) - this.angle

Tolnaftate2004
10-29-2007, 03:15 AM
Strange. You should perhaps split up the movement into vertical and horizontal components and check them individually to see if it's a horizontal or vertical wall.

DustyPorViva
10-29-2007, 06:23 AM
Instead of using angles, use a separate velocity for x and y. Then if it hits on the x-axis, invert the x velocity, and same for the y-axis.

coreys
10-30-2007, 11:44 PM
Strange. You should perhaps split up the movement into vertical and horizontal components and check them individually to see if it's a horizontal or vertical wall.
You mean like this.x += bla; this.y += bla;?
I'm not sure how to use that to go at a certain angle D:

Tolnaftate2004
10-31-2007, 12:23 AM
You mean like this.x += bla; this.y += bla;?
I'm not sure how to use that to go at a certain angle D:

move_dist*cos(angle) is the x component;
move_dist*sin(angle) is the y component (might need to be negative since (0,0) is the UPPER left corner on a level).

coreys
10-31-2007, 01:17 AM
Alright, thanks, but I think there's something wrong with my onwall checks...

function onCreated() {
this.anglex = this.angley = NULL;
this.moving = this.canhurt = false;
this.velocity = this.dist = this.momentum = NULL;
this.distgone = this.time = this.timetotal = NULL;
}
function onActionHit(damage, accuracy, effects, acc, px, py) {
temp.px = px+1.5; temp.py = py+2;
this.distgone = 0;
this.anglex = getangle(temp.px-this.x,temp.py-this.y);
if (this.anglex > degtorad(180))
this.anglex -= degtorad(180);
else this.anglex += degtorad(180);
this.angley = this.anglex;
this.velocity = ((damage*4.45)/this.weight)*.05;
temp.momentum = this.weight * this.veolocity;
if (temp.momentum > 5) this.canhurt = true;
else this.canhurt = false;
temp.friction = this.weight/damage;
if (temp.friction>=1) this.dist = 0;
else this.dist = .75 / temp.friction;
this.moving = true;
onTimeOut();
}
function onTimeOut() {
if (this.moving) {
if (this.distgone<this.dist) {
temp.dx = this.x+(this.velocity*cos(this.anglex));
temp.dy = this.y+(this.velocity*(-sin(this.angley)));
if (!onwall(temp.dx,temp.dy)) {
this.x = temp.dx; this.y = temp.dy;
this.distgone += this.velocity;
}
else {
temp.bx = onwall(temp.dx,this.y);
temp.by = onwall(this.x,temp.dy);
if (temp.bx && temp.by) {
this.anglex = pi - this.anglex;
this.angley = this.anglex;
}
else {
if (temp.bx) this.anglex = pi - this.anglex;
if (temp.by) this.angley = pi - this.angley;
}
//this.velocity = this.velocity/2;
this.dist = this.dist-this.distgone;
this.distgone = 0;
}
setTimer(0.05);
}
}
}
They're pretty off...

coreys
10-31-2007, 04:32 AM
-bump-
Halp D:

Tolnaftate2004
10-31-2007, 06:28 AM
You only need one angle...

coreys
10-31-2007, 07:14 AM
Well...I was gonna do that...I actually kinda forgot what forced me to do that, actually...
What would you suggest I do? ._.
What I did there works, except that the onwall checks are off by 1-2 tiles

Tolnaftate2004
10-31-2007, 08:57 AM
That's probably an issue with the position of the onwall checks. You need to check from the center of the object outwards, or you'll have it hitting walls about 1 tile too soon when headed up/left, and a tile too late the other directions. But this all also depends on the velocity, as is apparent in your script.

More elegant scripts use a for loop to check more elementary distances (e.g. 1 pixel) and determine if a wall is within 1 "velocity's" range.

DustyPorViva
10-31-2007, 06:18 PM
This is what I used when I was messing around with a pong thing:
this.velocity={random(-1,1),random(-1,1)};
x+=this.velocity[0];
y+=this.velocity[1];
if (onwall(x+this.velocity[0],y+.5)) this.velocity[0]=this.velocity[0]*-1; //Assuming the center is half a tile in
if (onwall(x+.5,y+this.velocity[1])) this.velocity[1]=this.velocity[1]*-1;

Of course, this script itself isn't going to work, but you can see where I'm going with it.

coreys
11-03-2007, 07:55 PM
I've tried everything I could think of, and I still can't get the onwall checks to be correct:

function onTimeOut() {
if (this.distgone < this.dist) {
temp.x = this.x+1; temp.y = this.x+1;
temp.dx = temp.x+(this.velocity*cos(this.anglex));
temp.dy = temp.y+(this.velocity*(-sin(this.angley)));
temp.dir = getdir(temp.dx-temp.x, temp.dy-temp.y);
if (!onwall(temp.dx,temp.dy)) {
this.x += this.velocity*cos(this.anglex);
this.y += this.velocity*(-sin(this.angley));
this.distgone += this.velocity;
this.velocity = (this.velocity/5)*4;
}
else {
temp.bx = onwall(temp.dx,temp.y);
temp.by = onwall(temp.x,temp.dy);
if (temp.bx && temp.by) {
this.anglex = pi - this.anglex;
this.angley = this.anglex;
}
else {
if (temp.bx) this.anglex = pi - this.anglex;
if (temp.by) this.angley = pi - this.angley;
}
temp.dx = this.x+1+(this.velocity*cos(this.anglex));
temp.dy = this.y+1+(this.velocity*(-sin(this.angley)));
if (!onwall(temp.dx,temp.dy)) {
this.x = temp.dx-1;
this.y = temp.dy-1;
this.distgone += this.velocity;
}
this.velocity = (this.velocity/5)*3;
}
if (this.velocity <= .005) this.dist = this.distgone = 0;
else setTimer(0.05);
}
}
I only have the angles split into x and y because of checking if it's hitting a wall vertically or horizontally. That's the only way I could think of doing it.

This is really starting to frustrate me.

Tolnaftate2004
11-03-2007, 09:53 PM
I only have the angles split into x and y because of checking if it's hitting a wall vertically or horizontally. That's the only way I could think of doing it.

This is probably why it's not functioning like you'd want it to. sin() and cos() already split an angle into y- and x-components. So, you only need a single angle.

Here is an example:
//#CLIENTSIDE
function onCreated() {
this.img = showimg(2001,"block.png",40,40);
this.img.layer = 7;
this.img.angle = pi/8;
this.img.velocity = 8;
this.img.w = getimgwidth(this.img.image);
this.img.h = getimgheight(this.img.image);
onTimeout();
}
function onTimeout() {
with (this.img) {
for (temp.i=0; temp.i<this.velocity; temp.i++) {
if (abs(screenwidth/2-this.x-cos(this.angle)-this.w/2)<screenwidth/2-this.w/2)
this.x += cos(this.angle);
else
this.angle = pi-this.angle;
if (abs(screenheight/2-this.y+sin(this.angle)-this.h/2)<screenheight/2-this.h/2)
this.y -= sin(this.angle);
else
this.angle = -this.angle;
}
}
timeout = 0.05;
}

coreys
11-03-2007, 10:57 PM
But shouldn't the first onwall (onwall(temp.dx, temp.dy)) still work when it's first hit, then? Because in that case this.anglex and this.angley are exactly the same.

In any case, I just plain ****ed it up...

function onActionHit(damage, accuracy, effects, acc, px, py) {
this.distgone = 0;
this.angle = getangle(px-this.x,py-this.y);
if (this.angle > degtorad(180))
this.angle -= degtorad(180);
else this.angle += degtorad(180);
this.velocity = ((damage*4.45)/this.weight)*.05;
temp.friction = this.weight/damage;
if (temp.friction>=1) this.dist = 0;
else this.dist = .75 / temp.friction;
onTimeOut();
}
function onTimeOut() {
if (this.distgone < this.dist) {
temp.x = this.x+1; temp.y = this.y+1;
temp.dx = temp.x+(this.velocity*cos(this.angle));
temp.dy = temp.y+(this.velocity*(-sin(this.angle)));
if (!onwall(temp.dx, temp.dy)) {
this.x = temp.dx; this.y = temp.dy;
this.distgone += this.velocity;
this.velocity = (this.velocity/5)*4;
}
else {
temp.bx = onwall(temp.bx,temp.y);
temp.by = onwall(temp.y,temp.by);
if (temp.bx && temp.by) {
if (this.angle > degtorad(180))
this.angle -= degtorad(180);
else this.angle += degtorad(180);
}
else {
if (temp.bx) this.angle = pi - this.angle;
if (temp.by) this.angle = -this.angle;
}
this.velocity = (this.velocity/5)*3;
temp.dx = temp.x+(this.velocity*cos(this.angle));
temp.dy = temp.y+(this.velocity*(-sin(this.angle)));
if (!onwall(temp.dx, temp.dy)) {
this.x = temp.dx; this.y = temp.dy;
this.distgone += this.velocity;
}
}
if (this.velocity <= .005) this.dist = this.distgone = 0;
else setTimer(0.05);
}
}

coreys
11-03-2007, 11:16 PM
(Sorry for double posting)
I changed it to this:

function onTimeOut() {
if (this.distgone < this.dist) {
temp.x = this.x+1; temp.y = this.y+1;
if (!onwall(temp.x+cos(this.angle)*this.velocity, temp.y))
this.x += cos(this.angle)*this.velocity;
else
this.angle = pi - this.angle;
if (!onwall(temp.x,temp.y+(-sin(this.angle))*this.velocity))
this.y += -sin(this.angle)*this.velocity;
else
this.angle = -this.angle;
this.distgone += this.velocity;
this.velocity = (this.velocity/7)*6;
setTimer(0.05);
}
}
But the onwall checks are still off o.o

coreys
11-04-2007, 01:19 AM
Sorry to triple post, but I fixed it. :D