组装10 人物动画的简单实现 添加人物发型

实现原理

建立一个ACTOR类

在PLAY按钮中设置好人物的属性,计算出初始帧数据

RUN 中 计算出当前帧,装载帧图片

DrawChr 进行绘画

 

unit Movies;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, DXDraws, WILIB;

type
  TAction = (ActStand, ActWalk, ActRun, ActRushLeft, ActRushRight, ActWarMode,
    ActHit, ActHeavyHit, ActBigHit, ActFireHitReady, ActSpell,
    ActSitdown, ActStruck, ActDie);

  TActionInfo = packed record
    start: Word;
    frame: Word;
    skip: Word;
    ftime: Word;
    usetick: Word;
  end;

  THumanAction = packed record
    ActStand: TActionInfo;
    ActWalk: TActionInfo;
    ActRun: TActionInfo;
    ActRushLeft: TActionInfo;
    ActRushRight: TActionInfo;
    ActWarMode: TActionInfo;
    ActHit: TActionInfo;
    ActHeavyHit: TActionInfo;
    ActBigHit: TActionInfo;
    ActFireHitReady: TActionInfo;
    ActSpell: TActionInfo;
    ActSitdown: TActionInfo;
    ActStruck: TActionInfo;
    ActDie: TActionInfo;
  end;

  TForm1 = class(TForm)
    DXDrawHuman: TDXDraw;
    ButtonPlay: TButton;
    TimerShow: TTimer;
    ListBoxAction: TListBox;
    ListBoxDirect: TListBox;
    ListBoxSex: TListBox;
    ListBoxJob: TListBox;
    ListBoxDress: TListBox;
    MemoResult: TMemo;
    ButtonStop: TButton;
    ListBoxHair: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure DXDrawHumanInitialize(Sender: TObject);
    procedure ButtonPlayClick(Sender: TObject);
    procedure TimerShowTimer(Sender: TObject);
    procedure PlayScence(MSurface: TDirectDrawSurface);
    procedure ButtonStopClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

const
  HUMANFRAME = 600;

  DR_UP = 0;
  DR_UPRIGHT = 1;
  DR_RIGHT = 2;
  DR_DOWNRIGHT = 3;
  DR_DOWN = 4;
  DR_DOWNLEFT = 5;
  DR_LEFT = 6;
  DR_UPLEFT = 7;

  HA: THumanAction = (
    ActStand: (start: 0; frame: 4; skip: 4; ftime: 200; usetick: 0);
    ActWalk: (start: 64; frame: 6; skip: 2; ftime: 180; usetick: 2);
    ActRun: (start: 128; frame: 6; skip: 2; ftime: 200; usetick: 3);
    ActRushLeft: (start: 128; frame: 3; skip: 5; ftime: 200; usetick: 3);
    //先左手
    ActRushRight: (start: 131; frame: 3; skip: 5; ftime: 200; usetick: 3);
    //先右手
    ActWarMode: (start: 192; frame: 1; skip: 0; ftime: 200; usetick: 0);
    //ActHit:    (start: 200;    frame: 5;  skip: 3;  ftime: 140;  usetick: 0);
    ActHit: (start: 200; frame: 6; skip: 2; ftime: 140; usetick: 0);
    ActHeavyHit: (start: 264; frame: 6; skip: 2; ftime: 140; usetick: 0);
    ActBigHit: (start: 328; frame: 8; skip: 0; ftime: 120; usetick: 0);
    //这里指的烈火蓄力的动作?
    ActFireHitReady: (start: 192; frame: 1; skip: 0; ftime: 140; usetick: 0);
    ActSpell: (start: 392; frame: 6; skip: 2; ftime: 200; usetick: 0);
    ActSitdown: (start: 456; frame: 2; skip: 0; ftime: 240; usetick: 0);
    ActStruck: (start: 472; frame: 3; skip: 5; ftime: 140; usetick: 0);
    ActDie: (start: 536; frame: 4; skip: 4; ftime: 200; usetick: 0)
    );

