Friday 12 April 2013

Part Three - Making the Ball

Welcome back to Computing with Greenie, and the third part of our Ball of Hair tutorial series.
Today we're going to deal with a couple of important things.
First, we're going to be drawing the player's sprite on the screen, and dealing with "Sine Wave" mathematics.
As well as that, we'll be storing data in an array, and also dealing with player input.
That's a lot of things, in a single tutorial, so we'd better get started.

First off, we'll again make a fresh copy of our tutorial project, so we can head back to the previous version if need be.



Copy, and Rename.


We'll start off by giving our player some co-ordinates.
PlayerX=96, a nice simple number.
PlayerY will need to be worked out as we go, using a Sine Wave.

We'll create a new "DoPlayer()" function to handle most of what we need.

Inside here, add a simple drawing function.


Run our project (Ctrl+S, Ctrl+R) for some stationary ball fun!

Next we'll get it bouncing.
This is where we need our SineWave maths.

Sine Waves


A SineWave is generated using the Sin() command.
Every 360 degrees, a SineWave will loop.
At 0 it's flat, at 90 it hits a peak, then it goes back down to 180, and further down to 270, then back up at 360 for it's loop.

The values it returns are 0 for flat, 1 at it's peak and -1 at it's trough.

We'll start by adding a new $Bounce variable, which we'll use to generate our SineWave.

As well as this, we'll keep it ticking along, inside the main loop. (Don't forget the Delta!)

Next up comes the maths.
First, we work out where the ground is.
This is relatively easy. From our previous work, the ground image is drawn when y>4, so the ground level is 5*Layer Size, which is 64 pixels.
Therefore, the ground will always be at 5*64.

Our ball sprite is 64 pixels high, so we need to offset the drawing by 64 pixels to make the bottom of our sprite meet up with the top of the ground.

If we run it now, we'll see the ball running along, at the top of the floor.

It's at this point that I've realised I'm drawing the wrong sprite!  D'oh!!
I should be drawing the Face, not the Ball! Silly me!
It's a simple enough fix, though. We just switch the $Ball for the $Face inside the drawing function.


Job done!

PlayMyCode also does simple Sprite Rotation, so let's add some of that into the mix, too!
Change the DrawImage command to a DrawRotatedImage command instead.
Since the $Bounce variable is constantly being added to, we can use it to rotate our sprite, too.
Place the variable into the second parameter of the DrawRotatedImage function.

If you run it at this point, you'll notice a slight issue.

The face is spinning wildly out of control!
This is because PlayMyCode is trying to deal with angles as Radians, but we're giving it angles in Degrees.
You can read all about Radians and Degrees here. Each has good points and bad points, but I tend to stick to degrees, as those are what I was brought up with, and those are the numbers that work for me. You may be different. Who knows!

To convert between the two, PlayMyCode gives us a handy function. We need only add .toRadians() to the end of our variable name.

Give it another test, and you'll find the face is happily rolling along the floor.
Lovely stuff!

Now for that bounce.

Sin() will only give us a number between -1 and 1, so we need to multiply it by a larger number to get our proper offset.
We start with $PlayerY (which is currently the ground level - 64 pixels), and then subtract Sin()*200 of our toRadians() $Bounce value.
Oooh, complex!

If you run it now, you'll notice an ever so slight issue with our bouncing.
It's not actually bouncing!
Instead, the ball is performing the complete Sine Wave, both the up, and the down.
This is because the SineWave is doing the negative and the positive sides of the wave.
We can fix this in either of two ways..

Method One - Abs()
Since we only need the "Plus" values of our Sine Wave, we can shove a simple .Abs() onto it's value, to ensure it only gives up plus numbers.
Abs() removes the "Positive/Negative" part of a number, so any negative numbers will become positive ones.
It works nice and easily, too.


Method Two - % 180
We used % in the previous tutorial. % "wraps" values to a certain limit.
Since the Sine Wave hits a loop at 180 degrees, we can use the % to loop the values from 0 to 180.
Be sure to enclose the $Bounce % 180 value inside a set of brackets, so that the .toRadians part effects both the Bounce and it's %180 bit, otherwise it'll only be working on the number 180, and that won't work!

You can use either method to bounce your ball.
Since the resulting value will be held in the $PlayerY variable, it doesn't matter which method you choose.
The end result is the important bit.

Array

An array is a large variable which can hold many values.
You shove the values into different boxes, and can easily retrieve them later.
Instead of doing $MyVariable=1, we can use $MyVariable[1]=1 and $MyVariable[2]=32, and so on.

In our little project, we'll be using Arrays to hold the last few $PlayerX and $PlayerY values, so can do that simple faded ball effect that's in the original SpikeDislike

We'll start by creating our arrays, and prepare them to hold 16 values each.

Next, we place a little loop into the DoPlayer function.
Basically we take the current PlayerX and PlayerY location, pop it into the end of the array, and flick through the array, filtering the values down as we go.
The loop goes first, then the new position addition comes afterwards.

We'll also add a drawing into the mix, too.



To help "Fade" the image, we shift it's Alpha setting below 1.
SetAlpha(1) will draw exactly as it should, SetAlpha(0) is invisible, and anything inbetween is nicely faded.
Since we already have a value for each position (n), we can divide this by 20 to get a nice faded value.

And don't forget to set the Alpha value back to 1 when drawing our actual face.

You'll notice that our faded ball movement isn't scrolling along as it should.
Let's add some proper movement into the game, shall we?

Movement & Input


First off, we need another Global to keep track of how fast we're currently moving.

Set it up with a speed inside our main loop, and add THAT value to the scrolling, instead of the hard coded scrolling we've previously used.

We can also then add the movement speed onto the Face's Faded values.

Now we're looking a bit more playable, but we're still not actually playable yet.
To make things playable, we need to incorporate some input.

In PlayMyCode, GetControls() is used to store all the current control variables, and we can then access them using a simple variable and it's functions.
We'll setup a simple if statement, and make the $MovingSpeed be either 0 or 12, depending on whether the spacebar is currently held.  First we set it to 0, then if the spacebar is held, we change it to 12.

We can then expand on this, to incorporate other buttons, too.
isLeftDown() checks for the left mouse button, and Key(:right) checks for the right cursor key.

With one simple line, we've given our game three control buttons. You can even add more, if you wish!

.. and there we'll leave it for today.
We've learned to use simple arrays, added controls, used alpha drawing and rotation, as well as doing some fancy maths.
'cor blimey, that's a lot for a single tutorial!

Next time, we'll be adding in the spikes, and making everything a little more "Gamey", so be sure to check back for that.
You can Play My Code here, where you can easily tweak the code, or just play about with the spinning face.

See you next time. Keep Coding!

No comments:

Post a Comment