Sidescrollers
101
A Feature by Adam Perry
So you want to make a sidescroller. This is a multi-part series on advanced plotscripting that will take you from the most basic basics to the final steps needed to create your very own sidescroller.
Because this is the first installment, we're going to lay down a framework that we can build on in future issues. Take a good look:
include, plotscr.hsd |
Okay, our script doesn't do much right now. Here's the quick and dirty: we have a new game script, which we'll use as the startup script. It calls an initialize script to do any setup stuff we need to do before starting. Finally, the do game script has a continuous loop. Pressing Esc will quit the game.
The most important part of the script is The Loop. Everything will go in there. (Does this sound like an exaggeration? Hardly!) Note the TODO comments. That means there's something left for us To Do there. We'll fill in those parts as we go along.
Ready to move on?
Today, we're going back to high school (or forward, if that's how you roll) to talk about movement. Specifically, we're going to talk about physics (kinematics, really) and just a little bit of calculus hidden in there. Yes, there's math in today's lesson, but it's all at the very heart of platformer magic. You'll want to understand how this stuff works.
At a very fundamental level, movement is made up of positions. Right now, the hero is standing on the platform at the entrance of the level. In two seconds, he'll be further to the right. Position is represented in the OHRRPGCE in terms of pixels. (A lot of the time, you'll deal with it in terms of tiles, but for this lesson, let's forget about tiles.) Everything has pixel coordinates. The top left corner of your map is (0, 0); that is, X=0, Y=0. One pixel to the right of that would be (1, 0); that is, X=1, Y=0. As you go right, X increases, and as you go down, Y increases. An NPC's pixel coordinates are also measured from the top-left corner of his sprite.
A pixel is the smallest graphical unit. Your hero can't move half a pixel onscreen. However, even though we won't be able to represent it graphically, we still want to store the hero's position down to fractions of a pixel internally. This will make movement a lot smoother. To this end, we're going to multiply everything to do with movement by 10. Hamsterspeak doesn't handle fractions, so we're just going to have to do this ourselves. Make a mental note and move on.
From one frame to the next, the hero's position changes. He was five pixels to the left one tick ago, next tick he'll be five pixels to the right. The hero's X-velocity, or horizontal speed, is +5 pixels per frame.
Everything that moves has two velocity values: X-velocity and Y-velocity. We'll store these values in variables, since they'll change as the player moves the hero around. We'll also store the hero's position as variables, so we can remember fractions of pixels as mentioned above. While we're at it, let's define two more variables: friction and gravity.
global variable, begin |
What do gravity and friction mean? Think of gravity as how fast you fall and friction as how easy it is to slow down on a surface. The moon has low gravity; ice has low friction. In our script, friction and gravity are both acceleration values. Velocity is how fast position changes; acceleration is how fast velocity changes. You might want to play around with these values.
Let's initialize all of our new variables now. (You can give them different values if you'd like.) We can also remove that TODO flag from the initialize script.
script, initialize, begin |
Tada! We'll also update The Loop to use some of those values.
script, do game, begin |
Oh! Looks like a new script has popped up. Don't worry about it for now. Notice the part marked "Apply friction"? If the hero is on the ground, he'll come to a stop unless he keeps moving. Changing the value of friction will determine how quickly the hero slows down.
Okay, the hero's position is being updated onscreen, but it's not changing. Let's allow the player to move the hero. First, let's make some new variables to decide how fast he can move.
global variable, begin |
Three new variables. Hero-speed is the hero's acceleration: how much faster will he move this frame than last frame? Hero-max-vx and hero-max-vy are what they sound like: the maximum x and y velocity. Play around with these values for some fun...
Now, let's change around The Loop to accept the player's input. It goes a little something like this:
# Let's do The Loop! |
For now, our hero can't jump. He'll move left and right, though. There's one other change: we don't apply friction if the player is moving the hero in his current direction, otherwise he'd run more slowly on the ground. Friction is applied when trying to change direction, though. On a frictionless surface, it's just as hard to change direction as it is in midair. (This is also true in real life, but with different consequences.)
That's it for now! This is is what our script looks like at the end of the day:
include, plotscr.hsd |
The hero can move! Isn't that exciting? You should be excited. Right now, compiling this script will give you a warning, but you can ignore that. Go ahead, import this script into your RPG file and run it.
Next time: Jumps, Falls, and Walls. For an exciting sample of what's coming, try changing can fall to return true.