10. Keyboard Control <<< Contents >>> 12. Feeding the Snake
We will try to make a little game. You would not believe what has happened. Peter has found monsters in the maze. However, do not worry, we will arm him, and he will handle them. We will continue with the Way program from the previous chapter, in which the last method of control is turned on Controlling by Holding Keys 2. The other possibility is to open the Monsters program, which is prepared as a sample program.
First, we will prepare the monster. In the Global Variables and
Functions window, make a copy
of the empty
square element. Rename it to Monster and draw a monster into it, e.g. like this:
Monsters will be generated randomly. Add
the conditional
executing of commands element into the main
program loop. Into the
if valid
condition test, insert
the is less
than
comparative function (from the calculations
group, comparisons
subgroup). The first parameter for comparison will be the random number (0 <= x
< 1)
function (from the calculations
group, functions
subgroup). The second parameter will be a numeric constant
set
to 0.2 (either as the element text or using the digits and
decimal point elements). In a while, we will add the monster
creation construction.
What will the random function do? The elements texts tell us: "If it is valid that a random number is less than 0.2, create a monster." The random number is a decimal number with a random value between zero and one. 0.2 is one fifth of one. The random number is less than 0.2 in every fifth case. This means that the monster will be generated in one fifth of cases.
To create the monster, we will use
Peters friend Lucy. First, we will specify a random
place where the monster will be created. Into the condition
validity branch, drag the horizontal position and
vertical
position
elements (from the Lucy
group, Lucy -
extension
subgroup). Add the integer part
function to both elements (from the calculations
group, functions
subgroup), as the squares coordinates are integers. Add the
random number
(0 <= x < 1)
function to the
integer elements. The random number can have a parameter
specifying its range. For example, if you add 10, the random
number is generated in the range from 0 to 10. We will add the width of sheet
element to the random number for the horizontal position, and the
height of sheet
element for the vertical position (both elements are from the sheet
group).
Let us take a closer look at the
calculation of the horizontal
random position. The
referential element in the horizontal direction is the width of sheet .
This element returns a number indicating the width of the sheet
as a number of steps (squares). In our case, it will be 12, which
is the width of sheet that we had set before. This number is
passed to the random
number (0 <= x < 1)
function, which
generates a number in the range from zero to the width of sheet
(without the border value), that is, a number between 0 and
11.99999999. The random number is passed to the integer part
function, which truncates the part of the number behind the
decimal point and returns only its integer. This creates a number
between 0 and 11, which are the coordinates of the first and last
square in the horizontal direction. You may have noticed that the
squares are numbered from the bottom left square, starting with
zero.
Now we have Lucy on a random position on the sheet. We could lay the monster item onto the sheet now, but first we have to verify that the square is not occupied, e.g. by a wall. If the square is not free, nothing will be performed and no monster will be created. Here is the result; try to run the program:
Now we will improve the routines for controlling Peters steps. In the Global Variables and Functions window, use the right mouse button to copy the Cautious Step Forward function. A new function called Cautious Step Forward 2 is created. Rename it to Cautious Step in the Specified Direction.
Double-click the new function to edit it,
and look at the bottom left window. It is called Local Variables and
Functions. We dont have
to worry about the function of this window; we will only use the input variables
element. From the Library
of Variables and Functions
window, drag a new numeric variable number
into this element, and
call the variable requested
direction.
Switch back into the main program function.
In the Controlling
by Holding Keys 2
construction, find the first branch (for the Up arrow). Insert
the new function called Cautious
Step in the Specified Direction
here. When you drop the function, you can see that the numeric
variable called requested
direction is connected to it.
It is the one that we have just created. It will pass the
requested direction of the step to the function. From the
direction setting command, drag the up element to the
function parameter. You can discard the remaining commands from
the branch (the direction setting and the Cautious Step Forward function). Adjust the branches for the remaining
directions in a similar way. This will be the construction for
the step upwards:
Now we will prepare the contents of the Cautious Step in the Specified Direction function. Switch into it. First, for testing purposes, try to add the command for setting Peters direction, and add the requested direction variable as the parameter. This restores the original functionality of the program, and we can verify that we did not make any mistake. Run the program and test it, it should work as before. If everything is all right, you can delete the direction setting command.
If we used the original control method for shooting, it would be unpleasant that we would not be able to turn to the target without making a step towards it. For this reason, we will improve the control. If Peter is not turned in the requested direction, he will turn first, and only after that, he will go. By pressing the key once, we will turn Peter around, and by holding the key, we will tell him to go. Edit the function accordingly to the following picture.
The function begins by comparing Peters actual direction with the requested direction, which is passed as the function parameter. This way, we will check if Peter is already turned to the requested direction.
If Peter is turned in the appropriate direction, he can make a step forward. However, he will do so cautiously. First, he tests if there is a wall in front of him. If there is not, he can make a step. If there is, he will stay on his place, and the wait command will be executed. The main program loop has to last for at least one wait interval, so that new monsters can be generated evenly. One wait interval is performed in the main loop, if no key for movement is pressed. The waiting when a key is pressed is handled in the movement function. The program does not wait after the step command, the step ensures the waiting internally.
If Peter is not turned to the requested direction, he turns, and the program waits for a while. The waiting ensures that Peter does not start to go when a key is pressed shortly.
Run the program and test its control. Pay special attention to testing Peters turning on his place and changing directions during walking.
Now we will handle the shooting at the monsters. Once again, we will use Peters friend Lucy. Lucy will be the shot. She will surely not mind and will be glad to do this for Peter.
Double-click the Lucy
sprite in the Global
Variables and Functions window
to edit it (note sprite is a moving animated object). You
will see a sheet with 4 x 5 pictures of Lucy. Click the Properties
button. A window for setting the sprite properties appears.
Change the Phases
per Step (0 = Immediately)
setting from 8 to 2 (the shot will fly quickly), and change the Moving Phases settings from 4 to 0 (the shot does not have to change its appearance
during the flight). Press Enter (or
click OK). The pictures of the sprite have changed, so that
Lucy is only in one column now.
Drag the first picture of Lucy with the
left mouse button, and drop it outside the pictures sheet. The
picture disappears; we have deleted it from the sprite.
Double-click the freed empty square. The sprite picture editor
appears. Draw a picture of the shot for example, a small
gray ball (use the sphere
tool and white color):
Keep the original violet color as the background. It is a transparent color, through which the original contents of the square around the shot can be seen. In the color picker of the editor, it is the color in the upper left corner.
Click Previous Edit to
switch back to editing the Lucy sprite. Drag the first modified
picture with the right mouse button to copy it into the remaining
sprite squares. Later you can move the pictures, so that the
shots will fly exactly from the barrel of the gun.
Test the modified sprite now. Click the Test
button. A window with a green sheet appears, with the sprite of
the shot in the middle. Click somewhere into the sheet, and the
shot moves to the specified location. You can quit the test by
clicking Cancel.
The shot is prepared, and now we have to
handle its control. Return to the main program function. Into the
main loop, right behind the construction for generating monsters,
insert a new conditional
executing of commands element, and call it shot from the gun. As shooting will be activated by the spacebar,
insert the there
is pressed key
function with the spacebar
element (from the keys
group, character
keys
subgroup) into the if valid
condition test.
The whole construction that handles shooting is on the following picture. We set the shot (Lucy) in the starting position, then the shot flies, and when it reaches a target, we turn it off.
In the beginning of the shots flight, we set its position and direction accordingly to those of Peter, and then we make it visible. We know the position and direction elements, but what is a visibility element? All sprites (moving objects, including Peter and Lucy) have two basic states visible and invisible. When in the visible state, the sprite is animated, and moves slowly. If it is invisible, it moves to a new position immediately. Peter becomes a "Super Peter", as quick as lightning.
Lucys visibility will be set by the visible
command. As the sprite visibility parameter, we usually use a
logical constant yes
or no
;
this way, we switch between the "Slowcoach" and "Superman"
modes. The activation of the shot is on the following picture.
For the sake of readability, it is in a separate group.
Now we will handle the movement of the
shot. Behind the group for preparation of the starting position
of the shot, add a command
repeating with specified run number
cycle and label it shot
flight. As a number of
repetitions, type 4. This is the maximum distance that the shot can
fly.
The flight will be interrupted, if the shot
hits a wall. For this reason, in the beginning of the cycle body,
add a condition testing if there is a Wall item in front of Lucy. If there is, the execution
of the cycle will be interrupted by the break executing
command (from the program
control
group). After we check
for the wall, we can add the step
element for the
shots movement.
When the shot moves one step, we will test if it has hit the target. We will use a conditional command that will test, whether the item on Lucys position is a Monster. If it is, the monster will be deleted by laying down an empty square item, and the cycle of the shots flight will be interrupted. Some time in the future, you can add other elements here, such as a hit counter or a monsters moan.
The whole construction for the shots flight is on the following picture. Add an element for turning off the visibility of Lucy behind it, and you can test the program.
If you want to make further
improvements, you can equip Peter with a gun. You can also add a
sound of the shot by using the play sound
element. From the
bank of sounds, drag e.g. [examples]\Weapon\Rifle and Pistol\Pistol sound into the Global Variables and Functions window, and use it in the play sound feature. You
can also add a moan of the hit monster e.g. the [examples]\Human\Shouts\Au 2 sound.