Graal Forums  

Go Back   Graal Forums > Development Forums > NPC Scripting
FAQ Members List Calendar Today's Posts

Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old 06-23-2012, 01:47 AM
Emera Emera is offline
Delterian Hybrid
Emera's Avatar
Join Date: Mar 2011
Location: Newcastle Upon-Tyne
Posts: 1,704
Emera is a jewel in the roughEmera is a jewel in the rough
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?
Reply With Quote
  #2  
Old 06-23-2012, 02:12 AM
DustyPorViva DustyPorViva is offline
Will work for food. Maybe
DustyPorViva's Avatar
Join Date: Sep 2003
Location: Maryland, USA
Posts: 9,589
DustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond repute
Send a message via AIM to DustyPorViva Send a message via MSN to DustyPorViva
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.
Reply With Quote
  #3  
Old 06-23-2012, 03:09 AM
cbk1994 cbk1994 is offline
the fake one
cbk1994's Avatar
Join Date: Mar 2003
Location: San Francisco
Posts: 10,718
cbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond repute
Send a message via AIM to cbk1994
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_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.



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



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



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
    
};
  }

__________________
Reply With Quote
  #4  
Old 06-23-2012, 07:39 AM
Tricxta Tricxta is offline
The Muffin Man
Tricxta's Avatar
Join Date: Oct 2010
Location: Australia
Posts: 563
Tricxta is a jewel in the roughTricxta is a jewel in the rough
That's a nice method you have there :o
Reply With Quote
  #5  
Old 06-23-2012, 01:06 PM
Emera Emera is offline
Delterian Hybrid
Emera's Avatar
Join Date: Mar 2011
Location: Newcastle Upon-Tyne
Posts: 1,704
Emera is a jewel in the roughEmera is a jewel in the rough

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.
Reply With Quote
  #6  
Old 06-23-2012, 02:06 PM
callimuc callimuc is offline
callimuc's Avatar
Join Date: Nov 2010
Location: Germany
Posts: 1,015
callimuc is a splendid one to beholdcallimuc is a splendid one to beholdcallimuc is a splendid one to beholdcallimuc is a splendid one to beholdcallimuc is a splendid one to behold
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.
__________________
MEEP!
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 12:29 PM.


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