游戏人生Silverlight:星际竞技场

开发 后端
使用 Silverlight 2.0(c#, Farseer Physics Engine) 开发一个射击游戏:星际竞技场。思路:使用一个开源的 Silverlight 物理引擎:Farseer Physics Engine.....

介绍

使用 Silverlight 2.0(c#, Farseer Physics Engine) 开发一个射击游戏:星际竞技场

玩法

W 或者 ↑ = 前进;S 或者 ↓ = 后退:A 或者 ← = 左转;D 或者 → = 右转;J 或者 Ctrl = 开火

思路

1、使用一个开源的 Silverlight 物理引擎:Farseer Physics Engine

2、将 Farseer Physics Engine 中的物理运算器 PhysicsSimulator 放到一个全局变量中,对 Body 和 Geom 做即时运算,

3、写个 IPhysicsControl 接口,用于描述物理对象的各个属性,需要运动和碰撞的对象,要实现该接口抽象出来的各个属性

4、写个抽象类(Sprite),在其内封装好物理引擎。各种类型的物理对象的模拟器,都需要重写该抽象类的两个方法GetForce()和GetTorque()即可,其分别要返回对象在当前时刻所受到的牵引力和力矩

5、写个 IFire 接口,所有可开火的对象都要实现该接口

6、写个控件 PhysicsBox,用于包装 IPhysicsControl,从而将模拟器计算出的运动和碰撞结果呈现到界面上

关键代码Sprite.cs(Sprite 模拟器的基类)

  1. using System;  
  2. using System.Net;  
  3. using System.Windows;  
  4. using System.Windows.Controls;  
  5. using System.Windows.Documents;  
  6. using System.Windows.Ink;  
  7. using System.Windows.Input;  
  8. using System.Windows.Media;  
  9. using System.Windows.Media.Animation;  
  10. using System.Windows.Shapes;  
  11.  
  12. using FarseerGames.FarseerPhysics;  
  13. using FarseerGames.FarseerPhysics.Mathematics;  
  14. using FarseerGames.FarseerPhysics.Dynamics;  
  15. using FarseerGames.FarseerPhysics.Collisions;  
  16.  
  17. namespace YYArena.Core  
  18. {  
  19.     /**//// <summary> 
  20.     /// Sprite 基类  
  21.     /// </summary> 
  22.     public abstract class Sprite  
  23.     {  
  24.         private PhysicsSimulator _physicsSimulator;  
  25.  
  26.         protected PhysicsBox playerBox;  
  27.         protected Geom playerGeometry;  
  28.  
  29.         /**//// <summary> 
  30.         /// 构造函数  
  31.         /// </summary> 
  32.         /// <param name="physicsSimulator">PhysicsSimulator</param> 
  33.         /// <param name="physicsControl">IPhysicsControl</param> 
  34.         /// <param name="position">初始位置</param> 
  35.         /// <param name="angle">初始转角</param> 
  36.         /// <param name="originalVelocity">初始速度</param> 
  37.         public Sprite(PhysicsSimulator physicsSimulator,  
  38.             IPhysicsControl physicsControl, Vector2 position, float angle, float originalVelocity)  
  39.         {  
  40.             _physicsSimulator = physicsSimulator;  
  41.  
  42.             playerBox = new PhysicsBox(physicsControl);  
  43.             playerBox.Body.Position = position;  
  44.             playerBox.Body.Rotation = (float)Helper.Angle2Radian(angle);  
  45.             playerBox.Body.LinearVelocity = Helper.Convert2Vector(originalVelocity, (float)Helper.Angle2Radian(angle));  
  46.  
  47.             // Body 和 Geom 的 Tag 保存为 Sprite,方便引用  
  48.             playerBox.Body.Tag = this;  
  49.             playerBox.Geom.Tag = this;  
  50.  
  51.             playerBox.Update();  
  52.         }  
  53.  
  54.         /**//// <summary> 
  55.         /// 即时计算力和力矩  
  56.         /// </summary> 
  57.         void CompositionTarget_Rendering(object sender, EventArgs e)  
  58.         {  
  59.             if (Enabled)  
  60.             {  
  61.                 var force = GetForce();  
  62.                 var torque = GetTorque();  
  63.  
  64.                 playerBox.Body.ApplyForce(force);  
  65.                 playerBox.Body.ApplyTorque(torque);  
  66.  
  67.                 playerBox.Update();  
  68.             }  
  69.         }  
  70.  
  71.         /**//// <summary> 
  72.         /// 返回 Sprite 当前受的力  
  73.         /// </summary> 
  74.         protected abstract Vector2 GetForce();  
  75.         /**//// <summary> 
  76.         /// 返回 Sprite 当前受的力矩  
  77.         /// </summary> 
  78.         protected abstract float GetTorque();  
  79.  
  80.         public PhysicsBox PhysicsBox  
  81.         {  
  82.             get { return playerBox; }  
  83.         }  
  84.  
  85.         private bool _enabled = false;  
  86.         /**//// <summary> 
  87.         /// 是否启用此 Sprite  
  88.         /// </summary> 
  89.         public bool Enabled  
  90.         {  
  91.             get { return _enabled; }  
  92.             set  
  93.             {   
  94.                 _enabled = value;  
  95.  
  96.                 if (value)  
  97.                 {  
  98.                     CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);  
  99.  
  100.                     _physicsSimulator.Add(playerBox.Body);  
  101.                     _physicsSimulator.Add(playerBox.Geom);  
  102.                 }  
  103.                 else  
  104.                 {  
  105.                     CompositionTarget.Rendering -new EventHandler(CompositionTarget_Rendering);  
  106.  
  107.                     GC.SuppressFinalize(this);  
  108.                     _physicsSimulator.Remove(playerBox.Body);  
  109.                     _physicsSimulator.Remove(playerBox.Geom);  
  110.                 }  
  111.             }  
  112.         }  
  113.     }  

#p#

PlayerSprite.cs(玩家 Sprite 模拟器)

  1. using System;  
  2. using System.Net;  
  3. using System.Windows;  
  4. using System.Windows.Controls;  
  5. using System.Windows.Documents;  
  6. using System.Windows.Ink;  
  7. using System.Windows.Input;  
  8. using System.Windows.Media;  
  9. using System.Windows.Media.Animation;  
  10. using System.Windows.Shapes;  
  11.  
  12. using System.Collections.Generic;  
  13. using FarseerGames.FarseerPhysics.Mathematics;  
  14. using FarseerGames.FarseerPhysics;  
  15. using FarseerGames.FarseerPhysics.Collisions;  
  16.  
  17. namespace YYArena.Core  
  18. {  
  19.     /**//// <summary> 
  20.     /// 玩家 Sprite  
  21.     /// </summary> 
  22.     public class PlayerSprite : Sprite, IFire  
  23.     {  
  24.         private List<Key> _upKeys { get; set; }  
  25.         private List<Key> _downKeys { get; set; }  
  26.         private List<Key> _leftKeys { get; set; }  
  27.         private List<Key> _rightKeys { get; set; }  
  28.         private List<Key> _fireKeys { get; set; }  
  29.  
  30.         private KeyboardHandler _keyHandler;  
  31.         private IPhysicsControl _physicsControl;  
  32.  
  33.         /**//// <summary> 
  34.         /// 构造函数  
  35.         /// </summary> 
  36.         /// <param name="physicsSimulator">PhysicsSimulator</param> 
  37.         /// <param name="physicsControl">IPhysicsControl</param> 
  38.         /// <param name="position">初始位置</param> 
  39.         /// <param name="angle">初始转角</param> 
  40.         /// <param name="originalVelocity">初始速度</param> 
  41.         /// <param name="keyboardHandler">KeyboardHandler</param> 
  42.         /// <param name="up">操作玩家向前移动的按键集合</param> 
  43.         /// <param name="down">操作玩家向后移动的按键集合</param> 
  44.         /// <param name="left">操作玩家向左转动的按键集合</param> 
  45.         /// <param name="right">操作玩家向右转动的按键集合</param> 
  46.         /// <param name="fire">操作玩家开火的按键集合</param> 
  47.         public PlayerSprite(PhysicsSimulator physicsSimulator,  
  48.             IPhysicsControl physicsControl, Vector2 position, float angle, float originalVelocity,  
  49.             KeyboardHandler keyboardHandler,  
  50.             List<Key> up, List<Key> down, List<Key> left, List<Key> right, List<Key> fire)  
  51.             : base(physicsSimulator, physicsControl, position, angle, originalVelocity)  
  52.         {  
  53.             PrevFireDateTime = DateTime.MinValue;  
  54.             MinFireInterval = 500d;  
  55.  
  56.             _upKeys = up;  
  57.             _downKeys = down;  
  58.             _leftKeys = left;  
  59.             _rightKeys = right;  
  60.             _fireKeys = fire;  
  61.  
  62.             _keyHandler = keyboardHandler;  
  63.             _physicsControl = physicsControl;  
  64.  
  65.             CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);  
  66.         }  
  67.  
  68.         void CompositionTarget_Rendering(object sender, EventArgs e)  
  69.         {  
  70.             if (Enabled)  
  71.             {  
  72.                 // 如果按了开火键,是否可开火  
  73.                 if (_keyHandler.AnyKeyPressed(_fireKeys) && (DateTime.Now - PrevFireDateTime).TotalMilliseconds > MinFireInterval)  
  74.                 {  
  75.                     PrevFireDateTime = DateTime.Now;  
  76.                     if (Fire != null)  
  77.                         Fire(this, EventArgs.Empty);  
  78.                 }  
  79.             }  
  80.         }  
  81.  
  82.         public DateTime PrevFireDateTime { get; set; }  
  83.  
  84.         public double MinFireInterval { get; set; }  
  85.  
  86.         public event EventHandler<EventArgs> Fire;  
  87.  
  88.         protected override Vector2 GetForce()  
  89.         {  
  90.             Vector2 force = Vector2.Zero;  
  91.  
  92.             if (_keyHandler.AnyKeyPressed(_upKeys))  
  93.                 force += Helper.Convert2Vector(_physicsControl.ForceAmount, playerBox.Body.Rotation);  
  94.             if (_keyHandler.AnyKeyPressed(_downKeys))  
  95.                 force += Helper.Convert2Vector(_physicsControl.ForceAmount, playerBox.Body.Rotation - Helper.Angle2Radian(180));  
  96.  
  97.             // 最大线性速度限制  
  98.             if (playerBox.Body.LinearVelocity.Length() > _physicsControl.MaxLinearVelocity)  
  99.                 force = Vector2.Zero;  
  100.  
  101.             return force;  
  102.         }  
  103.  
  104.         protected override float GetTorque()  
  105.         {  
  106.             float torque = 0;  
  107.  
  108.             if (_keyHandler.AnyKeyPressed(_leftKeys))  
  109.                 torque -_physicsControl.TorqueAmount;  
  110.             if (_keyHandler.AnyKeyPressed(_rightKeys))  
  111.                 torque += _physicsControl.TorqueAmount;  
  112.  
  113.             // 用于修正 RotationalDragCoefficient (在没有任何 Torque 的情况下,如果转速小于 1.3 则设其为 0)  
  114.             // 如果不做此修正的话,转速小于 1.3 后还会转好长时间  
  115.             if (!_keyHandler.AnyKeyPressed(_leftKeys) && !_keyHandler.AnyKeyPressed(_rightKeys) && Math.Abs(playerBox.Body.AngularVelocity) < 1.3)  
  116.                 playerBox.Body.AngularVelocity = 0;  
  117.  
  118.             // 最大转速限制  
  119.             if (Math.Abs(playerBox.Body.AngularVelocity) > _physicsControl.MaxAngularVelocity)  
  120.                 torque = 0;  
  121.  
  122.             return torque;  
  123.         }  
  124.     }  

#p#

AISprite.cs(敌军 Sprite 模拟器)

  1. using System;  
  2. using System.Net;  
  3. using System.Windows;  
  4. using System.Windows.Controls;  
  5. using System.Windows.Documents;  
  6. using System.Windows.Ink;  
  7. using System.Windows.Input;  
  8. using System.Windows.Media;  
  9. using System.Windows.Media.Animation;  
  10. using System.Windows.Shapes;  
  11.  
  12. using System.Collections.Generic;  
  13. using FarseerGames.FarseerPhysics.Mathematics;  
  14.  
  15. using FarseerGames.FarseerPhysics;  
  16. using FarseerGames.FarseerPhysics.Collisions;  
  17. using FarseerGames.FarseerPhysics.Dynamics;  
  18.  
  19. namespace YYArena.Core  
  20. {  
  21.     /**//// <summary> 
  22.     /// 敌军 Sprite  
  23.     /// </summary> 
  24.     public class AISprite : Sprite, IFire  
  25.     {  
  26.         private Sprite _attackTarget;  
  27.         private int _aiLevel;  
  28.         private IPhysicsControl _physicsControl;  
  29.  
  30.         /**//// <summary> 
  31.         /// 构造函数  
  32.         /// </summary> 
  33.         /// <param name="physicsSimulator">PhysicsSimulator</param> 
  34.         /// <param name="physicsControl">IPhysicsControl</param> 
  35.         /// <param name="position">初始位置</param> 
  36.         /// <param name="angle">初始转角</param> 
  37.         /// <param name="originalVelocity">初始速度</param> 
  38.         /// <param name="attackTarget">攻击目标</param> 
  39.         /// <param name="aiLevel">ai等级</param> 
  40.         public AISprite(PhysicsSimulator physicsSimulator,  
  41.             IPhysicsControl physicsControl, Vector2 position, float angle, float originalVelocity, Sprite attackTarget, int aiLevel)  
  42.             : base(physicsSimulator, physicsControl, position, angle, originalVelocity)  
  43.         {  
  44.             // 上次开火时间  
  45.             PrevFireDateTime = DateTime.Now.AddSeconds(3);  
  46.             // 最小开火间隔  
  47.             MinFireInterval = 3000d;  
  48.  
  49.             _attackTarget = attackTarget;  
  50.             _aiLevel = aiLevel;  
  51.             _physicsControl = physicsControl;  
  52.  
  53.             InitAI();  
  54.  
  55.             CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);  
  56.         }  
  57.  
  58.         private void InitAI()  
  59.         {  
  60.             // 根据 ai 等级设置最小开火间隔  
  61.             double fireCoefficient = 1 + 30 / _aiLevel;  
  62.             MinFireInterval = Helper.GenerateRandom((int)MinFireInterval, (int)(fireCoefficient * MinFireInterval));  
  63.         }  
  64.  
  65.         void CompositionTarget_Rendering(object sender, EventArgs e)  
  66.         {  
  67.             if (Enabled && AttackTarget.Enabled)  
  68.             {  
  69.                 // 是否开火  
  70.                 if ((DateTime.Now - PrevFireDateTime).TotalMilliseconds > MinFireInterval)  
  71.                 {  
  72.                     PrevFireDateTime = DateTime.Now;  
  73.  
  74.                     if (Fire != null)  
  75.                         Fire(this, EventArgs.Empty);  
  76.                 }  
  77.             }  
  78.         }  
  79.  
  80.         public DateTime PrevFireDateTime { get; set; }  
  81.  
  82.         public double MinFireInterval { get; set; }  
  83.  
  84.         public event EventHandler<EventArgs> Fire;  
  85.  
  86.  
  87.         public Sprite AttackTarget  
  88.         {  
  89.             get { return _attackTarget; }  
  90.             set { _attackTarget = value; }  
  91.         }  
  92.  
  93.         protected override Vector2 GetForce()  
  94.         {  
  95.             Vector2 force = Vector2.Zero;  
  96.  
  97.             if (!_attackTarget.Enabled)  
  98.                 return force;  
  99.  
  100.             force += Helper.Convert2Vector(_physicsControl.ForceAmount, playerBox.Body.Rotation);  
  101.  
  102.             // 根据 ai 等级做最大线性速度限制  
  103.             if (playerBox.Body.LinearVelocity.Length() > _physicsControl.MaxLinearVelocity * Helper.GenerateRandom(50, 200) / 1000)  
  104.                 force = Vector2.Zero;  
  105.  
  106.             return force;  
  107.         }  
  108.  
  109.         protected override float GetTorque()  
  110.         {  
  111.             float torque = 0f;  
  112.  
  113.             if (!_attackTarget.Enabled)  
  114.                 return torque;  
  115.  
  116.             // 按某个方向旋转,原则是以最小的旋转角度对准目标  
  117.             Vector2 relativePosition = _attackTarget.PhysicsBox.Body.Position - playerBox.Body.Position;  
  118.             double targetRotation = Helper.Convert2Rotation(relativePosition);  
  119.             double currentRotation = playerBox.Body.Rotation;  
  120.             double relativeAngle = Helper.Radian2Angle(targetRotation - currentRotation);  
  121.             if (relativeAngle < 0)  
  122.                 relativeAngle += 360;  
  123.  
  124.             if (relativeAngle > 1)  
  125.             {  
  126.                 if (relativeAngle < 180 && relativeAngle > 0)  
  127.                     torque += _physicsControl.TorqueAmount;  
  128.                 else if (relativeAngle > 180 && relativeAngle < 360)  
  129.                     torque -_physicsControl.TorqueAmount;  
  130.             }  
  131.             else  
  132.             {  
  133.                 playerBox.Body.AngularVelocity = 0;  
  134.             }  
  135.  
  136.  
  137.             // 最大转速限制  
  138.             if (Math.Abs(playerBox.Body.AngularVelocity) > _physicsControl.MaxAngularVelocity)  
  139.                 torque = 0;  
  140.              
  141.             return torque;  
  142.         }  
  143.     }  

[源码下载]

原文链接:http://www.cnblogs.com/webabcd/archive/2009/06/22/1508042.html

责任编辑:张伟 来源: webabcd的博客
相关推荐

2013-09-12 11:17:02

2014-10-31 15:43:02

华为智慧

2022-04-12 18:35:03

元宇宙

2012-06-05 14:42:57

Silverlight

2013-03-22 14:08:14

智能手表IT巨头竞技场

2024-04-22 08:40:00

LLM模型开源

2024-03-08 13:02:56

Claude 3GPT-4Opus

2024-03-27 15:37:24

2018-04-16 14:16:01

无人驾驶百度阿里巴巴

2011-06-24 15:20:48

2024-04-10 12:35:50

2011-02-21 17:15:14

SilverlightNEY

2012-05-24 15:49:35

HTML5

2017-07-17 13:10:07

人工智能uSensVR

2012-03-09 10:35:18

360可信网站Versign

2015-07-15 14:53:38

Windows 10游戏

2011-04-29 15:04:10

hpe 355cn

2012-06-20 13:16:35

欧洲杯华为黑莓

2011-09-15 15:49:54

笔记本评测
点赞
收藏

51CTO技术栈公众号