Tolland Middle School PTO



Pyramid Panic..Intelligent Behavior: Animating the Dead Maze game using GMLDirections from the Game Maker’s Apprentice book by Jacob Habgood and Mark OvermarsAn interesting and challenging game must involve tricky opponents that require clever thinking or quick reactions to defeat. Up to now, our enemies haven’t been the brightest- they were just following predefined rules or randomly attacking. For this game, we will make the enemies a bit brighter, but we do not want them to be too clever so that we (as the player) has a chance to win.To do this, we will introduce some artificial intelligence techniques. These are quite easy to implement using Game Maker.Designing the Game: Pyramid PanicThe game we are going to create is a maze game similar to Koalabr8 but the gameplay is much different. Here is the story:You play an explorer who is trapped while investigating a pyramid. All around lie treasures of an ancient pharaoh but pyramids are hazardous and danger is around every corner. Deadly scorpions and beetles will block your progress and mummies will hunt you down. You must keep your wits about you to unravel the secrets of the pyramid and escape a rich man.You control the explorer using the arrow keys. Many obstacles block your path, keeping you from taking the treasures and escaping. Beetles will move vertically while scorpions move horizontally. Mummies move in all directions. These enemies are clever and will react when they see you by trying to catch you and stop your explorations. Some walls can be pushed, letting you reach areas or hide from enemies. The pyramid has scarabs that you can use to make the mummies temporarily vulnerable—you can hunt them for extra points. Deep within the center of the pyramid is the fabled sword of the sun god Ra. It is the greatest treasure that casts unnatural light that reaches throughout the pyramid and lets you see your way clearly. But when you take it, you upset the system within the pyramid by plunging it into an eerie darkness. Only a small glow from the sword will light your way and previous puzzles will become harder to solve. The sword has a secondary function. When wielding the sword, you can press and hold the spacebar to reactivate its glow. The sword makes gold into pure light, lighting your way but reducing your score. When the sword is active, mummies flee as they do when a scarab is active, making your journey easier and draining your wealth.The Basic FrameworkCreating the front-end: Open Game Maker and a new game file.Create sprites using the following files: Title.png, Button_start.png, Button_load.png, Button_help.png, Button_scores.png, and Button_quit.png.Create 2 backgrounds using Backgroudn1.png and Barckground2.png.Create sounds using Music.mp3 and Click.wav.Create a title object using the title sprite. Add an Other, Game start and include an action to play music with loop set to True.Add a Create event. Include a Set Score action and set score to 0. Also include a Set Lives action and set the number to 3. Include a Score Caption action and indicate that the score must not be shown.Create a start button object using the start sprite. Add a Left Pressed mouse event and include an action to play the click sound followed by an action to move the next room. Add Key Press events for the <Space> and <Enter> with the same actions.Create a load button object using the load sprite. Add a Left Pressed mouse event and include an action to play the click sound followed by the Load Game action.Create a help button using the help sprite. Add a Left Pressed mouse event and include an action to play the click sound followed by a Show Info action.10.Create a scores button using the scores sprite. Add a Left Pressed mouse event and include an action to play the click sound followed by a Show Highscore action. Use the 2nd background as an image for the high-score list and choose some coordinating colors and font.11.Create a quit button object using the quit sprite. Add a Left Pressed mouse event and include an action to play the click sound followed by an End Game action. Also add a Key Press, Others, <Escape> event with the same actions.12.Create a front-end room using the first background and place the title and five button objects in it.Creating a Completion screen:Create a sprite using the file Congratulations.png.Create a new object using this sprite. Add a Create event and include a Set Alarm set to Alarm0 using 60 steps. Include a Set Score action and set the score to score*2. This give the player an incentive to escape the pyramid alive.Add an Alarm0 event and include Show Highscore action. Use the same settings as before. Include a Different Room action to move to the front-end room.Create a completion room using background2 and place an instance of the congratulation object in it.Changing the game settings:Double Click the Game Information and create a short help text based on the game’s description.Double click the Global Game Settings.Select the Other tab and disable the Let <Esc> end the game.Creating the controller object: Create a new object named object_controller. No sprite needed. Add a Key Press, Others, <Escape> event, and include the Different Room action to move to the front-end room.Add the Other, No More Lives event. Include a Sleep action, setting the milliseconds to 1000. Include a Display Message action with the message “YOU LOST ALL YOUR LIVES!”In the No More Lives event, include the Show Highscore action with the same settings as the completion screen. Lastly, include a Different Room action to move to the front-end room.To test what has been made, add a room between the front –end and completion to act as a level.Creating a basic room:Right-click on the completion room. Choose the Insert Room option.Select the Backgrounds tab and select the 2nd background.Select the Settings tab to give the room a caption and type room_pyramid.Select the Objects tab and place one instance of the controller at the top left of the room.Test is and not the only way to stop the game is using the <Esc> key which brings you to the front end. Save your game as pyramid1.gmkCreating the Maze and the ExplorerOur next goal is to create the basic maze. This will be similar to Koalabr8 but we will use Execute Code actions and not the regular actions. We will start by creating wall objects. We will use 2 different ones to add variety but they will behave the same by making the 1st wall the parent of the 2nd wall.Creating the wall objects: Create two sprites using Wall1.png and Wall2.png.Create a new object for the 1st wall and name it object_wall1. Use the 1st wall sprite and enable Solid.Create a new object for the 2nd wall and name it object_wall2. Use the Wall2 sprite, enable Solid and set Parent to the 1st wall option.Next we will use the explorer to create our hero. Use the 4 animated sprites for this. To make sure the explorer stays correctly aligned within the cells, disable precise collision checking and increase the bounding box for the sprints. game Maker will act as if the sprites are 32X32.Creating the explorer sprites: Create a sprite using Explorer_left_strip4.png. Name it sprite_explorer_left.Click Modify Mask to open the mask properties form for this sprite. Under Bounding Box, select Full Image. Under Shape, choose Rectangle. Click OK to close the mask properties form.In the same way, create 3 other sprites using Explorer_right_strip4.png, Explorer_up_strip4.png, and Explorer_down_strip4.png.The explorer object must pick the correct sprite depending on its direction of motion. This time, we will do all the motion using code. When the explorer reaches the area outside the room, he has escaped and will move to the completion room.Creating the Explorer object: Create a new object for the explorer and call it object_explorer. Use the sprite_explorer_down.Add a Create event and include the Execute Code action (Control). Type in the following code:{image_speed = 0;}The image_speed variable will store the speed in which the animation is played. When the explorer is standing still, the speed is 0. Add a Collision event with the first wall and include the Execute code action. Here we will stop the motion and set the animation speed to 0. Type the following code:{speed = 0;image_speed = 0;} Add a Keyboard, <Left> event and include an Execute Code action using this code:{if ( !place_snapped(32,32) ) exit;speed = 4;direction = 180;sprite_index = sprite_explorer_left;image_speed = 0.25’}In the first line of code, we call the function place_snapped() to test whether the instance is aligned with the grid. If this is not the case, (the ! means not), we exit the code. Otherwise, the speed and direction will be set. We use a small value for the animation speed to make sure the animation look realistic and doesn’t go too fast. Add similar events for <Right>, <Up>, and <Down> keys. The directions should be 0, 90. and 270 and you need to assign the correct sprite.Add a Keyboard, <no key> event. If aligned with the grid, we must stop the motion. Include an Execute Code action with the following coding:{if ( !place_snapped(32,32)) exit;speed = 0;image_speed = 0;} Add the Other, Outside Room event and include the Next Room action.Adapting the room: Open room_pyramid.In the toolbar set Snap X and Snap Y to 32.Using your 1st wall object, create a maze in the room. (Do not remove the controller object). Make sure there is one exit to the outside. In some spots, use the 2nd wall object to add some variety.Add one instance of the explorer.Test the room to make sure that the explorer’s motion is working correctly. Once you exit the room, you should be at the completion room.Save as pyramid2.gmk.Expanding Our HorizonsOne of the main features of our game is exploration. We will create the whole pyramid as one whole level. This will provide the explorer with a worthy challenge, as well as giving you plenty of space to devise tricks and traps.For this game, we will need a single view that shows the pyramid and explorer. The view will scroll around the pyramid, following the explorer. We did this in the Tank War game.Creating the View: Open room_pyramid and select the settings tab. Change the width to 1920 and the height to 2400. Select the views tab. Enable the option Enable the use of views.Select View0. Enable Visible when room starts.Under View in Room keep the defaults as X:0, Y:0, W:640, H:480. This is the view shown in the room already.Under Port on screen, keep the defaults as X:0, Y:0, W:640, H:480. Under Object following click the menu icon and select object_explorer. Set Hbor to 300 and Vbor to 220. This keeps the explorer centered in view.Now you can extend the maze to fill the whole room.Test your game to see if the view works. As you move, the view should scroll so the explorer is always in view. Next we will adapt the controller object ot draw a status panel with information about the number of lives and score.Modifying the Controller object:Create 2 sprites using the Panel.png and Lives.png files.Create a font that will be used for the score. Make sure it is readable and set it size 14 and bold.Reopen the Controller properties form. Set the Depth to -100 to make it lie in front of all other objects.Add a Draw event. Include a Jump to Position and set X to view_xview[0] and Y to view_yview[0]+448.Include a Draw Sprite action with the sprite set to the panel sprite and X and Y to 0 and relative. Also include the Draw Life Images action with the Image set to Lives sprite, X to 80, Y set to 2 and Relative enabled.Include the Set Font action and select the score font. Align right. Include a Set Color action and choose Yellow. Finally include a Draw Score action with X to 585, Y to 5, Caption set to empty string and Relative enabled.Save the game as pyramid3.gmk and test to make sure the panel is drawn correctly.Reactive BehaviorWe want the pyramid to be inhabited with creatures the explorer needs to avoid. We will create a number of enemies: the first ones are dumb and are controlled by simple reactive behavior. Later the enemies will use rules to guide their behaviors. The cleverest enemies will have different states- depending on the situation. Reactive behavior is the simplest kind you can think of. The beetle enemy will move simply up and down,. It will react to 2 different events: when it hits a block it changes direction, or when the explorer is in front of it, it moves toward the player and double its speed. This gives the impression that the beetle sees the explorer and runs to catch him, making the game more interesting. We will also create the scorpion that operates on the same principle but moves only right or left.First we will create a dummy object called object_enemy. This object will be the parent of all enemy objects which makes it possible to define one collision event for the explorer dealing with all different enemies. We will also use it to destroy our enemy. The explorer isn’t going down without a fight. It is a good habit to divide your objects into subgroups and make them share a parent object for common behavior.Creating the basic enemy object: Create a sound from file die.wav and call it sound_die.Create an object and call it object_enemy. No sprite is assigned.Reopen the explorer object form and add a Collision event with object_enemy. Include the Execute Code action. We will play the dying sound, reduce the number of lives, redraw the screen, sleep a bit and then set the explorer to his starting position while destroying the enemy:{sound_play(sound_die);lives -= 1;screen_redraw();sleep(1000);x = xstart;y = ystart;move_snap(32,32);with(other){instance_destroy();}}Note the use of WITH. We can execute code as if it were being run by another object. We can also and will also use it to control a whole group of objects in the same way. Now we will create the beetle object.Creating the beetle object:Create 2 sprites using Beetle_up_strip4.png and Beetle_down_strip4.png and name them sprite_beetle_up and sprite-beetle_down. In both cases, click Modify Mask. Under Bounding Box, select Full Image and under Shape choose Rectangle.Create an object and call it object_beetle. Use sprite_bettle_down and indicate object_enemy as its parent.Add a Create event and include Move Fixed. Use the down arrow and Speed of 2.Add a Collision event with object_wall1 and include the Reverse Vertical action.Add a Step, End Step event. Include Execute Code with the following code which modifies the sprite to the direction of motion:{if ( vspeed > 0 )sprite_index = sprite_beetle_downelsesprite_index = sprite_beetle_up;}Add some beetles to the room and test the room. The beetles will move up and down and the explorer dies if he is touched by one. Now we will add a piece of code that makes the beetle react to the presence of the explorer. If the explorer is in the same row of the maze as the beetle and in front of it, the beetle will speed up and run at him.Making the beetle object more intelligent:Add the Step, Step event and include an Execute Code action with the following code:{speed = 2;if ( x == object_explorer.x ){if ( (direction == 90) && ( y > object_explorer.y) ){speed = 4;}else if ( (direction == 270) && (y < object_explorer.y) ){speed = 4:}}}Now we will create the scorpion that acts like the beetle but moves horizontally, not vertically.Creating the scorpion object: Create 2 sprites using the Scorpion_left_strip4.png and Scorpion_right_strip4.png and name then sprite_scorpion_left and sprite_scorpion_right. In both cases, click Modify Mask. Under Bounding Box, select full image and under Shape choose Rectangle.Create an object and name it object-scorpion. Assign the sprite_scorpion_right and indicate object_enemy as its Parent.Define the behavior using the same events and similar actions and code as the beetle object.Try out the game or wait patiently for some of the treasure. You need some type of reward Time For TreasureNow it is time to add treasure for the explorer to uncover. There will be 2 different types: one that will occur many times in the maze and each piece is worth 10 points. The second type is rarer so it is worth more when collected. The treasure will be placed in different areas in the room to give the player a challenge.Creating Treasure objects:Create 2 sprites using the files Treasure1.png and Treasure2.png. Click Modify Mask. Under Bounding Box choose Full Image and under Shape choose Rectangle.Create a sound using Treasure.wav and name it sound_treasure.Create an object for the 1st treasure and use sprite1. Give it a Depth of 10 to make sure enemies can appear on top of it. Add a Collision event with the explorer object and include an Execute Code action with the following code to increase the score, destroy the treasure as it is found and to play the treasure sound:{score += 10;instance_destory();sound_play(sound_treasure);}Create an object for treasure 2, assign the 2nd sprite and set the Depth to 10. Add a Collision event with the explorer and include an Execute Code action with the same code except the score will change to 100 rather than 10.Now add treasures to your level for the explorer to find and enemies to guard. Test the game to see the beetles and scorpions add to the challenge.Movable BlocksNow we will introduce 2 special blocks that can be pushed by the player. One block only moves horizontally while the other moves vertically. Only the explorer can push the blocks. These may be magical block, which return to their original position when the explorer stops pushing them. The original position is easily determined, as it is always available in the variables xstart and ystart. By checking the current position compared to its start position, we can determine which direction the block must move to get back to its original position. We will do this will an End Step even to make sure it happens after all other events.Creating the block objects:Create a sprite using Block_hor.png.Create a sound using Block.wav and name it sound_block.Create an object for the horizontal block using the sprite named above. Enable SOLID, and make the first wall its Parent.Add a Step, End Step event. Include the Execute Code action and type the following code which will make the block move back toward its start position and play the sound:{if ( (x < xstart) && place_empty(x+2,y) ){x += 2;sound_play(sound_block);}if ( (x > xstart) && place_empty(x-2,y) ){x -= 2;sound_play(sound_block);}} Reopen the explorer properties. Add a Collision event with the horizontal block. Include an Execute Code action and indicate Other object in Applies To so we can move the block. Type the following code to check if the explorer has moved horizontally. If so, the we check to see if we can move the block that same amount.{if ( object_explorer.hspeed == 0) exit;if ( place_empty(x+object_explorer.hspeed,y) ){x += object_explorer.hspeed;sound_play(sound_block);}}Repeat the steps to create the vertical block. Create the sprite and object, including similar code, except using movement vertically.NOTE: You might wonder why the collision with the explorer and moving block was defined using just the explorer. We want to replace the default collision behavior with the first wall. Otherwise, the explorer would stop moving.Now test the blocks by adding in some horizontal and vertical moving blocks. make sure there is space next to them so they can be moved Save your game as pyramid4.gmk Rule-Based BehaviorTo make our ultimate opponent, we have to make some pretty complicated behavior. A convenient way to define behavior is with rules. Rules help you clearly describe how entities must behave. A rule indicates that if certain conditions are met, certain actions must be taken. So a rule has the form84772510795condtions actionsYou may not have realized but we have been using a rule in the previous section. We said if the x-coordinates of the beetle and explorer were the same, the beetle must move fast toward the explorer:312420031750 x-coordinates equal and facing explorer must move fast toward the explorerThere was a 2nd, default rule that stated if the x-coordinates of the beetle and explorer weren’t equal, or the beetle was facing the other way, then the beetle moves slower. The collision with the wall can be formulated as a rule. So here are the 3 rules:312420029845x-coordinates equal and facing explorer move faster toward explorer306705044450x-coordinates not equal or facing away move slowly135255020955collision with wall reverse vertical direction away from wall The first 2 rules are exclusive, they can never both be true. The third can be true along with rule one or two. In such a situation, it is important to decide what should happen. Should one or both actions be executed or if so, which one? Does one rule have priority over another or should a random one be picked? In this example, the 3rd rule has priority so the beetle cannot move into the wall.Creating a rule based behavior consists of defining the rules and indicating what will happen if multiple rules are valid. A rule consists of one or more conditions and the actions that must be followed if the conditions are true. Typical conditions used in games are:is the position or direction collision free:Is the enemy near the player?Is the player in a particular direction relative to the enemy?Can the enemy see the player?Does the enemy or player carry a particular item (weapon)?All of these can be tested in Game Maker but first we will create the mummu object that can use these conditions to drive its behavior.Creating the mummy object:Create four sprites using mummy_left_strip4.png, mummy_right_strip4.png, mummy_up_strip4.png, and mummy_down_strip4.png. Name them sprite_mummy_left, sprite_mummy_right, sprite_mummy_up and sprite_mummy_down.For each sprite click Modify Mask. Under Bounding Box select Full Image. Under Shape choose Rectangle.Create a new object for the mummy and name it object_mummy. Give it the downward movement and indicate object_enemy as its Parent.Add a Create event and include a move Fixed action. Give it a downward direction and Speed of 4.Add the Step, End Step event. Here we set the correct sprite and animation speed. Include an Execute Code action and type the following code:{image_speed = 1/3;if (hspeed < 0) sprite_index = sprite_mummy_left;if (hspeed > 0) sprite_index = sprite_mummy_right;if (vspeed < 0) sprite_index = sprite_mummy_up;if (vspeed > 0) sprite_index = sprite_mummy_down;}Right now, the mummy will walk throught the walls. We will fix that.Walking AroundThe first behavior we want to define for the mummy is walking around through the level. This is not easy. At each cell, there are 4 possible directions the mummy can choose. Some might be blocked by walls, and therefore unusable. Once the forbidden choices are removed, we must pick the available one. To ensure natural motion. we make sure we never go back to where we started, unless this is our only choice. For other directions, we choose one randomly.How do we change these into rules? Let ahead, left, and right indicate whether these 3 positions are free. We have the following rules:33051757620not ahead and not left and not right move back100012541275ahead move straight ahead73342516510left turn left88582550165vvright turn rightThe first rule is exclusive of the others so if the first rule is valid, all the others are not. The other 3 can be valid at the same time and we should pick a random one.The next step is to turn the rule into GML script. To determine the value of ahead, left and right, we will use the function place_free and to make a random choice, we will use something similar to what we did in the Tic Tac Toe game. We will split the code up based on if the mummy is moving horizontally or vertically.{var ahead, left, right;if ( !place_snapped(32,32) ) exit;if (vspeed == 0){ahead = place_free(x+hspeed, y);left = place_free(x,y+4);right = place_free(x, y-4)’if ( !ahead && !left && !right) {direction += 180; exit;}while (true) // forever{if (ahead && random(3)<1) {exit;}if (left && random(3)<1) {direction = 270; exit;}if (right && random(3)<1) {direction = 90; exit;}}}else{ahead = place_free(x, y+vspeed);left = place_free(x+4,y);right = place_free(x-4,y);if (!ahead && !left && !right) {vspeed = -vspeed; exit;}while (true) // forever{if (ahead && random(3)<1) {exit;}if (left && random(3)<1) {direction = 0; exit;}if (right && random(3)<1) {direction = 180; exit;}}}}We use three variables to store values that specify whether 3 possible positions are collision free. We test whether the mummy is aligned to the grid. If not, we exit the script.Next we distinguish between the horizontal motion(vspeed ==0) and a vertical motion. We will focus on the horizontal motion since vertical is treated similarly. We determine the values of ahead, left and right. Next we check whether the first rule is valid. If so, we change direction and exit the code. To pick one of the other rules randomly, we use a loop that runs forever until a rule is chosen. To pick a rule with a 1-in-3 chance, we check whether random(3)<1. This happens on average 1 out of 3 times. So in each execution of the loop, we try each rule with a one in 3 chance and if one is valid, we execute the rule and exit the code. It is essential that we know at least one rule is valid or the loop will run forever.Note that we use a script rather than Execute Code. This is because we want to use this as a function in later code. For the moment, we will use this script in the Step event of the mummy object.Giving the mummy object behavior:Create the script script_behavior_walk from above.Reopen the properties for the mummy object.Add the Step, Step event then include the Execute Script action and indicate script_beheavior_walk.Place mummies in some of the room and test their behaviors. The mummies should move through the maze successfully.Moving Toward the ExplorerOur 2nd behavior for the mummy is to make it move toward the explorer. We must first determine the direction the player is in relation to the mummy. We will store this in the local variable called dir. This direction between the 2 points can be calculated using the function point_direction() which give a value between 0 and 360. To turn into 1 of 4 choices, we divide it by 90 and round to the nearest integer, making our decision based on the answer. This will always be 0, 1, 2 or 3. 0 means right, 1 means top, 2 means left and 3 is bottom. We now will make the following rules:2762250175895vv277177523495vvdir == 0 and can move right move rightdir == 1 and can move up move up2714625-3810 v vdir == 2 and can move left move left282892520320vmovevmovedir == 3 and can move down move downThese rules are exclusive. Whether we can move in a particular direction depends on whether the direction is collision free. Also we want to avoid the mummy reversing direction. If all rules fail, we call the previous behavior. We will write that script.Script_behavior_towards{if ( !place_snapped(32,32) ) exit;// find out in which direction the explorer is facedvar dir;dir = point_direction(x.y,object-explorer.x, object_explorer.y);dir = round(dir/90);if (dir == 4) dir = 0;// the four rules that move the mummy toward the explorerif (dir == 0 && direction != 180 && place_free(x+4,y)){ direction = 0; exit; }if (dir == 1 && direction != 270 && place_free(x,y-4)){ direction = 90; exit; }if (dir == 2 && direction != 0 && place_free(x-4,y)){ direction = 180; exit; }if (dir == 3 && direction != 90 && place_free(x,y+4)){ direction = 270; exit; }// otherwise do the normal walking behaviorscript_behavior_walk()’}Replace the behavior of the mummy with this new one. You will notice that the mummy moves toward you rapidly and it is almost impossible to finish the game…the mummy is too smart! To make things more fair, we shouldn’t always use the intelligent behavior, especially if the explorer is far away. We will tweak the behavior so we compute the distance between the mummy and explorer. We will also check if the mummy can see the explorer. To do this we need to check if the line between the centers of the two instances avoids a collision with a wall. Use the new rules:228600027305vmovevmoveif a player can be seen move toward the player305752522860vmovevmoveif the distance is larger than 200 walk around1200150-635vmovevmoveotherwise with one in 2 chance move toward the explorer, otherwise walk aroundThese rules are listed in order of priority, so we will execute the 1st one that is valid.Script_behavior_total{if ( !place_snapped(32,32) ) exit;// Calculate the distance and visibilityvar dist, vis;dist = point_distance(x,y,object_explorer.x, object_explorer.y);vis = !collision_line(x+16, y+16,object_explorer.x+16,object_explorer.y+16, object_wall1, false, false);// Execute the rules in orderif (vis) { script_behavior_towards(); exit; }if (dist>200) { script_behavior_walk(); exit; }if (random(2)<1) { script_behavior_towards(); exit; }script_behavior_walk();}To use this script, make the following changes:Improving the mummy object behavior:Create a script script_behavior_towards and script_behavior_total.Reopen the properties for the mummy object.Select the Step event. Select Execute Script and change the script being used to script_behavior_total.The mummy will now display some interesting behavior. Put some mummies in the pyramid room is interesting configuration. Also try to change the behavior (ie the maximum distance away before it stops reacting to the explorer, or the chance that the mummy responds when in range). Save your game as pyramid5.gmkDealing with StatesSo far we have used rules to create the behavior of our creatures in the pyramid. But in real life, people don’t always behave according to rules. They adapt their behavior to the current situation. So we will now introduce states.For each situation, a character will choose the appropriate state. By creating a state for each situation, we keep the number of rules for each state small but create complicated and interesting behavior. When something happens, a character can change state and perform the accompanying behavior. To start, we will give our mummy 3 states, wandering, searching for the explorer and chasing the explorer.State changes can occur when specific events happen or according to rule. For example, a wandering mummy changes to the searching mummy when it gets close to the explorer. Such a system, with a finite number of states and events that cause the state changes are called finite-state machine. A graphic organizer is sometimes used to show the states and state changes.For each state, we then define behavior. For the wandering state, he just walks around. In the searching state, he moves toward the explorer from time to time. In the chasing state, he always moves toward the explorer. The basic behaviors have already been made. We will use states to control how they are used.Using states is very simple in Game Maker. We use a different object for each state. We will start with the mummy and remove the behaviors from it. It will serve as the parent for other mummy objects. The mummy is still attached to the enemy object as a parent so our new objects inherit the behavior from both. Three objects are created for the different states. In the step event of these objects we call the correct behavior script.The only thing left to do is indicate the state changes. We will use the Begin Step event. This event is executed at the beginning of each step, which is a good time to test whether the state needs to change. If you answer, “yes”, we use the instance_change() function to transform into the appropriate type. In addition to changing the behavior of the mummies, we will change the speed. This makes the mummies easier to avoid since they will not move at the same speed as the explorer.Creating a different mummy object:Reopen the mummy object.Select the Step event and delete it.Create a new object called object_mummy_wander, choose the downward-looking sprite and indicated object_mummy as its parent. Add a Step, Step event. Include an Execute Script action and indicate script_behavior_walk.Add the Step, Begin Step event. We want the mummy to change to the searching mummy when we get closer to the explorer. The searching mummy will move slightly faster, we need to check our position is snapped to the grid at the new speed. Without this, the mummy can get out of alignment and move through walls. Include an Execute Code action and type the following code:{speed = 1; // wandering mummies go slowlyif (point_distance(x,y,object_explorer.x, object_explorer.y) < 200){if (!place_snapped(2,2) ) exit;instance_change(object_mummy_search,false);}}Create a new object and call it object_mummy_search, assign the mummy sprite, and assign the object_mummy as its Parent.Add the Step, Step event. Include a Test Chance action and set sides to 2. Include an Execute Script action and assign script_behavior_walk.Next include an Else action and another Execute Script action and assign the script_behavior_towards. Add the Step, Begin Step event. We will want to change to the wandering mummy before we get too far from the explorer or change to the chasing mummy when we see the explorer. We need to check the snapped to grid at the new speed. Include an Execute Code and type the following code:{speed = 2;if ( !collision_line(x+16,y+16, object_explore.x+16, object_explorer.y+16,object_wall1,false,false) ){if ( !place_snapped(4,4) ) exit:instance_change(object_mummy_chase,false);}if ( point_distance(x,y,object_explorer.x,object_explorer.y) > 200 ){instance_change(object_mummy_wander,false);}}Create a new object and name it object_mummy_chase, use the sprite mummy and assign object_mummy as its Parent.Add the Step, Step event. Include an Execute Script action and indicate the script_behavior_towards.Add the Step, Begin Step event. We want to change the mummy back into a searching mummy who doesn’t see the explorer. We won’t check the place snapped. Include an Execute Code action and type the following code:{speed = 4; // chasing mummies really shiftif ( collision_line(x+16,y+16,object_explorer.x+16,object_explorer.y+16, object_wall1,false,false) )instance_change(object_mummy_search,false);}Delete the script_behavior_total.In the pyramid room, replace the mummies with wandering mummies.Test the game. The mummies should behave more realistically and create a challenge to sneak past them. Save your game as pyramid6.gmkScarabsIf you add a lot of mummies to your game, it is pretty difficult to escape the pyramid alive. To give the explorer a better chance, we are introducing a scarab object. When the explorer uses it, the mummies are temporarily vulnerable and the explorer can destroy them. So we need an additional state for the mummy, the afraid state. When the mummy is afraid, it cannot move toward the explorer but will simply wander around. If the player catches the mummy, the mummy is destroyed and the player’s score increases.To implement this, we add a new mummy object for the afraid state. The afraid mummy will behave the same as the wandering mummy but its state changes are handled differently.Creating the afraid mummy object:Create a new object and call it object_mummy_afraid. Assign the mummy sprite and make object-mummy its Parent.Add the Step, Step event. Include an Execute Script action and assign the script_behavior_walk.Creating the scarab object:Create a sprite using the Scarab.png file.Create a new object called object-scarab, assign the scarab sprite and set the Depth to 10.Next we will set the explorer object to deal with the scarabs. As well as collecting them, the explorer needs to be able to use them. For this, we will use a Key Press, <Shift> event where we change the mummies to afraid mummies and we set some alrams to turn them back when the scarab is used up.Extending the explorer object:We need some sounds to let us know the scarab is active. Create sound_power_start using the PowerStart.wav and sound_power_end using PowerEnd.wav.Reopen the explorer object. Select the Create event and change the code by setting the variable scarab_count to 0. We will use scarab_count to check how many the explorer is carrying and whether he can use 1 to chase the mummies away. The new code looks like this:{image_speed = 0;scarab_count = 0;}Add a Collision event with object-scarab. Include an Execute Code action and add the following code, which plays a sound, increases a score and destroys the scarab object. It also adds 1 to the explorer’s scarab count.{sound_play(sound_treasure);score += 50;scarab_count += 1;with (other) instance_destroy();}Add a Key Pressed, <Shift> event. Include an Execute Code event with the following code, setting Alarm0 to 300 (10 seconds) and changing mummies to afraid mummies. We will set Alarm1 to play the end sound just before the timer ends so the explorer has a warning. But before this is done, the code checks that the explorer has collected a scarab, and if he has, it reduces the scarab_count by 1 to indicate a scarab has been used.{if ( scarab_count > 0 ){with (object_mummy) instance_change(object_mummy_afraid,false);alarm[0] = 300; // scarab timeralarm[1] = 240; // end of scarab sound timerscarab_count -= 1;sound_play(sound_power_start)}}Add the Alarm0 event. Include the Execute Code action with the following code to turn all surviving mummies back into wandering mummies:{with (object_mummy) instance_change(object_mummy_wander,false);}Add the Alarm1 event. Include the ` action with sound_power_end to play the end of power sound.Next we define the collision event between the explorer and scared mummy. Here we play a sound, increase the score and destroy the mummy. This event will override the collision event with the basic enemy object, the explorer is therefore not killed.Handling the collision between the explorer and the scared mummy:Create a sound with the name sound_scared using the Scared.wav.Reopen the explorer object.Add a Collision event with the object_mummy_afraid. Include an Execute Code action and ad the following code, which plays the sound, adds to the score, and destroys the mummy:{sound_played(sound_scared);score += 100;with (other) instance_destroy();}The explorer can now collect and use scarabs but there is no indication of how many have been collected. We will extend our display at the bottom of the screen to include the explorer’s scarab count.Extending the score display:Reopen the controller object.At the end of the Draw event, add a Draw Sprite action with Sprite set to sprite_scarab, X set to 290, Y set to 1 and Relative enabled.Add a Draw Variable action and choose object_explorer.scarab_count as the variable. Set X to 340 and Y to 5 and enable Relative.Creating a potion object:Create a sprite called sprite_potion using the Potion.png.Now create an object called object_potion and assign the sprite_potion. Set the Depth to 10 so the enemies move on top of it.Reopen the explorer object.Add a Collision event with the object_potion and insert the Execute Code action. In the code window type the following:{lives += 1;with (other) instance_destroy();}Add some scarabs, potions and mummies and test the game. If it is too hard, add more scarabs or potions. If is it too easy, add more mummies. SAVE the game as Pyramid7.gmkLet There Be LightAs a final touch, we will add a 2nd objective. In addition to escaping alive, our explorer must search for the Sword of Ra, the pyramid’s biggest treasure. The sword is worth 5,000 points but using it isn’t always a good thing. Drawing the sword will turn off all lights in the pyramid. The explorer will be able to use the dim light the sword throws and it will scare the mummies away but using it will drain the explorer’s score and reduce his wealth.To make this happen, we need a few things. First, we need to be able to show part of the world. We will use a global variable called global.swordon to indicate if the sword is activated. This tells us whether our light should light areas close to the explorer or farther out. We will extend the controller object to control the light. In its Create event, we set global.swordon to false to show it is inactive. When the player presses or releases the spacebar, we switch from false to true and back. In the Draw event on the controller, we must hide part of the world to make it unseen. To make sure that the bottom panel of the screen is untouched, we will do this draw step before drawing the panel.To hide part of the room, we use a semi-transparent image. We add the image as a background then draw this image on top of the room image.As the image is fully transparent in the center, the room is visible there but more is hidden as you travel father from the center until it is completely opaque at the edges. At that point everything is hidden. To leave the areas outside the image completely black ,we fill in this area with black rectangles so nothing can be seen there. The script script_light achieves this. As arguments, the script gets the location of the light. Depending on the value of the variable global.scowrdon, it determines the size of the lit area. Next it draws black rectangles about this area. Then it blends, draws a light image in the correct size and sets the blend mode back to normal.Script_light{// Only draw if the explorer has found the swordif ( !object_explorer.has_sword ) exit;// First determine the size of the lit areavar x1,y1,x2,y2,ww;if ( global.swordon ) ww = 800 else ww = 300x1 = argument0-ww/2;x2 = argument0+ww/2;y1 = argument1-ww/2;y2 = argument1+ww/2;// Hide things that are far away by drawing black rectanglesdraw_set_color(c_black);draw_rectangle(0,0,x1,room_height,false);draw_rectangle(x2,0,room_width,room_height,false);draw_rectangle(0,0,room_width,y1,false);draw_rectangle(0,y2,room_width,room_height,false);// Now hide nearby stuff by drawing the light imagedraw_background_stretched(back_light,x1,y1,ww,ww);}The script must be called at the beginning of the Draw event in the controller object.Extending the controller object:Create a background using the light.png file and name it back_light.Create the script from above.Reopen the controller object.Add the Create event and include a Set Variable action, with Variable set to global.swordon and Value to False.Select the Draw event. At the beginning of the list of actions include an Execute Script action. Use the script_light . As Argument0 indicate the object_explorer.x+16 and as Argument1, use object_explorer.y+16. This will center the light on the explorer.Next we will create the sword object.Creating the sword object:Create a sprite using sword.png.Create an object using this sprite and name it object_sword. Set the Depth to 10. No events or actions needed.Now we will edit the explorer to handle the collision with the sword and to let the player use the sword’s power when needed.Extending the explorer object:Reopen the Explorer object. In the Create event, open the Execute Code action and add the line has_sword + false; This makes sure the explorer starts without the sword.Add a Collision event with object_sword. Include the Execute Code action and type the following code:{score += 5000;sound_play(sound_treasure);show_message(“As you draw the mighty Sword of Ra the lights go out!” + “##Frighten the mummies, but don’t lose your treasures. “)has sword = true;with (other) instance_destroy();}This is similar to the Collision event with the other types of treasure but we also set the variable has_sword to true and show a message. Showing this message indicates to the player something has happened and makes the player feel a sense of accomplishment.Add the Keyboard,<Space> event, and include an Execute Code action. Add the following code:{if ( has_sword && (score > 0) ){global.swordone = true;with (object_mummy_ instance_change(object_mummu_afraid,false);score -= 10;}}This checks the explorer found the sword, and he still has a score to feed it. If both are true, it changes the mummies into scared mummies and subtracts 10 points from the score. Because the event happens every step that the spacebar is held, it subtracts 300 points per second. So if you aren’t careful, the 5000 bonus is quickly used!Add the Key Release,<Space> event. Include the Execute Code action and type the following:{if ( has_sword ){global.swordon = false;if (alarm[0] <= 0){with (object_mummy_afraid) instance_change(object_mummy_wander,false);}}}This sets global.swordon back to false and turns the mummies into wandering mummies. Before it does this, it checks Alarm0 is not running. This checks that it doesn’t turn the mummies back if a scarab is in use.Place one instance of the sword object at a special place in the pyramid and test that it works. We have one more change to make to the mummies. When the lights are out, it is unfair if the mummies can still detect the explorer in the same direction. To change that, check the object_explorer.has_sword variable. If true, we make the distance smaller to reflect the maller amount of light.Adapting the behavior of the mummy object:Reopen the wandering mummy object, select the Begin Step event and double click the Execute Code action. Now change the code as follows:{var maxdist;if ( !object_explorer.has_sword )maxdist = 200elsemaxdist = 75;speed = 1; //wandering mummies go slowlyif ( point_distance(x,y,object_explorer.x,object_explorer.y) < maxdist ){if ( !place_snapped(2,2) ) exit;instance_change(object_mummy_search,false);}}Reopen the searching mummy, select the Begin Step event and double-click the Execute Code action. Change the code as follows:{var maxdist;if ( !object_explorer.has_sword )maxdist = 200elsemaxdist = 75;speed = 2;if ( !collision_line(x+16,y+16,object_explorer.x+16,object_explorer.y+16,object_wall1,false,false) ){if ( !place_snapped(4,4) ) exit;instance_change(object_mummy_chase,false);}if ( point_distance(x,y,object_explorer.x,object_explorer.y) > maxdist ){instance_change(object_mummy_wander,false);} }SAVE THE GAME as Pyramid8.gmk. Have your friends test out the game to make sure it isn’t too hard. ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download