Post new topic
Author Message

<  Programming Corner  ~  Here's some actionscript for a wii platformer!

Djmr
Posted: Wed Feb 21, 2007 2:37 pm Reply with quote
GameBoy
Joined: 13 Feb 2007 Posts: 109 Location: I got lost
I've looked around the wiicade action games and I cant find any platformers Sad

So, to resolve this, I've decided to make a tutorial on platformers, with two different actionscripts!

The first set of scripts is all my own work, and the second set of scripts was made by a guy called rystix, edited to work on the wii by me. They both follow the same basis though, to follow the mouse and jump on the mouseclick (the A button).

The first set of scripts
Here's the coding to make a character that follows the wiimote's position:
Code:
onClipEvent (load) {
   var jumpheight = 15;
   var maxfall = 20;
   var pulldown = 1;
   var speed = 0;
   var xdiff = 0;
   var land = 0;
   var jumping = 0;
   var ybottom = 0;
   var platformy = 0;
   _name = "character";
}
onClipEvent (enterFrame) {
   _y += pulldown;
   ybottom = this._y+_height;
   xdiff = _root._xmouse-this._x;
   speed = xdiff/10;
   _x += speed;
   function jump() {
      this.gotoAndStop(2);
      if (jumping == 1) {
         land = 0;
         pulldown = -jumpheight;
         jumping = 0;
      }
   }
   if (land == 0) {
      pulldown += 1;
   } else if (land == 1) {
      pulldown = 0;
   }
   if (pulldown>=maxfall) {
      pulldown = maxfall-1;
   }
}
onClipEvent (mouseDown) {
   jump();
}

If you're a programmer, you should know how simple this all looks, and how you are kicking yourselves by thinking "Why didnt I think of that!". For everyone else, here's an explanation of all the variables:
    Jumpheight is how high your character jumps. This can be changed in the load event.
    Maxfall is how strong gravity is pulling your character down after the jump. This can be changed in the load event.
    pulldown is basically the y axis of your character. This cant be changed in the load event.
    Speed is how fast your character moves left or right. This cant be changed in the load event.
    xdiff is the x axis difference between the character and the mouse. This cant be changed in the load event.
    Land tells flash if the character is on land or not. This cant be changed in the load event.
    Jumping tells flash if the character is jumping or not. This cant be changed in the load event.
    ybottom measures the bottom of the platform that your character is on. This cant be changed in the load event.
    platformy measures how big the platform that your character is on at the y axis. This cant be changed in the load event.

The platform code is unbelivably simple:
Code:
onClipEvent (enterFrame) {
   var endx = this._x + _width;
   if (this.hitTest(_root.character)) {
      if (_root.character.jumping==0) {
         _root.character.land = 1;
         _root.character.jumping = 1;
      }
      if (_root.character.pulldown==0) {
         _root.character._y = this._y;
      }
      if (_root.character._x<this._x) {
         _root.character.land = 0;
         _root.character.jumping = 0;
      }
      if (_root.character._x>endx) {
         _root.character.land = 0;
         _root.character.jumping = 0;
      }
   }
}

As you can see, its basically just changing variables in the character's actionscript, except for endx, which measures where the end of the platform is.

The only bug I've found is when there's two or more platforms together (in a row), the actionscript doesnt like that for some reason, so just make it into a whole platform.

The second set of scripts
DONT READ THIS IF YOU ARE HAPPY WITH THE FIRST SET OF SCRIPTS.

Right, here's the character code:
Code:
onClipEvent (load) {
   var fall = false;
   _name = "character";
   var jump = 0;
   var speed = 8;
   var jumpheight = 13;
   var maxfall = -20;
   var speed = 0;
   var xdiff = 0;
}
onClipEvent (enterFrame) {
   xdiff = _root._xmouse-this._x;
   speed = xdiff/10;
   _x += speed;
   xmin = getBounds(_root).xMin;
   xmax = getBounds(_root).xMax;
   ymin = getBounds(_root).yMin;
   ymax = getBounds(_root).yMax;
   function jump() {
      if (fall == false && jump == undefined) {
         fall = true;
         jump = jumpheight;
      }
      if (jump<>undefined) {
         if (jump>maxfall) {
            jump--;
         }
         _y -= jump;
      }
   }
}
onClipEvent (mouseDown) {
   jump();
}

