从无到有写一个C#弹球小游戏(二)

父类写完之后,考虑子类应该怎么写。

最简单的子类:砖块类,砖块类基本上没有什么新的字段和方法,不过为了方便画图,我加了一部分常量字段。顺便说一句,C#里常量字段默认是静态的,可是操作常量字段的get和set访问器得自己显示的定义为静态。

上代码:

using System.Drawing;

namespace 弹球
{
    /// 
    /// 方块:弹球世界中的矩形物体,被撞击后消失
    /// 
    class Block : Actor
    {
        /// 
        /// 方块的宽度
        /// 
        private const int width = 50;

        /// 
        /// 获取方块的宽度
        /// 
        public static int Width
        {
            get { return width; }
        }

        /// 
        /// 方块的高度
        /// 
        private const int height = 10;

        /// 
        /// 获取方块的高度
        /// 
        public static int Height
        {
            get { return height; }
        }

        public Block()
        { }

        /// 
        /// 构造函数:设置方块的左上角顶点位置
        /// 
        /// 
        /// 
        /// 
        /// 
        public Block(int iX, int iY)
        {
            PositionBounds.SetBounds(iX, iY, Block.width, Block.height);
            CollisionBounds.SetBounds(iX, iY, Block.width, Block.height);

            MoveBounds.SetBounds(0, 0, 0, 0);
        }

        /// 
        /// 绘制方块
        /// 
        /// 
        public override void Draw(Graphics g)
        {
            g.FillRectangle(new SolidBrush(Color.Black), new Rectangle(PositionBounds.Left, PositionBounds.Top, Block.width, Block.height));
            g.DrawRectangle(Pens.White, new Rectangle(PositionBounds.Left, PositionBounds.Top, Block.width, Block.height));
        }

        public override void Update()
        {
            //该物体不更新信息
        }
    }
}
然后写球拍类,这个类相当于在基类的基础上新增一个移动方向,并且定义了自己的update()方法用来更新信息,其实球拍的移动就是更新了位置信息(包括碰撞)。

相应的我也给这个类写了几个静态字段用来表示球拍的一些参数,以后如果要修改这些参数的话只需要改一个部分就行了。

代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace 弹球
{
    /// 
    /// 拍子:玩家通过拍子使弹球反弹,击打砖块
    /// 
    class Paddle : Actor
    {
        /// 
        /// 拍子的宽度
        /// 
        private const int width = 80;

        /// 
        /// 获取拍子的宽度
        /// 
        public static int Width
        {
            get { return width; }
        }

        /// 
        /// 拍子的高度
        /// 
        private const int height = 10;

        /// 
        /// 获取拍子的高度
        /// 
        public static int Height
        {
            get { return height; }
        }

        /// 
        /// 拍子的移动方向,有三种情况,大于0为向右,小于0为向左,等于0为不移动,初始情况不移动
        /// 
        private Direction direction;

        /// 
        /// 获取和设置拍子的移动方向:大于0为向右,小于0为向左,等于0为不移动,初始情况不移动
        /// 
        public Direction Direction
        {
            get { return direction; }
            set { direction = value; }
        }

        /// 
        /// 拍子的速度
        /// 
        private const int speed = 20;

        /// 
        /// 获取拍子的移动速度:为10像素点
        /// 
        public static int Speed
        {
            get { return speed; }
        } 


        public Paddle()
        { }

        /// 
        /// 构造函数:根据左上方顶点信息和左右移动边界创建拍子
        /// 
        /// 
        /// 
        /// 
        /// 
        public Paddle(int iX, int iY, int iBoundsX, int iBoundsY, int iBoundsWidth, int iBoundsHeight)
        {
            PositionBounds.SetBounds(iX, iY, Paddle.width, Paddle.height);
            CollisionBounds.SetBounds(iX, iY, Paddle.width, Paddle.height);

            MoveBounds.SetBounds(iBoundsX, iBoundsY, iBoundsWidth, iBoundsHeight);

            direction = Direction.None;
        }

        public override void Draw(System.Drawing.Graphics g)
        {
            g.FillRectangle(new SolidBrush(Color.Yellow), new Rectangle(PositionBounds.Left, PositionBounds.Top, width, height));
            g.DrawRectangle(Pens.White, new Rectangle(PositionBounds.Left, PositionBounds.Top, width, height));

            //调试语句,绘制碰撞边界
            //g.DrawRectangle(Pens.Red, new Rectangle(CollisionBounds.Left, CollisionBounds.Top, width, height));
        }

        public override void Update()
        {
            //更新位置信息
            if (this.Direction == Direction.Left &&
                ((this.CollisionBounds.Left - Paddle.Speed) >= (MainWin.PlayerBounds.Left)))
            {
                this.MoveRight(-Paddle.Speed);
            }
            if (this.Direction == Direction.Right &&
                ((this.CollisionBounds.Right + Paddle.Speed) <= (MainWin.PlayerBounds.Right)))
            {
                this.MoveRight(Paddle.Speed);
            }
            this.Direction = Direction.None;
        }
    }
}
接下来就是最复杂的一个类了,其实也谈不上多么复杂,球这个东西除了子类具有的陈员外,还有一个矢量速度,和速度的绝对值这两个静态方法,同样是为了以后好修改,所以矢量速度的长度总是等于1,需要修改速度的话改绝对值大小就行。另外,为了给游戏增加一点变数,让它更好玩,所以球的初始速度包含一个随机值确定。代码如下:
        private void CreateRandomVector(vector2D Vector)
        {
            Random rand = new Random();
            Vector.setValue(rand.NextDouble() + 1, rand.NextDouble() + 1);
        }
