So far we have built a fun little toy, but it is not yet a game. We have no win or lose condition, no challenge, and no reward. We need to give the player something to do and challenge themselves with. We will start by implementing the win condition; remove all Pillars from a preset Zone. We will create some levels with a variety of Towers and Zones to clear. We will also create an Equipment Menu, so that the player can select what items they want to use and place them in the world.
The win condition for this game is to clear all Pillars and Debris from a specific Zone. The player will only be able to activate the equipment once and will have a small amount of time to clear the Zone. If they clear it, they win and move on. If it isn't cleared, they lose and they try again.
obj_Zone_Parent
. There is no sprite to attach.scr_Zone_Create
, and add it to a Create event.image_speed = 0; isTouching = true;
We start by stopping the animation of the assigned sprite. All the Zones will consist of sprites with two frames of animation. The first frame will indicate collision and the second frame is the all clear signal. We also have a variable that we will use to identify if a Pillar or Debris is in contact with the Zone.
scr_Zone_Step
, and attach it to a Step event with the following code:if (collision_rectangle(bbox_left, bbox_top, bbox_right , bbox_bottom, obj_Pillar_Parent, false, false)) { image_index = 0; isTouching = true; } else { image_index = 1; isTouching = false; }
Here we are using a function, collision_rectangle
, to determine whether the Pillar parent is currently in contact with the Zone. We cannot use a collision event to check for contact, as we need to watch for the lack of collision to happen. We are using the bounding box parameters of the Sprite to determine the size of the collision area. This will allow us to have multiple Zone sprites with a variety of sizes without any additional code. If there is collision, we switch to the first frame of the animation and indicate that collision is currently happening. Otherwise, we switch to the second frame of animation and indicate that the Zone is currently free of collision.
spr_Zone_01
, and load Chapter 6/Sprites/Zone_01.gif
with Remove Background checked. Leave the origin at X: 0
Y: 0
, so that collision will work correctly. Click on OK.obj_Zone_01
, and apply spr_Zone_01
as its Sprite.100
.obj_Zone_Parent
and click on OK.Chapter 6
for variety. Repeat steps 4 to 6 with the appropriate naming conventions for the additional zones.Sandbox
and place an instance of obj_Zone_01
, so that it covers some of the Glass Pillars only, as seen in the following screenshot:obj_Overlord
.scr_Overlord_Create
, and attach it to a Create event, so that we can initialize some variables.isTriggered = false; isVictory = false;
We have two variables that we will be using. We will use isTriggered
to check if the equipment has been activated or not. The isVictory
variable will determine whether the win condition has occurred.
obj_TNT
, obj_Anchor
, and obj_CraneBase
, and remove the Space event under Key Press.scr_Overlord_Step
, and add it to a Step event in obj_Overlord
.if (isTriggered) { if (instance_exists(obj_TNT)) { with(obj_TNT) { scr_TNT_Activate(); } } if (instance_exists(obj_Anchor)) { with(obj_Anchor) { scr_Anchor_Activate(); } } if (instance_exists(obj_CraneBase)) { with(obj_CraneBase) { scr_CraneBase_Activate(); } } alarm[0] = 8 * room_speed; isTriggered = false; }
This code will only execute if the variable isTriggered
is true
. If it is, we check to see if there are any instances of the TNT in existence. If there are instances, we use a with
statement to run the activation script for each instance. We do the same for the Anchor and Crane Base. We also add an alarm set for eight seconds, which is when we will check for the win condition. Finally, we set isTriggered
back to false
so that this runs for the second time.
scr_Overlord_KeyPress
, and add it to a Space event under Key Press.isTriggered = true;
false
. Create a new Script, scr_WinCondition
, with the following code:with (obj_Zone_Parent) { if (isTouching) { return false; } } return true;
By using a with
statement to check obj_Zone_Parent
, we are able to look for all instances of that object and all of its children. We are going to use return
statements here to help us exit the script. When a return is executed, the script will immediately stop and any code after it will not be run. If any instance has collision we return false
; otherwise, if no instances have collision, we return true
.
scr_WinCondition
in our alarm event. Create a new Script, scr_Overlord_Alarm0
, and add it to an Alarm 0 event.isVictory = scr_WinCondition(); if (isVictory) { if (room_exists(room_next(room))) { room_goto_next(); } } else { room_restart(); }
We start by capturing the returned boolean
from scr_WinCondition
in the isVictory
variable. If it is true
, we check to see if there is a room after the current room we are in. The order of rooms is determined by where they are placed in the Resource tree, with the next room being the one below it in the Resource tree. If there is a room, we go to it. If the win condition is false
, we restart the room.
Sandbox
and place a single instance of obj_Overlord
anywhere in the room.Sandbox
and name it Sandbox_02
.Sandbox_02
. When the equipment is activated this time, there will be some destruction, but there will still be Pillars and Debris in the Zone. After a few moments, this room will restart. The win condition works!While we now have a win condition, there still isn't anything for the player to do. We are going to fix that by adding an Equipment Menu. This menu will be placed along the bottom of the gameplay screen and have selectable icons for the TNT, Wrecking Ball, and Magnetic Crane. When an icon is clicked it will create a placeable ghost version of the appropriate piece of equipment. To place the equipment, the player just needs to click somewhere in the world and the ghost will become the real item.
Chapter 6/Sprites/
for the following sprites with Remove Background unchecked. Leave the origin at X: 0 and Y: 0
.spr_Menu_BG
spr_Menu_TNT
spr_Menu_WreckingBall
spr_Menu_MagneticCrane
obj_Menu
. We will not apply a Sprite to this object.scr_Menu_Create
, and apply it to a Create event.isActive = false;
scr_Menu_DrawGUI
, and apply it to a Draw GUI event.draw_sprite(spr_Menu_BG, 0, 0, 400); menuItem_Zone = 32; menuItems_Y = 440; menuItem1_X = 40; draw_sprite(spr_Menu_TNT, 0, menuItem1_X, menuItems_Y); menuItem2_X = 104; draw_sprite(spr_Menu_WreckingBall, 0, menuItem2_X, menuItems_Y); menuItem3_X = 168; draw_sprite(spr_Menu_MagneticCrane, 0, menuItem3_X, menuItems_Y);
As we know that every room is going to be displayed at a resolution of 640 x 480, we start by drawing the background sprite at the bottom of the screen. We are going to use a variable, menuItem_Zone
, to help with the mouse coordinates over the sprites. We will need to know exactly where the icon is placed when we code in the future, so we make variables for each menu item's coordinates and then draw the Sprite on the screen.
Sandbox
and change the Settings of the room to Width: 800
, Height: 600
.800
H: 600
. Do not change the values for Port on Screen. By doing this, we will be able to see the entire room and it will be displayed at the standard 640 x 480 resolution.obj_Menu
anywhere in the room.obj_Ghost_TNT
, and applying spr_TNT
as the Sprite.scr_Ghost_TNT_Create
, and apply it to a Create event with the following code:image_alpha = 0.5; myTool = obj_TNT;
In order to differentiate the Ghost TNT from the real TNT, we start by setting the transparency to 50 percent. We are going to use some common scripts for all ghosts, so we will need a variable to indicate what this Ghost represents.
scr_Ghost_Step
and apply it to a Step event.x = mouse_x; y = mouse_y;
scr_Ghost_Released
, and add it to a Left Released event under Mouse.winHeight = window_get_height(); winMouse = window_mouse_get_y(); if (!place_meeting(x, y, obj_Pillar_Parent) && winMouse < winHeight - 64) { instance_create(x, y, myTool); obj_Menu.isActive = false; instance_destroy(); }
We don't want to be able to place the item down on top of the menu, or on top of other instances we are trying to destroy. To make this happen we first need to grab the height of the display area and the position of the mouse within the display. It is important to note that we cannot use the standard mouseY
variable as it relates to the position within the world because we need to know its position on screen. We check to see if there is a lack of collision at the current location in the room with any Pillar, and that the mouse on screen is 64 pixels above the bottom, which ensures that it is above the menu. If this is all true, we create an instance of whatever item is to be placed, tell the Menu that it is no longer active and remove the Ghost from the world. We are now done with the Ghost TNT.
obj_Ghost_WreckingBall
and assign spr_Anchor
as its Sprite.scr_Ghost_Step
, and add a Left Released event under Mouse with scr_Ghost_Released
attached.scr_Ghost_WreckingBall_Create
, and add it to a Create event. All we need here is to initialize what item it will create when placed.myTool = obj_Anchor;
scr_Ghost_WreckingBall_Draw
with the following code:draw_set_alpha(0.5); draw_sprite(spr_Anchor, 0, x, y) for (i = 1; i < 10; i++) { draw_sprite(spr_ChainLink, 0, x + i * 16, y) } draw_sprite(spr_WreckingBall, 0, x + (9 * 16 + 24), y); draw_set_alpha(1);
We start by setting the instance to half transparent so that it looks like a Ghost. We then draw the Anchor, run a for
loop to draw the Chain, and then the Wrecking Ball is drawn at the end of the Chain. Finally, we need to reset the transparency back to full at the end of this code. It is critical that we do this, as Draw events affect everything that is drawn on screen. If we did not reset it, every object in the world would have half transparency.
obj_Ghost_MagneticCrane
, and apply spr_CraneBase
as the Sprite.scr_Ghost_MagneticCrane_Create
, and initialize the necessary variable.myTool = obj_CraneBase;
scr_Ghost_MagneticCrane_Draw
, and add it as a Draw event.draw_set_alpha(0.5); draw_sprite(spr_CraneBase, 0, x, y) draw_set_color(c_dkgray); draw_line_width(x, y, x, y + 144, 8); draw_sprite(spr_Magnet, 0, x, y + 160); draw_set_alpha(1);
In a similar manner as the Ghost Wrecking Ball, we start by setting the transparency to 50 percent. We then draw the crane base, draw a thick gray line and the magnet at the same position they would be when placed. We then set the transparency back to full.
scr_Menu_DrawGUI
and add the following code at the end:if (!isActive) { win_X = window_mouse_get_x(); win_Y = window_mouse_get_y(); if ((win_Y > menuItems_Y - menuItem_Zone && win_Y < menuItems_Y + menuItem_Zone)) { if ((win_X > menuItem1_X - menuItem_Zone && win_X < menuItem1_X + menuItem_Zone)) { draw_sprite(spr_Menu_TNT, 1, menuItem1_X, menuItems_Y); if (mouse_check_button_pressed(mb_left)) { instance_create(menuItem1_X, menuItems_Y, obj_Ghost_TNT); isActive = true; } } if ((win_X > menuItem2_X - menuItem_Zone && win_X < menuItem2_X + menuItem_Zone)) { draw_sprite(spr_Menu_WreckingBall, 1, menuItem2_X, menuItems_Y); if (mouse_check_button_pressed(mb_left)) { instance_create(menuItem1_X, menuItems_Y, obj_Ghost_WreckingBall); isActive = true; } } if ((win_X > menuItem3_X - menuItem_Zone && win_X < menuItem3_X + menuItem_Zone)) { draw_sprite(spr_Menu_MagneticCrane, 1, menuItem3_X, menuItems_Y); if (mouse_check_button_pressed(mb_left)) { instance_create(menuItem1_X, menuItems_Y, obj_Ghost_MagneticCrane); isActive = true; } } } }
We start by checking if the menu is active or not. If a menu item is selected and hasn't been placed, the menu will be considered active. If we are able to select a menu item, we grab the mouse location on screen. We check the mouse location on screen, first with the Y coordinate and the Zone offsets to see if the mouse is on top of the Menu, then with the X coordinate and the Zone of each item. If the mouse is over the top of one of the icons, we redraw the sprite on the second frame of animation to indicate the hover state. We then check to see if the left mouse button has been pressed, and if it has, we spawn the appropriate Ghost item and the menu is now active. Now we can spawn TNT, Wrecking Balls, and Magnetic Cranes.
We now have a working game and all that is left is to create some levels to play. We will build a few levels with a variety of different towers and room sizes to make sure all our code is working properly.
Level_01.Make
sure this is moved to the top of the Rooms section of the Resource tree.0
Y: 20
.obj_Ground
and place instances 64 pixels from the bottom and across the width of the room. The menu will take up the bottom 64 pixels, so we don't need to put any Ground down there.obj_Overlord
and obj_Menu
in the area below the Ground instances. While technically they can go anywhere in the room, this will just keep things a bit more organized.As this is the first level, let's make it easy for the player and only use Glass Pillars. Up to this point in the book, we have only been placing objects as they were created. When placing the Pillars, we can easily rotate them and place them in the world. To rotate an instance in the Room Properties editor, first place the instance in the room normally, and while it is still selected, change the Rotation value in the objects tab. There are options for scaling an instance, but we cannot use these in a physics simulation, as it does not affect the Fixture size.
obj_Pillar_Glass
and obj_Pillar_Glass_Small
, construct a simple two story tower as seen in the following screenshot:obj_Zone_01
behind the tower and roughly in the center vertically. This room is now complete.Level_12
, and change the Width to 1280
and Height to 960
.Level_01
.Level_01
, but we want to display it on screen at the same size. In the views tab, check the boxes for Enable the use of Views and Visible When Room Starts.1280
H: 960
. Do not change the values for Port on Screen. Again, by doing this we will be able to see the entire room at the standard 640 x 480 resolution.0
Y: 20
.obj_Ground
. As the room is twice as large, our numbers need to double as well. The menu will display with a height of 64 pixels of screen resolution in this room, which means the Ground should be 128 pixels from the bottom.obj_Overlord
and obj_Menu
in the area below the Ground instances.obj_Zone_01
behind each of the towers. An example of what the level could look like can be seen in the following screenshot:18.225.149.238