基于C#弹幕类射击游戏的实现——(一)概述

提到弹幕类游戏,想到的最多的应该是《东方Project》系列了吧
酷炫的弹幕酷炫的弹幕我只记得酷炫。。。。
今天我们也来实现一个仿制版,阉割版~

这个版本的目的是简单的理解游戏的基本实现,所以很多地方会出现写死或者设计不合理的

关于弹幕类游戏,有篇文章写的不错。我也就不重复写了
今天首先来实现以下辅助库,因为这些作为游戏的基石,还是很重要的
由于C#没有原生的Vector类(XNA有,但这里不打算用XNA)所以我们自己实现一个

public struct Vector2  
    {  
        public static readonly Vector2 Zero = new Vector2(0, 0);  
  
        public float X;  
        public float Y;  
  
        public Vector2(float x, float y)  
        {  
            this.X = x;  
            this.Y = y;  
        }  
  
        public Vector2(Vector2 v)  
        {  
            this.X = v.X;  
            this.Y = v.Y;  
        }  
  
        public override string ToString()  
        {  
            return "(" + X.ToString() + "," + Y.ToString() + ")";  
        }  
  
        public override bool Equals(object obj)  
        {  
            if (object.Equals(obj, null))  
            {  
                return false;  
            }  
  
            Vector2 v = (Vector2)obj;  
  
            return this.X == v.X && this.Y == v.Y;  
        }  
  
        public override int GetHashCode()  
        {  
            return X.GetHashCode() + Y.GetHashCode();  
        }  
  
        public void Normalize()  
        {  
            float m = this.X * this.X + this.Y * this.Y;  
  
            if (m < 0.00001f)  
            {  
                m = 1;  
            }  
  
            m = 1.0f / (float)Math.Sqrt((double)m);  
  
            X = X * m;  
            Y = Y * m;  
        }  
  
        public void Reverse()  
        {  
            this.X = -this.X;  
            this.Y = -this.Y;  
        }  
  
        public float Length()  
        {  
            return (float)Math.Sqrt(X * X + Y * Y);  
        }  
          
        public float Angle()  
        {  
            return (float)Math.Atan2(Y, X);  
        }  
          
        public float Angle(Vector2 vec)  
        {  
            Vector2 s = this;  
            s.Normalize();  
            vec.Normalize();  
            return (float)Math.Acos(Vector2.Dot(s, vec));  
        }  
          
        public void Rotate(float angle)  
        {  
            float x = X;  
            float y = Y;  
              
            x = X * (float)Math.Cos(angle) - Y * (float)Math.Sin(angle);  
            y = X * (float)Math.Sin(angle) + Y * (float)Math.Cos(angle);  
              
            X = x;  
            Y = y;  
        }  
  
        public static bool operator ==(Vector2 v1, Vector2 v2)  
        {  
            if (object.Equals(v1, null) || object.Equals(v2, null))  
            {  
                return object.Equals(v1, v2);  
            }  
  
            if (v1.X == v2.X)  
            {  
                return v1.Y == v2.Y;  
            }  
  
            return false;  
        }  
  
        public static bool operator !=(Vector2 v1, Vector2 v2)  
        {  
            if (object.Equals(v1, null) || object.Equals(v2, null))  
            {  
                return !object.Equals(v1, v2);  
            }  
  
            if (v1.X != v2.X || v1.Y != v2.Y)  
            {  
                return true;  
            }  
  
            return false;  
        }  
  
        public static Vector2 operator +(Vector2 v1, Vector2 v2)  
        {  
            return new Vector2(v1.X + v2.X, v1.Y + v2.Y);  
        }  
  
        public static Vector2 operator -(Vector2 v1, Vector2 v2)  
        {  
            return new Vector2(v1.X - v2.X, v1.Y - v2.Y);  
        }  
  
        public static Vector2 operator *(Vector2 v1, Vector2 v2)  
        {  
            return new Vector2(v1.X * v2.X, v1.Y * v2.Y);  
        }  
  
        public static Vector2 operator *(Vector2 v, float s)  
        {  
            return new Vector2(v.X * s, v.Y * s);  
        }  
  
        public static Vector2 operator *(float s, Vector2 v)  
        {  
            return new Vector2(v.X * s, v.Y * s);  
        }  
  
        public static Vector2 operator /(Vector2 v, float s)  
        {  
            if (Math.Abs(s) < float.MinValue)  
            {  
                return Vector2.Zero;  
            }  
  
            return new Vector2(v.X / s, v.Y / s);  
        }  
  
        public static Vector2 operator /(float s, Vector2 v)  
        {  
            if (Math.Abs(s) < float.MinValue)  
            {  
                return Vector2.Zero;  
            }  
  
            return new Vector2(v.X / s, v.Y / s);  
        }  
  
        public static Vector2 operator -(Vector2 v)  
        {  
            Vector2 vec;  
            vec.X = -v.X;  
            vec.Y = -v.Y;  
            return vec;  
        }  
  
        public static float Distance(Vector2 v1, Vector2 v2)  
        {  
            float x = v1.X - v2.X;  
            float y = v1.Y - v2.Y;  
            float total = x * x + y * y;  
            return (float)Math.Sqrt((double)total);  
        }  
  
        public static float Dot(Vector2 v1, Vector2 v2)  
        {  
            return v1.X * v2.X + v1.Y * v2.Y;  
        }  
  
        public static Vector2 Lerp(Vector2 min, Vector2 max, float value)  
        {  
            Vector2 v;  
            v.X = min.X + (max.X - min.X) * value;  
            v.Y = min.Y + (max.Y - min.Y) * value;  
            return v;  
        }  
    }