as you can see, there's many similarities to the two codes, its just the whole jumping aspect that is different. Here's the platform code:
Code:
onClipEvent (load) {
   activated = false;
   down = false;
}
onClipEvent (enterFrame) {
   _root.report.text = Math.round(_root.character.yMax)+" "+Math.round(yMin);
   xmin = getBounds(_root).xMin;
   xmax = getBounds(_root).xMax;
   ymin = getBounds(_root).yMin;
   ymax = getBounds(_root).yMax;
   if (_root.character.xMax>xMin && _root.character.xMin<xMax && _root.character.yMax<yMin) {
      if (_root.character.yMax-_root.character.jump*2>yMin) {
         _root.character._y = ymin-_root.character._height/2;
         _root.character.jump = undefined;
         _root.character.fall = false;
         activated = true;
      }
   }
   if (Math.round(_root.character.yMax)>Math.round(yMin)) {
      if (hitTest(_root.character) && _root.character.xmax<xmin) {
         _root.character._x -= _root.character.speed;
      }
      if (hitTest(_root.character) && _root.character.xmin>xmax) {
         _root.character._x += _root.character.speed;
      }
      if (hitTest(_root.character) && _root.character.ymin>ymax && _root.character.jump>-1) {
         _root.character.jump = -1*(_root.character.jump);
      }
   }
   if (activated == true && not hitTest(_root.character) && _root.character.jump == undefined) {
      _root.character.jump = 0;
      activated = false;
   }
   if (hitTest(_root.character) && _root.character.ymax>ymin && _root.character.jump<>undefined && _root.character._y<_y) {
      _root.character._y = ymin-_root.character._height/2;
      _root.character.jump = undefined;
      _root.character.fall = false;
      activated = true;
   }
   if (_root.character.ymax-_root.character.jump>ymin && _root.character.xMin<xMax && _root.character.xMax>xMin && _root.character.jump<>undefined && _root.character._y<_y) {
      _root.character._y = ymin-_root.character._height/2;
      _root.character.jump = undefined;
      _root.character.fall = false;
      activated = true;
   }
}

this is much longer than the last one, but at least i know that there's no bugs with this one.


So, thats it! Hope to see plenty of Wii jumping in the future!

Thanks for making this a sticky btw!


Last edited by Djmr on Thu Feb 22, 2007 11:55 am; edited 3 times in total

_________________
I know the easiest way to kill ganondorf on zelda tp!
View user's profile Send private message Visit poster's website MSN Messenger
Google
Posted: Wed Feb 21, 2007 2:37 pm


davekilljoy
Posted: Wed Feb 21, 2007 2:40 pm Reply with quote
dkj
Joined: 20 Nov 2006 Posts: 2121 Location: Toronto
Wow, thats incredible! I was actually going to ask you to maybe help me out with a platformer I wanna try to do. I'm learning to animate right now w. Neg, but I don't wanna bug him anymore for code. =P

_________________
WiiCade Forum Rules
<-- 8829 6959 2034 4630 -->
Until WiiCade's Birthday
View user's profile Send private message Visit poster's website
jbanes
Posted: Wed Feb 21, 2007 2:54 pm Reply with quote
Joined: 07 Feb 2007 Posts: 1009
Djmr wrote:
If you're a programmer, you should know how simple this all looks, and how you are kicking yourselves by thinking "Why didnt I think of that!".

Actually, I'm scratching my head at why this is done in such a complex fashion. Getting a platformer to work is super-easy with a smidge of simplified physics. All you need to handle a jump are:

Code:
y - location of the player along the y axis
gravity - a constant for the acceleration of gravity
acceleration - a +/- value that is applied to y every frame
jumppower - how much negative acceleration is in a jump


To start the jump:

Code:
acceleration = -jumppower;


The computation for gravity is:

Code:
acceleration += gravity;
y += acceleration;


If you detect that the character is on the ground, then you reset acceleration to zero before adding it to 'y'.

If you want to add "terminal velocity" (i.e. limit how fast the character can fall) you do this:

Code:
if(acceleration > terminalvelocity) acceleration = terminalvelocity;


This calculation produces a nice and curved jump in the tradition of platformers like Mario. Obviously, you'll need to work out the values for gravity, jumppower, and terminalvelocity, but that's not a difficult problem. You can usually use trial and error to get a feel for which values will work for your game. Just remember that the jumppower needs to be sufficiently greater than the gravity if you want the character to hang in the air for any reasonable period of time.

_________________
Pushing the Wiimote to new heights.

WiiCade Forum Rules
View user's profile Send private message
Djmr
Posted: Wed Feb 21, 2007 2:56 pm Reply with quote
GameBoy
Joined: 13 Feb 2007 Posts: 109 Location: I got lost
Davekilljoy wrote:
Wow, thats incredible! I was actually going to ask you to maybe help me out with a platformer I wanna try to do. I'm learning to animate right now w. Neg, but I don't wanna bug him anymore for code. =P

