Изучаем DelphiX (Часть 2)

Материал из DRKB


Изучаем DelphiX. Часть 2: Усложняем нашу игру.[править | править код]

"Хех! загружу:"

Прежде чем начать, объясню решение Д/З:


1. Сделайте так, чтобы при уходе патрона из зоны видимости он уничтожался:[править | править код]

Это очень легко сделать достаточно в процедуру DoMove патрона вставить:

if y <= 0 then Dead;
if y >= 600 then Dead;


Нужно это для того, чтобы повысилось качество игры.


2. Сделайте, чтобы патроны стреляли очередями, а не кучами как у меня:[править | править код]

Вот эта задача была посложнее первой. Во-первых, как я сделал в первой части этого туториала, делать нельзя из-за причины небольшой "кривости" DelphiX, он может держать только определённое количество спрайтов, а если их больше он или выходит или подвисает. Так что, делаем вот так:

В класс с плеером добавляем две переменные, он теперь выглядит так (я добавил комментарии к тем строчкам которые изменились):

  TPlayerSprite = class(TImageSprite)
  private
    LngPolet: Integer;    // расстояние которое пролетела пуля
    OldLngPolet: Integer; // расстояние которое пролетела предыдущая пуля
  protected
    procedure DoMove(MoveCount: Integer); override;
  end;


Процедура DoMove класса PlayerSprite изменяется следующим образом:

procedure TPlayerSprite.DoMove(MoveCount: Integer);
begin
  inherited DoMove(MoveCount);
  if isLeft in Form1.DXInput1.States then x := x-5;
  if isRight in Form1.DXInput1.States then x := x+5;
  if isUp in Form1.DXInput1.States then
  begin
    // Если расстояние между пулями меньше 250, то пуля не создаётся
    if (LngPolet - OldLngPolet) >= 250 then
    begin
      Inc(LngPolet);
      with TPlayerFa.Create(Engine) do
      begin
        PixelCheck := True;
        Image := Form1.dxImageList1.Items.Find('Pula');
        X := Self.X + Self.Width - 40;
        Y := Self.Y + Self.Height - 80;
        Width := Image.Width;
        Height := Image.Height;
      end;
      OldLngPolet := LngPolet; // после создания пули - последняя становится первой
    end;
  end;
  if y >= Form1.DXDraw1.SurfaceHeight - Image.Height then
    y := Form1.DXDraw1.SurfaceHeight - Image.Height;
  if  x >= Form1.DXDraw1.SurfaceWidth - Image.Width  then
    x := Form1.DXDraw1.SurfaceWidth - Image.Width;
  if y <= 0 then
    y := 1;
  if x <= 0 then
    x := 1;
  LngPolet := LngPolet + MoveCount;  // расстояние увеличиваем, когда пуля движется
end;


Вот и всё, что требовалось сделать.

В этой части вы узнаете:

  1. Создание анимации.
  2. Создание примитивного AI.
  3. Создадим простенькие взрывы.


Создание анимации.[править | править код]

Анимация в DelphiX строится следующим образом:

Dx 20532a.jpg


Это пример покадровой анимации. У каждого кадра должен быть одинаковый размер.

В данной ситуации:

  • Ширина: 40
  • Высота: 38

Давайте теперь, применим ее к нашей игре.

Идём в DXImageList, находим наш спрайт Pula и загружаем картинку с анимацией. Далее устанавливаем свойства спрайта следующим образом:

Dx 20532b.jpg


и в процедуре DoMove класса PlayerSprite изменяем код следующим образом:

procedure TPlayerSprite.DoMove(MoveCount: Integer);
begin
  inherited DoMove(MoveCount);
  if isLeft in Form1.DXInput1.States then x := x-5;
  if isRight in Form1.DXInput1.States then x := x+5;
  if isUp in Form1.DXInput1.States then
  begin
    if LngPolet - OldLngPolet >= 250 then
    begin
      Inc(LngPolet);
      with TPlayerFa.Create(Engine) do
      begin
        PixelCheck := True;
        Image := Form1.dxImageList1.Items.Find('Pula');
        X := Self.X + Self.Width - 40;
        Y := Self.Y + Self.Height - 80;
        Width := Image.Width;
        Height := Image.Height;
        AnimCount := Image.PatternCount; // число кадров
        AnimLooped := True;              // повторять ли анимацию
        AnimSpeed := 10 / 1000;          // скорость анимации
      end;
      OldLngPolet := LngPolet;
    end;
  end;
  if y >= Form1.DXDraw1.SurfaceHeight - Image.Height then
    y := Form1.DXDraw1.SurfaceHeight - Image.Height;
  if  x >= Form1.DXDraw1.SurfaceWidth - Image.Width  then
    x := Form1.DXDraw1.SurfaceWidth - Image.Width;
  if y <= 0 then
    y := 1;
  if x <= 0 then
    x := 1;
  LngPolet := LngPolet + MoveCount;
end;


Можно проделать тоже самое с другими классами для придания реалистичности игры.


Cоздание примитивного AI.[править | править код]

Для начала маленько улучшим наш класс плеера, добавим в него столкновение, и он теперь выглядит следующим образом:

TPlayerSprite = class(TImageSprite)
  private
    LngPolet: Integer;
    OldLngPolet: Integer;
  protected
    procedure DoMove(MoveCount: Integer); override;
    // добавляем
    procedure DoCollision(Sprite: TSprite; var Done: Boolean); override;
  end;