很简单,相应了Vector3和Vector4的实现没有给出,大体上一样的
另外,辅助库也很重要,因为子弹的运行轨迹,大多数需要数学公式进行计算的

public static class Helper  
    {  
        private static float[] mSinValue;  
        private static float[] mCosValue;  
          
        static Helper()  
        {  
            mSinValue = new float[360];  
            mCosValue = new float[360];  
              
            for ( float i = 0; i < 360.0f; i++ )  
            {  
                mSinValue[(int)i] = (float)Math.Sin(i * Data.Radian);  
                mCosValue[(int)i] = (float)Math.Cos(i * Data.Radian);  
            }  
        }  
          
        public static float FastSin(int angle)  
        {  
            angle = angle % 360;  
              
            if ( angle < 0 )  
            {  
                angle = -angle;  
                return -mSinValue[angle];  
            }  
              
            return mSinValue[angle];  
        }  
          
        public static float FastCos(int angle)  
        {  
            angle = angle % 360;  
              
            if ( angle < 0 )  
            {  
                angle = -angle;  
            }  
              
            return mCosValue[angle];  
        }  
          
        public static float Clamp(float value, float min, float max)  
        {  
            if ( value < min )  
            {  
                return min;  
            }  
            if ( value > max )  
            {  
                return max;  
            }  
            return value;  
        }  
          
        public static float GetRandomFloat(float min, float max)  
        {  
            return min + (float)Data.Rnd.NextDouble() * (max - min);  
        }  
          
        public static bool GetRandomBool()  
        {  
            return Data.Rnd.NextDouble() <= 0.5f;  
        }  
          
        public static int GetRandomInt(int min, int max)  
        {  
            return Data.Rnd.Next(min, max);  
        }  
          
        public static Vector2 GetRandomPosition(float left, float right, float top, float bottom)  
        {  
            return new Vector2(GetRandomFloat(left, right), GetRandomFloat(top, bottom));  
        }  
          
        public static Vector2 GetRandomVector(float xMin, float xMax, float yMin, float yMax)  
        {  
            return new Vector2(GetRandomFloat(xMin, xMax), GetRandomFloat(yMin, yMax));  
        }  
          
        public static Vector2 GetSpeedWithAngle(int angle, float speed)  
        {  
            float x = Helper.FastCos(angle) * speed;  
            float y = Helper.FastSin(angle) * speed;  
              
            return new Vector2(x, y);  
        }  
  
        public static Vector2 GetSpeedWithPosition(Vector2 start, Vector2 end, float speed)  
        {  
            Vector2 result = (end - start);  
            result.Normalize();  
            return result * speed;  
        }  
    }

还有一个类似于XNA中Rectangle的类,用于做碰撞盒的

