Typically when I do collision detection for rotating objects, I setup some points along the object where checks will be done. You can use as many of these as necessary, but for this example, I'll stick with just a few.
I'll be using this very simple car script I made as an example in another thread a while back:
PHP Code:
//#CLIENTSIDE
const MAX_SPEED = 3;
const FRICTION = 0.1;
const ACCELERATION = 1.2;
function onCreated() {
this.angle = (pi / 2);
this.trigger("timeOut"); // v6 only
}
function onTimeOut() {
player.client.freeze = true;
hideplayer(0.05);
// turn the car
if (keyDown(1)) {
// turn left
this.angle += 0.1;
} else if (keyDown(3)) {
// turn right
this.angle -= 0.1;
}
// accelerate or deccelerate
if (keyDown(0)) {
// increase speed
this.speed = min(MAX_SPEED, max(0.1, this.speed * ACCELERATION));
} else {
// decrease speed
this.speed *= (1 - FRICTION);
}
// move the car
temp.newX = player.x + cos(this.angle) * this.speed;
temp.newY = player.y - sin(this.angle) * this.speed;
player.x = temp.newX;
player.y = temp.newY;
// show car (you should do this in a GANI attribute so you don't have
// to have this timeout; it'll look smoother for other players too)
with (findImg(200)) {
image = "era_car1_0.png";
x = player.x;
y = player.y;
rotation = thiso.angle - (pi / 2);
}
// reset the timeout
this.setTimer(0.05);
}
To make it easy to visualize what we're doing, I typically setup a function like this for testing:
PHP Code:
function plotPoint(temp.idx, temp.x, temp.y) {
with (findImg(temp.idx)) {
red = green = blue = 1;
layer = 3;
polygon = {
temp.x - 0.1, temp.y - 0.1,
temp.x + 0.1, temp.y - 0.1,
temp.x + 0.1, temp.y + 0.1,
temp.x - 0.1, temp.y + 0.1
};
}
}
In my wall check code, I'll add this:
PHP Code:
temp.centerX = temp.newX + 2;
temp.centerY = temp.newY + 3.35;
// plot the center of the car
this.plotPoint(200, temp.centerX, temp.centerY);
It's crucial that you have the center point of the car picked. It should remain in the center regardless of the car's rotation.
This looks to be a bit off, but good enough for this example. Mess with it as necessary until it works for you. Now I'm going to establish an array of the points I want to check for walls at, basing them off the car facing up. I'll label the points in the script like so:
All I'm doing is making an array of the x and y offsets for each point when the car is facing up, and then displaying those points.
PHP Code:
// establish the points where we'll check for walls
temp.checks = {
// x offset, y offset
{- 0.5, - 3.5}, // F1
{ 0.5, - 3.5}, // F2
{- 2.0, - 3.0}, // L1
{- 2.0, - 1.7}, // L2
{- 2.0, - 0.4}, // L3
{ 2.0, - 3.0}, // R1
{ 2.0, - 1.7}, // R2
{ 2.0, - 0.4} // R3
};
temp.i = 0;
for (temp.check : temp.checks) {
temp.checkX = temp.centerX + temp.check[0];
temp.checkY = temp.centerY + temp.check[1];
this.plotPoint(201 + temp.i, temp.checkX, temp.checkY);
temp.i ++;
}
This looks good if I have the car facing up, but not when rotated.
We need these points to follow the rotation of the car. Fortunately, this is pretty easy; the math involved is beyond the scope of this answer, but pretty simple. Googling "2d rotation matrix" should get you to what you need, but here's the script:
PHP Code:
temp.checkX = temp.centerX + (temp.check[0] * sin(this.angle)) - (temp.check[1] * cos(this.angle));
temp.checkY = temp.centerY + (temp.check[0] * cos(this.angle)) + (temp.check[1] * sin(this.angle));
Now our check points follow the rotation of the car.
Let's have each check point look for walls and turn red if it detects one:
PHP Code:
if (onwall(temp.checkX, temp.checkY)) {
findImg(201 + temp.i).green = findImg(201 + temp.i).blue = 0;
} else {
findImg(201 + temp.i).green = findImg(201 + temp.i).blue = 1;
}
It's trivial now to prevent movement on walls; I'll leave the collision behavior up to you. Here's the final example script:
PHP Code:
//#CLIENTSIDE
const MAX_SPEED = 3;
const FRICTION = 0.1;
const ACCELERATION = 1.2;
function onCreated() {
this.angle = (pi / 2);
this.trigger("timeOut"); // v6 only
}
function onTimeOut() {
player.client.freeze = true;
hideplayer(0.05);
// turn the car
if (keyDown(1)) {
// turn left
this.angle += 0.1;
} else if (keyDown(3)) {
// turn right
this.angle -= 0.1;
}
// accelerate or deccelerate
if (keyDown(0)) {
// increase speed
this.speed = min(MAX_SPEED, max(0.1, this.speed * ACCELERATION));
} else {
// decrease speed
this.speed *= (1 - FRICTION);
}
// move the car
temp.newX = player.x + cos(this.angle) * this.speed;
temp.newY = player.y - sin(this.angle) * this.speed;
// determine if we can move the car here (are we touching a wall?)
temp.centerX = temp.newX + 2;
temp.centerY = temp.newY + 3.35;
// plot the center of the car
this.plotPoint(200, temp.centerX, temp.centerY);
// establish the points where we'll check for walls
temp.checks = {
// x offset, y offset
{- 0.5, - 3.5}, // F1
{ 0.5, - 3.5}, // F2
{- 2.0, - 3.0}, // L1
{- 2.0, - 1.7}, // L2
{- 2.0, - 0.4}, // L3
{ 2.0, - 3.0}, // R1
{ 2.0, - 1.7}, // R2
{ 2.0, - 0.4} // R3
};
temp.i = 0;
temp.foundWall = false;
for (temp.check : temp.checks) {
temp.checkX = temp.centerX + (temp.check[0] * sin(this.angle)) - (temp.check[1] * cos(this.angle));
temp.checkY = temp.centerY + (temp.check[0] * cos(this.angle)) + (temp.check[1] * sin(this.angle));
this.plotPoint(201 + temp.i, temp.checkX, temp.checkY);
if (onwall(temp.checkX, temp.checkY)) {
temp.foundWall = true;
findImg(201 + temp.i).green = findImg(201 + temp.i).blue = 0;
} else {
findImg(201 + temp.i).green = findImg(201 + temp.i).blue = 1;
}
temp.i ++;
}
if (! temp.foundWall) {
player.x = temp.newX;
player.y = temp.newY;
} else {
this.speed *= (- 0.7);
}
// show car (you should do this in a GANI attribute so you don't have
// to have this timeout; it'll look smoother for other players too)
with (findImg(200)) {
image = "era_car1_0.png";
x = player.x;
y = player.y;
rotation = thiso.angle - (pi / 2);
}
// reset the timeout
this.setTimer(0.05);
}
function plotPoint(temp.idx, temp.x, temp.y) {
with (findImg(temp.idx)) {
red = green = blue = 1;
layer = 3;
polygon = {
temp.x - 0.1, temp.y - 0.1,
temp.x + 0.1, temp.y - 0.1,
temp.x + 0.1, temp.y + 0.1,
temp.x - 0.1, temp.y + 0.1
};
}
}