Nice!

Glad I could be of help. Actually most of it is old stuff i dug up Razz

If you need any platformer help, I'm your man!


Last edited by Djmr on Wed Feb 21, 2007 3:02 pm; edited 1 time in total

_________________
I know the easiest way to kill ganondorf on zelda tp!
View user's profile Send private message Visit poster's website MSN Messenger
Djmr
Posted: Wed Feb 21, 2007 3:01 pm Reply with quote
GameBoy
Joined: 13 Feb 2007 Posts: 109 Location: I got lost
jbanes wrote:
Actually, I'm scratching my head at why this is done in such a complex fashion.
I dont see the complexity in mine, most of it is basically what you put down, except that yours is buggy. You'd land in different heights (lower, higher) depending where your character is when it lands, you could walk on thin air if you just walk off platforms, etc...

_________________
I know the easiest way to kill ganondorf on zelda tp!
View user's profile Send private message Visit poster's website MSN Messenger
davekilljoy
Posted: Wed Feb 21, 2007 3:04 pm Reply with quote
dkj
Joined: 20 Nov 2006 Posts: 2121 Location: Toronto
Uh Oh programming battle!!

_________________
WiiCade Forum Rules
<-- 8829 6959 2034 4630 -->
Until WiiCade's Birthday
View user's profile Send private message Visit poster's website
NegativeONE
Posted: Wed Feb 21, 2007 3:08 pm Reply with quote
Joined: 20 Nov 2006 Posts: 548 Location: Ontario, Canada
What Djmr says is true. You have to find the closest unobstructed pixel above the platform or you get all kinds of graphical anomalies with air walking and whatnot. Also, careful with your terminology. Acceleration is a constant in cases like this. The term you were looking for was velocity. Acceleration is what's added to your velocity, typically as gravity.
View user's profile Send private message Visit poster's website AIM Address MSN Messenger
Djmr
Posted: Wed Feb 21, 2007 3:10 pm Reply with quote
GameBoy
Joined: 13 Feb 2007 Posts: 109 Location: I got lost
lol

Im not arguing against jbanes, I agree that you can do a platformer like that, but I know from past experience that its really buggy. For example, in my platform code I wrote this:
Code:
if (_root.character.gravity==0) {
     _root.character._y = this._y;
}

This moves the character to the same position on the platform when stopping, instead of like I said, different heights.

_________________
I know the easiest way to kill ganondorf on zelda tp!
View user's profile Send private message Visit poster's website MSN Messenger
davekilljoy
Posted: Wed Feb 21, 2007 3:15 pm Reply with quote
dkj
Joined: 20 Nov 2006 Posts: 2121 Location: Toronto
As soon as i can animate this stupid character, well see where it goes...=D

_________________
WiiCade Forum Rules
<-- 8829 6959 2034 4630 -->
Until WiiCade's Birthday
View user's profile Send private message Visit poster's website
Djmr
Posted: Wed Feb 21, 2007 3:20 pm Reply with quote
GameBoy
Joined: 13 Feb 2007 Posts: 109 Location: I got lost
Here's an example of a game that ill never probably finish...
Hope that it gives you a few pointers

_________________
I know the easiest way to kill ganondorf on zelda tp!
View user's profile Send private message Visit poster's website MSN Messenger
jbanes
Posted: Wed Feb 21, 2007 3:39 pm Reply with quote
Joined: 07 Feb 2007 Posts: 1009
Djmr wrote:
I dont see the complexity in mine, most of it is basically what you put down, except that yours is buggy.


1. It's not buggy. When you have a collision, you should reset the player's location to just outside the bounds of the object. If you leave the location as-is, of course you're going to see some bugs. The bug would be in your collision handling, though, not the gravity simulation.

2. Yours is close, but your manipulation of the gravity itself could potentially create some odd results in the jump. Gravity is a constant and shouldn't change. The character's acceleration, however, is variable. The way you're handling it may seem to work, but it's likely to cause a lot of the "bugs" you're referring to.

Quote:
you could walk on thin air if you just walk off platforms, etc...

Nope. The sequence of events (in pseudocode) is:

Code:
acceleration += gravity;
if(isCollision(player, acceleration)) acceleration = 0;
y += acceleration;


If you walk off a ledge, the collisions will stop. Stopping the collisions means that the character will begin accelerating again. In fact, the physics of the situation is such that the character is always accelerating. The only reason why the acceleration gets set to zero is that the energy is transfered from the character to the ground. Obviously, just saying "acceleration = 0" is a simplified way of handling that.