type
  TActor = class
    m_btSex: Byte;
    m_btJob: Byte;
    m_btDress: Byte;
    m_btDir: Byte;
    m_btAtc: TAction;

    m_nStartFrame: Integer;
    m_nEndFrame: Integer;
    m_dwFrameTime: LongWord;
    m_dwStartTime: LongWord;
    m_nMaxTick: Integer;
    m_nCurTick: Integer;
    m_nCurrentFrame: Integer;

    m_BodySurface: TDirectDrawSurface;
    m_nPx: Integer;
    m_nPy: Integer;

    m_btHair : Byte;
    m_nHairOffset: Integer;
    m_HairSurface: TDirectDrawSurface;
    m_nHairPx: Integer;
    m_nHairPy: Integer;

    constructor Create;
    destructor Destroy;

    procedure CalcActorFrame;
    procedure Run;
    procedure LoadSurface;
    procedure DrawChr(dsurface: TDirectDrawSurface; dx, dy: integer);

  end;

var
  Form1: TForm1;
  Actor1: TActor;
  g_mainWil: TWILImages;
  g_WHumImgImages: TWILImages;
  g_WHairImgImages: TWILImages;
  g_cacheSurface: TDirectDrawSurface;
  bmpIndex: Integer;
  movetick: Boolean;
  m_dwMoveTime: LongWord;
implementation

{$R *.dfm}

function ToDXD7Color(Color: TColor): TColor;
var
  R, G, B: Integer;
begin
  R := Color and $FF;
  G := (Color and $FF00) shr 8;
  B := (Color and $FF0000) shr 16;
  Result := R shl 16 or G shl 8 or B;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  TimerShow.Enabled := False;
  bmpIndex := -1;
  ListBoxJob.ItemIndex := 0;
  ListBoxSex.ItemIndex := 0;
  ListBoxDress.ItemIndex := 0;
  ListBoxAction.ItemIndex := 0;
  ListBoxDirect.ItemIndex := 0;
  g_WHumImgImages := TWILImages.Create;
  g_WHairImgImages := TWILImages.Create;
  Actor1 := TActor.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  g_WHumImgImages.Destroy;
  g_WHairImgImages.Destroy;
  g_cacheSurface.Free;
  Actor1.Destroy;
end;

procedure TForm1.DXDrawHumanInitialize(Sender: TObject);
begin
  g_WHumImgImages.DDraw := DXDrawHuman.DDraw;
  g_WHumImgImages.FileName := 'E:\mirClient\Mir1.76\Data\Hum.wil';
  g_WHumImgImages.Initialize;
  g_WHairImgImages.DDraw := DXDrawHuman.DDraw;
  g_WHairImgImages.FileName := 'E:\mirClient\Mir1.76\Data\Hair.wil';
  g_WHairImgImages.Initialize;
end;

