|Top Previous Next|
I'm pretty sure that when you read the title of this article you said something like: "Yeah, right... how can you associate elevators with intelligence?" The elevator code in this article will start to work if the player is approaching a switch. The "intelligent" idea is that the switch and its corresponding elevator aren't connected at all! You can use many elevators and many switches and they will know how to work together without using pointers, handles, etc. You will use the same action for every button and for every platform and the code will do the rest! Now that I've got your attention, let's see how it is done.
The idea is (once again) simple: if you create a normal level, the distance between the elevators placed inside the level isn't that small. I am using a button that scans around it and if it finds an elevator entity nearby it starts to use it. Here's the code associated to the elevator button:
The action associated to the elevator entity is:
The elevator is sensitive to scanning; when this happens (the player comes close to a button placed close to the elevator), the event will be triggered:
We kill all the other instance of this function then we make the elevator insensitive to other scans.
if (my.z < you.z)
If the elevator is placed behind the button, it must go up until it reaches the height that corresponds to player's feet.
if (my.z > you.z)
Same thing here; the elevator goes down until its height is below player's feet.
my.z = player.z - (player.max_z - player.min_z) / 2;
We set the height of the elevator at player's feet (it was a little smaller or bigger).
We wait until the player has come close enough to the center of the platform and then we enable scanning again. We store player's speed (strength) and then we reset strength because we want to stop the player for now (we allow him to rotate).
while (my.z < my.elevator_height)
As long as elevator's z coordinate is below the value set in skill2, its z is increased and the player is kept in the center (and on top) of the platform by changing its x y z coords.
while (my.z > my.elevator_height)
Same thing here, if the elevator needs to go down.
vec_set (strength, player_strength);
When the elevator his reached its destination, we allow the player to move again by restoring strength.
I have provided an example level with two elevators and two buttons. Of course that you can add as many elevators and buttons as you want, as long as they aren't too close to each other. Play with temp.z = 500 in elevator_button to set different scanning ranges; the distance between my elevators is over 500 quants.
This standalone project teaches you how to create an inventory. The player will be able to pick up a mace, a shield, body armor and the ring of fire. He can let them stay in the inventory or he can use them in order to improve its abilities. Let's take a look at the main function:
I have disabled the "D" key because I'm using WSAD to move the player. Before I throw in the frightening check_inventory function, let's see some defines:
define items skill30;
define shield 1;
When the player picks up an item, its corresponding value is added to player.items (just another name for skill30); if the player collects a shield and a ring, player.items will be 1 (shield) + 8 (ring) = 9, got it? Let's see the function:
If the player has got at least an item (player.items > 0)
if (player.items == 1) // 1 + 0 + 0 + 0
If player.items = 1, the player has got the shield; only shield_pan is made visible.
if (player.items == 2) // 0 + 2 + 0 + 0
If player.items = 2, the player has got the mace; only mace_pan is made visible.
if (player.items == 3) // 1 + 2 + 0 + 0
If player.items = 3, the player has got the shield and the mace; shield_pan and mace_pan are made visible.
The things repeat for player.items = 1...15
if (player.items == 15) // 1 + 2 + 4 + 8
If player.items = 15, the player has got all the items so all the panels are made visible.
If player.items = 0, all the panels are invisible; we set the mouse pointer to be cursor_pcx; the position of the mouse will be calculated every frame.
if (mouse_right == 1)
If we press the right mouse button, mouse mode will be set to 0 or 2, depending on how many times we press it. This shows / hides the mouse pointer, allowing us to click the items in the inventory in order to use them. The while loop waits until we release the right mouse button otherwise the pointer would appear / disappear every frame.
I use 5 panels: the main inventory panel and another 4 panels for the items.
panel main_pan // the main panel for the items in the inventory
The main panel includes 3 hbars that show player's armor (I have used armour because armor is used), attack and strength.
panel shield_pan // displays the shield on the panel
panel mace_pan // displays the mace on the panel
panel armor_pan // displays the armor on the panel
panel ring_pan // displays the ring on the panel
The panels used for the items will appear over the main panel if they are picked up; before I forget, I have created the bitmaps for these panels by placing them inside a black room and taking screenshots. Every item panel has a simple function that will be executed if we click the panel:
We substract shield (1) from player.items; function check_inventory will remove its associated panel from the inventory. We create the "real" shield and we give it to the player, and then we increase strength; the corresponding hbar on the main panel will grow bigger.
We substract mace (2) from player.items; function check_inventory will take care of the rest. We create the mace and give it to the player; the attack hbar will grow.
We substract armor (4) from player.items; function check_inventory removes the panel from the inventory. We create the armor and give it to the player; the armour hbar will grow.
These 3 items are glued to the player because of this function:
The mace, the shield and the armor were animated together with the player and saved as separate models, so they use the same animation frames all the time. I have created the armor model by deleting all the triangles that weren't needed; I have scaled it up a little to make sure that it looks good on the player.
As long as the player exists, these items are placed at player's position, using its angles and frames all the time.
The ring is a special inventory item - let's see the code:
We substract ring (8) from player.items and then we enter inside a while (1) loop. If we press the left mouse button and the mouse pointer is invisible and the number of flames is zero, we create 120 flames around the player, 100 quants away from the player and then we wait until we release the left mouse button.
We don't want to use autofire on the ring of fire so number_of_flames is increased with every flame that is created; this way we make sure that a single ring of fire can be generated and we keep a decent frame rate. The flames are passable and oriented by a random pan angle; they will rotate until their pan will be 1500 (it works :) and they will decrease their z at the same time. When all the flames have been removed, number_fo_flames is zero and function use_ring can create another ring of fire.
Time to take a look at the actions associated to the items that can be picked up:
The shield is passable and plays its "idle" animation until the player comes closer than 50 quants to pick it up. When this happens, player.items is increased with shield (1) and the shield is removed. All the other actions are similar so I'll let you look at them:
Ready for the final action? We are talking about player_moves, the action associated to the player:
action player_moves // attached to the player
The player starts the game without any item and some values for armour, attack and strength.
The camera is placed 200 quants behind the player and above the player, looking down at it.
my.pan += 4 * (key_a - key_d) * time - 20 * mouse_force.x * time;
The player can rotate using the keys "A" and "D" or the mouse; it can move forward / back with the keys "W" and "S"
if ((key_w + key_s) != 0)
If the player is walking, the model will play its "walk" animation; the animation will be reversed if the player moves backwards.
If the left mouse button (LMB) isn't pressed, the player is standing so the model will play its "stand" animation.
else // the player has pressed the left mouse button
If LMB is pressed and the ring of fire was used and the mouse pointer is invisible and number_of_flames = 0, the model will play its "attack" animation frames once and then it will freeze at the last frame until we release the LMB.
move_mode = ignore_passable;
Ok, but I would like to kill my enemies using the ring of fire! How can I do that?