找回密码
 立即注册
首页 业界区 业界 Silverlight MMORPG网页游戏开发课程[一期] 第三课:封 ...

Silverlight MMORPG网页游戏开发课程[一期] 第三课:封装游戏控件

瞧厨 2025-5-29 19:36:17
引言
实际游戏开发中我们肯定不会将所有逻辑代码都方在一个文件中,不仅不利于阅读最重要的是非常不利于拓展与重用。面向对象的游戏开发思想告诉我们,是时候对游戏中的对象进行封装了。
3.1通过用户控件(UserControl)封装游戏对象(交叉参考:精灵控件横空出世!①  精灵控件横空出世!②  )
在2.2节的基础上首先我们为解决方案添加一个新的项目:Controls(解决方案上右键->添加->新建项目->Silverlight类库)。默认该项目中会包含一个Class1.cs文件,我们删除掉它。(注:解决方案中项目与项目之间交互必须添加引用,例如在MainPage中要使用Controls项目中的控件,那么我们需要在MainPage所在的项目上点右键->添加引用->项目->Controls->确定;后续课程还有创建新的项目,使用方法同样。)
关键时刻到了,在刚新建好的Controls项目上点击右键->添加->新建项,此时我们选择Silverlight用户控件并取名为Sprite。Sprite(精灵) - 游戏中第一个伟大的对象控件诞生了。
当然首先要做的还是把Sprite.xaml中的Grid换成Canvas,然后将2.2中关于精灵的所有逻辑代码均放进Sprite控件中以实现独立封装,转移及修改内容如下:
1)同创建Controls项目一样的方式创建一个游戏逻辑类库Logic,接下来在其中再新建一个名Enum的文件夹以保存枚举类型,创建两个枚举类分别为:SpriteDirection.cs(精灵朝向)和SpriteState.cs(精灵状态):
    /// 
    /// 精灵朝向
    /// 
    public enum SpriteDirection {
        North = 0,
        NorthEast = 1,
        East = 2,
        SouthEast = 3,
        South = 4,
        SouthWest = 5,
        West = 6,
        NorthWest = 7
    }    /// 
    /// 精灵状态
    /// 
    public enum SpriteState {
        /// 
        /// 站立(停止)
        /// 
        Stand = 0,
        /// 
        /// 跑动(移动)
        /// 
        Run = 1,
        /// 
        /// 攻击(物理)
        /// 
        Attack = 2,
        /// 
        /// 施法(魔法)
        /// 
        Casting = 3,
        /// 
        /// 无
        /// 
        None = 9,
    }    枚举类型不仅直观而且使用起来非常方便,后面的课程大家会逐渐感受到它非凡的魔力。
2)移植原先MainPage中关于精灵的所有属性到Sprite控件内部并公开:

1.gif
2.gif
代码         #region 属性

        /// 
        /// 获取或设置速度系数
        /// 
        public double Speed { get; set; }

        /// 
        /// 获取或设置脚底中心
        /// 
        public Point Center { get; set; }

        /// 
        /// 获取或设置朝向
        /// 
        public SpriteDirection Direction { get; set; }

        /// 
        /// 获取或设置状态
        /// 
        public SpriteState State { get; set; }

        #endregion
    3)移植原先MainPage中的精灵动作动画计时器及相关实行方法到精灵内部:



3.gif
4.gif
代码         Image body = new Image();

        DispatcherTimer dispatcherTimer = new DispatcherTimer() {
            Interval = TimeSpan.FromMilliseconds(120)
        };

        public Sprite() {
            this.Children.Add(body);
            Stand();
            dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
            dispatcherTimer.Start();
        }

        int currentFrame, startFrame, endFrame;
        void dispatcherTimer_Tick(object sender, EventArgs e) {
            if (currentFrame > endFrame) { currentFrame = startFrame; }
            body.Source = new BitmapImage(new Uri(string.Format(@"/{0};component/Res/Sprite/{1}-{2}-{3}.png", Global.ProjectName, (int)State, (int)Direction, currentFrame), UriKind.Relative));
            currentFrame++;
        }        #region 方法

        /// 
        /// 计算当前坐标与目标点之间的正切值以获取朝向
        /// 
        /// 当前坐标
        /// 目标坐标
        /// 朝向代号
        public void SetDirection(Point current, Point target) {
            double tan = (target.Y - current.Y) / (target.X - current.X);
            if (Math.Abs(tan) >= Math.Tan(Math.PI * 3 / 8) && target.Y  Math.Tan(Math.PI / 8) && Math.Abs(tan)  current.X && target.Y  Math.Tan(Math.PI / 8) && Math.Abs(tan)  current.X && target.Y > current.Y) {
                Direction = SpriteDirection.SouthEast;
            } else if (Math.Abs(tan) >= Math.Tan(Math.PI * 3 / 8) && target.Y >= current.Y) {
                Direction = SpriteDirection.South;
            } else if (Math.Abs(tan) > Math.Tan(Math.PI / 8) && Math.Abs(tan) 
您需要登录后才可以回帖 登录 | 立即注册