procedure TForm1.ButtonPlayClick(Sender: TObject);
begin
  TimerShow.Enabled := True;
  MemoResult.Text := ListBoxJob.Items[ListBoxJob.ItemIndex] + '  ' +
    ListBoxSex.Items[ListBoxSex.ItemIndex] + '  ' +
    ListBoxDress.Items[ListBoxDress.ItemIndex] + '  ' +
    ListBoxAction.Items[ListBoxAction.ItemIndex] + '  ' +
    ListBoxDirect.Items[ListBoxDirect.ItemIndex];

  case ListBoxSex.ItemIndex of
    0: Actor1.m_btSex := 0;
    1: Actor1.m_btSex := 1;
  else
    Actor1.m_btSex := 0;
  end;

  case ListBoxJob.ItemIndex of
    0: Actor1.m_btJob := 0;
    1: Actor1.m_btJob := 1;
    2: Actor1.m_btJob := 2;
  else
    Actor1.m_btJob := 0;
  end;

  case ListBoxDress.ItemIndex of
    0: Actor1.m_btDress := 0;
    1: Actor1.m_btDress := 1;
    2: Actor1.m_btDress := 2;
    3:
      begin
        case ListBoxJob.ItemIndex of
          0: Actor1.m_btDress := 3;
          1: Actor1.m_btDress := 4;
          2: Actor1.m_btDress := 5;
        else
          Actor1.m_btDress := 0;
        end;
      end;
    4:
      begin
        case ListBoxJob.ItemIndex of
          0: Actor1.m_btDress := 6;
          1: Actor1.m_btDress := 7;
          2: Actor1.m_btDress := 8;
        else
          Actor1.m_btDress := 0;
        end;
      end;

  else
    Actor1.m_btDress := 0;
  end;

  case ListBoxAction.ItemIndex of
    0: Actor1.m_btAtc := ActStand;
    1: Actor1.m_btAtc := ActWalk;
    2: Actor1.m_btAtc := ActRun;
    3: Actor1.m_btAtc := ActRushLeft;
    4: Actor1.m_btAtc := ActRushRight;
    5: Actor1.m_btAtc := ActWarMode;
    6: Actor1.m_btAtc := ActHit;
    7: Actor1.m_btAtc := ActHeavyHit;
    8: Actor1.m_btAtc := ActBigHit;
    9: Actor1.m_btAtc := ActFireHitReady;
    10: Actor1.m_btAtc := ActSpell;
    11: Actor1.m_btAtc := ActSitdown;
    12: Actor1.m_btAtc := ActStruck;
    13: Actor1.m_btAtc := ActDie;
  else
    Actor1.m_btAtc := ActStand;
  end;

  case ListBoxDirect.ItemIndex of
    0: Actor1.m_btDir := DR_UP;
    1: Actor1.m_btDir := DR_UPRIGHT;
    2: Actor1.m_btDir := DR_RIGHT;
    3: Actor1.m_btDir := DR_DOWNRIGHT;
    4: Actor1.m_btDir := DR_DOWN;
    5: Actor1.m_btDir := DR_DOWNLEFT;
    6: Actor1.m_btDir := DR_LEFT;
    7: Actor1.m_btDir := DR_UPLEFT;
  else
    Actor1.m_btDir := DR_UP;
  end;

  case ListBoxHair.ItemIndex of
    0: Actor1.m_btHair := 0;
    1: Actor1.m_btHair := 1;
    2: Actor1.m_btHair := 2;
    3: Actor1.m_btHair := 3;
    4: Actor1.m_btHair := 4;
    5: Actor1.m_btHair := 5;
    6: Actor1.m_btHair := 6;
  else
    Actor1.m_btSex := 0;
  end;

  Actor1.CalcActorFrame;
end;

procedure TForm1.TimerShowTimer(Sender: TObject);
begin
  DXDrawHuman.Surface.Fill(ToDXD7Color(clBlue));
  PlayScence(DXDrawHuman.Surface);
  DXDrawHuman.Flip;
end;

constructor TActor.Create;
begin
  m_BodySurface := nil;
  m_HairSurface := nil;
  m_nHairOffset := -1;
  m_btHair := 0;
  m_nCurrentFrame := -1;
  m_nPx := 0;
  m_nPy := 0;

end;

destructor TActor.Destroy;
begin

end;

procedure TActor.CalcActorFrame;

