c#如何使得飞机遇到气流边界后,不再继续向外侧移动

【图文】C#基础3-天机_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&10W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
C#基础3-天机
阅读已结束,下载本文到电脑
想免费下载本文?
登录百度文库,专享文档复制特权,积分每天免费拿!
你可能喜欢在线等【c#吧】_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:120,830贴子:
在线等收藏
c#如何使得飞机遇到边界后,不再继续向外侧移动
免费网上学习c#,国内名师机构专业授课,O基础快速学习,1小时快速入门,7天c#学习 能力快速提升 优质作品随手呈现
有人解答一下嘛
是在飞机类里面弄,还是在主函数里面弄,方便留个扣扣吗
首先 回去补习一下语文,这是个病句。在移动飞机的响应函数里,首先判断目标点的位置是否在边界内。如果在边界外,就移动到相应的边界点上。
碰到了边界就停下来
但是这个停下来是不是设定 坐标?
登录百度帐号程序写累了,就来玩玩酷跑小游戏吧,嘿嘿。
雨松MOMO送你一首歌曲,嘿嘿。
Unity3D研究院之IOS自定义游戏摇杆与飞机平滑的移动(十一)
Unity3D研究院之IOS自定义游戏摇杆与飞机平滑的移动(十一)
围观31185次
编辑日期: 字体:
移动开发游戏中使用到的触摸游戏摇杆在iPhone上是非常普遍的,毕竟是全触摸屏手机,今天MOMO 通过一个小例子和大家讨论Unity3D 中如何自定义一个漂亮的全触摸游戏摇杆。
值得高兴的是,Unity3D 游戏引擎的标准资源中已经帮助我们封装了一个游戏摇杆脚本,所以实现部分的代码可以完全借助它的,具体调用需要我们自己来。
Joystick.js是官方提供的脚本,具体代码如下,有兴趣的朋友可以仔细研究研究,MOMO就不多说啦。哇咔咔~
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
//////////////////////////////////////////////////////////////// Joystick.js// Penelope iPhone Tutorial//// Joystick creates a movable joystick (via GUITexture) that// handles touch input, taps, and phases. Dead zones can control// where the joystick input gets picked up and can be normalized.//// Optionally, you can enable the touchPad property from the editor// to treat this Joystick as a TouchPad. A TouchPad allows the finger// to touch down at any point and it tracks the movement relatively// without moving the graphic//////////////////////////////////////////////////////////////&@script RequireComponent( GUITexture )&// A simple class for bounding how far the GUITexture will moveclass Boundary{ var min : Vector2 = Vector2.zero; var max : Vector2 = Vector2.zero;}&static private var joysticks : Joystick[];
// A static collection of all joysticksstatic private var enumeratedJoysticks : boolean = false;static private var tapTimeDelta : float = 0.3;
// Time allowed between taps&var touchPad : boolean;
// Is this a TouchPad?var touchZone : Rect;var deadZone : Vector2 = Vector2.zero;
// Control when position is outputvar normalize : boolean = false;
// Normalize output after the dead-zone?var position : Vector2;
// [-1, 1] in x,yvar tapCount : int;
// Current tap count&private var lastFingerId = -1;
// Finger last used for this joystickprivate var tapTimeWindow : float;
// How much time there is left for a tap to occurprivate var fingerDownPos : Vector2;private var fingerDownTime : float;private var firstDeltaTime : float = 0.5;&private var gui : GUITexture;
// Joystick graphicprivate var defaultRect : Rect;
// Default position / extents of the joystick graphicprivate var guiBoundary : Boundary = Boundary();
// Boundary for joystick graphicprivate var guiTouchOffset : Vector2;
// Offset to apply to touch inputprivate var guiCenter : Vector2;
// Center of joystick&function Start(){ // Cache this component at startup instead of looking up every frame gui = GetComponent( GUITexture );& // Store the default rect for the gui, so we can snap back to it defaultRect = gui.pixelInset; &&&&&defaultRect.x += transform.position.x * Screen.width;// + gui.pixelInset.x; // -&&Screen.width * 0.5;&&&&defaultRect.y += transform.position.y * Screen.height;// - Screen.height * 0.5;&&&&&transform.position.x = 0.0;&&&&transform.position.y = 0.0;& if ( touchPad ) {
// If a texture has been assigned, then use the rect ferom the gui as our touchZone
if ( gui.texture )
touchZone = defaultRect; } else {
// This is an offset for touch input to match with the top left
// corner of the GUI
guiTouchOffset.x = defaultRect.width * 0.5;
guiTouchOffset.y = defaultRect.height * 0.5;&
// Cache the center of the GUI, since it doesn't change
guiCenter.x = defaultRect.x + guiTouchOffset.x;
guiCenter.y = defaultRect.y + guiTouchOffset.y;&
// Let's build the GUI boundary, so we can clamp joystick movement
guiBoundary.min.x = defaultRect.x - guiTouchOffset.x;
guiBoundary.max.x = defaultRect.x + guiTouchOffset.x;
guiBoundary.min.y = defaultRect.y - guiTouchOffset.y;
guiBoundary.max.y = defaultRect.y + guiTouchOffset.y; }}&function Disable(){ gameObject.active = false; enumeratedJoysticks = false;}&function ResetJoystick(){ // Release the finger control and set the joystick back to the default position gui.pixelInset = defaultRect; lastFingerId = -1; position = Vector2.zero; fingerDownPosition = Vector2.zero;& if ( touchPad )
gui.color.a = 0.025;}&function IsFingerDown() : boolean{ return (lastFingerId != -1);}&function LatchedFinger( fingerId : int ){ // If another joystick has latched this finger, then we must release it if ( lastFingerId == fingerId )
ResetJoystick();}&function Update(){ if ( !enumeratedJoysticks ) {
// Collect all joysticks in the game, so we can relay finger latching messages
joysticks = FindObjectsOfType( Joystick );
enumeratedJoysticks = true; } & var count = Input.touchCount;& // Adjust the tap time window while it still available if ( tapTimeWindow & 0 )
tapTimeWindow -= Time.deltaTime; else
tapCount = 0;& if ( count == 0 )
ResetJoystick(); else {
for(var i : int = 0;i & count; i++)
var touch : Touch = Input.GetTouch(i);
var guiTouchPos : Vector2 = touch.position - guiTouchOffset;&
var shouldLatchFinger = false;
if ( touchPad )
if ( touchZone.Contains( touch.position ) )
shouldLatchFinger = true;
else if ( gui.HitTest( touch.position ) )
shouldLatchFinger = true;
// Latch the finger if this is a new touch
if ( shouldLatchFinger && ( lastFingerId == -1 ?? lastFingerId != touch.fingerId ) )
if ( touchPad )
gui.color.a = 0.15;&
lastFingerId = touch.fingerId;
fingerDownPos = touch.position;
fingerDownTime = Time.time;
lastFingerId = touch.fingerId;&
// Accumulate taps if it is within the time window
if ( tapTimeWindow & 0 )
tapCount++;
tapCount = 1;
tapTimeWindow = tapTimeDelta;
// Tell other joysticks we've latched this finger
for ( var j : Joystick in joysticks )
if ( j != this )
j.LatchedFinger( touch.fingerId );
if ( lastFingerId == touch.fingerId )
// Override the tap count with what the iPhone SDK reports if it is greater
// This is a workaround, since the iPhone SDK does not currently track taps
// for multiple touches
if ( touch.tapCount & tapCount )
tapCount = touch.tapCount;&
if ( touchPad )
// For a touchpad, let's just set the position directly based on distance from initial touchdown
position.x = Mathf.Clamp( ( touch.position.x - fingerDownPos.x ) / ( touchZone.width / 2 ), -1, 1 );
position.y = Mathf.Clamp( ( touch.position.y - fingerDownPos.y ) / ( touchZone.height / 2 ), -1, 1 );
// Change the location of the joystick graphic to match where the touch is
gui.pixelInset.x =&&Mathf.Clamp( guiTouchPos.x, guiBoundary.min.x, guiBoundary.max.x );
gui.pixelInset.y =&&Mathf.Clamp( guiTouchPos.y, guiBoundary.min.y, guiBoundary.max.y );
if ( touch.phase == TouchPhase.Ended ?? touch.phase == TouchPhase.Canceled )
ResetJoystick();
} }& if ( !touchPad ) {
// Get a value between -1 and 1 based on the joystick graphic location
position.x = ( gui.pixelInset.x + guiTouchOffset.x - guiCenter.x ) / guiTouchOffset.x;
position.y = ( gui.pixelInset.y + guiTouchOffset.y - guiCenter.y ) / guiTouchOffset.y; }& // Adjust for dead zone var absoluteX = Mathf.Abs( position.x ); var absoluteY = Mathf.Abs( position.y );& if ( absoluteX & deadZone.x ) {
// Report the joystick as being at the center if it is within the dead zone
position.x = 0; } else if ( normalize ) {
// Rescale the output after taking the dead zone into account
position.x = Mathf.Sign( position.x ) * ( absoluteX - deadZone.x ) / ( 1 - deadZone.x ); }& if ( absoluteY & deadZone.y ) {
// Report the joystick as being at the center if it is within the dead zone
position.y = 0; } else if ( normalize ) {
// Rescale the output after taking the dead zone into account
position.y = Mathf.Sign( position.y ) * ( absoluteY - deadZone.y ) / ( 1 - deadZone.y ); }}
单击Create 创建一个GUI Texture,命名为Joy ,它用来显示游戏摇杆,如下图所示将摇杆的图片资源,与摇杆的脚本连线赋值给Joy.
Pixel Inset 中可以设置摇杆的显示位置与显示宽高。
到这一步 build and run 就可以在iPhone上看到这个游戏摇杆,并且可以通过触摸它,360度平滑过度。
在屏幕中绘制一个飞机,通过游戏摇杆去控制飞机的移动。
创建一个脚本,命名为Main.js 如下图所示
将 Main.js 、joy、plan 分别 绑定在Main Camera 上。
moveJoystick.position.x;
moveJoystick.position.y;
这两个值是非常重要的两个信息,它们的取值范围是 -1 到 +1 ,表示 用户触摸摇杆的位置, 上 下 左 右 的信息。
<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff<div class="crayon-num crayon-striped-num" data-line="crayon-5b40ff<div class="crayon-num" data-line="crayon-5b40ff
//游戏摇杆对象var moveJoystick : Joystick;&//飞机的贴图var plan : Texture;&//飞机在屏幕中的坐标var x = 0;var y = 0;&//避免飞机飞出屏幕,分别是X、Y最大坐标,最小坐标是0、0var cross_x = 0;var cross_y = 0;&//飞机移动的速度var planSpeed = 20;&function Start() { //初始化赋值 x = 100; y = 100; cross_x = Screen.width -&&plan.width; cross_y = Screen.height -&&plan.height;&}&function Update () { //得到游戏摇杆的反馈信息,得到的值是 -1 到 +1 之间&
var touchKey_x =&&moveJoystick.position.x;
var touchKey_y =&&moveJoystick.position.y;&
//摇杆向左
if(touchKey_x == -1){
x -= planSpeed;&
//摇杆向右
else if(touchKey_x == 1){
x += planSpeed;&
//摇杆向上&& if(touchKey_y == -1){
y += planSpeed;&
//摇杆向下
else if(touchKey_y == 1){
y -= planSpeed;&
//防止飞机飞出屏幕,出界检测
if(x & 0){
}else if(x & cross_x){
x = cross_x;
}&&& if(y & 0){
}else if(y & cross_y){
y = cross_y;
}}&function OnGUI () {&&&//将飞机绘制在屏幕中&&GUI.DrawTexture(Rect(x,y,128,128),plan);&&&}
导出 build and run
看看在iPhone 上的效果,通过触摸游戏摇杆可以控制飞机的移动啦,不错吧,哇咔咔~~
最后欢迎各位盆友可以和MOMO一起讨论Unity3D游戏开发,最近感冒的盆友越来越多,大家要多多注意身体健康噢。哇咔咔~~~ 附上Unity3D工程的下载地址,Xcode项目我就不上传了,须要的自己导出。
下载地址:
本文固定链接:
转载请注明:
雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
如果您愿意花10块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。
您可能还会对这些文章感兴趣!
Pingback 引用通告:21:22 提问
利用C#语言写飞机移动代码
能利用鼠标来控制的的飞机移动代码,大神们求帮啊
多谢了多谢了
按赞数排序
我有cocos2dx的,你要不要
在窗体form下的mouse move事件里面写
检测鼠标的坐标
改变飞机的坐标,即可
无非就是在mouse_move事件中移动一个picturebox,上面image属性设置为一个飞机的图片。
不是很懂。像是很高大上的样子
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!
其他相关推荐一、关于飞机大战
  要说微信中最火爆的小游戏是哪款,可能既不是精心打造的3D大作,也不是《植物大战僵尸2》,而是微信5.0刚开启时的《飞机大战》。
  就是这样一款铅笔手绘风格的简单到不能再简单的&打飞机&游戏,让国内的微信用户一次又一次地尝试,并表示似乎又找回了童年时玩电子游戏的那份单纯的快乐。至于游戏的玩法都不用加以介绍,就是简单的&打飞机&。
二、关于游戏设计
2.1 总结游戏印象
  (1)一个玩家飞机,多个电脑飞机
  ①  ②  ③  ④
  (2)玩家飞机可以发射子弹,电脑飞机也可以发射子弹
  ①  ②
  (3)玩家和电脑飞机被击中后有爆炸效果,并且有一定几率出现大型飞机
  ①  ②
2.2 总结设计思路
  (1)万物皆对象
  在整个游戏中,我们看到的所有内容,我们都可以理解为游戏对象(GameObject),每一个游戏对象,都由一个单独的类来创建;在游戏中主要有三类游戏对象:一是飞机,二是子弹,三是背景;其中,飞机又分为玩家飞机和电脑飞机,子弹又分为玩家子弹和电脑子弹。于是,我们可以对飞机进行抽象形成一个抽象父类:PlaneBase,然后分别创建两个子类:PlanePlayer和PlaneEnemy;然后对子弹进行抽象形成一个抽象类:BulletBase,然后分别创建两个子类:BulletPlayer和BulletEnemy。但是,我们发现这些游戏对象都有一些共同的属性和方法,例如X,Y轴坐标,长度和宽度,以及绘制(Draw())和移动(Move())的方法,这时我们可以设计一个抽象类,形成了GameObject类:将共有的东西封装起来,减少开发时的冗余代码,提高程序的可扩展性,符合面向对象设计的思路:
  (2)计划生育好
  在整个游戏中,我们的玩家飞机对象只有一个,也就是说在内存中只需要存一份即可。这时,我们想到了伟大的计划生育政策,于是我们想到了使用单例模式。借助单例模式,可以保证只生成一个玩家飞机的实例,即为程序提供一个全局访问点,避免重复创建浪费不必要的内存。当然,除了玩家飞机外,我们的电脑飞机集合、子弹集合等集合对象实例也保证只有一份存储,降低游戏开销;
  (3)对象的运动
  在整个游戏过程中,玩家可以通过键盘上下左右键控制玩家飞机的上下左右运动,而飞机的运动本质上还是改变游戏对象的X轴和Y轴的坐标,然后一直不间断地在窗体上重绘游戏对象。相比玩家飞机的移动,电脑飞机的移动则完全是通过程序中设置的随机函数控制左右方向移动的,而玩家飞机发出的子弹执行的运动则是从下到上,而电脑飞机发出的子弹执行的运动则是从上到下。
  (4)设计流程图
三、关键代码实现&
3.1 客户端开发
  (1)设计GameObject类:封装所有游戏对象的公有属性
/// &summary&
/// 抽象类:游戏对象基类
/// &/summary&
public abstract class GameObject
public int X
public int Y
public int Width
public int Height
public int Speed
public int Life
public Direction Dir
public GameObject(int x, int y, int width, int height, int speed, int life, Direction dir)
this.Width =
this.Height =
this.Speed =
this.Life =
this.Dir =
public GameObject(int x, int y)
// 实例方法:返回所在矩形区域用于碰撞检测
public Rectangle GetRectangle()
return new Rectangle(this.X, this.Y, this.Width, this.Height);
// 抽象方法:游戏对象的绘制各不相同
public abstract void Draw(Graphics g);
// 虚方法:游戏对象的移动各不相同
public virtual void Move()
// 根据指定的移动方向进行移动
switch (Dir)
case Direction.Up:
this.Y -= this.S
case Direction.Down:
this.Y += this.S
case Direction.Left:
this.X -= this.S
case Direction.Right:
this.X += this.S
// 移动之后判断是否超出了边界
if (this.X &= 0)
this.X = 0;
if (this.X &= 380)
this.X = 380;
if (this.Y &= 0)
this.Y = 0;
if (this.Y &= 670)
this.Y = 670;
  一切皆对象,这里封装了游戏对象:飞机、子弹以及其他游戏对象共有的属性,以及两个抽象方法,让对象们(飞机?子弹?爆炸效果?等)自己去实现。
  (2)设计SingleObject类:保证游戏中的类都只有一个实例
/// &summary&
单例模式类
/// &/summary&
public class SingleObject
private SingleObject()
private static SingleObject singleInstance = null;
public static SingleObject GetInstance()
if (singleInstance == null)
singleInstance = new SingleObject();
return singleI
#region 单一实例对象列表
// 1.游戏背景单一实例
public GameBackground Background
// 2.游戏标题单一实例
public GameTitle Title
// 3.玩家飞机单一实例
public PlanePlayer Player
// 4.玩家飞机子弹集合单一实例
public List&BulletPlayer& PlayerBulletList
// 5.敌人飞机集合单一实例
public List&PlaneEnemy& EnemyList
// 6.敌人飞机子弹集合单一实例
public List&BulletEnemy& EnemyBulletList
// 7.玩家飞机爆炸效果单一实例
public List&BoomPlayer& PlayerBoomList
// 8.敌人飞机爆炸效果单一实例
public List&BoomEnemy& EnemyBoomList
#endregion
// 为游戏屏幕增加一个游戏对象
public void AddGameObject(GameObject go)
if (go is GameBackground)
this.Background = go as GameB
if (go is GameTitle)
this.Title = go as GameT
if (go is PlanePlayer)
this.Player = go as PlaneP
if (go is BulletPlayer)
if(this.PlayerBulletList == null)
this.PlayerBulletList = new List&BulletPlayer&();
this.PlayerBulletList.Add(go as BulletPlayer);
if (go is PlaneEnemy)
if (this.EnemyList == null)
this.EnemyList = new List&PlaneEnemy&();
this.EnemyList.Add(go as PlaneEnemy);
if(go is BulletEnemy)
if (this.EnemyBulletList == null)
this.EnemyBulletList = new List&BulletEnemy&();
this.EnemyBulletList.Add(go as BulletEnemy);
if (go is BoomPlayer)
if (this.PlayerBoomList == null)
this.PlayerBoomList = new List&BoomPlayer&();
this.PlayerBoomList.Add(go as BoomPlayer);
if (go is BoomEnemy)
if (this.EnemyBoomList == null)
this.EnemyBoomList = new List&BoomEnemy&();
this.EnemyBoomList.Add(go as BoomEnemy);
// 移除指定的游戏对象
public void RemoveGameObject(GameObject go)
if (go is GameTitle)
this.Title = null;
if (go is BulletPlayer)
this.PlayerBulletList.Remove(go as BulletPlayer);
if (go is PlaneEnemy)
this.EnemyList.Remove(go as PlaneEnemy);
if (go is BulletEnemy)
this.EnemyBulletList.Remove(go as BulletEnemy);
if (go is BoomPlayer)
this.PlayerBoomList.Remove(go as BoomPlayer);
if (go is BoomEnemy)
this.EnemyBoomList.Remove(go as BoomEnemy);
// 为游戏屏幕绘制游戏背景对象
public void DrawFirstBackground(Graphics g)
if (Background != null)
Background.Draw(g);
if (Title != null)
Title.Draw(g);
if (Player != null)
Player.Draw(g);
// 为游戏屏幕绘制所有游戏对象
public void DrawGameObjects(Graphics g)
if (Background != null)
Background.Draw(g);
if (Player != null)
Player.Draw(g);
if (PlayerBulletList != null)
for (int i = 0; i & PlayerBulletList.C i++)
PlayerBulletList[i].Draw(g);
if (EnemyList != null)
for (int i = 0; i & EnemyList.C i++)
EnemyList[i].Draw(g);
if(EnemyBulletList != null)
for (int i = 0; i & EnemyBulletList.C i++)
EnemyBulletList[i].Draw(g);
if (PlayerBoomList != null)
for (int i = 0; i & PlayerBoomList.C i++)
PlayerBoomList[i].Draw(g);
if (EnemyBoomList != null)
for (int i = 0; i & EnemyBoomList.C i++)
EnemyBoomList[i].Draw(g);
// 玩家得分
public int Score
  这里借助单例模式,保证玩家飞机对象只有一个存储,电脑飞机集合也只有一个,而具体的电脑飞机对象则分别在单例类中的集合中进行Add和Remove。
  (3)设计CollisionDetect方法:不停地进行碰撞检测
  ①Rectangle的IntersectsWith方法
  在游戏界面中,任何一个游戏对象我们都可以视为一个矩形区域(Rectangle类实例),它的坐标是X轴和Y轴,它还有长度和宽度,可以轻松地确定一个它所在的矩形区域。那么,我们可以通过Rectangle的IntersectsWith方法确定两个Rectangle是否存在重叠,如果有重叠,此方法将返回&true;否则将返回&false。那么,在飞机大战中主要是判断两种情况:一是玩家或电脑飞机发射的子弹是否击中了对方?二是玩家是否撞到了敌人飞机?
  ②在定时器事件中定期执行碰撞检测方法
// 碰撞检测方法
public void CollisionDetect()
#region 1.判断玩家的子弹是否打到了敌人飞机身上
for (int i = 0; i & PlayerBulletList.C i++)
for (int j = 0; j & EnemyList.C j++)
if(PlayerBulletList[i].GetRectangle().IntersectsWith(EnemyList[j].GetRectangle()))
// 1.敌人的生命值减少
EnemyList[j].Life -= PlayerBulletList[i].P
// 2.生命值减少后判断敌人是否死亡
EnemyList[j].IsOver();
// 3.玩家子弹打到了敌人身上后将玩家子弹销毁
PlayerBulletList.Remove(PlayerBulletList[i]);
#endregion
#region 2.判断敌人的子弹是否打到了玩家飞机身上
for (int i = 0; i & EnemyBulletList.C i++)
if(EnemyBulletList[i].GetRectangle().IntersectsWith(Player.GetRectangle()))
// 使玩家发生一次爆炸但不阵亡
Player.IsOver();
#endregion
#region 3.判断敌人飞机是否和玩家飞机相撞
for (int i = 0; i & EnemyList.C i++)
if (EnemyList[i].GetRectangle().IntersectsWith(Player.GetRectangle()))
EnemyList[i].Life = 0;
EnemyList[i].IsOver();
#endregion
3.2 服务端开发
  (1)创建监听玩家连接的Socket,不停地监听玩家的游戏连接请求
private void btnBeginListen_Click(object sender, EventArgs e)
if (isEndService)
SetTxtReadOnly();
if (socketWatch == null)
// 创建Socket-&绑定IP与端口-&设置监听队列的长度-&开启监听连接
socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketWatch.Bind(new IPEndPoint(IPAddress.Parse(txtIPAddress.Text), int.Parse(txtPort.Text)));
socketWatch.Listen(10);
threadWatch = new Thread(ListenClientConnect);
threadWatch.IsBackground = true;
threadWatch.Start(socketWatch);
isEndService = false;
this.btnStartGame.Enabled = true;
ShowMessage("^_^:飞机大战服务器端启动服务成功,正在等待玩家进入游戏...");
MessageBox.Show("服务已启动,请不要重复启动服务!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
private void ListenClientConnect(object obj)
Socket serverSocket = obj as S
while (!isEndService)
Socket proxSocket = null;
// 注意:Accept方法会阻断当前所在的线程
proxSocket = serverSocket.Accept();
dictClients.Add(proxSocket.RemoteEndPoint.ToString(), proxSocket);
ShowMessage("*_*:玩家&" + proxSocket.RemoteEndPoint.ToString() + "&连接上了,请准备开始游戏。");
playerCount++;
ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveData), proxSocket);
catch (SocketException ex)
ShowMessage("#_#:异常【" + ex.Message + "】");
// 让方法结束,终结当前监听客户端数据的异步线程
catch (Exception ex)
ShowMessage("#_#:异常【" + ex.Message + "】");
// 让方法结束,终结当前监听客户端数据的异步线程
  在.NET中进行网络编程,一般都会涉及到Socket,其过程大概会经历如下图所示的流程:
PS:Socket非常类似于电话插座,以一个电话网为例:电话的通话双方相当于相互通信的2个程序,电话号码就是IP地址。任何用户在通话之前,首先要占有一部电话机,相当于申请一个Socket;同时要知道对方的号码,相当于对方有一个固定的Socket。然后向对方拨号呼叫,相当于发出连接请求。对方假如在场并空闲,拿起电话话筒,双方就可以正式通话,相当于连接成功。双方通话的过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向Socket发送数据和从Socket接收数据。通话结束后,一方挂起电话机相当于关闭socket,撤消连接。
  (2)使用线程池ThreadPool新开线程,不停地接收玩家发送的信息
  ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveData), proxSocket);
  在监听线程中使用了线程池,开启了一个新的线程来接收客户端发送过来的数据,那么这个ReceiveData方法如何实现的:
