AD商业广告自由选择
AD商业广告自由选择

mir2res人物或怪物移动

正文概述 开源人   2024-11-04 11:35:40  
mir2res优秀的地方之一:精灵移动2XJ1234FCOM专注游戏工具及源码例子分享
尽管有很多人说它是拉几,但我从来都相信mir2从coderes到picres都是一个优秀的游戏,超越同类mmrpg很多,下面谈谈它的一个方面2XJ1234FCOM专注游戏工具及源码例子分享
:精灵移动2XJ1234FCOM专注游戏工具及源码例子分享
因为对这个的讨论涉及到地图格及地图单元,先在头脑中想象一下地图格,这里不打算讨论地图单元2XJ1234FCOM专注游戏工具及源码例子分享
这里仅讨论actor.pas中跟动作有关的函数,,验证它的优越之处,,2XJ1234FCOM专注游戏工具及源码例子分享
现在开始,,下面是从mir2res中提取的源程序片断,,正是它们构成了精灵移动的基础2XJ1234FCOM专注游戏工具及源码例子分享
2XJ1234FCOM专注游戏工具及源码例子分享
 
{------------------------------------------------------------------------------}
// 常量定义
{------------------------------------------------------------------------------}
const
  MAX_HUMANFRAME            = 600;        // 人类动画总帧数 [0..599]
  MAX_HAIR                  = 3;          // 头发种类数     [0..2]
  MAX_WEAPON                = 34;         // 武器种类数     [0..34]
  
{------------------------------------------------------------------------------}
// 数据结构定义
{------------------------------------------------------------------------------}
type

  // 动作定义
  PActionInfo = ^TActionInfo;
  TActionInfo = record
    start   : word;              // 开始帧
    frame   : word;              // 帧数
    skip    : word;              // 跳过的帧数
    ftime   : word;              // 每帧的延迟时间(毫秒)
  end;

  // 玩家的动作定义
  PHumanAction = ^THumanAction;
  THumanAction = record
    ActStand       : TActionInfo;   //1
    ActWalk        : TActionInfo;   //8
    ActRun         : TActionInfo;   //8
    ActRushLeft    : TActionInfo;
    ActRushRight   : TActionInfo;
    ActWarMode     : TActionInfo;   //1
    ActHit         : TActionInfo;   //6
    ActHeavyHit    : TActionInfo;   //6
    ActBigHit      : TActionInfo;   //6
    ActFireHitReady: TActionInfo;   //6
    ActSpell       : TActionInfo;   //6
    ActSitdown     : TActionInfo;   //1
    ActStruck      : TActionInfo;   //3
    ActDie         : TActionInfo;   //4
  end;

{------------------------------------------------------------------------------}
// TActor class 精灵类定义 
{------------------------------------------------------------------------------}
  TActor = class(TObject)
  protected
    FrameCount      : Word;       // 当前动作的总帧数
    FrameStart      : Word;       // 当前动作的开始帧索引
    FrameEnd        : Word;       // 当前动作的结束帧索引
    FrameTime       : Word;       // 当前动作每帧等待的时间

    FrameIndex      : Word;       // 当前帧索引
    FrameTick       : Cardinal;   // 当前帧显示时的 GetTickCount 

  public
    CurrentMap      : TMirMap;    // 当前人物所在地图

    CurrentAction   : Byte;       // 当前动作
    Direction       : Byte;       // 当前方向
    Appearance      : Word;       // 外观显示(对 HumanActor 则相当于级别,初级,高级,,中级,,最高级-顶级)


    MapX            : Word;       // 处于地图上的位置(以 MapPoint 为单位)
    MapY            : Word;
    ShiftX          : Integer;    // 当前位移(以像素为单位, 用于 Walk, Run)
    ShiftY          : Integer;
    MovX            : Integer;    // 上次 Walk, Run 的偏移值,,
    MovY            : Integer;

    constructor Create(Map: TMirMap); virtual; abstract; //需要子类的重载

    // 重新计算动画帧
    procedure ReCalcFrames; virtual; abstract;
    // 根据经过的时间处理下一帧
    procedure ProcessFrame; virtual; abstract;
  end;


