Graal Forums

Graal Forums (https://forums.graalonline.com/forums/index.php)
-   NPC Scripting (https://forums.graalonline.com/forums/forumdisplay.php?f=8)
-   -   Collision detection advice? (https://forums.graalonline.com/forums/showthread.php?t=134266706)

Emera 06-23-2012 01:47 AM

Collision detection advice?
 
I'm working on a car script, and I'm having a lot of trouble figuring out how to stop the car from driving over a wall, and also being able to turn the car away from the wall and drive off again without the collision detection catching it and stopping it from moving.

Does anybody have any ideas about how to do this?

PHP Code:

//#CLIENTSIDE

const CAR_MAX 2;
const 
CAR_FRI 0.1;
const 
CAR_ACC 1.2;

function 
onCreated() {
  
this.angle 0;
  
client.incar false;
  
onTimeout();
}

function 
onPlayerChats() {
  if (
player.chat == "car") {
    
client.incar = !client.incar;
    
player.chat "Car:" SPC client.incar;
  }
}

function 
onTimeout() {
  if (
client.incar) {
    
freezeplayer(0.05);
    if (
keydown(0)) {
      
this.speed min(CAR_MAXmax(0.1CAR_ACC this.speed));
    } else {
      
this.speed *= (CAR_FRI);
    }
    if (
keydown(1)) this.angle -= 0.1;
    if (
keydown(3)) this.angle += 0.1;
    
    if (
client.stuck == true) {
      
this.angle += 0.2;
    }
    if (
player.dir == || player.dir == 2) {
      
temp.cpos = {player.0.5player.1};
      if (
onwall(cpos[0] - 2cpos[1] - 1) || onwall(cpos[0] + 4cpos[1] - 1) || onwall(cpos[0] + 4cpos[1] + 2) || onwall(cpos[0] - 2cpos[1] + 2)) {
        
//Stop from driving onto wall
      
} else {
        
player.-= sin(this.angle) * this.speed;
        
player.+= cos(this.angle) * this.speed;
      }
    } elseif (
player.dir == || player.dir == 3) {
      
temp.cpos = {player.0.5player.1};
      if (
onwall(cpos[0] - 3cpos[1] - 1.5) || onwall(cpos[0] + 6cpos[1] - 1.5) || onwall(cpos[0] + 6cpos[1] + 3.5) || onwall(cpos[0] - 2cpos[1] + 3.5)) {
        
//Stop from driving onto wall
      
} else {
        
player.-= sin(this.angle) * this.speed;
        
player.+= cos(this.angle) * this.speed;
      }
    }
    
player.dir getdir(-sin(this.angle), cos(this.angle));
  }
  
setTimer(0.05);


(Pardon the messy code. I'm yet to clean it up since I'm still working on it)

Also, is there a simpler method of checking for walls rather than checking for walls by calling onwall() a gazillion times?

DustyPorViva 06-23-2012 02:12 AM

Collision detection for something like this that involves angles is not simple since there's no way to check for rotated boxes or such. You're going to have to create a "line" of about 8 or so checks in the front of the char(or rear, if backing up) with a loop and check if any of those hit a wall.

cbk1994 06-23-2012 03:09 AM

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.

http://uploads.graalcenter.org/uploa...22.20%20PM.png http://uploads.graalcenter.org/upload/collision_1.png

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_SPEEDmax(0.1this.speed ACCELERATION));
  } else {
    
// decrease speed
    
this.speed *= (FRICTION);
  }
  
  
// move the car
  
temp.newX player.cos(this.angle) * this.speed;
  
temp.newY player.sin(this.angle) * this.speed;
  
  
player.temp.newX;
  
player.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";
    
    
player.x;
    
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.idxtemp.xtemp.y) {
  
with (findImg(temp.idx)) {
    
red green blue 1;
    
layer 3;
    
    
polygon = {
      
temp.0.1temp.0.1,
      
temp.0.1temp.0.1,
      
temp.0.1temp.0.1,
      
temp.0.1temp.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(200temp.centerXtemp.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.

http://uploads.graalcenter.org/uploa...37.38%20PM.png http://uploads.graalcenter.org/uploa...37.47%20PM.png

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:

http://uploads.graalcenter.org/uploa...dcarpoints.png

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.0;

for (
temp.check temp.checks) {
  
temp.checkX temp.centerX temp.check[0];
  
temp.checkY temp.centerY temp.check[1];
  
  
this.plotPoint(201 temp.itemp.checkXtemp.checkY);
  
  
temp.++;


This looks good if I have the car facing up, but not when rotated.

http://uploads.graalcenter.org/uploa...48.29%20PM.png http://uploads.graalcenter.org/uploa...49.34%20PM.png

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.

http://uploads.graalcenter.org/uploa...59.15%20PM.png

Let's have each check point look for walls and turn red if it detects one:

PHP Code:

if (onwall(temp.checkXtemp.checkY)) {
  
findImg(201 temp.i).green findImg(201 temp.i).blue 0;
} else {
  
findImg(201 temp.i).green findImg(201 temp.i).blue 1;


http://uploads.graalcenter.org/uploa...03.54%20PM.png

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_SPEEDmax(0.1this.speed ACCELERATION));
  } else {
    
// decrease speed
    
this.speed *= (FRICTION);
  }
  
  
// move the car
  
temp.newX player.cos(this.angle) * this.speed;
  
temp.newY player.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(200temp.centerXtemp.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.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.itemp.checkXtemp.checkY);
    
    if (
onwall(temp.checkXtemp.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.++;
  }
  
  if (! 
temp.foundWall) {
    
player.temp.newX;
    
player.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";
    
    
player.x;
    
player.y;
    
    
rotation thiso.angle - (pi 2);
  }
  
  
// reset the timeout
  
this.setTimer(0.05);
}

function 
plotPoint(temp.idxtemp.xtemp.y) {
  
with (findImg(temp.idx)) {
    
red green blue 1;
    
layer 3;
    
    
polygon = {
      
temp.0.1temp.0.1,
      
temp.0.1temp.0.1,
      
temp.0.1temp.0.1,
      
temp.0.1temp.0.1
    
};
  }



Tricxta 06-23-2012 07:39 AM

That's a nice method you have there :o

Emera 06-23-2012 01:06 PM

http://uploads.graalcenter.org/upload/cbkrep.png
Apparently I've given to you not that long ago, but be expecting a rep from me when I can. That helped so much, thank you.

callimuc 06-23-2012 02:06 PM

That's very nice! You should post it in the code gallery since there are lots of people wanting to make such scripts or similar ones.


All times are GMT +2. The time now is 01:09 AM.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2026, vBulletin Solutions Inc.
Copyright (C) 1998-2019 Toonslab All Rights Reserved.