Aliens, Objects and Things
========================================================================
Just4Fun Productions presents:
Part 2 of: the Techtutor
(Topics never covered)
Aliens, Objects and Things
========================================================================
Introduction
Aliens, now here's a challenge. Every alien/enemy or object can have its own AI code, so I'm not explaining how to make them move, or animate, I will just explain procedures or functions to create them and use them. For a small, but not complete example, look at TECH02.PAS. In this text I mainly talk about aliens, but objects and bonus things should be seen as static aliens (or maybe moving, but at least they can use the same kind of code).
----------------------------------------------------------------
For contacting Just4Fun or me (PeeBee) use the following ways:
Internet : http://people.zeelandnet.nl/rpb
Email : just4fun@zeelandnet.nl
SnailMail: P.Bestebroer
Anthony Edenlaan 28
4463 JC Goes (Zld.)
Holland
ICQ : 2309110 (probably fastest way to contact me)
----------------------------------------------------------------
OOP s?
I program my aliens by using Object Oriented Programming. This is something I'm not going to explain here since it's not that easy to understand, or to explain. Just buy a good book about OOP and read it carefully.
Some people might think that OOP can not really be used for games but that's where they are wrong. OOP let's you create a base-alien object, and then you can simply add new aliens by creating objects based on the "base-alien". The "base-alien" should only have things like drawing it, collision-detections, initialisation for bullets, player-collision checking and a few other things. Since most alien-types will act different, you can easily create a new object-type for a certain allien. That object will then incorporate the movement, AI, animation and other SPECIFIC things about that alien type. Let's use an example.
Most people favourite game is QUAKE, Quake has a lot of different monsters, but they don't all "act" the same way. Let's see what we could do as a BASE-ALIEN object, and then I'll gave an example.
Collision Detection
All aliens, will need to be stopped when walking against a wall. Now you'r game could have "ghost" aliens which are able to walk thru a wall, in that case you'll just write 1 extra collision routine specific for the "ghost" type aliens. But all other aliens can simply use the Base_Alien collision detections
Searching
All aliens will have to "SEE" if the player is in their sight. This procedure is the same for all aliens, so it can be put inside the Base_Alien. Just take a look at the enemies in Quake. If you sneak from behind every type will just be walking a certain path. This is the Base_Alien's routine which can be called from all alien-types.
Falling, Jumping, Diving
Most aliens will fall if there's no ground below them. So the "Gravity" procedures should be put in the Base_Alien. Note, however, that not all aliens will "walk" some might be flying in which case you won't have to call the procedure. There are a lot more procedures which can be put into the Base_Alien, but it depends on you'r game. As you might have noticed the Base_Alien contains a lot of procedures that have to do with "game-physics" (ie. falling, looking, colliding ) that's exactly what should be in the Base_Alien! the physic-laws of you'r game-environment.
What's left for the other objects?
Well the alien-specific object will include things like:
- Shooting
- Animating (but this could be done in the Base_Alien as well)
- Thinking (only if you use multiple AI's )
and a lot of other things which you need for only a few aliens..
{=-=-= Example =-=-=}
TYPE Pactor = ^Tactor; { this is the Base_Alien code }
Tactor = object
Xposition,
Yposition : integer; { Xposition and Yposition }
Xstart,Ystart: integer; { X+Y start positions }
Xspeed,
Yspeed : real; { Xspeed and Yspeed }
xdir,ydir : shortint; { direction of movement }
AI : byte; { AI state }
energy : byte; { energy of the alien }
ID : byte; { alien number }
killed : boolean; { if actor is out of loop }
I_frame,
f_Frame, { Animation frame data }
a_Frame,
c_frame,
t_frame,
s_Frame : byte;
n_frame : shortint;
cycle : boolean;
CONSTRUCTOR INIT(xp,yp:integer); { initialisation of alien }
PROCEDURE sub_init; Virtual; { for some extra init }
PROCEDURE animate; Virtual; { animate the images }
FUNCTION see_if_hit:boolean; Virtual; { see if hit by bullet }
FUNCTION PLAYER_HIT:boolean; Virtual; { see if hitting the player}
PROCEDURE putit; Virtual; { draw the alien }
PROCEDURE movement; Virtual; { moving the alien }
PROCEDURE acting; Virtual; { the AI procedure }
DESTRUCTOR DONE; { For erasing alien }
END;
{=-=-= Extra objects could look like this: =-=-=-=}
TYPE Psoldier = ^Tsoldier; { A ground-walker (ie. soldier) }
Tsoldier = object(TACTOR) { is based on the Base_Actor }
PROCEDURE SUB_INIT; Virtual; { For specific initialisations }
PROCEDURE Acting; VIRTUAL; { For the AI of the soldiers }
END;
{=-=-= End of Example =-=-=}
How to set it up
Just like bullets, you could also use a linked-list for the aliens but I usually just use an array of pointers. You'll first need a procedure which will create a new alien by specifying which alien-type you need. This could look something like this:
{=-=-= Example =-=-=-=}
FUNCTION AddActor(ai:byte;xp,yp:integer):Pactor;
BEGIN
Addactor:=NIL;
case ai of
1 : addActor:=new(PGroundWalker,init(xp,yp)); { first alien type }
2 : addActor:=new(PFlying,init(xp,yp)); { second alien type }
{ ... }
end;
END;
{=-=-= End of Example =-=-=-=}
To process the aliens, you'll simply make a procedure that will go thru the list, and call the "main_acting" procedure of the alientype.
{=-=-= Example =-=-=-=}
PROCEDURE DoActors;
VAR i : word;
BEGIN
if actor_a=0 then exit; { no actors to process }
i:=1; { start with first actor }
while i<actor_a+1 do begin
with act[i]^ do begin
if not KILLED then begin { if alien still lives, }
Acting; { make it act (moving, shooting, etc...) }
PutIt; { and draw it. }
end;
end;
inc(i); { go to next actor in the array }
end;
END;
{=-=-= End of Example =-=-=-=}
The "Main_Acting" procedure will handle the things like:
- Movement, usually a procedure in the Base_alien object
- Collision checking on walls, player(s), and other aliens.
- and the alien-specific procedures and AI.
Examples?
As I said at the beginning of this text, I won't go into procedure details for creating AI routines, there are other tutors and documents for that..
if you want to see some good AI routines, just take a look at Quake-C source codes, maybe you learn a few nice tricks from that...
I hope you learned something, and keep coding!
Next Tech topic: HighScores
PeeBee - September 10th '97
tech02.pas
{
TechTutor2
Alien code, a simple (not working) example.
Coding by P.Bestebroer
FreeWare
This source will not work on it's own, it just shows how to
do alien-code into you'r game...
The source code was ripped from one of my game-projects, but
because of this little tech-info I extruded variables wich where
needed in my game, but are not allways used.
Contacting:
HTTP://people.zeelandnet.nl/rpb/
EMAIL:just4fun@zeelandnet.nl
}
PROGRAM Tech02;
USES CRT,OBJECTS;
{-----------------------------------------------------------------------------}
{
First create the BASE_ALIEN variables
}
TYPE Pactor = ^Tactor; { this is the Base_Alien code }
Tactor = object
Xposition,
Yposition : integer; { Xposition and Yposition }
Xstart,Ystart: integer; { X+Y start positions }
Xspeed,
Yspeed : real; { Xspeed and Yspeed }
xdir,ydir : shortint; { direction of movement }
AI : byte; { AI state }
energy : byte; { energy of the alien }
ID : byte; { alien number }
killed : boolean; { if actor is out of loop }
I_frame,
f_Frame, { Animation frame data }
a_Frame,
c_frame,
t_frame,
s_Frame : byte;
n_frame : shortint;
cycle : boolean;
CONSTRUCTOR INIT(xp,yp:integer); { initialisation of alien }
PROCEDURE sub_init; Virtual; { for some extra init }
PROCEDURE animate; Virtual; { animate the images }
FUNCTION see_if_hit:boolean; Virtual; { see if hit by bullet }
FUNCTION PLAYER_HIT:boolean; Virtual; { see if hitting the player}
PROCEDURE putit; Virtual; { draw the alien }
PROCEDURE movement; Virtual; { moving the alien }
PROCEDURE acting; Virtual; { the AI procedure }
DESTRUCTOR DONE; { For erasing alien }
END;
{=-=-=-=-= Now create the Specific_Alien variables =-=-=-=-=}
TYPE PGroundWalker = ^TGroundWalker; { A ground-walker (ie. soldier) }
TGroundWalker = object(TACTOR) { is based on the Base_Actor }
PROCEDURE SUB_INIT; Virtual; { For extra variables initialisation }
PROCEDURE Acting; VIRTUAL; { For the AI of the Ground-Walkers }
END;
PFlying = ^TFlying; { A flying enemie }
TFlying = object(TACTOR) { is based on the Base_Actor }
PROCEDURE SUB_INIT; Virtual; { for extra variables initialisation }
PROCEDURE Acting; VIRTUAL; { for the AI of the Ground-Walkers }
end;
VAR act : array[0..255] of Pactor; { array of the actors }
actor_a : byte; { amount of actors in game }
{----------------------------------------------------------------------------}
{
These are the procedures wich could be used....
}
CONSTRUCTOR TACTOR.Init(xp,yp:integer); { to initialise an alien }
BEGIN
{
Set the position variables,
the energy, the default values (ie. Killed=False)
}
END;
PROCEDURE TACTOR.SUB_INIT; { this is replaced by the specific_alien code }
BEGIN
ABSTRACT;
END;
PROCEDURE TACTOR.ANIMATE; { For the image-animations }
BEGIN
{
Animate the alien walking, flying, shooting, etc...
}
END;
FUNCTION TACTOR.PLAYER_HIT:boolean; { see if hitting the player }
BEGIN
{
Check on collision between the player and the alien
}
END;
FUNCTION TACTOR.SEE_IF_HIT:boolean; { See if hit by a bullet }
BEGIN
{
Walk thru the bullets, and check on collision with the alien..
if hit set the KILLED flag to TRUE
}
END;
PROCEDURE TACTOR.PUTIT; { Draw the alien on screen }
BEGIN
{
Draw the current frame-image of the alien on screen
}
END;
PROCEDURE TACTOR.MOVEMENT; { This is for the moving of the specific_aliens }
BEGIN
ABSTRACT
END;
PROCEDURE TACTOR.ACTING; { This will handle the AI of the specific_alien }
BEGIN
ABSTRACT;
END;
DESTRUCTOR TACTOR.DONE; { For erasing the alien from memory }
BEGIN
END;
{----------------------------------------------------------------------------}
{ The custom-home-made-do-it-yourself enemy code }
{----------------------------------------------------------------------------}
PROCEDURE TGroundWalker.SUB_INIT;
BEGIN
{
Put the specific initialisation for the GroundWalking enemy
in this little procedure...
}
END;
PROCEDURE TGroundWalker.Acting;
BEGIN
{
Put all code for movement, collision detection and other things in this
procedure...
This is the "core" of the GroundWalking enemy, or call it his
Artificial Intelligence routines
}
END;
{----------------------------------------------------------------------------}
PROCEDURE TFlying.SUB_INIT;
BEGIN
{
Put the specific initialisation for the Flying enemy
in this little procedure...
}
END;
PROCEDURE TFlying.Acting;
BEGIN
{
Put all code for movement, collision detection and other things in this
procedure...
This is the "core" of the Flying enemy, or call it his
Artificial Intelligence routines
}
END;
{----------------------------------------------------------------------------}
{
This code will intialise all the different aliens
Expects : AI Number of the alien and other init variables
Returns : a Pointer to the new TACTOR type
}
FUNCTION AddActor(ai:byte;xp,yp:integer):Pactor;
BEGIN
Addactor:=NIL;
case ai of
1 : addActor:=new(PGroundWalker,init(xp,yp)); { first alien type }
2 : addActor:=new(PFlying,init(xp,yp)); { second alien type }
{ ... }
end;
END;
{----------------------------------------------------------------------------}
{
Process the actor_list
Expects: Nothing
Returns: Nothing
}
PROCEDURE DoActors;
VAR i : word;
BEGIN
if actor_a=0 then exit; { no actors to process }
i:=1; { start with first actor }
while i<actor_a+1 do begin
with act[i]^ do begin
if not KILLED then begin { if alien still lives, }
Acting; { make it act (moving, shooting, etc...) }
PutIt; { and draw it. PUTIT could be cald from within ACTING}
end;
end;
inc(i); { go to next actor in the array }
end;
END;
{----------------------------------------------------------------------------}
BEGIN
while port[$60]<>156 do ;
textcolor(7); textbackground(0); clrscr;
writeln('TechTutor #2');
writeln('written by P.Bestebroer, Just4Fun Productions');
writeln('');
writeln('This examples contains procedures for some great aliens/objects and things');
writeln;
writeln('Just like the previous tutor, this example needs some extra work aswell');
writeln('Although the examples work, they wont display anything on the screen.');
writeln('There are also no real "acting/movement" procedures because that is');
writeln('upto you to implement (the easiest and most fun job!)');
writeln;
writeln('You should use a great VGA unit (SuperFX engine for example ;) and ');
writeln('implement the things like drawing the objects');
writeln;
writeln('Watch out for the other techtutors...');
writeln;
writeln('Press a key');
writeln;
writeln;
writeln;
writeln('----------------------------------');
writeln('Contacting: just4fun@zeelandnet.nl');
writeln('http://people.zeelandnet.nl/rpb ');
writeln('----------------------------------');
repeat until port[$60]<>156;
END.