玩传奇论坛

 找回密码
立即注册

扫一扫,访问移动社区

论坛喇叭+ 发布

01-25 10:01
系统通知全站压缩包解压密码:www.wanmirbbs.com
01-25 10:01
01-25 10:01
查看: 2642|回复: 0
打印 上一主题 下一主题

传奇人物或怪物移动介绍说明

[复制链接]
跳转到指定楼层
楼主
发表于 2021-12-13 18:51:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,以游结友!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
精灵移动
尽管有很多人说它是拉几,但我从来都相信mir2从coderes到picres都是一个优秀的游戏,超越同类mmrpg很多,下面谈谈它的一个方面
:精灵移动
因为对这个的讨论涉及到地图格及地图单元,先在头脑中想象一下地图格,这里不打算讨论地图单元
这里仅讨论actor.pas中跟动作有关的函数,,验证它的优越之处,,
现在开始,,下面是从mir2res中提取的源程序片断,,正是它们构成了精灵移动的基础

{------------------------------------------------------------------------------}
// 常量定义
{------------------------------------------------------------------------------}
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.


法律声明:
1. 本站所有资源和素材来源于网络收集,如有侵权内容请联系站长删除处理!
2. 本站大部分下载资源收集于网络,版权归原作者所有,如有侵权请联系删除。
3. 本站提供的素材、源码、等等其他资源,都不包含技术服务支持!
4. 若因线路和服务器问题非本站所能控制范围的故障导致暂停服务期间造成的一切不便与损失,论坛不负任何责任。
5. 注册会员通过任何手段和方法针对论坛进行破坏,我们有权对其行为作出处理。并保留进一步追究其责任的权利。
收藏收藏 分享分享 分享淘帖 支持支持 反对反对
懒得打字嘛,点击右侧快捷回复 【乱回复纯数字纯字母将禁言】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

必备工具

地图查看分析转换三合一

目前地图转换 单纯的OB真彩地图转换编...号想必很多人都会, 也有很多工具

南宫地图编辑器v5.0

使用方法,放置传奇客户端DATA文件夹...

Tiles转换工具,支持支持255

支持255地图转换工具!

关于本站

玩传奇论坛 - 专业提供游戏素材、游戏工具、传奇单机、传奇服务端,致力于打造最精品的版本素材分享平台!

Archiver|小黑屋|玩传奇吉ICP备18002996号-1) |网站地图 

GMT+8, 2024-9-22 05:40 , Processed in 0.040480 second(s), 35 queries , Gzip On. 

 Powered by Discuz! X3.2

 © 2001-2013 Comsenz Inc.

返回顶部