依星源码资源网,依星资源网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

【好消息,好消息,好消息】VIP会员可以发表文章赚积分啦 !
查看: 4|回复: 0

[游戏架设教程] [传奇技术]mir2res人物或怪物移动

[复制链接] 主动推送

1万

主题

1万

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
12523
发表于 4 小时前 | 显示全部楼层 |阅读模式
[传奇技术]mir2res人物或怪物移动
mir2res优秀的地方之一:精灵移动
尽管有很多人说它是拉几,但我从来都相信mir2从coderes到picres都是一个优秀的游戏,超越同类mmrpg很多,下面谈谈它的一个方面
:精灵移动
因为对这个的讨论涉及到地图格及地图单元,先在头脑中想象一下地图格,这里不打算讨论地图单元
这里仅讨论actor.pas中跟动作有关的函数,,验证它的优越之处,,
现在开始,,下面是从mir2res中提取的源程序片断,,正是它们构成了精灵移动的基础
  1. {------------------------------------------------------------------------------}
  2. // 常量定义
  3. {------------------------------------------------------------------------------}
  4. const
  5.   MAX_HUMANFRAME            = 600;        // 人类动画总帧数 [0..599]
  6.   MAX_HAIR                  = 3;          // 头发种类数     [0..2]
  7.   MAX_WEAPON                = 34;         // 武器种类数     [0..34]
  8.   
  9. {------------------------------------------------------------------------------}
  10. // 数据结构定义
  11. {------------------------------------------------------------------------------}
  12. type

  13.   // 动作定义
  14.   PActionInfo = ^TActionInfo;
  15.   TActionInfo = record
  16.     start   : word;              // 开始帧
  17.     frame   : word;              // 帧数
  18.     skip    : word;              // 跳过的帧数
  19.     ftime   : word;              // 每帧的延迟时间(毫秒)
  20.   end;

  21.   // 玩家的动作定义
  22.   PHumanAction = ^THumanAction;
  23.   THumanAction = record
  24.     ActStand       : TActionInfo;   //1
  25.     ActWalk        : TActionInfo;   //8
  26.     ActRun         : TActionInfo;   //8
  27.     ActRushLeft    : TActionInfo;
  28.     ActRushRight   : TActionInfo;
  29.     ActWarMode     : TActionInfo;   //1
  30.     ActHit         : TActionInfo;   //6
  31.     ActHeavyHit    : TActionInfo;   //6
  32.     ActBigHit      : TActionInfo;   //6
  33.     ActFireHitReady: TActionInfo;   //6
  34.     ActSpell       : TActionInfo;   //6
  35.     ActSitdown     : TActionInfo;   //1
  36.     ActStruck      : TActionInfo;   //3
  37.     ActDie         : TActionInfo;   //4
  38.   end;

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

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

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

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


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

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

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


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

  77.    public
  78.     Sex                 : Byte;       // 性别
  79.     Job                 : Byte;       // 职业
  80.     Hair                : Byte;       // 发型
  81.     Weapon              : Byte;       // 武器

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

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

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


  93. const

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

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

  104.   HUMANACTION_STAND         = 0;
  105.   HUMANACTION_WALK          = 1;
  106.   HUMANACTION_RUN           = 2;
  107.   HUMANACTION_RUSHLEFT      = 3;
  108.   HUMANACTION_RUSHRIGHT     = 4;
  109.   HUMANACTION_WARMODE       = 5;
  110.   HUMANACTION_HIT           = 6;
  111.   HUMANACTION_HEAVYHIT      = 7;
  112.   HUMANACTION_BIGHIT        = 8;
  113.   HUMANACTION_FIREHITREADY  = 9;
  114.   HUMANACTION_SPELL         = 10;
  115.   HUMANACTION_SITDOWN       = 11;
  116.   HUMANACTION_STRUCK        = 12;
  117.   HUMANACTION_DIE           = 13;

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

  136. {------------------------------------------------------------------------------}
  137. // 武器绘制顺序 (是否先于身体绘制: 0是/1否)
  138. // WEAPONORDERS: array [Sex, FrameIndex] of Byte
  139. {------------------------------------------------------------------------------}
  140.   WEAPONORDERS: array[0..1, 0..MAX_HUMANFRAME - 1] of Byte =
  141.   (
  142.     (
  143.       //
  144.       0,0,0,0,0,0,0,0,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
  145.       1,1,1,1,1,1,1,1,    0,0,0,0,0,0,0,0,    0,0,0,0,1,1,1,1,
  146.       0,0,0,0,1,1,1,1,    0,0,0,0,1,1,1,1,
  147.       //
  148.       0,0,0,0,0,0,0,0,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
  149.       1,1,1,1,1,1,1,1,    0,0,0,0,0,0,0,0,    0,0,0,0,0,0,0,1,
  150.       0,0,0,0,0,0,0,1,    0,0,0,0,0,0,0,1,
  151.       //
  152.       0,0,0,0,0,0,0,0,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
  153.       1,1,1,1,1,1,1,1,    0,0,1,1,1,1,1,1,    0,0,1,1,1,0,0,1,
  154.       0,0,0,0,0,0,0,1,    0,0,0,0,0,0,0,1,
  155.       //
  156.       0,1,1,1,0,0,0,0,
  157.       //
  158.       1,1,1,0,0,0,1,1,    1,1,1,0,0,0,0,0,    1,1,1,0,0,0,0,0,
  159.       1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,    1,1,1,0,0,0,0,0,
  160.       0,0,0,0,0,0,0,0,    1,1,1,1,0,0,1,1,
  161.       //
  162.       0,1,1,0,0,0,1,1,    0,1,1,0,0,0,1,1,    1,1,1,0,0,0,0,0,
  163.       1,1,1,0,0,1,1,1,    1,1,1,1,1,1,1,1,    0,1,1,1,1,1,1,1,
  164.       0,0,0,1,1,1,0,0,    0,1,1,1,1,0,1,1,
  165.       //
  166.       1,1,0,1,0,0,0,0,    1,1,0,0,0,0,0,0,    1,1,1,1,1,0,0,0,
  167.       1,1,0,0,1,0,0,0,    1,1,1,0,0,0,0,1,    0,1,1,0,0,0,0,0,
  168.       0,0,0,0,1,1,1,0,    1,1,1,1,1,0,0,0,
  169.       //
  170.       0,0,0,0,0,0,1,1,    0,0,0,0,0,0,1,1,    0,0,0,0,0,0,1,1,
  171.       1,0,0,0,0,1,1,1,    1,1,1,1,1,1,1,1,    0,1,1,1,1,1,1,1,
  172.       0,0,1,1,0,0,1,1,    0,0,0,1,0,0,1,1,
  173.       //
  174.       0,0,1,0,1,1,1,1,    1,1,0,0,0,1,0,0,
  175.       //
  176.       0,0,0,1,1,1,1,1,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
  177.       1,1,1,1,1,1,1,1,    0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1,
  178.       0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1,
  179.       //
  180.       0,0,1,1,1,1,1,1,    0,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
  181.       1,1,1,1,1,1,1,1,    0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1,
  182.       0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1
  183.     ),
  184.     //以上为男600,,下面开始女600
  185.     (
  186.       //
  187.       0,0,0,0,0,0,0,0,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
  188.       1,1,1,1,1,1,1,1,    0,0,0,0,0,0,0,0,    0,0,0,0,1,1,1,1,
  189.       0,0,0,0,1,1,1,1,    0,0,0,0,1,1,1,1,
  190.       //
  191.       0,0,0,0,0,0,0,0,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
  192.       1,1,1,1,1,1,1,1,    0,0,0,0,0,0,0,0,    0,0,0,0,0,0,0,1,
  193.       0,0,0,0,0,0,0,1,    0,0,0,0,0,0,0,1,
  194.       //
  195.       0,0,0,0,0,0,0,0,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
  196.       1,1,1,1,1,1,1,1,    0,0,1,1,1,1,1,1,    0,0,1,1,1,0,0,1,
  197.       0,0,0,0,0,0,0,1,    0,0,0,0,0,0,0,1,
  198.       //
  199.       1,1,1,1,0,0,0,0,
  200.       //
  201.       1,1,1,0,0,0,1,1,    1,1,1,0,0,0,0,0,    1,1,1,0,0,0,0,0,
  202.       1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,    1,1,1,0,0,0,0,0,
  203.       0,0,0,0,0,0,0,0,    1,1,1,1,0,0,1,1,
  204.       //
  205.       0,1,1,0,0,0,1,1,    0,1,1,0,0,0,1,1,    1,1,1,0,0,0,0,0,
  206.       1,1,1,0,0,1,1,1,    1,1,1,1,1,1,1,1,    0,1,1,1,1,1,1,1,
  207.       0,0,0,1,1,1,0,0,    0,1,1,1,1,0,1,1,
  208.       //
  209.       1,1,0,1,0,0,0,0,    1,1,0,0,0,0,0,0,    1,1,1,1,1,0,0,0,
  210.       1,1,0,0,1,0,0,0,    1,1,1,0,0,0,0,1,    0,1,1,0,0,0,0,0,
  211.       0,0,0,0,1,1,1,0,    1,1,1,1,1,0,0,0,
  212.       //
  213.       0,0,0,0,0,0,1,1,    0,0,0,0,0,0,1,1,    0,0,0,0,0,0,1,1,
  214.       1,0,0,0,0,1,1,1,    1,1,1,1,1,1,1,1,    0,1,1,1,1,1,1,1,
  215.       0,0,1,1,0,0,1,1,    0,0,0,1,0,0,1,1,
  216.       //
  217.       0,0,1,0,1,1,1,1,    1,1,0,0,0,1,0,0,
  218.       //
  219.       0,0,0,1,1,1,1,1,    1,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
  220.       1,1,1,1,1,1,1,1,    0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1,
  221.       0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1,
  222.       //
  223.       0,0,1,1,1,1,1,1,    0,1,1,1,1,1,1,1,    1,1,1,1,1,1,1,1,
  224.       1,1,1,1,1,1,1,1,    0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1,
  225.       0,0,0,1,1,1,1,1,    0,0,0,1,1,1,1,1
  226.     )
  227.   );


  228. implementation

  229. { THumanActor }

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

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

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

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

  249. end;


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

  256.   CurrTick := GetTickCount;

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

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

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

  276.   if FrameIndex > FrameEnd then
  277.   begin
  278.     case CurrentAction of
  279.       HUMANACTION_WALK:
  280.         begin
  281.           Inc(MapX, MovX);
  282.           Inc(MapY, MovY);
  283.         end;

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

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

  295. end;

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

  309. procedure THumanActor.ReCalcFrames;
  310. var
  311.   InfoPtr: PActionInfo;
  312. begin
  313.   inherited;

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

  387.   if not CurrentMap.CanMove(MapX + MovX, MapY + MovY) then Exit; //如果地图不能走当然也就不能继续walk()了
  388.   CurrentAction := HUMANACTION_WALK;
  389.   ReCalcFrames; //动作由站立改为走也要重新计算帧,,也就是说,,recalcframes,,,的影响因素有二个1,动作,,2方向
  390. end;

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

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

  397.   if CalcNextDirection then ReCalcFrames;

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

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

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

  413.   CalcNextDirection;
  414.   CurrentAction := HUMANACTION_HIT;
  415.   ReCalcFrames;
  416. end;

  417. end.
