Graal Forums (http://forums.graalonline.com/forums/index.php)
-   Code Gallery (http://forums.graalonline.com/forums/forumdisplay.php?f=179)
-   -   Movement/Wall Detection for Variable sizes (http://forums.graalonline.com/forums/showthread.php?t=134257861)

 DustyPorViva 02-03-2010 10:21 AM

Movement/Wall Detection for Variable sizes

3 Attachment(s)
A small script I threw together to show how you can create a movement system with various speeds(without skipping over walls), and more importantly: various sizes. This means you can shrink your player down to 1 tile and squeeze through cracks, or apply a better wall detection to larger players. What it is lacking is detail to anything else but those two things. It initially started as an experiment with onwall2 for a solid wall detection(instead of lots of onwall()'s), and I decided to add size support later. Lacks important things like sliding around corners, but that's not what this is focused on.

Graal Script Code:

``` function onCreated() {  clientr.movementSpeed = .5;  clientr.movementSize = 2;}//#CLIENTSIDEfunction onCreated() {  showstats(1024);  disabledefmovement();  clientr.movementSpeed = .5;  clientr.movementSize = 2;  player.x = int(player.x)+.5;  player.y = int(player.y);  setTimer(0.05);}function onTimeout() {  temp.speed = clientr.movementSpeed;  temp.size = clientr.movementSize;  player.zoom = size/2;  for (temp.k=0;k<4;k++) {    if (keydown(k)) {      player.dir = k;      temp.cx = (player.x+.5)-((size - 2)/2);      temp.cy = (player.y+1)-((size - 2)/2);      temp.horizontalwall = onwall2(cx + vecx(k)*speed,cy,size-1/16,size-1/16);      temp.verticalwall = onwall2(cx,cy + vecy(k)*speed,size-1/16,size-1/16);      if (horizontalwall == 0) player.x += vecx(k)*speed;      else {        for (i=0;i<(speed > client.size ? speed : size);i+=1/16) {          if (onwall2(cx+vecx(k)*i,cy,size-1/16,size-1/16)) {            player.x += vecx(k)*i;            player.x = int(playerx+((size%2 == 1)*.5))+((size%2 == 0)*.5);            break;          }        }      }      if (verticalwall == 0) player.y += vecy(k)*speed;      else {        for (i=0;i<(speed > size ? speed : size);i+=1/16) {          if (onwall2(cx,cy+vecy(k)*i,size-1/16,size-1/16)) {            player.y += vecy(k)*i;            player.y = int(playery+((size%2 == 0)*.5))+((size%2 == 1)*.5);            break;          }        }      }    }  }  showpoly 200,{    (player.x+.5)-((size - 2)/2),(player.y+1)-((size - 2)/2),    (player.x+.5)-((size - 2)/2)+size,(player.y+1)-((size-2)/2),    (player.x+.5)-((size - 2)/2)+size,(player.y+1)-((size-2)/2)+size,    (player.x+.5)-((size - 2)/2),(player.y+1)-((size - 2)/2)+size,    (player.x+.5)-((size - 2)/2),(player.y+1)-((size - 2)/2),    (player.x+.5)-((size - 2)/2),(player.y+1)-((size - 2)/2)+(1/16),    (player.x+.5)-((size - 2)/2)+size-(1/16),(player.y+1)-((size - 2)/2)+(1/16),    (player.x+.5)-((size - 2)/2)+size-(1/16),(player.y+1)-((size - 2)/2)+size-(1/16),    (player.x+.5)-((size - 2)/2)+(1/16),(player.y+1)-((size - 2)/2)+size-(1/16),    (player.x+.5)-((size - 2)/2)+(1/16),(player.y+1)-((size - 2)/2)+(1/16)  };  setTimer(0.05);}function onPlayerChats() {  if (player.chat.starts("size")) {    temp.newsize = player.chat.substring(5);    if (newsize >= 1 && newsize <= 20) clientr.movementSize = newsize;    else if (newsize > 20) player.chat = "Seriously, are you nuts?";    else player.chat = "Not a compatible size!";  } else if (player.chat.starts("speed")) {    temp.newspeed = player.chat.substring(6);    if (newspeed > 0) clientr.movementSpeed = newspeed;  }}  ```
Video as soon as I can get it uploaded without my internet timing out.

 Imperialistic 02-03-2010 03:42 PM

please donate this script to UN, they need it.

Anyways great job dusty, I'm loving the work lately.

 Chompy 02-03-2010 04:18 PM

Quote:
 Originally Posted by Imperialistic (Post 1553941) please donate this script to UN, they need it. Anyways great job dusty, I'm loving the work lately.
Why just UN? Placing this in the code gallery would help many, instead of just one server. UN can just get the script from the code gallery, so that's not a problem if they need it.

Great script Dusty, could have an awesome use for server having interesting quests, like drinking an elixir to become smaller or something like that.

 DustyPorViva 02-03-2010 10:10 PM

Oh, this should be moved to the code gallery, my bad!

 WhiteDragon 02-04-2010 12:01 AM

How I did the movement on Classic was by having a function that works a long a "primary axis". That could be x-axis, y-axis, or say 45deg.

Then it moves along that access, then when it encounters a wall in its path, it will slide perpendicular to the primary axis.

I made it even more complex (for the sake of efficiency), by doing a conquer-and-divide algorithm along the movement path. With built-in onwall() and onwall2() it literally had 0% impact on CPU. With our scripted onwall (i.e., loop through every player, npc, blocking tile and check if they are blocking & intersect), it matched default performance.

Getting it pixel perfect was a little annoying, but the script came out nicely in the end (probably about 200 lines if all the extra documentation and lines were removed). It supports variable speeds and sizes as well.

I might release it in Code Gallery at some point, but it'd require some cleaning up so it wouldn't rely on some of the other systems we have on Classic, so that is a project for when I have free time. ;)

 DustyPorViva 02-04-2010 12:10 AM

Well making sliding isn't that hard, especially in GS2 since I can use passing parameters to simply make a function that checks for a wall in a given direction, making it much simpler to do accurate wall sliding. Maybe I'll add that later.

 Twinny 02-04-2010 07:27 AM

I <3 you Dusty....saved me a hell of alot of effort.

p.s.
Graal Script Code:

```      else if (newsize > 20) player.chat = "Seriously, are you nuts?"  ```
needs a semicolon

p.p.s

If you do add sliding, I will love you even more =)

p.p.p.s

On further usage, it doesn't seem very smooth. I also found it suffered the same problem I had whereby faster speeds can cause you to jump obstacles... it was this problem that caused me to delay working on it since it was either efficiency or accuracy :(

 DustyPorViva 02-04-2010 07:59 AM

Quote:
 Originally Posted by Twinny (Post 1554104) I <3 you Dusty....saved me a hell of alot of effort. p.s. Graal Script Code: ```      else if (newsize > 20) player.chat = "Seriously, are you nuts?"  ``` needs a semicolon p.p.s If you do add sliding, I will love you even more =) p.p.p.s On further usage, it doesn't seem very smooth. I also found it suffered the same problem I had whereby faster speeds can cause you to jump obstacles... it was this problem that caused me to delay working on it since it was either efficiency or accuracy :(
I just tested it at size 2, speed 5 and didn't even jump over a 1 tile thick wall. Though I suppose circumstance has a lot to do with it. The wall check is checking the desired position, instead of the space BETWEEN the player and the desired position. So at the speed of 10, at the size of 2, the new position is ahead 10 spaces, and the size is 2 so that's 8 tiles not being checked.

It's a fairly easy fix though, which just involves adding the speed to the size of the onwall2.

 Twinny 02-04-2010 01:42 PM

Quote:
 Originally Posted by DustyPorViva (Post 1554105) I just tested it at size 2, speed 5 and didn't even jump over a 1 tile thick wall. Though I suppose circumstance has a lot to do with it. The wall check is checking the desired position, instead of the space BETWEEN the player and the desired position. So at the speed of 10, at the size of 2, the new position is ahead 10 spaces, and the size is 2 so that's 8 tiles not being checked. It's a fairly easy fix though, which just involves adding the speed to the size of the onwall2.
I found I was able to jump over a tree line whilst moving diagonally but yeah it's exactly the same problem I've had before...I eventually went insane trying to create a method which would check for a wall within your speed, move you right before that wall but still allow for the other axis movement and sliding....it's beyond me :(

 12171217 02-04-2010 11:37 PM

Quote:
 Originally Posted by Twinny (Post 1554114) I found I was able to jump over a tree line whilst moving diagonally but yeah it's exactly the same problem I've had before...I eventually went insane trying to create a method which would check for a wall within your speed, move you right before that wall but still allow for the other axis movement and sliding....it's beyond me :(
Perhaps you're going so fast that you slide under and around the tree in a single frame?

 Twinny 02-05-2010 02:01 AM

Quote:
 Originally Posted by 12171217 (Post 1554155) Perhaps you're going so fast that you slide under and around the tree in a single frame?
The area I eventually got into was enclosed

 DustyPorViva 02-07-2010 12:10 AM

I'm rescripting this from scratch right now. I'm instead breaking the wall detection into 4 quadrants and basing wall collisions off of that. This will make it easier to implement sliding, and easier to handle the wall data.

 scriptless 02-12-2010 11:13 AM

Must say, very impressed. Tho size doesn't show for other players, so I came up with this. Maybe you could impliment something to show size properly in your next rescript?

Graal Script Code:

``` function onActionServerside() {   if ( params[0] == "size" ) {     clientr.movementSpeed = .5;     clientr.movementSize = 2;   }   if ( params[0] == "getsize" ) {     temp.var = findplayerbycommunityname(params[1]).clientr.movementSize;     triggerClient("gui", this.name, "gotsize", params[1], temp.var);   } } //#CLIENTSIDE function onCreated() {   player.x = int(player.x)+.5;   player.y = int(player.y);   triggerserver( "gui", this.name, "size", null );   setTimer(0.05); } function onActionClientSide() {   if ( params[0] == "gotsize" ) {     findplayerbycommunityname(params[1]).zoom = params[2]/2;   } } function onTimeout() {   temp.speed = clientr.movementSpeed;   temp.size = clientr.movementSize;   triggerserver( "gui", this.name, "getsize" );   for( temp.pl : allplayers ) {     triggerserver( "gui", this.name, "getsize", pl.communityname );   }   player.zoom = temp.size/2;   for (temp.k=0;k<4;k++) {     if (keydown(k)) {       player.dir = k;       temp.cx = (player.x+.5)-((size - 2)/2);       temp.cy = (player.y+1)-((size - 2)/2);       temp.horizontalwall = onwall2(cx + vecx(k)*speed,cy,size-1/16,size-1/16);       temp.verticalwall = onwall2(cx,cy + vecy(k)*speed,size-1/16,size-1/16);       if (horizontalwall == 0) player.x += vecx(k)*speed;       else {         for (i=0;i<(speed > client.size ? speed : size);i+=1/16) {           if (onwall2(cx+vecx(k)*i,cy,size-1/16,size-1/16)) {             player.x += vecx(k)*i;             player.x = int(playerx+((size%2 == 1)*.5))+((size%2 == 0)*.5);             break;           }         }       }       if (verticalwall == 0) player.y += vecy(k)*speed;       else {         for (i=0;i<(speed > size ? speed : size);i+=1/16) {           if (onwall2(cx,cy+vecy(k)*i,size-1/16,size-1/16)) {             player.y += vecy(k)*i;             player.y = int(playery+((size%2 == 0)*.5))+((size%2 == 1)*.5);             break;           }         }       }     }   }   setTimer(0.05); }  ```

 Twinny 02-12-2010 02:07 PM

Quote:
 Originally Posted by scriptless (Post 1555793) Must say, very impressed. Tho size doesn't show for other players, so I came up with this. Maybe you could impliment something to show size properly in your next rescript? Graal Script Code: ```  triggerserver( "gui", this.name, "getsize" );   for( temp.pl : allplayers ) {     triggerserver( "gui", this.name, "getsize", pl.communityname );   }  ``` Would love to see some updates/addons to this :)
You have suggested that the weapon should trigger the server every 0.05 seconds for the size of allplayers clientside... Imagine Zodiac with 100 people on the server. You would be triggering the server 1 + 100 + amount of people on your buddy list every 0.05 seconds.... bad....

A better way would be to put the players size in an attr[] and simply update the local (someone in a different gmap won't care how the player is being drawn afterall) player's size via some method clientside script (weapon/gani)....

 DustyPorViva 02-12-2010 02:11 PM

Typically you will use a gani as an attr, with ganiscript in it to handle zoom. You set the script in to one attr, then the size of your player(and other visual aspects like alpha and such, if you'd like) to another attr. Use the ganiscript to parse the other attr and then set the player's effects.

However, it was not my responsibility to do this, as that's not what the script was about :)

All times are GMT +2. The time now is 08:55 PM.