private void ReceiveData(object obj)
Socket proxSocket = obj as S
byte[] data = new byte[1024 * 1024];
int length = 0;
while (!isEndService)
length = proxSocket.Receive(data);
catch (SocketException ex)
ShowMessage("#_#:异常【" + ex.Message + "】");
StopConnection(proxSocket);
// 让方法结束,终结当前接收客户端数据的异步线程
catch (Exception ex)
ShowMessage("#_#:异常【" + ex.Message + "】");
StopConnection(proxSocket);
// 让方法结束,终结当前接收客户端数据的异步线程
if (length &= 0)
ShowMessage("*_*:玩家&" + proxSocket.RemoteEndPoint.ToString() + "&退出了游戏");
StopConnection(proxSocket);
if (playerCount & 0)
playerCount--;
// 让方法结束,终结当前接收客户端数据的异步线程
// 接受客户端发送过来的消息
string playerScore = Encoding.UTF8.GetString(data, 0, length);
dictScores.Add(proxSocket.RemoteEndPoint.ToString(), Convert.ToInt32(playerScore));
if (dictScores.Count & 0 && dictScores.Count == playerCount)
ComparePlayerScores();
  (3)当所有玩家都发送完游戏分数,服务器端对所有分数进行排序并发送最终名次
private void ComparePlayerScores()
List&KeyValuePair&string, int&& scoreList = dictScores.OrderByDescending(s =& s.Value).ToList();
for (int i = 0; i & scoreList.C i++)
string result = string.Format("您本次的成绩是第{0}名,分数为{1}分", i + 1, scoreList[i].Value);
byte[] bytes = Encoding.UTF8.GetBytes(result);
byte[] data = new byte[bytes.Length + 1];
data[0] = 2;
Buffer.BlockCopy(bytes, 0, data, 1, bytes.Length);
dictClients[scoreList[i].Key].Send(data, 0, data.Length, SocketFlags.None);
  在服务端有一个键值对集合专门存储玩家对应分数,然后对其按分数进行降序排序,排序后再遍历集合一一向玩家发送名次信息;
四、个人开发小结
4.1 服务端开启服务
  服务器端主要开启监听玩家连接请求的服务,当几个处在同一局域网的玩家连接后,服务端管理员点击&开始游戏&则客户端会启动游戏。
4.2 客户端开始游戏
  在客户端中,玩家飞机可以通过不停地发射子弹向不同类型的电脑飞机来获取得分,但是如果被敌人飞机的子弹击中分数也会被扣去一部分。
4.3 服务端计算成绩客户端显示
  当两个玩家连接游戏服务端后,便开始了&打飞机&的战斗,当指定时间后游戏结束,显示各自的游戏名次和分数。
  当然,还有很多核心的内容没有实现。希望有兴趣的童鞋可以去继续完善实现,这里提供一个我的飞机大战实现仅供参考,谢谢!
  赵剑宇,《C#开发太空大战》:
  MyPlaneGame:
阅读(...) 评论()

我要回帖

更多关于 飞机遇到气流 的文章

 

随机推荐