复制代码


相关帖子

扫码关注微信公众号,及时获取最新资源信息!下载附件优惠VIP会员6折;永久VIP4折
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

免责声明:
1、本站提供的所有资源仅供参考学习使用,版权归原著所有,禁止下载本站资源参与商业和非法行为,请在24小时之内自行删除!
2、本站所有内容均由互联网收集整理、网友上传,并且以计算机技术研究交流为目的,仅供大家参考、学习,请勿任何商业目的与商业用途。
3、若您需要商业运营或用于其他商业活动,请您购买正版授权并合法使用。
4、论坛的所有内容都不保证其准确性,完整性,有效性,由于源码具有复制性,一经售出,概不退换。阅读本站内容因误导等因素而造成的损失本站不承担连带责任。
5、用户使用本网站必须遵守适用的法律法规,对于用户违法使用本站非法运营而引起的一切责任,由用户自行承担
6、本站所有资源来自互联网转载,版权归原著所有,用户访问和使用本站的条件是必须接受本站“免责声明”,如果不遵守,请勿访问或使用本网站
7、本站使用者因为违反本声明的规定而触犯中华人民共和国法律的,一切后果自己负责,本站不承担任何责任。
8、凡以任何方式登陆本网站或直接、间接使用本网站资料者,视为自愿接受本网站声明的约束。
9、本站以《2013 中华人民共和国计算机软件保护条例》第二章 “软件著作权” 第十七条为原则:为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。若有学员需要商用本站资源,请务必联系版权方购买正版授权!
10、本网站如无意中侵犯了某个企业或个人的知识产权,请来信【站长信箱312337667@qq.com】告之,本站将立即删除。
郑重声明:
本站所有资源仅供用户本地电脑学习源代码的内含设计思想和原理,禁止任何其他用途!
本站所有资源、教程来自互联网转载,仅供学习交流,不得商业运营资源,不确保资源完整性,图片和资源仅供参考,不提供任何技术服务。
本站资源仅供本地编辑研究学习参考,禁止未经资源商正版授权参与任何商业行为,违法行为!如需商业请购买各资源商正版授权
本站仅收集资源,提供用户自学研究使用,本站不存在私自接受协助用户架设游戏或资源,非法运营资源行为。
 
在线客服
点击这里给我发消息 点击这里给我发消息 点击这里给我发消息
售前咨询热线
312337667

微信扫一扫,私享最新原创实用干货

QQ|免责声明|小黑屋|依星资源网 ( 鲁ICP备2021043233号-3 )|网站地图

GMT+8, 2025-1-24 17:58

Powered by Net188.com X3.4

邮箱:312337667@qq.com 客服QQ:312337667(工作时间:9:00~21:00)

快速回复 返回顶部 返回列表