{------------------------------------------------------------------------------}
// THumanActor class 角色精灵类定义
{------------------------------------------------------------------------------}
  THumanActor = class(TActor)
  private
  protected
    BodyOffset          : Word;       // 身体图片索引的主偏移
    HairOffset          : Word;       // 头发图片索引的主偏移
    WeaponOffset        : Word;       // 武器图片索引的主偏移
    WeaponOrder         : Byte;       // 武器绘制顺序(是否先于身体绘制)

   public
    Sex                 : Byte;       // 性别
    Job                 : Byte;       // 职业
    Hair                : Byte;       // 发型
    Weapon              : Byte;       // 武器

    constructor Create(Map: TMirMap); override; //重载

    procedure ReCalcFrames; override;
    procedure ProcessFrame; override;
    procedure Draw(Surface: IDirectDrawSurface7; X, Y, Width, Height: Integer);

    function CalcNextDirection: Boolean;
    // 移动至 MapPoint, 虽然 MapPoint 坐标定义为 Word, 这里必须用 Integer 代替
    // 因为玩家可以点击至 Map 坐标负方向进行转向
    procedure Walk(X, Y: Integer);
    procedure Run(X, Y: Integer);
    procedure Hit(X, Y: Integer);
  end;


const

{------------------------------------------------------------------------------}
// 人物动作图片索引
{------------------------------------------------------------------------------}
  // 以下二项数据组成 9 * 2 * 600 = 10800 幅图片
  // Appearance = [0..8] [没穿衣服/初级/中级/高级(武/法/道)/最高级(武/法/道)]
  // Sex        = [0..1] [男/女]

  // 每个 Appearance 包含 14 种 Action
  // 不同 Direction 的 Action = Action 的起始帧 * 8 * Direction  
  // Action     = [0 - 13] (Action 数量与总帧数无关, 并非每个 Action 都 8 帧)
  // Direction  = [0 - 7]

  HUMANACTION_STAND         = 0;
  HUMANACTION_WALK          = 1;
  HUMANACTION_RUN           = 2;
  HUMANACTION_RUSHLEFT      = 3;
  HUMANACTION_RUSHRIGHT     = 4;
  HUMANACTION_WARMODE       = 5;
  HUMANACTION_HIT           = 6;
  HUMANACTION_HEAVYHIT      = 7;
  HUMANACTION_BIGHIT        = 8;
  HUMANACTION_FIREHITREADY  = 9;
  HUMANACTION_SPELL         = 10;
  HUMANACTION_SITDOWN       = 11;
  HUMANACTION_STRUCK        = 12;
  HUMANACTION_DIE           = 13;

  HUMANACTIONS: THumanAction =
  (
    //                开始帧      有效帧    跳过帧   每帧延迟(每帧经过的时间,单位:毫秒)
    ActStand:        (start: 0;   frame: 4; skip: 4; ftime: 200);
    ActWalk:         (start: 64;  frame: 6; skip: 2; ftime: 80);
    ActRun:          (start: 128; frame: 6; skip: 2; ftime: 90);
    ActRushLeft:     (start: 128; frame: 3; skip: 5; ftime: 120);
    ActRushRight:    (start: 131; frame: 3; skip: 5; ftime: 120);
    ActWarMode:      (start: 192; frame: 1; skip: 0; ftime: 200);
    ActHit:          (start: 200; frame: 6; skip: 2; ftime: 85);
    ActHeavyHit:     (start: 264; frame: 6; skip: 2; ftime: 90);
    ActBigHit:       (start: 328; frame: 8; skip: 0; ftime: 70);
    ActFireHitReady: (start: 192; frame: 6; skip: 4; ftime: 70);
    ActSpell:        (start: 392; frame: 6; skip: 2; ftime: 60);
    ActSitdown:      (start: 456; frame: 2; skip: 0; ftime: 300);
    ActStruck:       (start: 472; frame: 3; skip: 5; ftime: 70);
    ActDie:          (start: 536; frame: 4; skip: 4; ftime: 120);
  );

