c#GDI+游戏编程:《疯狂的炸弹之幽灵之战v1.0》角色动画、绘制、走动 . | 学步园

/*_______________________________________________________________

动画的原理就是连续绘制/播放图片,当每秒绘制/播放不同表情、动作图片一定幅数的时候就是造成视觉错觉,就会看到很流畅的动画效果!有了动画,物体才有了灵魂和生命。

游戏对象分析:

游戏中只有一部分对象是有生命的,主要包括主角和幽灵等。下面先看下游戏的结构图:

可以看到游戏主要分为2个部分,静止的对象和活动的对象,大家都继承一个基类,基类有一个抽象方法,就是绘制,所有的对象必须重写绘制方法以呈现自己的画面。

BaseEntity

  1. public abstract class BaseEntity
  2. {
  3. /// <summary>
  4. /// 对象坐标
  5. /// </summary>
  6. public Point Poi;
  7. /// <summary>
  8. ///  绘制对象
  9. /// </summary>
  10. public abstract void Draw(Graphics g);
  11. }

以游戏中炸弹的绘制为例,代码如下:

Bomb

  1. /// <summary>
  2. /// 炸弹
  3. /// </summary>
  4. public class Bomb : BaseEntity
  5. {
  6. //爆炸延迟时间
  7. public int ExplodeDelay = 50;
  8. Bitmap[] bmps = new Bitmap[Utility.BombFrames];
  9. /// <summary>
  10. /// 默认从资源初始化数据
  11. /// </summary>
  12. public Bomb()
  13. {
  14. bmps = InitResources.Instance.InitStaticObjects(
  15. Utility.BombValue,
  16. Utility.BombFrames,
  17. new Size(Utility.BombSizeWidth, Utility.BombSizeHeight),
  18. InitMode.FromResource);
  19. }
  20. private int i = 0;
  21. public override void Draw(Graphics g)
  22. {
  23. i = i + 1 < Utility.BombFrames ? i + 1 : 0;
  24. g.DrawImage(bmps[i], Poi.X, Poi.Y, Utility.GridSize,Utility.GridSize);
  25. }
  26. }

首先初始化炸弹素材,然后重写绘制方法,逐帧绘制,这样一个简单的动画效果就出现了!

区别于静止的对象,活动的对象自然会有自己运动的方法,比如移动、跳跃等动作,这也很简单,只是改变对象x,y坐标即可。游戏中的主角和怪物都是有生命的活动体,基本属性成员一致,所以定义一个ActivityEntity类,以便更好重用代码。

ActivityEntity

  1. /// <summary>
  2. /// 方向枚举
  3. /// </summary>
  4. public enum Direction
  5. {
  6. Left,   //向左
  7. Up,     //向上
  8. Right,  //向右
  9. Down,   //向下
  10. Static  //原地不动
  11. }
  12. /// <summary>
  13. /// 有生命的对象
  14. /// </summary>
  15. public class ActivityEntity:BaseEntity
  16. {
  17. //角色(包括主角和敌人)
  18. public string Role;
  19. //生命
  20. public int Life;
  21. //速度
  22. public int Speed=1;
  23. //方向
  24. public Direction Direction;
  25. //记录帧
  26. private int Frame=0;
  27. //存放角色行走图
  28. protected Bitmap[][] bmps = new Bitmap[Utility.RoleDirections][]
  29. {
  30. new Bitmap[Utility.RoleSteps], //下
  31. new Bitmap[Utility.RoleSteps], //左
  32. new Bitmap[Utility.RoleSteps], //右
  33. new Bitmap[Utility.RoleSteps]  //上
  34. };
  35. //默认从资源访问
  36. public ActivityEntity(string role)
  37. {
  38. if (!string.IsNullOrEmpty(role))
  39. {
  40. this.Role = role;
  41. InitActivityEntity(Role, InitMode.FromResource);
  42. }
  43. }
  44. public ActivityEntity(string role, InitMode mode)
  45. {
  46. if (!string.IsNullOrEmpty(role))
  47. {
  48. this.Role = role;
  49. InitActivityEntity(Role, mode);
  50. }
  51. }
  52. /// <summary>
  53. /// 初始化游戏角色
  54. /// </summary>
  55. /// <param name="role">角色名称</param>
  56. /// <param name="mode"></param>
  57. private void InitActivityEntity(string role, InitMode mode)
  58. {
  59. switch (mode)
  60. {
  61. case InitMode.FromResource:
  62. bmps = InitResources.Instance.InitActivityObjects(role, InitMode.FromResource);
  63. break;
  64. case InitMode.FromFilePath:
  65. if (System.IO.File.Exists(role))
  66. bmps = InitResources.Instance.InitActivityObjects(role, InitMode.FromFilePath);
  67. break;
  68. }
  69. }
  70. /// <summary>
  71. /// 角色移动
  72. /// </summary>
  73. public virtual void Move()
  74. {
  75. switch (Direction)
  76. {
  77. case Direction.Left:
  78. Poi.X -= Speed;
  79. break;
  80. case Direction.Up:
  81. Poi.Y -= Speed;
  82. break;
  83. case Direction.Right:
  84. Poi.X += Speed;
  85. break;
  86. case Direction.Down:
  87. Poi.Y += Speed;
  88. break;
  89. case Direction.Static:
  90. break;
  91. }
  92. }
  93. /// <summary>
  94. /// 记录帧
  95. /// </summary>
  96. public void RecordFrame()
  97. {
  98. switch (Direction)
  99. {
  100. case Direction.Left:
  101. Frame = 1;
  102. break;
  103. case Direction.Up:
  104. Frame = 3;
  105. break;
  106. case Direction.Right:
  107. Frame = 2;
  108. break;
  109. case Direction.Down:
  110. Frame = 0;
  111. break;
  112. case Direction.Static:
  113. break;
  114. }
  115. }
  116. /// <summary>
  117. /// 重写绘制对象方法
  118. /// </summary>
  119. private int i = 0;
  120. public override void Draw(Graphics g)
  121. {
  122. switch (Direction)
  123. {
  124. case Direction.Down:
  125. case Direction.Left:
  126. case Direction.Right:
  127. case Direction.Up:
  128. i = i + 1 < Utility.RoleSteps ? i + 1 : 0;
  129. break;
  130. case Direction.Static:
  131. i = 0;
  132. break;
  133. }
  134. g.DrawImage(bmps[Frame][i], Poi.X, Poi.Y, Utility.GridSize, Utility.GridSize);
  135. }
  136. }

可以看到Move()方法就是根据不同方向改变对象的x,y,这样简单的几句我们的主角就可以移动了。以主角为例:

Actor

  1. /// <summary>
  2. /// 游戏主角
  3. /// </summary>
  4. public class Actor : ActivityEntity
  5. {
  6. //财富
  7. public int Money;
  8. public Actor()
  9. : base(Utility.ActorValue)
  10. {
  11. }
  12. public Actor(string role, InitMode mode)
  13. : base(role, mode)
  14. { }
  15. public void Move(bool passable)
  16. {
  17. if (passable)
  18. {
  19. base.Move();
  20. base.RecordFrame();
  21. }
  22. else
  23. {
  24. base.RecordFrame();
  25. }
  26. }
  27. }

继承活动体,并重载了Move()方法,这个方法主要是实现如果没有障碍物,则移动并实现主角动画;反之只记录帧。

效果图:(看不到效果保存到本地浏览)

(0)

相关推荐