Далее создаём процедуру DoCollision и вставляем в неё следующее:

procedure TPlayerSprite.DoCollision(Sprite: TSprite; var Done: Boolean);
begin
  if Sprite is TPlayerFa then Dead;
  Collision;
end;


Дальше пред implementation добавляем 1 переменную:

  plx: double;            // X плеера


Далее обновим класс TPlayerFa и он станет таким:

  TPlayerFa = class(TImageSprite)
  private
    Stril: Integer; // Как вы заметили, добавилась переменная
  protected
    procedure DoCollision(Sprite: TSprite; var Done: Boolean); override;
    procedure DoMove(MoveCount: Integer); override;
   public
    constructor Create(AParent: TSprite); override;
    destructor Destroy; override;
  end;


А в TPlayerFa добавляем строчку:

procedure TPlayerFa.DoMove(MoveCount: Integer);
begin
   y := y - Stril; // когда стреляет игрок, с этой скоростью будет двигаться пуля
   y := y + Stril; // когда стреляет AI, с этой скоростью будет двигаться пуля
   if y <= 0 then Dead;
   if y >= 600 then Dead;
end;


А процедура TBoSS.DoMove становиться такой:

procedure TBoSS.DoMove(MoveCount: Integer);
begin
  inherited DoMove(MoveCount);
  if x >= 600 then I := False;
  if x <= 0 then I := True;
  if i = True then X := X+5;
  if i = False then X := X-5;
  if plx = x then // если равна х плеера стреляем
  begin
    with TPlayerFa.Create(Engine) do
    begin
      PixelCheck := True;
      Image := Form1.dxImageList1.Items.Find('Pula');
      X := Self.X + Self.Width - 70;
      Y := Self.Y + Self.Height + 10;
      Width := Image.Width;
      Height := Image.Height;
      Stril := 5;        // скорость патрона
    end;
  end;
  Collision;
end;


И естественно полнеет и TPlayerSprite:

procedure TPlayerSprite.DoMove(MoveCount: Integer);
begin
  inherited DoMove(MoveCount);
  plx := x;            // чтобы наш комп видел нашего плеера
  if isLeft in Form1.DXInput1.States then
  begin
    x := x-5;
    plx := x;
  end;
  if isRight in Form1.DXInput1.States then
  begin
    x := x+5;
    plx := x;
  end;
  if isUp in Form1.DXInput1.States then
  begin
    if LngPolet - OldLngPolet >= 250 then
    begin
      Inc(LngPolet);
      with TPlayerFa.Create(Engine) do
      begin
        PixelCheck := True;
        Image := Form1.dxImageList1.Items.Find('Pula');
        X := Self.X + Self.Width - 40;
        Y := Self.Y + Self.Height - 80;
        Width := Image.Width;
        Height := Image.Height;
        Stril := -4;
      end;
      OldLngPolet := LngPolet;
    end;
  end;
  if y >= Form1.DXDraw1.SurfaceHeight - Image.Height then
    y := Form1.DXDraw1.SurfaceHeight - Image.Height;
  if  x >= Form1.DXDraw1.SurfaceWidth - Image.Width  then
    x := Form1.DXDraw1.SurfaceWidth - Image.Width;
  if y <= 0 then
    y := 1;
  if x <= 0 then
    x := 1;
  LngPolet := LngPolet + MoveCount;
  Collision;
end;


И поменялся конструктор PlayerFa:

constructor TPlayerFa.Create(AParent: TSprite);
begin
  inherited Create(AParent);
  Image := Form1.DXImageList1.Items.Find('Pula');
  Width := Image.Width;
  Height := Image.Height;
  AnimCount := Image.PatternCount;    // число кадров
  AnimLooped := True;                 // повторять ли анимацию
  AnimSpeed:= 10 / 1000;
  Collision;
end;


Создадим простенькие взрывы.[править | править код]

Для начала загрузим спрайт взрыва в DXImageList вот он:

Dx 20532e.gif

Назовём его "ex" и установим размер кадра на 32Х48 (PatternHeight - PatternWidth)

Дальше, в класс TPlayerSprite в private добавляем procedure Hit; и создаём обработчик:

procedure TplayerSprite.Hit;
begin
  Collisioned := False;
  Image := Form1.dxImageList1.Items.Find('Ex');
  Width := Image.Width;
  Height := Image.Height;
  AnimCount := Image.PatternCount;
  AnimLooped := False;
  AnimSpeed := 15/1000;
  AnimPos := 0;
end;


и в процедуре TPlayerSprite.DoCollision вставляем следующий код:

procedure TPlayerSprite.DoCollision(Sprite: TSprite; var Done: Boolean);
begin
  if Sprite is TPlayerFa then
  begin
    TPlayerSprite(Sprite).Hit;
    Dead;
  end;
  Done := False;
end;


Этот код надо разместить и в Tboss. DoCollision.

И под конец маленький бонус:

Можно создать бэкграунд, без создания нового класса достаточно в FormCreate написать:

  with TBackgroundSprite.Create(DXSpriteEngine1.Engine) do
  begin
    SetMapSize(1, 1);
    Image := dxImageList1.Items.Find('bgr');
    Z := -2;
    Tile := True;
  end;


Где bgr спрайт-бэкграунд.

Вот мой БГ:

Dx 20532c.jpg


Нравиться? Здесь можно скачать исподники всей этой части. part2.rar (77,5 kB)


Author: Влад Энгельгардт
ID: 03930