Game Maker For Beginners: Part III
Main Topics: Views, BackgroundsLevel:
Total newb to Game Maker. Suitable for programming nubs, also.Abstract: We're going to make a simple, one-level side-scrolling shoot 'em up using Game Maker and GML. In this third part, we're going to create a scrolling level using views and backgrounds.Introduction
(T.V. narration) Last week
, on Game Maker for Beginners
We let you go Michael Bay on a game's ass. Now, we're going to create a level that scrolls. Because even in a Michael Bay movie, explosions aren't simply enough. If a truck carrying flammable liquids blows up, it also has to skid down the freeway and blow up 50 other cars (and possibly an airplane, too).
Let's build that freeway.Creating a View
So we have rooms, which are like a "set" for our game. Now we need to create a camera to film the action. Most games have at least
one camera, whether it's a first person shooter (camera fixed in front of the face) or an RTS (camera looking down on the action) or what have you. In Game Maker these are called "views." In our game, we're going to make the view scroll from left to right.
First, let's stretch out our room horizontally. Open up the room, go to Settings
and change the width from 320 to 2560 (that's 8 screens wide instead of 1). If you try running this, you'll see that Game Maker is trying to fit the entire room on the screen, and is probably squashing it to do so.
So let's create a view! Go to Views
, and make sure that "Enable the use of Views" is checked. View 0 should also be highlighted by default - make sure that the view is visible.
Also:View in room
- the size of the view. For our purposes, let's set this to 320x240.Port to screen
- how big the view looks. For a low-resolution game such as this one, you may want to double the port (640x480 in this case). This is known as "view scaling." HOWEVER
, there are some serious problems with this method - it can cause unsightly seams in your graphics on certain graphics cards. A much better way to handle scaling is to use surfaces, which are fairly advanced and we'll cover much later. But check out ChevyRay's Seamless Scaling Tutorial
if you're curious.Object following
- in our game, the scrolling will be automatic, but in many games, you want the view to follow the player or some other object. You can set horizontal and vertical border around the object you want to follow, as well as how fast the view can move to achieve this.
With the view created, you should see a white rectangle in your room defining its boundaries (this will not appear in the game, of course).Make It Scroll
Now that we have our wide room and our view, let's make the view scroll.
A view is not tied to any particular object, so to tell it to scroll, we'll have to create some sort of controller object
. Create an object called oGame. This object will not only handle the screen scrolling, but it will keep track of some other variables, like score, drawing the HUD, etc. In a more complex game, you may want to have multiple controller objects, each charged with a specific task. But since this is a relatively simple game, we'll put it all in a single oGame object.
Put this code in the Step Event of oGame:
view_xview += 1;
Each view has x,y coordinates that define where the view is by the upper left corner of the view. view_xview
is an array that stores all the x coordinates of all the views (view_yview
for y). view_xview
stores the x coordinate of View 0. Our code is telling the view to move right 1 pixel with each step.
If you run this, you'll notice that the view quickly leaves the player behind. We want the player to scroll, too. The Step Event should actually look like this:
view_xview += 1;
if (instance_exists(oPlayerShip)) oPlayerShip.x += 1;
The "if (instance_exists(oPlayerShip))" part of the code is to ensure that the game does not crash if there is no oPlayerShip active in the room (we might, for example, destroy the player object when the player dies). Even if there is no possible case in which the player object would be destroyed, it's generally good programming practice to add protection like this when we are accessing data from another object.
Now put oGame somewhere in the room (usually the upper left corner). Because there's no sprite associated with the controller, it will appear as a little question mark in the editor and be invisible during the game.
That's it! Yay, screen scrolling!
...oh wait, it looks like the player can still steer his or her ship off the edges of the screen, that's no good. Let's alter our control code slightly to keep the player within the confines of the view:
if (y > 0) y -= speedUp;
if (y + 12 < room_height) y += speedUp;
if (x > view_xview) x -= speedUp;
if (x + 16 < view_xview + view_wview) x += speedUp;
A couple of new GM variables here: room_height, which is what it sounds like, and view_wview, which is the width of View 0 (in this case, 320).
The reason we check "y + 12" and "x + 16" is to compensate for the fact that the origin of our player ship sprite is in the upper left corner.Backgrounds
Alright, time to populate the VOID.
So we got Sprites, and we got Objects. You'll notice there are also these things called Backgrounds. Backgrounds are kind of like sprites, except that they aren't animated and you can't use them with objects. You can, however, set them to a room and have Game Maker tile them for you.
I made a simple star field background that will be tiled across the entire map. I called it "bgStarField."
To set a background to the room, go to Backgrounds
, select bgStarField from the drop-down menu (where it currently says "no background") and then check "Visible when room starts." You can see there are lots of other options available - you can make the background tile, make it scroll, or set it as the foreground (in front of all the objects). And you can even have multiple backgrounds working at the same time.
If you have a background that covers the entire screen, uncheck "Draw background color" to save Game Maker from performing that extra drawing function.
For now, let's just tile the star field.Adding Tiles
Another thing you can do with backgrounds is create "tile maps." A tile map is a grid of tiles that can be used to decorate your levels. Using tile maps not only makes it very easy to build levels that look nice, but because tiles are static images, they are much faster than objects at runtime, as well. In other words, you want to try and use tiles for anything that doesn't need to move, animate, or otherwise interact with your game.
To create a tile map, first create a background, and then check "Use as tile map" in the Background Properties
. This will open a new menu called Tile Properties
that let's you define the width and height of each tile, among other things.
Here's the tile map I created for the game (which uses 16x16 tiles):
To add tiles to the room, first select the Tiles
tab. Then simply click on a tile to select it and click again to place it, as you would an object. You'll notice at the bottom that you can add depth layers to add your tiles to (the default is 1000000).
It's not too hard to make a nice-looking level this way. Just make sure your trees are happy trees!Adding Walls
We're going to want our ship, bullets, and whatever else to collide with parts of the background, but you can't do collision checks on tiles. So what we're going to do is create a wall object that we can do the checks on. These wall objects will have a simple "block" sprite attached to them, but they will be set to invisible - other objects can interact with them but you will only ever see the tiles behind them.
To set up the collisions, put a Collision Event in both the oPlayerShip and oPlayerShot objects, and set the collision target to oWall. Have them both be destroyed in that event. Easy enough for you now, right?
With the oWall object created and the Collision Events in place, start dropping the walls in the room:
Now when the game starts, you should be able to shoot the walls and explode against them like a gasoline truck on a freeway in a Jerry Bruckheimer movie.One Mo' Thing: Deactivating Objects Outside the View
One more thing: every object that is active in the game will slow the game down significantly, especially when doing collision checks. To minimize this, you should try to deactivate any objects that are not needed. This usually includes all the objects that are outside of the view.
The other reason we might want to do this is to prevent the player from killing baddies off screen by firing indiscriminately!
Add some code to your oGame controller to do this:
// Deactivate objects outside of the view
instance_deactivate_region(view_xview, 0, view_wview, room_height, false, true);
instance_activate_region(view_xview, 0, view_wview, room_height, true);
This deactivates every object outside of the view and then activates every object inside the view, with each step. Make sure that the last two parameters of instance_deactivate_region()
, respectively. This specifies that you want to deactivate objects outside the region, but don't want to deactivate the controller itself (that would be very bad!).
If you have any other controller objects or otherwise important objects that you want to leave on, make sure you activate them with instance_activate_object()
. Extra Credit:
See if you can add some code to oPlayerShip and oGame that makes it so that after the player's ship dies, it reappears on the screen after a few moments. Or you can check the source to see how I did it.[Download the Source for this Tutorial]Next Up:
Let's add a HUD to this thing. No, not a CHUD
, I said a HUD! [link]