/// <summary>  
    /// 矩形盒子  
    /// </summary>  
    public struct Box  
    {  
        public static readonly Box Zero = new Box(0, 0, 0, 0);  
  
        private int mX;  
        private int mY;  
        private int mWidth;  
        private int mHeight;  
        private int mHalfWidth;  
        private int mHalfHeight;  
  
        public int X  
        {  
            get  
            {  
                return mX;  
            }  
            set  
            {  
                mX = value;  
            }  
        }  
        public int Y  
        {  
            get  
            {  
                return mY;  
            }  
            set  
            {  
                mY = value;  
            }  
        }  
        public int Width  
        {  
            get  
            {  
                return mWidth;  
            }  
            set  
            {  
                mWidth = value;  
                mHalfWidth = value / 2;  
            }  
        }  
        public int Height  
        {  
            get  
            {  
                return mHeight;  
            }  
            set  
            {  
                mHeight = value;  
                mHalfHeight = value / 2;  
            }  
        }  
  
        public int Left  
        {  
            get  
            {  
                return mX - mHalfWidth;  
            }  
        }  
  
        public int Right  
        {  
            get  
            {  
                return mX + mHalfWidth;  
            }  
        }  
  
        public int Top  
        {  
            get  
            {  
                return mY - mHalfHeight;  
            }  
        }  
  
        public int Bottom  
        {  
            get  
            {  
                return mY + mHalfHeight;  
            }  
        }  
  
        public Box(int x, int y, int width, int height)  
        {  
            this.mX = x;  
            this.mY = y;  
            this.mWidth = width;  
            this.mHeight = height;  
            this.mHalfWidth = width / 2;  
            this.mHalfHeight = height / 2;  
        }  
  
        public Box(Box v)  
        {  
            this.mX = v.mX;  
            this.mY = v.mY;  
            this.mWidth = v.mWidth;  
            this.mHeight = v.mHeight;  
            this.mHalfWidth = v.mHalfWidth;  
            this.mHalfHeight = v.mHalfHeight;  
        }  
  
        public override string ToString()  
        {  
            return "(" + mX.ToString() + "," + mY.ToString() + "," + mWidth.ToString() + "," + mHeight.ToString() + ")";  
        }  
  
        public Rectangle ToRectangle()  
        {  
            return new Rectangle(this.mX - mHalfWidth, this.mY - mHalfHeight, this.mWidth, this.mHeight);  
        }  
  
        public override bool Equals(object obj)  
        {  
            if (object.Equals(obj, null))  
            {  
                return false;  
            }  
  
            Box v = (Box)obj;  
  
            return this.mX == v.mX && this.mY == v.mY && this.mWidth == v.mWidth && this.mHeight == v.mHeight;  
        }  
  
        public override int GetHashCode()  
        {  
            return mX.GetHashCode() + mY.GetHashCode() + mWidth.GetHashCode() + mHeight.GetHashCode();  
        }  
  
        public static bool operator ==(Box v1, Box v2)  
        {  
            if (object.Equals(v1, null) || object.Equals(v2, null))  
            {  
                return object.Equals(v1, v2);  
            }  
  
            if (v1.mX == v2.mX)  
            {  
                return v1.mY == v2.mY && v1.mWidth == v2.mHeight && v1.mHeight == v2.mHeight;  
            }  
  
            return false;  
        }  
  
        public static bool operator !=(Box v1, Box v2)  
        {  
            if (object.Equals(v1, null) || object.Equals(v2, null))  
            {  
                return !object.Equals(v1, v2);  
            }  
  
            if (v1.mX != v2.mX || v1.mY != v2.mY || v1.mWidth != v2.mWidth || v1.Height != v2.mHeight)  
            {  
                return true;  
            }  
  
            return false;  
        }  
  
        public bool Contains(int x, int y)  
        {  
            if (Math.Abs(x - mX) < mHalfWidth && Math.Abs(y - mY) < mHalfHeight)  
            {  
                return true;  
            }  
              
            return false;  
        }  
  
        public bool Contains(GPoint p)  
        {  
            return Contains(p.X, p.Y);  
        }  
  
        public bool Collide(Box box)  
        {  
            if (this.Left > box.Right || this.Right < box.Left)  
            {  
                return false;  
            }  
            if (this.Top > box.Bottom || this.Bottom < box.Top)  
            {  
                return false;  
            }  
            return true;  
        }  
  
        public static bool Collide(Box box1, Box box2)  
        {  
            return box1.Collide(box2);  
        }  
    } 

大体上用的比较多的就是这三个类了,其余的都不算重要
而且这三个类很简单,不需要太多的说明,下一章开始进入游戏逻辑代码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容