Become a coder Part 4

Page 1

MOTHERBOARD SUPERTEST ISSUE 226 MAY 2009

PERFORMANCE GEAR & GAMING

ISSUE 226 I’VE BEEN IONIZED, BUT I’M OK NOW

BRAIN MELTING

I’VE BEEN IONIZED, BUT I’M OK NOW

HARDCORE PC ADVICE Pro tips Hacking, Tweaking, Overclocking and Modding

BUDGET PROJECTION: BUILD A SCREEN AND MOUNT ON THE CHEAP

Big screen action on a shoe-string budget

WWW.PCFORMAT.CO.UK

THERE’S MORE… £550 Intel vs AMD PCs How to fix any PC problem The tech behind new MMOs How to build an

EVE Corp

Issue 226 May 2009 £5.99 Outside UK & ROI £6.49

WORLD IN CONFLICT SOVIET ASSAULT PCF226.cover 1

GODFATHER 2 THOU SHALT NOT KILL 20/3/09 5:30:40 pm


Game coding

Become a game coder Fed up of waiting for all your WoW patches to download? Why not make your own gaming masterpiece while you wait…

A

situation has developed inbetween me writing the previous instalment of this series and now – it seems a number of fellow coders aren’t happy and have had a long and angry rant about some of the things I’ve said – namely that coding is easy, that anyone can do it without going to university or reading stacks of books, and that the easiest way to learn is just by jumping in. Of course, less than a week after they got all righteous about my comments, a news story came out about a nine-year-old child who’s released a drawing game for the iPhone, having already been programming for two years. Of course, being the responsible, mature adult that I am, I’m not going to make any further comment. Wait one cotton-pickin’ minute, what am I saying? If a nine-year-old can do it, what’s your excuse for whinging about how hard it is? Quit filling the internet with your incessant bleating and leave the coding to people who don’t cry about having to learn a couple of simple techniques to make games.

70

PCF226.prog 70

And now back to our regularly scheduled broadcast: coding your own XNA game. Previously we’ve covered how to get graphics on the screen and how to play sounds. In this issue you’re going to learn how to let the player take control with a game pad. Now, XNA being a Microsoft API for Microsoft hardware, it should come as no surprise to you that this system is primarily designed for the Microsoft Xbox gamepad. There are ways to wrapping the input API to make other controllers work (see sourceforge.net/ projects/xnadirectinput/ for example), but it’s much easier to start off with an official controller to make sure everything works smoothly. One minor niggle: the Microsoft wireless controller continues to operate wirelessly even when used with the play and charge kit connected to your computer. If your computer has wireless functionality you should be okay, otherwise get a wired controller. Either way, make sure you snag the right driver for your controller from here: www. microsoft.com/hardware/download/ download.aspx?category=Gaming.

Above The game so far – note the new score counter at the top left

But first…

You didn’t think I’d forget your homework from last issue, did you? Let’s start with the easiest item: changing your font to be bigger and bolder. This is easy because it doesn’t require you to change any of your game’s code – it’s all controlled using the SpriteFont XML that VC# automagically generates. So, look in your Solution explorer for the file ‘fntMain.spritefont’ (it will be under ‘Content’), then find this line: <Size>14</Size>

Change that ‘14’ to ‘28’. Now look for this line: <Style>Regular</Style>

And change the ‘Regular’ to read ‘Bold’. Homework assignment one done – have it, nine-year-old! Moving on, the Tricky assignment was to play a different sound when the player tries to fire but their energy is too low. I’ve provided a new sound (empty.wav) on your disc to use with

May 2009

19/3/09 3:30:31 pm


Game coding

You can read every button on that controller using IsButtonDown()

Reading buttons

Left Add two more sounds to your game, using XACT the sound bank