begin


  if m_btHair > -1 then 
    m_nHairOffset := HUMANFRAME * m_btHair
  else
    m_nHairOffset := -1;

  m_nCurrentFrame := -1;
  case m_btAtc of
    ActStand:
      begin
        m_nStartFrame := HA.ActStand.start + m_btDir * (HA.ActStand.frame +
          HA.ActStand.skip);
        m_nEndFrame := m_nStartFrame + HA.ActStand.frame - 1;
        m_dwFrameTime := HA.ActStand.ftime;
        m_dwStartTime := GetTickCount;

      end;
    ActWalk:
      begin
        m_nStartFrame := HA.ActWalk.start + m_btDir * (HA.ActWalk.frame +
          HA.ActWalk.skip);
        m_nEndFrame := m_nStartFrame + HA.ActWalk.frame - 1;
        m_dwFrameTime := HA.ActWalk.ftime;
        m_dwStartTime := GetTickCount;
        m_nMaxTick := HA.ActWalk.UseTick;
        m_nCurTick := 0;

      end;
    ActRun:
      begin
        m_nStartFrame := HA.ActRun.start + m_btDir * (HA.ActRun.frame +
          HA.ActRun.skip);
        m_nEndFrame := m_nStartFrame + HA.ActRun.frame - 1;
        m_dwFrameTime := HA.ActRun.ftime;
        m_dwStartTime := GetTickCount;
        m_nMaxTick := HA.ActRun.UseTick;
        m_nCurTick := 0;

      end;

    ActRushLeft:
      begin
        m_nStartFrame := HA.ActRushLeft.start + m_btDir * (HA.ActRushLeft.frame
          + HA.ActRushLeft.skip);
        m_nEndFrame := m_nStartFrame + HA.ActRushLeft.frame - 1;
        m_dwFrameTime := HA.ActRushLeft.ftime;
        m_dwStartTime := GetTickCount;
        m_nMaxTick := HA.ActRushLeft.UseTick;
        m_nCurTick := 0;
      end;
    ActRushRight:
      begin
        m_nStartFrame := HA.ActRushRight.start + m_btDir *
          (HA.ActRushRight.frame + HA.ActRushRight.skip);
        m_nEndFrame := m_nStartFrame + HA.ActRushRight.frame - 1;
        m_dwFrameTime := HA.ActRushRight.ftime;
        m_dwStartTime := GetTickCount;
        m_nMaxTick := HA.ActRushRight.UseTick;
        m_nCurTick := 0;

      end;
    ActWarMode:

      begin
        m_nStartFrame := HA.ActWarMode.start + m_btDir * (HA.ActWarMode.frame +
          HA.ActWarMode.skip);
        m_nEndFrame := m_nStartFrame + HA.ActWarMode.frame - 1;
        m_dwFrameTime := HA.ActWarMode.ftime;
        m_dwStartTime := GetTickCount;
        m_nMaxTick := HA.ActWarMode.UseTick;

      end;
    ActHit:
      begin
        m_nStartFrame := HA.ActHit.start + m_btDir * (HA.ActHit.frame +
          HA.ActHit.skip);
        m_nEndFrame := m_nStartFrame + HA.ActHit.frame - 1;
        m_dwFrameTime := HA.ActHit.ftime;
        m_dwStartTime := GetTickCount;
      end;

    ActHeavyHit:
      begin
        m_nStartFrame := HA.ActHeavyHit.start + m_btDir * (HA.ActHeavyHit.frame
          + HA.ActHeavyHit.skip);
        m_nEndFrame := m_nStartFrame + HA.ActHeavyHit.frame - 1;
        m_dwFrameTime := HA.ActHeavyHit.ftime;
        m_dwStartTime := GetTickCount;
      end;
    ActBigHit:
      begin
        m_nStartFrame := HA.ActBigHit.start + m_btDir * (HA.ActBigHit.frame +
          HA.ActBigHit.skip);
        m_nEndFrame := m_nStartFrame + HA.ActBigHit.frame - 1;
        m_dwFrameTime := HA.ActBigHit.ftime;
        m_dwStartTime := GetTickCount;
      end;
    ActFireHitReady:
      begin
        m_nStartFrame := HA.ActFireHitReady.start + m_btDir *
          (HA.ActFireHitReady.frame +
          HA.ActFireHitReady.skip);
        m_nEndFrame := m_nStartFrame + HA.ActFireHitReady.frame - 1;
        m_dwFrameTime := HA.ActFireHitReady.ftime;
        m_dwStartTime := GetTickCount;
      end;
    ActSpell:
      begin
        m_nStartFrame := HA.ActSpell.start + m_btDir * (HA.ActSpell.frame +
          HA.ActSpell.skip);
        m_nEndFrame := m_nStartFrame + HA.ActSpell.frame - 1;
        m_dwFrameTime := HA.ActSpell.ftime;
        m_dwStartTime := GetTickCount;
      end;
    ActSitdown:
      begin
        m_nStartFrame := HA.ActSitdown.start + m_btDir * (HA.ActSitdown.frame +
          HA.ActSitdown.skip);
        m_nEndFrame := m_nStartFrame + HA.ActSitdown.frame - 1;
        m_dwFrameTime := HA.ActSitdown.ftime;
        m_dwStartTime := GetTickCount;
      end;
    ActStruck:
      begin
        m_nStartFrame := HA.ActStruck.start + m_btDir * (HA.ActStruck.frame +
          HA.ActStruck.skip);
        m_nEndFrame := m_nStartFrame + HA.ActStruck.frame - 1;
        m_dwFrameTime := HA.ActStruck.ftime;
        m_dwStartTime := GetTickCount;
      end;
    ActDie:
      begin
        m_nStartFrame := HA.ActDie.start + m_btDir * (HA.ActDie.frame +
          HA.ActDie.skip);
        m_nEndFrame := m_nStartFrame + HA.ActDie.frame - 1;
        m_dwFrameTime := HA.ActDie.ftime;
        m_dwStartTime := GetTickCount;
      end;
  end;