As for the isCollision() function, that's highly dependent on how the platformer represents the map. Usually, you have tiles of objects that can be tested against. For example, in Super Mario Bros. all the boxes and walkways are large squares. To compute collisions in a playfield like that, you might have code like this:

Code:

//Size of blocks in pixels
var BLOCK_SIZE = 16;
//The number of tiles wide the level is
var BLOCKS_WIDTH = 1000;
//The number of tiles high the level is
var BLOCKS_HEIGHT = 1000;

//An array holding BLOCKS_WIDTHx BLOCKS_HEIGHT tiles.
//We assume that < 0 is space for the character to move in.
var tiles[BLOCKS_HEIGHT][BLOCKS_WIDTH];

function isCollision(character, acceleration)
{
    return (isCollisionUp(character, acceleration) || isCollisionDown(character, acceleration));
}

function isCollisionUp(character, acceleration)
{
    var x1 = character.x/BLOCK_SIZE; //Left Point
    var x2 = character.x/BLOCK_SIZE; //Right Point
    var y = (character.y+acceleration)/BLOCK_SIZE; //Top Point

    if(tiles[y][x1] >= 0 || tiles[y][x2] >= 0) return true;

    return false;
}

function isCollisionDown(character, acceleration)
{
    var x1 = character.x/BLOCK_SIZE; //Left Point
    var x2 = character.x/BLOCK_SIZE; //Right Point
    var y = (character.y+character.height+acceleration)/BLOCK_SIZE; //Bottom Point

    if(tiles[y][x1] >= 0 || tiles[y][x2] >= 0) return true;

    return false;
}


Since our game is composed of fixed size tiles, we can make the following change to the previous code:

Code:
acceleration += gravity;
if(isCollision(player, acceleration))
{
    y += acceleration;
    y = y - ((y+player.height)%BLOCK_SIZE);
    acceleration = 0;
}
y += acceleration;


That change will cause the player to adhere to the surface of the tile rather than passing through. It's a bit more complex than I'd like to use for an example, but it basically computes how many pixels past the tile the character is, and gets rid of them.

You'll also note that the code I gave has an interesting feature. Hitting the character's head on something will immediately negate their jump, preventing them from having odd "hang time" from failing to pass through a block.

Handling things along the X axis are almost exactly the same, except that you need to deal with drag instead of gravity. Depending on your game, drag can either be constant or variable. Constant is a lot easier, but variable gives nicer results.

_________________
Pushing the Wiimote to new heights.

WiiCade Forum Rules
View user's profile Send private message
jbanes
Posted: Wed Feb 21, 2007 3:41 pm Reply with quote
Joined: 07 Feb 2007 Posts: 1009
NegativeONE wrote:
Also, careful with your terminology. Acceleration is a constant in cases like this. The term you were looking for was velocity.

Good point! I have no idea why I was using the term acceleration. Velocity is the correct term. Smile

_________________
Pushing the Wiimote to new heights.

WiiCade Forum Rules
View user's profile Send private message
penetraitor
Posted: Wed Feb 21, 2007 4:33 pm Reply with quote
SNES
Joined: 28 Nov 2006 Posts: 483
Djmr wrote:

Add a skip intro button Razz

The mechanics of the game are pretty cool. Reminds me of some old school 8-bit stuff. I am not as big a fan of the hover. I think it kind of makes the game a little too easy. Also, the mechanics of holding the jump button down makes it strange when you hit another cloud midjump and immediately jump again.

Gravity should definitely be treated as a constant that modifies Y velocity. You can confuse people that may be going into your code later by having gravity be a variable term.
View user's profile Send private message
gamebittk
Posted: Wed Feb 21, 2007 5:48 pm Reply with quote
The Almighty Wii
Joined: 06 Dec 2006 Posts: 2743 Location: In my profile...
Nice code. Mybe I'll make a platformer now! Very Happy

_________________

...
I AM A WII!
__
WiiCade forums are gone! But they relive on as WiiNode. It was a good run. Hopefully, these posts remain as memories.
View user's profile Send private message Visit poster's website
23450
Posted: Wed Feb 21, 2007 8:13 pm Reply with quote
SNES
Joined: 12 Dec 2006 Posts: 362 Location: Albertta, Canada
if you just use shapeflag for all your hitTests you dont need all that platform calculations. and you would make a platform by simply drawing it in the ground movieclip, no platform code at all. Seems like alot of code for a simple platform engine.
View user's profile Send private message Send e-mail AIM Address Yahoo Messenger MSN Messenger

Display posts from previous:  

All times are GMT - 5 Hours
Page 1 of 3
Goto page 1, 2, 3  Next
Post new topic

Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum