Friday, October 8, 2010

Putting all together into something easy

In BB.Game there are two classes, TGame and his child T2dGame, they try to put help in the creation of a game (very much like XNA), let's see the skeleton:


TGame = class abstract(TComponentEx, IRegistrator, IGame)
public
    constructor Create; override;
    destructor Destroy; override;
    procedure Save(const aFileName: string); virtual;
    procedure Load(const aFileName: string); virtual;
    procedure Clear; override;
    procedure Run(aForm: TForm);
    procedure Pause; virtual;
    procedure Resume; virtual;
    procedure Stop; virtual;
    function CreateMP3: ISound;
    function CreateModule: ISound;
    //IRegistrator
    function AsObject: TObject;
    procedure RegisterObject(aObject: IPersistent); virtual;
    procedure UnregisterObject(aObject: IPersistent); virtual;

    property Persistent: TInterfaceList read FPersistent;
    property Input: TInput read FInput;
    property GraphicsInfo: IGraphicInfo read GetInfo;
    property Paused: boolean read GetPaused;
    property Path: string read GetPath;
    property Primitives: IPrimitives read GetPrimitives;
    property Form: TForm read FForm;
    property BPP: cardinal read GetBPP;
    property CurrentFPS: cardinal read GetCurrentFPS;
  published
    property Width: integer read FWidth write FWidth default 640;
    property Height: integer read FHeight write FHeight default 480;
    property InputDevices: TInputDevices read FInputs write FInputs;
    property State: TGameState read FGameState write FGameState;
    property ScreenFlags: TScreenFlags read FScreenFlags write FScreenFlags;
    property Provider: TGraphicsProvider read FProvider write FProvider default gpD3D;
  end;
Creating a custom game is a matter of override a few methods
TMyGame = class(TGame)
protected
    procedure Update(aEllapsedTime: Int64); override;
    procedure Draw(aEllapsedTime: Int64); override;
    procedure Initialize; override;
end;
Implementation
procedure TMyGame.Draw(aEllapsedTime: Int64);
var
  i: integer;

begin
  inherited;

  Primitives.Rectangle(0, 0, CurrentFPS, 16, TRGB.Red);
  Primitives.Rectangle(Input.Mouse.X, Input.Mouse.Y, Input.Mouse.X + 10, Input.Mouse.Y + 10, TRGB.White);
end;
procedure TMyGame.Initialize;
begin
  inherited;

  InputDevices := [idMouse, idKeyboard];

  Engines.Add;
  Engines[0].FileNames.Add('sprites\astuteroto.bmp');
  Engines[0].FileNames.Add('sprites\arthur.bmp');
  Engines[0].LoadFile;

  FBoss := TAnimationSprite.Create;
  FBoss.Engine := Engines[0];
  FBoss.AnimationName := 'walk';
  FBoss.GoCenterX;
  FBoss.Bottom := 400;
  FBoss.KillOnTimeOut := False;
  FBoss.CollisionShape := csAuto;
  FBoss.CollisionAccuracy := caMax;


  FArthur := TAnimationSprite.Create;
  FArthur.Engine := Engines[0];
  FArthur.AnimationName := 'arthur_walk';
  FArthur.X := 50;
  FArthur.Bottom := 400;
  FArthur.CollisionShape := csAuto;
  FArthur.CollisionAccuracy := caMax;

  FCurrentL := nil;
  FCurrentR := nil;
  FOfsX := 0;
  FOfsY := 0;
end

procedure TMyGame.Update(aEllapsedTime: Int64);
var
  spr: ISprite;

begin
  inherited;

  spr := Engines[0].SpriteAt(input.Mouse.X, input.Mouse.Y);
  if spr <> nil then
  begin
    FCurrent := TSprite(spr);

    //Left
    if input.Mouse.ButtonL = bsDown then
    begin
      FCurrentL := FCurrent;
      FOfsX := Trunc(FCurrentL.X) - input.Mouse.X;
      FOfsY := Trunc(FCurrentL.Y) - input.Mouse.Y;
    end;

    //Right
    if input.Mouse.ButtonR = bsDown then
      FCurrentR := FCurrent;

    if input.Mouse.Z > 0 then
      FCurrent.Zoom := FCurrent.Zoom + 5
    else
      if input.Mouse.Z < 0 then
        FCurrent.Zoom := FCurrent.Zoom - 5;
  end;

  //Right
  if (input.Mouse.ButtonR = bsUp) and (FCurrentR <> nil) then
  begin
    FCurrentR.FlipX := not FCurrentR.FlipX;
    FCurrentR := nil;
  end;

  //Left
  if (input.Mouse.ButtonL = bsUp) and (FCurrentL <> nil) then
    FCurrentL := nil;

  if FCurrentL <> nil then
  begin
    FCurrentL.X := input.Mouse.X + FOfsX;
    FCurrentL.Y := input.Mouse.Y + FOfsY;
  end;

  if FBoss.AnimationName = 'stop' then
  begin
    FBoss.HorizontalSpeed := 0;
    if FBoss.IsAnimationFinish then
      FBoss.AnimationName := 'walk';
  end else
    if Random(10) = 1 then
      FBoss.HorizontalSpeed := (-1 + Random(3)) / 2;

  if random(250) = 1 then
    BossFires;

  if Input.Keyboard[DIK_1] then
    FArthur.CoordinateOrigin := coTopLeft;

  if Input.Keyboard[DIK_2] then
    FArthur.CoordinateOrigin := coCenter;

  if Input.Keyboard[DIK_3] then
    FArthur.CoordinateOrigin := coBottomRight;

  if Input.Keyboard[DIK_ESCAPE] then
    Stop;
end;
Put the following code into the main form:
procedure TfrmMain.FormActivate(Sender: TObject);
var
  g: TMyGame;

begin
  g := TMyGame.Create;
  try
    g.Provider := gpD3d{gpDirectDraw};
    g.Run(self);
  finally
    g.Free;
  end;

  Close;
end

And voila! (no need to create engines, music, sound, inputs, etc)

No comments:

Post a Comment