Tuesday, October 19, 2010

Another game example

This is another example creating a three layer space game with a few lines of code:


unit Game;

interface

uses
  BB.Screen, BB.Screen.Sprites, BB.Input, BB.Screen.Engines, BB.Game, 
BB.Screen.Interfaces, BB.Screen.Types, BB.Colors, BB.Sound;

type
  TWave = class(T2DGame)
  private
    FBack1,
    FBack2,
    FBack3: TBackground;
    FShip: TAnimationSprite;
    FExplosion: ISound;

    procedure HandleShip;
    procedure HandleEnemies;
    procedure Fire;
  protected
    procedure Update(aEllapsedTime: Int64); override;
    procedure Draw(aEllapsedTime: Int64); override;
    procedure Initialize; override;
    procedure Uninitialize; override;
  end;

  TGameSprite = class(TAnimationSprite)
  protected
    function Game: IGame;
  end;

  TEnemy1 = class(TGameSprite)
  end;

  TShoot = class(TGameSprite)
  public
    function Render: integer; override;
  end;

  THero = class(TGameSprite)
  public
    function Render: integer; override;
  end;

implementation

{ TShoot }

function TShoot.Render: integer;
var
  i, x, y: integer;
  explosion: TGameSprite;
  Enemy1: ISprite;

begin
  result := inherited Render;

  for i := 0 to Engine.Count - 1 do
  begin
    enemy1 := Engine[i];
    if (enemy1 is TEnemy1) and (Collision(enemy1, x, y)) then
    begin
      Game.CreateThreadedSound('explosion').Run;

      explosion := TGameSprite.Create;
      explosion.Engine := Engine;
      explosion.AnimationName := 'explosion';
      explosion.CenterFrom(TSimpleSprite(Enemy1));

      Die;
      Enemy1.Die;
    end;
  end;
end;

{ THero }

function THero.Render: integer;
var
  enemy1: ISprite;
  x, y, i: integer;
  explosion: TGameSprite;

begin
  result := inherited;

  for i := 0 to Engine.Count - 1 do
  begin
    enemy1 := Engine[i];
    if (enemy1 is TEnemy1) and (Collision(enemy1, x, y)) then
    begin
      Game.CreateThreadedSound('explosion').Run;

      explosion := TGameSprite.Create;
      explosion.Engine := Engine;
      explosion.AnimationName := 'explosion';
      explosion.CenterFrom(TSimpleSprite(Enemy1));

      Enemy1.Die;
    end;
  end;
end;

{ TWave }

procedure TWave.Draw(aEllapsedTime: Int64);
begin
  FBack3.Render;
  FBack2.Render;
  FBack1.Render;

  inherited;
end;

procedure TWave.HandleEnemies;
const
  ENEMY1_SPEED = 3;
  ENEMY1_ALIVE = 2;

var
  enemy1: TAnimationSprite;
  i: integer;

begin
  if Random(100) = 73 then
  begin
    for i := 1 to 10 do
    begin
      enemy1 := TEnemy1.Create;
      enemy1.Engine := Engines[0];
      enemy1.AnimationName := 'enemy1';
      enemy1.VerticalSpeed := ENEMY1_SPEED;
      enemy1.X := GraphicsInfo.GetWidth div 10 * i;
      enemy1.Y := -enemy1.Height;
      enemy1.TimeOut := GraphicsInfo.GetMaxFPS * ENEMY1_ALIVE;
      enemy1.CollisionShape := csAuto;

      if Random(2) = 1 then
        enemy1.AngleSpeed := 0.5
      else
        enemy1.AngleSpeed := -0.5;
    end;
  end;
end;

procedure TWave.HandleShip;
const
  SHIP_SPEED = 2; //Seconds

begin
  FShip.AnimationName := 'main';

  if Input.Keyboard[DIK_LEFT] then
  begin
    FShip.AnimationName := 'main_left';
    FShip.MoveLeft(SHIP_SPEED, True);
  end;

  if Input.Keyboard[DIK_RIGHT] then
  begin
    FShip.AnimationName := 'main_right';
    FShip.MoveRight(SHIP_SPEED, True);
  end;

  if Input.Keyboard[DIK_UP] then
    FShip.MoveUp(SHIP_SPEED, True);

  if Input.Keyboard[DIK_DOWN] then
    FShip.MoveDown(SHIP_SPEED, True);

  if (Input.Keyboard[DIK_Z]) and (GraphicsInfo.GetTotalFrames mod 7 = 0) then
    Fire;

  if Input.Keyboard[DIK_ESCAPE] then
    Stop;
end;

procedure TWave.Initialize;
begin
  inherited;

  InputDevices := [idKeyboard];

  GraphicsInfo.SetMaxFPS(100);
  GraphicsInfo.SetScreenFlags([]);

  Engines.Add;
  Engines[0].FileNames.Add('ship.bmp');
  Engines[0].FileNames.Add('shoot.bmp');
  Engines[0].FileNames.Add('enemy1.bmp');
  Engines[0].FileNames.Add('explosion.bmp');
  Engines[0].LoadFile;

  FBack1 := TBackground.Create;
  FBack1.FileName := 'layer1.bmp';
  FBack1.LoadFile(TRGB.Create(255, 0, 255).ToInt(32));
  FBack1.Zoom := Round(GraphicsInfo.GetWidth / FBack1.Width * 100);
  FBack1.Seamless := True;
  FBack1.Filter := sfPoint;

  FBack2 := TBackground.Create;
  FBack2.FileName := 'layer2.bmp';
  FBack2.LoadFile(TRGB.Create(255, 0, 255).ToInt(32));
  FBack2.Zoom := Round(GraphicsInfo.GetWidth / FBack2.Width * 100);
  FBack2.Seamless := True;
  FBack2.Filter := sfPoint;

  FBack3 := TBackground.Create;
  FBack3.FileName := 'layer3.bmp';
  FBack3.LoadFile(TRGB.Create(255, 0, 255).ToInt(32));
  FBack3.Zoom := Round(GraphicsInfo.GetWidth / FBack3.Width * 100);
  FBack3.Seamless := True;
  FBack3.Filter := sfPoint;

  FShip := THero.Create;
  FShip.Engine := Engines[0];
  FShip.AnimationName := 'main';
  FShip.GoCenterX;
  FShip.Y := GraphicsInfo.GetHeight - FShip.Height;
  FShip.CollisionShape := csAuto;
  FShip.Registrator := self;

  FExplosion := LoadSound('explosion');
end;

procedure TWave.Uninitialize;
begin
  FBack1.Free;
  FBack2.Free;
  FBack3.Free;

  inherited;
end;

procedure TWave.Fire;
const
  SHOOT_SPEED = 4;
  SHOOT_ALIVE = 2;

var
  shoot: TAnimationSprite;

begin
  shoot := TShoot.Create;
  shoot.Engine := Engines[0];
  shoot.AnimationName := 'shoot';
  shoot.VerticalSpeed := -SHOOT_SPEED;
  shoot.X := FShip.X;
  shoot.Y := FShip.Y;
  shoot.TimeOut := GraphicsInfo.GetMaxFPS * SHOOT_ALIVE;
  shoot.Registrator := self;

  shoot := TShoot.Create;
  shoot.Engine := Engines[0];
  shoot.AnimationName := 'shoot';
  shoot.VerticalSpeed := -SHOOT_SPEED;
  shoot.X := FShip.Right - shoot.Width;
  shoot.Y := FShip.Y;
  shoot.TimeOut := GraphicsInfo.GetMaxFPS * SHOOT_ALIVE;
  shoot.Registrator := self;
end;

procedure TWave.Update(aEllapsedTime: Int64);
begin
  inherited;

  HandleShip;
  HandleEnemies;

  FBack3.MoveDown(2);
  FBack2.MoveDown(1);
  FBack1.MoveDown(0.5);
end;

{ TGameSprite }

function TGameSprite.Game: IGame;
begin
  result := TWave(Registrator.AsObject);
end;

end.
The overview is:
  • Loading the necessary stuff in Initialize()
  • Draw the backgrounds in Draw(), the bitmaps are automatically draw via Engine class
  • Handling the logic in Update()
    • Move ship (using the keyboard)
    • Move enemies
    • Move background
  • Unloading all suff in Uninitialize()
    
    

    No comments:

    Post a Comment