{------------------------------------------------------------------------------}
// 武器绘制顺序 (是否先于身体绘制: 0是/1否)
// WEAPONORDERS: array [Sex, FrameIndex] of Byte
{------------------------------------------------------------------------------}
  WEAPONORDERS: array[0..1, 0..MAX_HUMANFRAME - 1] of Byte =
  (
    (
      //
      0,0,0,0,0,0,0,0,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,    0,0,0,0,0,0,0,0,    0,0,0,0,1,1,1,1,
      0,0,0,0,1,1,1,1,    0,0,0,0,1,1,1,1,
      //
      0,0,0,0,0,0,0,0,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,    0,0,0,0,0,0,0,0,    0,0,0,0,0,0,0,1,
      0,0,0,0,0,0,0,1,    0,0,0,0,0,0,0,1,
      //
      0,0,0,0,0,0,0,0,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,    0,0,1,1,1,1,1,1,    0,0,1,1,1,0,0,1,
      0,0,0,0,0,0,0,1,    0,0,0,0,0,0,0,1,
      //
      0,1,1,1,0,0,0,0,
      //
      1,1,1,0,0,0,1,1,    1,1,1,0,0,0,0,0,    1,1,1,0,0,0,0,0,
      1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,    1,1,1,0,0,0,0,0,
      0,0,0,0,0,0,0,0,    1,1,1,1,0,0,1,1,
      //
      0,1,1,0,0,0,1,1,    0,1,1,0,0,0,1,1,    1,1,1,0,0,0,0,0,
      1,1,1,0,0,1,1,1,    1,1,1,1,1,1,1,1,    0,1,1,1,1,1,1,1,
      0,0,0,1,1,1,0,0,    0,1,1,1,1,0,1,1,
      //
      1,1,0,1,0,0,0,0,    1,1,0,0,0,0,0,0,    1,1,1,1,1,0,0,0,
      1,1,0,0,1,0,0,0,    1,1,1,0,0,0,0,1,    0,1,1,0,0,0,0,0,
      0,0,0,0,1,1,1,0,    1,1,1,1,1,0,0,0,
      //
      0,0,0,0,0,0,1,1,    0,0,0,0,0,0,1,1,    0,0,0,0,0,0,1,1,
      1,0,0,0,0,1,1,1,    1,1,1,1,1,1,1,1,    0,1,1,1,1,1,1,1,
      0,0,1,1,0,0,1,1,    0,0,0,1,0,0,1,1,
      //
      0,0,1,0,1,1,1,1,    1,1,0,0,0,1,0,0,
      //
      0,0,0,1,1,1,1,1,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,    0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1,
      0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1,
      //
      0,0,1,1,1,1,1,1,    0,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,    0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1,
      0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1
    ),
    //以上为男600,,下面开始女600
    (
      //
      0,0,0,0,0,0,0,0,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,    0,0,0,0,0,0,0,0,    0,0,0,0,1,1,1,1,
      0,0,0,0,1,1,1,1,    0,0,0,0,1,1,1,1,
      //
      0,0,0,0,0,0,0,0,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,    0,0,0,0,0,0,0,0,    0,0,0,0,0,0,0,1,
      0,0,0,0,0,0,0,1,    0,0,0,0,0,0,0,1,
      //
      0,0,0,0,0,0,0,0,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,    0,0,1,1,1,1,1,1,    0,0,1,1,1,0,0,1,
      0,0,0,0,0,0,0,1,    0,0,0,0,0,0,0,1,
      //
      1,1,1,1,0,0,0,0,
      //
      1,1,1,0,0,0,1,1,    1,1,1,0,0,0,0,0,    1,1,1,0,0,0,0,0,
      1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,    1,1,1,0,0,0,0,0,
      0,0,0,0,0,0,0,0,    1,1,1,1,0,0,1,1,
      //
      0,1,1,0,0,0,1,1,    0,1,1,0,0,0,1,1,    1,1,1,0,0,0,0,0,
      1,1,1,0,0,1,1,1,    1,1,1,1,1,1,1,1,    0,1,1,1,1,1,1,1,
      0,0,0,1,1,1,0,0,    0,1,1,1,1,0,1,1,
      //
      1,1,0,1,0,0,0,0,    1,1,0,0,0,0,0,0,    1,1,1,1,1,0,0,0,
      1,1,0,0,1,0,0,0,    1,1,1,0,0,0,0,1,    0,1,1,0,0,0,0,0,
      0,0,0,0,1,1,1,0,    1,1,1,1,1,0,0,0,
      //
      0,0,0,0,0,0,1,1,    0,0,0,0,0,0,1,1,    0,0,0,0,0,0,1,1,
      1,0,0,0,0,1,1,1,    1,1,1,1,1,1,1,1,    0,1,1,1,1,1,1,1,
      0,0,1,1,0,0,1,1,    0,0,0,1,0,0,1,1,
      //
      0,0,1,0,1,1,1,1,    1,1,0,0,0,1,0,0,
      //
      0,0,0,1,1,1,1,1,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,    0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1,
      0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1,
      //
      0,0,1,1,1,1,1,1,    0,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,    0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1,
      0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1
    )
  );


