Delphi Graphics and Game Programming Exposed! with DirectX For versions 5.0-7.0:Artificial Intelligence Techniques
Search Tips
Advanced Search
Title
Author
Publisher
ISBN
Please Select
-----------
Artificial Intel
Business & Mgmt
Components
Content Mgmt
Certification
Databases
Enterprise Mgmt
Fun/Games
Groupware
Hardware
IBM Redbooks
Intranet Dev
Middleware
Multimedia
Networks
OS
Productivity Apps
Programming Langs
Security
Soft Engineering
UI
Web Services
Webmaster
Y2K
-----------
New Arrivals
Delphi Graphics and Game Programming Exposed with DirectX 7.0
by John Ayres
Wordware Publishing, Inc.
ISBN: 1556226373 Pub Date: 12/01/99
Search this book:
Previous
Table of Contents
Next
Modeling aggression is simple enough. The application simply examines the horizontal and vertical position of the enemy unit and the player unit, and adjusts the enemy units horizontal and vertical positions to bring it close to the player. For example, if the player units horizontal position is less than the enemys, subtracting 1 from the enemys horizontal position brings it closer to the player. If the players horizontal position is greater than the enemys, adding 1 to the enemys horizontal position brings it closer to the player. The same holds true for the vertical position. This is illustrated below.
Figure 121: Chasing the player
Modeling evasion is just as simple. Indeed, if we simply reverse the signs of the values being added to the horizontal and vertical position of the enemy, it will run from the player instead of chasing after it. This is illustrated below.
Figure 122: Evading the player
Of course, most games would need to take into account obstacles and line of sight, but the basic principle holds true. The following example illustrates how to implement chase and evasion algorithms. The players dot is controlled by the cursor keys, and the enemy dot will either chase or flee from the user based on its current status, which is toggled by the Enter key.
Listing 122: Aggression and evasion in action
type
.
.
.
TSprite = class
XPos, YPos: Integer;
procedure MoveSprite(XOffset, YOffset: Integer);
end;
var
.
.
.
Enemy, Player: TSprite;
Chase: Boolean;
implementation
.
.
.
procedure TfrmDXAppMain.FormActivate(Sender: TObject);
begin
.
.
.
{create the two sprites}
Enemy := TSprite.Create;
Player := TSprite.Create;
{initialize the enemy and player sprite positions}
Enemy.XPos := 320;
Enemy.YPos := 0;
Player.XPos := 320;
Player.YPos := 477;
{start out in aggression/chase mode}
Chase := TRUE;
.
.
.
end;
.
.
.
procedure TfrmDXAppMain.DrawSurfaces;
var
SrfcDc: HDC;
TempCanvas: TCanvas;
EnemyOffset: Integer;
begin
{erase the last frame of animation}
ColorFill(FBackBuffer, clBlack, nil);
{if the Enter key was pressed, toggle aggression/evasion}
if (GetAsyncKeyState(VK_RETURN) and $8000) = $8000 then
Chase := not Chase;
{move the player sprite based on the cursor keys}
if (GetAsyncKeyState(VK_LEFT) and $8000) = $8000 then
Player.MoveSprite(2, 0);
if (GetAsyncKeyState(VK_RIGHT) and $8000) = $8000 then
Player.MoveSprite(2, 0);
if (GetAsyncKeyState(VK_UP) and $8000) = $8000 then
Player.MoveSprite(0, 2);
if (GetAsyncKeyState(VK_DOWN) and $8000) = $8000 then
Player.MoveSprite(0, 2);
{determine the appropriate movement for chasing or evading}
if Chase then
EnemyOffset := 1
else
EnemyOffset := 1;
{move the enemy accordingly}
if Player.XPos > Enemy.XPos then
Enemy.MoveSprite(EnemyOffset, 0);
if Player.XPos < Enemy.XPos then
Enemy.MoveSprite(EnemyOffset, 0);
if Player.YPos > Enemy.YPos then
Enemy.MoveSprite(0, EnemyOffset);
if Player.YPos < Enemy.YPos then
Enemy.MoveSprite(0, EnemyOffset);
{retrieve a device context and create a canvas}
FBackBuffer.GetDC(SrfcDc);
TempCanvas := TCanvas.Create;
try
{set up the canvas}
TempCanvas.Handle := SrfcDc;
TempCanvas.Font.Color := clWhite;
{draw the two sprites as small dots}
TempCanvas.Pen.Style := psClear;
TempCanvas.Brush.Style := bsSolid;
TempCanvas.Brush.Color := clBlue;
TempCanvas.Ellipse(Player.XPos, Player.YPos, Player.XPos+3, Player.YPos+3);
TempCanvas.Brush.Color := clRed;
TempCanvas.Ellipse(Enemy.XPos, Enemy.YPos, Enemy.XPos+3, Enemy.YPos+3);
{indicate which state the enemy sprite is in}
TempCanvas.Brush.Style := bsClear;
if Chase then
TempCanvas.TextOut(0, 0, Chasing)
else
TempCanvas.TextOut(0, 0, Evading);
TempCanvas.TextOut(0, 440, Press Enter to toggle state);
finally
{clean up}
TempCanvas.Handle := 0;
FBackBuffer.ReleaseDC(SrfcDc);
TempCanvas.Free;
end;
end;
procedure TSprite.MoveSprite(XOffset, YOffset: Integer);
begin
{update the sprites position}
XPos := XPos + XOffset;
YPos := YPos + YOffset;
{clip to the screen boundaries}
if XPos < 0 then
XPos := 0;
if XPos > DXWIDTH 1 then
XPos := DXWIDTH 1;
if YPos < 0 then
YPos := 0;
if YPos > DXHEIGHT 1 then
YPos := DXHEIGHT 1;
end;
We could have just as easily made the chase/evade decision based upon whether or not the player was actively moving. If the players sprite positioned has changed, we could have switched to evade mode; if the player hadnt moved, we could go right to chase mode. This would certainly keep players on their toes, and in the event our enemy units could kill a player, this would certainly discourage anyone from waiting around somewhere for very long!
Patterned Movement
Chasing the player, running from the player, and moving around randomly can get pretty boring after a while. Typically, enemy units need to exhibit more complex movement, and one way to simulate this is through movement patterns.
For example, take the old arcade game Galaxian. When the enemies appeared in each round, they flew onto the screen in a complex flight path. Although their movements were a bit predictable, it made their appearance more menacing and deliberate. We can use patterned movement in our games to model similar complex, deliberate movements and make our enemies appear to move about more intentionally. Indeed, we could create several patterns and choose one randomly (or in a more contextsensitive manner), as illustrated in Figure 123.
Figure 123: Movement patterns
There are several methods by which patterned movement can be implemented based on the type of game and the sprite engine. If we had a simple, 2D shooter, our patterns could simply be based off of a series of horizontal and vertical offsets that move the unit in the desired manner. These offsets would be relative to the current position of the sprite, so the patterns could be used anywhere within the game world.
Tip: It is relatively easy to flip the movement pattern horizontally or vertically, thus increasing the flexibility of this technique.
To implement this method of patterned movement, we could make an array of TPoints, filling each entry with the horizontal or vertical offset for that position within the pattern. As we move the sprite, we keep track of an index into this array of offsets, incrementing the offset at a preset time to advance to the next movement within the pattern. Once the pattern is complete, we can choose another array (or another row within a multidimensional array) and reset the index to 0, thus starting a new pattern. This technique is illustrated below.
Listing 123: Implementing patterned movement
TSprite = record
XPos, YPos: Integer;
CurPattern,
CurPatternIdx: Integer;
PatternIdxChange,
CurTimer: Longint;
end;
TPatterns = array[0..5, 0..31] of TPoint;
const
{in this example, the patterns are stored as direct X and Y offsets, but
any method of specifying a direction and/or offset will do}
Patterns: TPatterns = (
((x: 1; y: 0), (x: 1; y: 0), (x: 1; y: 0), (x: 0; y: 1), (x: 0; y: 1), ...
((x: 1; y: 1), (x: 1; y: 1), (x: 1; y: 1), (x: 1; y: 1), ...
((x: 1; y: 0), (x: 1; y: 0), (x: 1; y: 1), (x: 1; y: 1), (x: 0; y: 1), ...
((x: 1; y: 0), (x: 1; y: 0), (x: 1; y: 0), (x: 1; y: 0), (x: 0; y: 1), ...
((x: 1; y: 0), (x: 1; y: 0), (x: 1; y: 0), (x: 1; y: 1), (x: 0; y: 1), ...
((x: 0; y: 1), (x: 0; y: 1), (x: 0; y: 1), (x: 0; y: 1), ...
var
.
.
.
Enemy: TSprite;
implementation
.
.
.
procedure TfrmDXAppMain.FormActivate(Sender: TObject);
begin
.
.
.
{initialize the enemy sprite}
Randomize;
Enemy.XPos := 320;
Enemy.YPos := 240;
Enemy.CurPattern := Random(6); // start at a random pattern
Enemy.CurPatternIdx := 0;
Enemy.PatternIdxChange := 100; // change the pattern index often
Enemy.CurTimer := timeGetTime;
.
.
.
end;
.
.
.
procedure TfrmDXAppMain.DrawSurfaces;
var
SrfcDc: HDC;
TempCanvas: TCanvas;
begin
{erase the last frame of animation}
ColorFill(FBackBuffer, clBlack, nil);
{if it is time to change the pattern index...}
if timeGetTime Enemy.CurTimer > Enemy.PatternIdxChange then
begin
{...move to the next step in the pattern}
Enemy.CurPatternIdx := Enemy.CurPatternIdx + 1;
{if we have moved the entire pattern...}
if Enemy.CurPatternIdx > 31 then
begin
{...choose a new pattern}
Enemy.CurPattern := Random(6);
Enemy.CurPatternIdx := 0;
end;
{track for the next pattern index change}
Enemy.CurTimer := timeGetTime;
end;
{update the enemy sprites position based on the current step with
the pattern}
Enemy.XPos := Enemy.XPos + Patterns[Enemy.CurPattern, Enemy.CurPatternIdx].X;
Enemy.YPos := Enemy.YPos + Patterns[Enemy.CurPattern, Enemy.CurPatternIdx].Y;
{clip the enemy to the screen boundaries}
if Enemy.XPos < 0 then
Enemy.XPos := 0;
if Enemy.XPos > DXWIDTH 1 then
Enemy.XPos := DXWIDTH 1;
if Enemy.YPos < 0 then
Enemy.YPos := 0;
if Enemy.YPos > DXHEIGHT 1 then
Enemy.YPos := DXHEIGHT 1;
{retrieve a device context and create a canvas}
FBackBuffer.GetDC(SrfcDc);
TempCanvas := TCanvas.Create;
try
{set up the canvas}
TempCanvas.Handle := SrfcDc;
TempCanvas.Font.Color := clWhite;
{draw the enemy sprite}
TempCanvas.Pen.Style := psClear;
TempCanvas.Brush.Style := bsSolid;
TempCanvas.Brush.Color := clRed;
TempCanvas.Ellipse(Enemy.XPos, Enemy.YPos, Enemy.XPos + 3, Enemy.YPos + 3);
{indicate the pattern number}
TempCanvas.Brush.Style := bsClear;
TempCanvas.TextOut(0, 0, Pattern: +IntToStr(Enemy.CurPattern));
finally
{clean up}
TempCanvas.Handle := 0;
FBackBuffer.ReleaseDC(SrfcDc);
TempCanvas.Free;
end;
end;
Previous
Table of Contents
Next
Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.
Wyszukiwarka
Podobne podstrony:
Kopia pliku Medycyna ratunkowa 12 02 14 r Arkusz1BEKO chassis 12 7 0211 12 02 wyklad algebraWyniki egzaminu z Chemii (12 02 06)12 022012 12 0212 02Ruszyła kampania wyborcza (12 02 2010)TI 99 12 02 T B M pl(2)więcej podobnych podstron