this homework, but hopefully you’ve created your own sound by now! Either way, open up the ‘GameAudio.xap’ file you created last time and add the new WAV file into the wave bank and then into the sound bank as a cue, just like we did last time. Now, the quick-and-easy way to make this homework happen is to jump into ‘CheckForFiring()‘ and add some code in the part that reads ‘if (LaserRecharge < 500)’, but, while that certainly works, it’s not a good solution

to play the ‘empty’ sound if the player doesn’t have enough power to fire – put this just before the ‘return’ line: Sounds.PlayCue(“empty”);

Boom biddy bye bye

And that’s homework #2 down, which ushers onto the need to keep track of how many asteroids have been shot. This needs to be split into three parts: creating a score variable to track the number of shot asteroids, changing that

“IF A NINE-YEAR-OLD CAN MAKE A GAME, WHAT’S YOUR EXCUSE FOR WHINGING ABOUT HOW HARD IT IS?” because the homework specifically stated that the sound should only play when the player tries to fire. Go to CheckForFiring, select these four lines, and press [Ctrl]+[X] and cut them to your clipboard: // don’t let players fire if their lasers are dead if (LaserRecharge < 500) { return; }

Now go down and put them into the top of FireLaser() by pressing [Ctrl]+[V] – put them before the line ‘// deplete the laser batteries a little’. At this point the only thing that has been changed is that FireLaser() will be called whenever the player tries to fire, regardless of whether they have enough energy to fire. This means we now have a chance

score whenever we hit something and then drawing it to the screen. To create the score variable, go up to where you have all the ‘int’ lines, and you’ll find this: int LastAsteroidCreation; int AsteroidCreationSpeed = 1000;

Immediately after those two, put a new ‘int’ for the score: int Score;

Now you’ll need to scroll down to ‘CheckForCollisions()’ and look for the section where ‘Lasers.RemoveAt()’ and ‘Asteroids.RemoveAt()’ are both used. Immediately after those two, we will need to add one to the score, so put in the following:

In this project you learn how to read the positions for both the left and the right thumbstick on a controller. But you can actually read any of the buttons on a 360 controller by using the IsButtonDown() method on a game pad state. For example: if (state.IsButtonDown(Buttons.A)) { // do something funky }

When you’re typing that, just pause after ‘Buttons’. and you’ll see a long list of options to choose from. Every button on the controller is there, along with support for the ‘Big Button’ in the rarely used ‘Big Button Controller’. If you want to be sure of the type of controller you have, just read the game pad capabilities data, like this: GamePadCapabilities capab = GamePad. GetCapabilities(PlayerIndex.One); if (capab.GamePadType == GamePadType. Guitar) { // do something even funkier }

Yes, that means you can make guitar games or racing wheel games, or even dancing pad games. There really is nothing stopping your imagination from running wild! Score = Score + 1;

Drawing that score to the screen is just a matter of scrolling down to ‘Draw()’, looking for the existing ‘DrawString()’ call that draws the ‘LaserRecharge’ variable, duplicating it then making some minor tweaks. Add this immediately below that DrawString() line: spriteBatch.DrawString(fntMain, “Score: “ + Score, new Vector2(30, 70), Color.White);

Now that there’s an incentive to destroy the asteroids, it’s time to make them go boom – literally! I’ve added a May 2009

PCF226.prog 71

71

19/3/09 3:30:32 pm


Game coding third new sound for you to use here (explode.wav – see your coverdisc), so put it into your game audio the same way we just did for empty.wav. Up where you just put the ‘Score = Score + 1’ line, you’ll need to add something that plays a new sound with the emitter at the asteroid’s location and the listener in the screen’s centre, as per usual. This is nearly identical to the code we’re using to fire a laser, so I really hope you managed to do this yourself. If not, here’s the code – put it just after the Score line: AudioListener listener = new AudioListener(); listener.Position = new Vector3(ScreenWidth / 2, ScreenHeight / 2, 10.0f); AudioEmitter emitter = new AudioEmitter(); emitter.Position = new Vector3(asteroid. Position.X, asteroid.Position.Y, 0.0f); Sounds.PlayCue(“explode”, listener, emitter);

See, that wasn’t so hard at all, was it?

Working with a controller

As long as you have the right driver installed, you should be able to plug in your Xbox 360 gamepad and start going straight away. When the player light comes on, press the ‘Guide’ button and a little user interface window should appear on your screen saying ‘Click for help’. Press the Guide button again to get rid of the screen – we don’t need it, it’s just there to make sure your controller works before we continue. Right now the UFO’s position on the screen is controlled by a mere five lines of code inside the ‘UpdateUfo()’ section of your code: KeyboardState keys = Keyboard.GetState(); if (keys.IsKeyDown(Keys.W)) UfoVelocity.Y -= 1.0f; if (keys.IsKeyDown(Keys.S)) UfoVelocity.Y += 1.0f;

if (keys.IsKeyDown(Keys.A)) UfoVelocity.X -= 1.0f; if (keys.IsKeyDown(Keys.D)) UfoVelocity.X += 1.0f;

Above Intellisense is great – just press the [.] key after a variable to see what it can do

We can replace those five with just three by switching to the 360 controller. First up, we don’t need Keyboard. GetState() any more, because the keyboard is so 1990s. Instead, you (somewhat predictably) need to use GamePad.GetState(), because that’s, of course, what we’re trying to do. What’s more, we can read the precise X and Y values of the left and right thumbsticks, whose values fall between ‘-1’ (maximum left/maximum down) and ‘1’ (maximum right/maximum up). Putting that all together means we can write code like this:

If you try and build your game now, it won’t work. The problem lies in this line, further down: CheckForFiring(keys);

You’ll notice that right now the CheckForFiring() method looks to see whether left is pressed, whether up is pressed, whether left and up are pressed, and so on. And it does all that using the Keyboard state that our program used up until a moment ago. Fortunately, it turns out this is another example where we can write less code by switching to using a gamepad, so let’s jump in. First, change ‘CheckForFiring(keys);’ to ‘CheckForFiring(state);’ as we’re going to have it use the gamepad state. Now go down to CheckForFiring() itself and change this:

GamePadState state = GamePad. GetState(PlayerIndex.One); UfoVelocity.X += state.ThumbSticks.Left.X; UfoVelocity.Y -= state.ThumbSticks.Left.Y;

void CheckForFiring(KeyboardState keys) {

…to this: void CheckForFiring(GamePadState state) {

Now comes the cool bit. Inside the CheckForFiring() method is a lot of code, starting with this: if (LastLaserFire + LaserFireSpeed > Environment.TickCount) return;

Leave that one line alone. But I want you to delete the rest. Go on, get rid of it. Now replace it with this: Left You’ll need to install the correct drivers for your controller – go to tinyurl.com/5fwq5f to see the full list

72

PCF226.prog 72

if (state.ThumbSticks.Right.LengthSquared() > 0.0f) { Vector2 fire = state.ThumbSticks.Right; fire.Normalize(); FireLaser(fire.X, -fire.Y); }

May 2009

19/3/09 3:30:32 pm


Game coding There are two things that might confuse you if mathematics makes you go weak in the head. First up, state. ThumbSticks.Right.LengthSquared() means ‘take the total movement of the right thumbstick, and multiply it by itself.’ If that is greater than 0, it means the player has moved the thumbstick a little. The reason we need to multiply the movement by itself is because the movement range is from ‘-1’ to ‘1’, and multiplying a negative number by another negative number makes it positive – ensuring that any movement, positive or negative, is read as positive. The second potentially confusing part is ‘fire.Normalize()’. If you can remember all that maths your teachers tried to cram into your heads, then if I write this ‘normalises the vector’ you’ll

The solution is to ‘normalise’ the length of the thumbstick push, which means to make its length add up to 1 regardless of what direction it was pushed in. You end up with exactly the same direction, just now with a length of 1, meaning that all presses, regardless of their strength, have the same length. Once we have a normalised direction for firing, that gets passed into FireLaser() like before. So, now we have the left stick moving the player around, and the right stick firing lasers in all directions. And with less code, too – win!

In this game, the way we can do that is by only vibrating the controller when a bad guy was destroyed recently. Scroll up to where it says ‘int Score;’ and add this: int LastAsteroidDestroy;

Now skip down to CheckForCollisions(), and put these two after “Score = Score + 1;”: LastAsteroidDestroy = Environment. TickCount; GamePad.SetVibration(PlayerIndex.One, 1.0f , 0.0f);

Feel the force

It would be remiss of me to cover controllers without mentioning the most fun thing of all: force feedback,

“IT’D BE REMISS OF ME TO COVER CONTROLLERS WITHOUT MENTIONING THE MOST FUN… FORCE FEEDBACK” already understand. If not, it takes a few more words! First, visualise for a moment the thumbstick’s movement as a dot. If we move directly upwards as far as possible, that dot will be at (0, +1), meaning if we draw a line from the origin (where the thumbstick is when it isn’t being moved) to the dot, it’s directly upwards. If we moved the thumbstick only part way up, the line would be in the same direction, but rather than having a length of +1 it will now be shorter. In terms of direction it’s identical, but as we’re using that length to fire the laser at the right speed, it’s possible for players to fire faster or slower by pressing the thumbsticks in different ways – which doesn’t really make sense.

aka rumble. This is built into all 360 controllers as standard, and as a developer you get to set both lowfrequency vibration and high-frequency vibration – or a combination of both, according to your taste. Now, before you dive in and make everything shake, there’s something important you need to know: not only do you have to tell XNA when to start rumbling, but you also need to tell it when to stop. If some cunning little bug in your code accidentally means that your code to make vibration stops never gets run, the controller will carry on vibrating, which will annoy your player. The best option is to play it safe and do whatever you can to make the vibration definitely, definitely stop.

Your homework is here We’ve put together the basics to help you get started working with a controller. Hopefully you can see how much code it saves you, and how actually we can do far more with a controller than we can with a keyboard! But there’s even more – and I’d like you to explore a little of that for yourself… Fun: Make the ‘empty’ and ‘explode’ sounds vary in pitch. We’ve done this before, so it shouldn’t be hard for you to do again! Tricky: Only show the score and laser

recharge information when the Right Trigger is held down. See the box ‘Reading Buttons’ for some help. Taxing: Make pressing the ‘A’ button on the controller fire a shot in four directions – it should use 400 energy, and should only be possible if the player has at least 900 energy left. Nightmare: Make the ‘B’ button change weapons to a gun that fires very slowly, but doesn’t stop firing when it destroys an asteroid – it just carries on moving, so it can destroy mulitple asteroids.

That first line is just there to track the last time an asteroid was destroyed, but the second one shows you how ridiculously easy it is to make a gamepad judder and vibrate – just specify a number between ‘0’ (no vibration) and ‘1’ (max vibration) for the low-frequency motor and then the high-frequency motor and you’re good to shake your stuff. In that example, I’m making the low-frequency motor buzz at its maximum level, while ignoring the high-frequency motor. So now that the motor has started to buzz, we need to make sure it stops. Fortunately that ‘LastAsteroidDestroy’ can be used to check whether half a second has passed, and, if it has, stop the vibration – put this at the start of your Update() code: if (LastAsteroidDestroy + 500 < Environment. TickCount) { GamePad.SetVibration(PlayerIndex.One, 0.0f, 0.0f); }

That guarantees the gamepad will stop vibrating if at least half a second has passed between now and when an asteroid is destroyed. ¤ Paul Hudson

The results of your Taxing homework should look something like this

May 2009

PCF226.prog 73

73

19/3/09 3:30:32 pm


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.