首页 » .NET » c# 手把手教你撸一个吃鸡游戏跑圈机制

c# 手把手教你撸一个吃鸡游戏跑圈机制

原文 http://blog.csdn.net/qq_35561857/article/details/79182790

2018-01-30 02:00:24阅读(506)

 最近迷上吃鸡游戏,慢慢对他的跑圈机制产生了兴趣,于是就试着写了个吃鸡游戏跑圈机制出来~~~

一、话不多少,先上跑圈效果图:

c# 手把手教你撸一个吃鸡游戏跑圈机制


二、知识提要:  1.C# winform程序中比较简单的绘图控件就是 PictureBox。

 用到的主要辅助类有:Bitmap,Graphics,Brush,Pen。用形象的方式介绍下他们:PictureBox控件相当于一块土地,为画图腾出空间;但有了土地不能直接开始画,因为没有画板对吧,所以Bitmap相当于画布或者画纸,用于覆盖在地面上,方便我们进行画图;Graphics就是画图的手;Pen就是画笔很简单;但是有了画笔,不知道笔的粗细和颜色,那么Brush就是用来定义这两者的。

	int width = pBox_home.Width; //获取PictureBox的宽高
	int height = pBox_home.Height;
	map_bg = new Bitmap(width, height); //设置要涂改的背景
	mGraphics = Graphics.FromImage(map_bg); //设置设置画手
	pBox_home.Image = map_bg;   //添加背景  
	mBrush = new SolidBrush(Color.Blue);
	mPen_outer = new Pen(mBrush, 2);
	mBrush = new SolidBrush(Color.White);
	mPen_inner = new Pen(mBrush, 2);


 2.在C#语言中,Y轴是朝下的。

 这个不用过多解释,好多语言都是这样定义的,但这点很重要,用红色标记吧。

 

 3.Graphics中的 DrawEllipse(Pen pen, int x, int y, int width, int height) 是我们主要用到的画圆函数。

 他将椭圆和标准圆整合到一起。说下每个参数的意思:

 pen:用来画椭圆(圆)的笔

 x:画圆的x坐标

 y:画圆的y坐标

 width:长轴

 height:短轴(不清楚椭圆的长轴,短轴可以自行百度下~)

 在这个函数中有2个坑,看清楚了别陷阱去了!

 ①这里的 x 和 y 指的是将整个圆(椭圆)包含在其中的最小的正方形(矩形)的最左上角那个点。意思就是如果我们想在(100,100)这个点画一个半径为20的圆的话,必须要减去圆的半径,在(90,90)上调用这个函数才能达到效果,如下图:

c# 手把手教你撸一个吃鸡游戏跑圈机制

 ②然后是 width 和 height,指的是长轴和短轴,换做是圆则长轴和短轴相等,但这个长度量实际上指的是直径,不是半径啊!记清楚了哟!

	public void drawCircle(Pen pen, PointF point, float radius) //自定义画圆函数
	{
		//将想要画的位置减去半径radius, 以及radius*2 代表的就是①和②的意思
		Rectangle mRect = new Rectangle((int)(point.X - radius), (int)(point.Y - radius), (int)(radius * 2), (int)(radius * 2));
		mGraphics.DrawEllipse(pen, mRect);
	}

三、具体讲解:  难点1:跑圈时内部安全区动态创建问题

 玩过吃鸡的朋友都知道,在一定时间到后开始跑圈,内外两个圆重合时,随机加载下一个安全区,但这个安全区不能超出外圆原来的界限,必须把整个新的安全区包含在内,那么如何来实现这一点,如下图:

c# 手把手教你撸一个吃鸡游戏跑圈机制

 灰色圆圈的半径为 R1-R2,实际上内部安全区的新圆心只能在灰色圆圈上及以内产生,如果在图上绿色随机产生点的画,那么画出来的新安全区就超出外圈的界限了。

		/// <summary>
		/// 在圆心为point,半径为radius的圆内,产生一个半径为radius_inner的圆的圆心
		/// </summary>
		/// <param name="point">外圆圆心</param>
		/// <param name="radius_outer">外圆半径</param>
		/// <param name="radius_inner">内圆半径</param>
		/// <returns>内圆圆心</returns>
		public PointF PointOfRandom(PointF point, float radius_outer, float radius_inner)
		{
			int x = random.Next((int)(point.X - (radius_outer - radius_inner)), (int)(point.X + (radius_outer - radius_inner)));
			int y = random.Next((int)(point.Y - (radius_outer - radius_inner)), (int)(point.Y + (radius_outer - radius_inner)));
			
			while (!isInRegion(x - point.X, y - point.Y, radius_outer - radius_inner))
			{
				x = random.Next((int)(point.X - (radius_outer - radius_inner)), (int)(point.X + (radius_outer - radius_inner)));
				y = random.Next((int)(point.Y - (radius_outer - radius_inner)), (int)(point.Y + (radius_outer - radius_inner)));
			}
			PointF p = new PointF(x, y);
			return p;
		}
		
		/// <summary>
		/// 
		/// </summary>
		/// <param name="x_off">与大圆圆心的x方向偏移量</param>
		/// <param name="y_off">与大圆圆心的y方向偏移量</param>
		/// <param name="distance">大圆与小圆半径的差</param>
		/// <returns>判断点是否在范围内</returns>
		public bool isInRegion(float x_off, float y_off, float distance)
		{
			if (x_off * x_off + y_off * y_off <= distance * distance)
			{
				return true;
			}
			return false;
		}
		


 难点2:毒圈和安全域相内切问题

 在缩圈时,外部毒圈不断缩小,有那么个时刻,内圈和外圈相内切即有且仅有一个点重合,这是的状态为内切,如下图:

c# 手把手教你撸一个吃鸡游戏跑圈机制


 那么这个重合点必定在外圈和内圈圆心所在的直线上,相信这个不难理解。那么此刻的判定条件就是 相差距离 = 0,即R2+两圆心距离 = R1。

		/// <summary>
		/// 判断两个圆是否重合,或者是相内切
		/// </summary>
		/// <param name="p_outer">外圆圆心</param>
		/// <param name="r_outer">外圆半径</param>
		/// <param name="p_inner">内圆圆心</param>
		/// <param name="r_inner">内圆半径</param>
		/// <returns>是否相内切</returns>
		public bool isIntersect(PointF p_outer, float r_outer, PointF p_inner, float r_inner)
		{
			//判定条件:两圆心的距离 + r_inner = r_outer
		float distance = (float)Math.Sqrt((p_outer.X - p_inner.X) * (p_outer.X - p_inner.X) + (p_outer.Y - p_inner.Y) * (p_outer.Y - p_inner.Y));
			if (distance + r_inner >= r_outer)
			{
				return true;
			}
			return false;
		}
		


 难点3:内切后的运行状态?

 实际上在内切后,外圈的圆心以直线的方式不断向内圈圆心靠近,这条直线就是外圈圆心和内圈圆心所在的直线,并且外圈半径依旧在不断变小,如下图:

c# 手把手教你撸一个吃鸡游戏跑圈机制


 直线的斜率和直线方程在图上,我就不做过多解释,相信大家能看懂。值得一提的是,在人为设定外圈半径每次减少1个单位长度的情况下,即外圈圆心在所在直线上向内圈圆心移动1个单位,所以 x_off^2 + y_off^2 = 1,那么在知道斜率k和直角三角形中斜边为1的情况下就能够求出每次外圈圆心 x 和 y的移动距离。那么这个过程的结束条件就是:外圈半径r1 = 内圈半径r2。

		if (mRadius_outer != mRadius_inner)  //外圈和内圈圆心重合,半径相同
		{
			// k = y/x
			// y = kx
			// x^2+y^y = 1
			// x^2 = 1/(k^2+1)
			float k = (mPoint_outer.Y - mPoint_inner.Y) / (mPoint_outer.X - mPoint_inner.X);
			float x_off = 1 * (float)Math.Sqrt(1 / (k * k + 1));
			// 通过mPoint_outer和mPoint_inner的x坐标来判断此时外圆圆心要移动的是该 + x_off(x轴偏移量)还是 -x_off
			mPoint_outer.X += 1 * (mPoint_outer.X < mPoint_inner.X ? 1 : -1) * x_off;
			// 知道变化后的外圈圆心的x坐标,和直线方程来求对应的y坐标
			mPoint_outer.Y = k * (mPoint_outer.X - mPoint_inner.X) + mPoint_inner.Y;
			mDrawHelper.drawCircle(mPen_outer, mPoint_outer, mRadius_outer);
			mDrawHelper.drawCircle(mPen_inner, mPoint_inner, mRadius_inner);
		}
		

 

 至此,所有的问题都解决了,快去撸一个你自己的吃鸡跑圈游戏吧~(滑稽脸)


四、源代码获取:

 git地址:https://gitee.com/jefferychen/ChickenCircle.git

 csdn地址:http://download.csdn.net/download/qq_35561857/10227407


最新发布

CentOS专题

关于本站

5ibc.net旗下博客站精品博文小部分原创、大部分从互联网收集整理。尊重作者版权、传播精品博文,让更多编程爱好者知晓!

小提示

按 Ctrl+D 键,
把本文加入收藏夹