这样的话能够保证球大致的方向是右下角,而且是在一个范围内随机的。

全部代码如下:

using System;
using System.Drawing;

namespace 弹球
{
    class Ball : Actor
    {
        /// 
        /// 球的大小
        /// 
        private const int size = 10;

        /// 
        /// 静态属性:获取球的大小
        /// 
        public static int Size
        {
            get { return size; }
        } 


        /// 
        /// 球运动的方向
        /// 
        public vector2D Vector;

        /// 
        /// 球运动的速度
        /// 
        public const int Speed = 5;

        public Ball()
        { }

        /// 
        /// 根据顶点位置,移动边界信息创建一个球
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public Ball(int iX, int iY, int iBoundsX, int iBoundsY, int iBoundsWidth, int iBoundsHeight)
        {
            PositionBounds.SetBounds(iX, iY, size, size);
            CollisionBounds.SetBounds(iX, iY, size, size);

            MoveBounds.SetBounds(iBoundsX, iBoundsY, iBoundsWidth, iBoundsHeight);

            //随机设置方向
            CreateRandomVector(Vector);
        }

        public Ball(int iX, int iY, Bounds OtherBounds)
        {
            PositionBounds.SetBounds(iX, iY, size, size);
            CollisionBounds.SetBounds(iX, iY, size, size);

            MoveBounds.SetBounds(OtherBounds);

            //随机设置方向
            CreateRandomVector(Vector);
        }

        private void CreateRandomVector(vector2D Vector)
        {
            Random rand = new Random();
            Vector.setValue(rand.NextDouble() + 1, rand.NextDouble() + 1);
        }

        public void Move()
        {
            CollisionBounds.Move(Vector, Speed);
            PositionBounds.Move(Vector, Speed);
        }

        /// 
        /// 绘制球
        /// 
        /// 
        public override void Draw(System.Drawing.Graphics g)
        {
            g.FillEllipse(Brushes.Red, new Rectangle(PositionBounds.Left, PositionBounds.Top, Size, Size));
        }

        public override void Update()
        {
            //更新位置
            Bounds newPosition = new Bounds(this.PositionBounds);
            newPosition.Move(Vector, Speed);

            //检测是否碰撞到了边界
            if ((newPosition.Left < this.MoveBounds.Left))
            {
                newPosition.Left = this.MoveBounds.Left;
                newPosition.Right = this.MoveBounds.Left + Ball.Size;
                this.Vector.NegateX();
            }
            else if (newPosition.Right > this.MoveBounds.Right)
            {
                newPosition.Right = this.MoveBounds.Right;
                newPosition.Left = this.MoveBounds.Right - Ball.Size;
                this.Vector.NegateX();
            }
            if (newPosition.Top < this.MoveBounds.Top)
            {
                newPosition.Top = this.MoveBounds.Top;
                newPosition.Bottom = this.MoveBounds.Top + Ball.Size;
                this.Vector.NegateY();
            }
            else if (newPosition.Bottom > this.MoveBounds.Bottom)
            {
                newPosition.Bottom = this.MoveBounds.Bottom;
                newPosition.Top = this.MoveBounds.Bottom - Ball.Size;
                this.Vector.NegateY();
            }

            this.PositionBounds.SetBounds(newPosition);
            this.CollisionBounds.SetBounds(newPosition);
        }
    }

    /// 
    /// 二维向量,用来表示平面上的方向,只有方向,没有大小
    /// 
    public struct vector2D
    {
        /// 
        /// 横向的值
        /// 
        private double x;

        /// 
        /// 获得横向的值
        /// 
        public double X
        {
            get { return x; }
        }

        /// 
        /// 将横向值取反
        /// 
        public void NegateX()
        {
            x = -x;
        }

        /// 
        /// 纵向的值
        /// 
        private double y;

        /// 
        /// 将纵向值取反
        /// 
        public void NegateY()
        {
            y = -y;
        }

        /// 
        /// 获得纵向的值
        /// 
        public double Y
        {
            get { return y; }
        }


        /// 
        /// 构造函数:向量为单位长度,参数只代表方向
        /// 
        /// 
        /// 
        public vector2D(double iX, double iY)
        {
            double length = Math.Sqrt(iX*iX + iY*iY);
            x = iX/length;
            y = iY/length;
        }

        /// 
        /// 注意:向量为单位长度
        /// 
        /// 
        /// 
        public void setValue(double iX, double iY)
        {
            double length = Math.Sqrt(iX * iX + iY * iY);
            x = iX / length;
            y = iY / length;
        }
    }
}
现在这个游戏的class彻底完成了,然而如何组织各种不同的类才是最重要的。

你可能感兴趣的:(C#,c#,弹球,面向对象)