implementation

{ THumanActor }

procedure THumanActor.Draw(Surface: IDirectDrawSurface7; X, Y, Width, Height: Integer);
var
  Index: Word;
begin
  // 绘制武器,允许的范围 [0..33] (WeaponOrder = 0)
  if (WeaponOrder = 0) and (Weapon > 0) and (Weapon < MAX_WEAPON) then
    G_WilWeapon.DrawEx(WeaponOffset + FrameIndex, Surface, X, Y,
      CLIENT_WIDTH, CLIENT_HEIGHT, True);

  // 绘制身体
  G_WilHuman.DrawEx(BodyOffset + FrameIndex, Surface, X, Y,
    CLIENT_WIDTH, CLIENT_HEIGHT, True);

  // 绘制头发,允许的范围 [0..2]
  if (Hair > 0) and (Hair < MAX_HAIR) then
    G_WilHair.DrawEx(HairOffset + FrameIndex, Surface, X, Y,
      CLIENT_WIDTH, CLIENT_HEIGHT, True);

  // 绘制武器,允许的范围 [0..33] (WeaponOrder = 1)
  if (WeaponOrder = 1) and (Weapon > 0) and (Weapon < MAX_WEAPON) then
    G_WilWeapon.DrawEx(WeaponOffset + FrameIndex, Surface, X, Y,
      CLIENT_WIDTH, CLIENT_HEIGHT, True);

end;


procedure THumanActor.ProcessFrame;
var
  CurrTick: Cardinal;
  NewIndex: Integer; //重要的是把握它的实际用意,,下面会谈到
begin
  inherited;

  CurrTick := GetTickCount;

  case CurrentAction of //这里计算shiftx,,y,,注意,这里只是计算,,而不实际实现人物在地图上的位移效果,
//shiftx,,y是地图单元用的,,精灵移动好像根本不用到它,,故下面几行不讨论
    HUMANACTION_WALK:
      begin
        ShiftX := MovX * MAPUNIT_WIDTH  * Integer((CurrTick - FrameTick)) div (FrameTime * FrameCount);
        ShiftY := MovY * MAPUNIT_HEIGHT * Integer((CurrTick - FrameTick)) div (FrameTime * FrameCount);
      end;

    HUMANACTION_RUN:
      begin
        ShiftX := MovX * 2 * MAPUNIT_WIDTH  * Integer((CurrTick - FrameTick)) div (FrameTime * FrameCount);
        ShiftY := MovY * 2 * MAPUNIT_HEIGHT * Integer((CurrTick - FrameTick)) div (FrameTime * FrameCount);
      end;
  end;
//ProcessFrame对精灵移动的实际作用真正从下面这行开始
  NewIndex := FrameStart + (CurrTick - FrameTick) div (FrameTime); //经过的时间除以每帧经过的时间,,就可以得出理论上应该过多少帧
  if NewIndex = FrameIndex then Exit;   // 判断是否需要计算帧,如果理论与实际相符,此函数不发挥作用,如果不符,就要经过这个函数的作用作一点处理

  FrameIndex := NewIndex; //处理的第一步:把frameindex拉回正确位置,,为什么要这么做:mir2是一个网络游戏,由于本地和网络的延迟,,
  // TODO: 可能 GetTickCount 会在 49 天内循环回来,,mir2的B/S模型中,gettickcount是本地的计算(毫秒级的timer)而不是服务端的计算
  if FrameIndex < FrameStart then FrameIndex := FrameStart; //处理的第二步,,注意:在这之前frameindex经过了frameindex=newindex的作用,不是原来的frameindex了,

  if FrameIndex > FrameEnd then
  begin
    case CurrentAction of
      HUMANACTION_WALK:
        begin
          Inc(MapX, MovX);
          Inc(MapY, MovY);
        end;

      HUMANACTION_RUN:
        begin
          Inc(MapX, MovX * 2); //inc,,按movx*2递增mapx
          Inc(MapY, MovY * 2);
        end;
    end;
    CurrentAction := HUMANACTION_STAND; //最终的动作总是停下来
    ReCalcFrames; //停下来就是动作改变,就要重新计算帧,,,等待下一次的processframe过程
  end;

  // 计算武器绘制顺序
  WeaponOrder := WEAPONORDERS[Sex, FrameIndex];