end;

procedure TActor.Run;
var
  prv: integer;

begin
  prv := m_nCurrentFrame;
  if (m_nCurrentFrame < m_nStartFrame) or (m_nCurrentFrame > m_nEndFrame) then
    m_nCurrentFrame := m_nStartFrame;

  if GetTickCount - m_dwStartTime > m_dwFrameTime then //帧时间到
  begin
    if m_nCurrentFrame < m_nEndFrame then
    begin

      begin
        Inc(m_nCurrentFrame); //增加帧
        m_dwStartTime := GetTickCount;
      end;

    end
    else //到行为动作的尾帧
    begin

      begin
        m_nCurrentFrame := m_nStartFrame;
        m_dwStartTime := GetTickCount;
      end;

    end;
  end;

  if prv <> m_nCurrentFrame then
  begin
    // m_dwLoadSurfaceTime := GetTickCount;
    LoadSurface;
  end;
end;

procedure TActor.LoadSurface;

begin
  m_BodySurface := g_WHumImgImages.GetCachedImage(HUMANFRAME * (m_btDress * 2 +
    m_btSex) +
    m_nCurrentFrame, m_nPx, m_nPy);
   if m_nHairOffset >= 0 then
    m_HairSurface := g_WHairImgImages.GetCachedImage(m_nHairOffset +
      m_nCurrentFrame, m_nHairPx, m_nHairPy)
  else
    m_HairSurface := nil;
end;

procedure TActor.DrawChr(dsurface: TDirectDrawSurface; dx, dy: integer);
begin
  if m_BodySurface <> nil then
    dsurface.Draw(dx + m_nPx, dy + m_nPy, m_BodySurface.ClientRect,
      m_BodySurface, True);

  if m_HairSurface <> nil then
    dsurface.Draw(dx + m_nHairPx, dy + m_nHairPy, m_HairSurface.ClientRect,
      m_HairSurface, True);

end;

procedure TForm1.PlayScence(MSurface: TDirectDrawSurface);
var
  m_dwFrameTime: LongWord;
begin
  {
  movetick := False;
  if GetTickCount - m_dwMoveTime > 60 then
  begin
    m_dwMoveTime := GetTickCount;
    movetick := True;
  end;

  if movetick then
  begin
    Actor1.Run;
  end;
  }
  Actor1.Run;
  Actor1.DrawChr(MSurface, 80, 120);
end;

procedure TForm1.ButtonStopClick(Sender: TObject);
begin
  TimerShow.Enabled := False;
end;

end.

 

有趣点:

男女发型是有区别的,只能是2,4为男性发型,3,5为女性发型

 

在原始翎风的程序中,对发型进行了男女判断,

 

posted @ 2025-06-26 22:57  D7mir  阅读(17)  评论(0)    收藏  举报