end;

constructor THumanActor.Create(Map: TMirMap);
begin
  inherited; //继承父类TActor的create过程
  Appearance := 7;
  Job := 1;
  Sex := 1;
  Hair := 2;
  Direction := 5;
  Weapon := 31;
  CurrentAction := HUMANACTION_STAND; //一开始被create出来,,动作当然是stand
  MapX := 300;
  MapY := 300;
end;

procedure THumanActor.ReCalcFrames;
var
  InfoPtr: PActionInfo;
begin
  inherited;

  case CurrentAction of //每一个动作额定对应一个系列的动作图片(开始于多少帧,每帧多少)及图片信息(如每帧持久多少)
//这个可以说是所有属性的重置,,重置工作的初始过程:为infoprt这个指针变量赋值
    0: InfoPtr := @HUMANACTIONS.ActStand;
    1: InfoPtr := @HUMANACTIONS.ActWalk;
    2: InfoPtr := @HUMANACTIONS.ActRun;
    3: InfoPtr := @HUMANACTIONS.ActRushLeft;
    4: InfoPtr := @HUMANACTIONS.ActRushRight;
    5: InfoPtr := @HUMANACTIONS.ActWarMode;
    6: InfoPtr := @HUMANACTIONS.ActHit;
    7: InfoPtr := @HUMANACTIONS.ActHeavyHit;
    8: InfoPtr := @HUMANACTIONS.ActBigHit;
    9: InfoPtr := @HUMANACTIONS.ActFireHitReady;
   10: InfoPtr := @HUMANACTIONS.ActSpell;
   11: InfoPtr := @HUMANACTIONS.ActSitdown;
   12: InfoPtr := @HUMANACTIONS.ActStruck;
   13: InfoPtr := @HUMANACTIONS.ActDie;
  else
    raise Exception.CreateFmt('Unknown Human Action : %d', [CurrentAction]);
  end;

  // 身体图片偏移值
  BodyOffset := MAX_HUMANFRAME * (Appearance * 2 + Sex) + Direction * 8;
  // 头发图片偏移值
  if (Hair > 0) and (Hair < MAX_HAIR) then
    HairOffset := MAX_HUMANFRAME * (Hair * 2 + Sex) + Direction * 8;
  // 武器图片偏移值
  if (Weapon > 0) and (Weapon < MAX_WEAPON) then
    WeaponOffset := MAX_HUMANFRAME * (Weapon * 2 + Sex) + Direction * 8;
//为infoprt赋值后这里就是具体的重置过程了
  FrameCount := InfoPtr^.frame;
  FrameStart := InfoPtr^.start;
  FrameEnd   := FrameStart + FrameCount - 1; //这是什么用意,,最后一帧为什么不显示?
  FrameTime  := InfoPtr^.ftime;
  FrameIndex := FrameStart; //从头开始,,注意frameindex,是thumactor的成员
  FrameTick  := GetTickCount;

  ShiftX := 0; //x,,y上的位移都置0,,跟movx,,,movy有关,在procseeframe中 
  ShiftY := 0; //
end;

function THumanActor.CalcNextDirection: Boolean; //计算下一个方向为什么要返回boolean??walk(),run()中会看到作判断用
var
  NewDir: Byte;
begin //这里比较容易理解吧:坐标系统跟数学坐标不一样
  if (MovX = -1) and (MovY = -1) then NewDir := DIR_UPLEFT    else
  if (MovX = -1) and (MovY =  0) then NewDir := DIR_LEFT      else
  if (MovX = -1) and (MovY =  1) then NewDir := DIR_DOWNLEFT  else
  if (MovX =  0) and (MovY = -1) then NewDir := DIR_UP        else
  if (MovX =  0) and (MovY =  1) then NewDir := DIR_DOWN      else
  if (MovX =  1) and (MovY = -1) then NewDir := DIR_UPRIGHT   else
  if (MovX =  1) and (MovY =  0) then NewDir := DIR_RIGHT     else
  if (MovX =  1) and (MovY =  1) then NewDir := DIR_DOWNRIGHT else
    raise Exception.Create('CalcNextDirection');

  Result := NewDir <> Direction; //比较计算出的新方向与当前方向,,看是不是相等,,到此为止实际上函数的作用已经完成了,但是还要加入一个附加处理
  if Result then Direction := NewDir; //附加处理:如果不等(为真),,那么置当前dir为newdir
end;

procedure THumanActor.Walk(X, Y: Integer); //x,,y为目标位置
begin
  if CurrentAction <> HUMANACTION_STAND then Exit; //走之前一定要是站立状态

  MovX := Min(1, Max(-1, X - MapX));  //movx,,movy是上次 Walk, Run Action 的偏移值,这个语句值得深究,我们来推导一下
if min(1,max())= 取max  then,,max只能取0,,负数,,因此在max内部,,要么为0,不能是-1(为0时,此时x-mapx=-1,x=mapx-1),,要么为负(此时x-mapx<-1,,x<mapx-1)
也即x<=mapx-1
实际意义就是用户点了(这里只讨论x方向)人物当前x坐标前一个方向
   

if min(1,max())= 取1 then, , max内部只能取2,,或2以上(max不能是1),,因此x-mapx是,,即x>=mapx+2,,此时x在水平方向总是要比mapx大二个或二个地图格以上
  
即(实际意义):用户在水平向上点击了比mapx大二个或二个的地图格以上的地图位置,,此时movx被计算出来,为>=2


  
以上讨论水平方向,这里讨论垂直方向,二个方向共同作用,,确定movx,movy,,注意到在上面的过程中,min()只能取1,,或>=2的数值max(),,

下面讨论竖直方向的情况,同一个道理

MovY := Min(1, Max(-1, Y - MapY)); 

三种情况,,,1,,y=mapy 2,,y<mapy 3,,y>=mapy+2

设想一下,y仅仅>mapy,,而不规定y>=mapy+2时,比如y=mapy+1时也就是用户点击人物当前位置竖直方向再往下一个伴置,此时
y>mapy,,但y不>=mapy+2,(至少要3个地图格),此时不满足上面三种情况的任何一种情况

  if (MovX = 0) and (MovY = 0) then Exit; 用户点了站立的位置,,相当于不走,exit,,即walk()函数不发挥作用

  if CalcNextDirection then ReCalcFrames; //如果方向改变了,,那么也要重新计算帧

  if not CurrentMap.CanMove(MapX + MovX, MapY + MovY) then Exit; //如果地图不能走当然也就不能继续walk()了
  CurrentAction := HUMANACTION_WALK;
  ReCalcFrames; //动作由站立改为走也要重新计算帧,,也就是说,,recalcframes,,,的影响因素有二个1,动作,,2方向
end;
 
procedure THumanActor.Run(X, Y: Integer); x,,y为目标位置
begin
  if CurrentAction <> HUMANACTION_STAND then Exit; //跑之前一定要是站立状态

  MovX := Min(1, Max(-1, X - MapX));
  MovY := Min(1, Max(-1, Y - MapY));
  if (MovX = 0) and (MovY = 0) then Exit; //用户点了站立的位置,,相当于不跑

  if CalcNextDirection then ReCalcFrames;

  if not CurrentMap.CanMove(MapX + MovX, MapY + MovY) then Exit;
  if not CurrentMap.CanMove(MapX + MovX * 2, MapY + MovY * 2) then
  begin
    Walk(X, Y);
    Exit; //这里为什么不要recalcframe,,因为包括在walk(x,y)中了
  end;
  CurrentAction := HUMANACTION_RUN; //这句语句的上面计算run产生的地图位移,下面就是产生动画效果
  ReCalcFrames;
end;

procedure THumanActor.Hit(X, Y: Integer);
begin
  if CurrentAction <> HUMANACTION_STAND then Exit;

  MovX := Min(1, Max(-1, X - MapX));
  MovY := Min(1, Max(-1, Y - MapY));
  if (MovX = 0) and (MovY = 0) then Exit;

  CalcNextDirection;
  CurrentAction := HUMANACTION_HIT;
  ReCalcFrames;
end;

end.
2XJ1234FCOM专注游戏工具及源码例子分享


声明:本文系互联网搜索而收集整理,不以盈利性为目的,文字、图文资料源于互联网且共享于互联网。
如有侵权,请联系 yao4fvip#qq.com (#改@) 删除。