欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【flash基础】简单的 打飞机小游戏

程序员文章站 2024-02-03 20:32:46
...

学校还教这东西,也真是迷。比起 普通的游戏库 应该舒服的多。
纯当练手写了一个demon。很简陋,不过 代码量很少应该比较好参考。
网上的资料不是很多,有兴趣的可以拿去参考下。
代码
链接:https://pan.baidu.com/s/1Vx_A37a07qJIkg443N3Jwg
提取码:opi9
--------------------------效果---------------------------
【flash基础】简单的 打飞机小游戏
【flash基础】简单的 打飞机小游戏
【flash基础】简单的 打飞机小游戏

--------------------------需求---------------------------

先分析一下我们需要什么。
小炮塔
1.可以被wasd控制 【事件绑定】
2.炮塔会跟着鼠标转 【坐标转向量转角度】
3.点击鼠标会发射炮弹 【事件绑定 和 new出来子弹】

敌人
1.被击中的时候会消失 【碰撞检测】

子弹
1会沿着一个方向一直飞 【坐标转单位向量*速度】
2 击中敌人会消失 【碰撞检测】

主循环
最重要的 游戏是运行在一个主循环里面的 我们需要去创造一个主循环。

--------------------------类的介绍---------------------------
几个类 以下的类都实现了以上的功能
bullet是子弹
enamy是敌人
Gloablinput 用来接收输入的。比如你输入w 的forward就会变成1
鼠标点击 里面一个布尔类型的变量就会变true
Mycharacter 是自机。
【flash基础】简单的 打飞机小游戏
--------------------------代码---------------------------
第一帧 主要是一些变量的初始化。很对应的 事件回调函数的绑定。
allObjList数组
包含舞台上所有的游戏对象。
所有的游戏对象都会有一个Tick()方法。这个数组是用来执行这个方法的。
这个tick方法很很重要,可以认为 他是一个对象的主函数,用于 对象参与到游戏循环检测。
enemy_list 和 bullet_list
用于子弹和敌人的碰撞检测用。

"第一帧"
import GlobalInput
import Math
GlobalInput.Right =  0
GlobalInput.Forward = 0 
GlobalInput.mouseDown = false

//1 变量初始化
//2 事件处理函数
//3 按钮绑定
//12-14 游戏主循环

//监听处理各种输入 
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);	
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
stage.addEventListener(MouseEvent.MOUSE_UP,mouseUpHandler);

var allObjList:Array = new Array()  //Tick方法调用
var enemy_list:Array = new Array()  //方便碰撞检测
var bullet_list:Array = new Array()  //子弹产生就放进去
var self_char = new Mycharacter(this,new mychar1())
allObjList.push(self_char)

var i,j,k
 
for (i=0;i<20;i++)  //创造敌人
{	 
	j = new Enamy(this,Math.random()*550+1,Math.random()*400+1)
	enemy_list.push(j)
	allObjList.push(j)
}



第二帧
这里是绑定了 上下左右 和 鼠标点击的输入。
值得一提的是
当按下 左 的时候 GlobalInput.Right =1
按下 右 的时候 GlobalInput.Right =-1
这里假设了右边是正方向。因为物体移动的时候 实际上就是坐标在变化。
右边移动的时候是
对象.x+=speed
左边移动的时候
对象.x-=speed
我这里规定了右边是正方向因此。对象的左右移动
对象.x+= speed * GlobalInput.Right 也就是 速度*方向

"第二帧"

function keyDownHandler(e:KeyboardEvent):void

		{
			switch(e.keyCode)

			{
				case "W".charCodeAt():
				case Keyboard.UP:
					GlobalInput.Forward  =-1

					break;

				case "S".charCodeAt():
				case Keyboard.DOWN:
					GlobalInput.Forward  = 1;
					break;

				case "A".charCodeAt():
				case Keyboard.LEFT:
					GlobalInput.Right    = -1;
					break;

				case "D".charCodeAt():
				case Keyboard.RIGHT:
					GlobalInput.Right	 = 1;
					break;
			}
		}
	
function keyUpHandler(e:KeyboardEvent):void

		{
			switch(e.keyCode)
			{
				case "W".charCodeAt():
				case Keyboard.UP:
				case "S".charCodeAt():
				case Keyboard.DOWN:
					GlobalInput.Forward = 0;
					break;

				case "A".charCodeAt():
				case Keyboard.LEFT:			
				case "D".charCodeAt():
				case Keyboard.RIGHT:
					GlobalInput.Right	 = 0;
					break
			}

		}
	

		 function mouseDownHandler(e:MouseEvent):void

		{
			GlobalInput.mouseDown = true;
		}

		 function mouseUpHandler(e:MouseEvent):void

		{
			GlobalInput.mouseDown = false;

		}

第3帧 写了个按钮的 不是很重要
显示按钮界面 并且吧游戏暂停在这里。


bt1.addEventListener(MouseEvent.CLICK, bt1Action);
bt2.addEventListener(MouseEvent.CLICK, bt2Action);

function bt1Action (event:MouseEvent)
{
	gotoAndPlay(4)
}

 
function bt2Action(event:MouseEvent):void
{	var url = "https://www.bilibili.com/"
	navigateToURL(new URLRequest(url), "_blank");
}

stop()

游戏主循环部分
gotoAndPlay(11) 表示从第11帧执行,可以看出来游戏 一直在执行第12帧的代码。

再次说下 Tick方法
他是每一个参与游戏的物体都会有的一个函数,游戏循环的时候 每一个参与游戏互动的对象都会执行他。所以 看一个类的时候 去看Tick就行了。
你可以把它当成是一个接口函数,只是代码量太少我没写。

for each (i in allObjList)
	i.Tick()
	
//鼠标按下 调用 炮台的attack方法
//attck方法会返回一个子弹对象   或者是一个假 这里主要是吧生成的子弹存数组
if (GlobalInput.mouseDown){
	j = self_char.attack()
	if (j){                      //武器未冷却的时候 会返回一个假
	allObjList.push(j) 
	bullet_list.push(j)
	}
}

//碰撞检测  让所有的子弹i  和 所有的敌人j 进行碰撞检测
//如果返回 true  就执行 对敌人的伤害
for each(i in bullet_list)
	for each (j in enemy_list)
		if (i.drawObject.hitTestObject(j))
			j.applyDamage(300)
		
gotoAndPlay(11)

----------------------------------类--------------------------------------
好了 开始说类。
重要的事情说3次
注意Tick函数

炮台类
move 函数的if 条件 主要是一些边界检测。没写完 就用true代替
移动的逻辑
drawObject.x = 速度 * 方向
这一行很重要 相关的数学算法 让炮台会跟着鼠标转
drawObject.rotation = Math.atan2(vector[1],vector[0]) * 180/Math.PI -90
首先 可以获得的是 鼠标坐标 和 炮台坐标,获得一个向量vector。指向鼠标的向量。
用 Math.atan()函数 获得他的 弧度。
弧度* 180/Math.PI 转化为角度
至于那个-90 emmm 我也不清楚。可能是坐标轴的原因吧。gui程序的坐标轴是 这样子的。 我-90度 他就对了。
O→ X

Y

attack函数
打炮low,new子弹。
这里 又用到了 前面说的那个向量了。 【鼠标坐标-炮塔坐标】
这个向量决定了 子弹的飞行方向,当然 new 子弹的时候一定要传参给他。
当然 这里 有个攻击间隔时间。
攻击一次 攻击timer 变为4。Tick 函数 攻击timer-1
只有小于0的时候才攻击

package  {
	import Math
	public class Mycharacter   {
		
		public var speed:int = 10 //速度
		public var drawObject;  //影片剪辑 就是那个炮台长什么样子
		var attackTime = 10   //攻击计时器
		var attack_interval = 4 //攻击的间隔时间
		var stage
		public function Mycharacter(_stage,actor) {
			this.stage = _stage
			drawObject = actor
			
			drawObject.y = 200
			drawObject.x =  200
			// constructor code
		}

		public function attack(){	
			if (attackTime<0){
			var v:Array = [drawObject.x-stage.mouseX+drawObject.width/2,drawObject.y-stage.mouseY+drawObject.height/2] 
			attackTime=attack_interval
			return  new bullet(this.stage,this, new bullet_image(),v)
			}
			else
				return false
		}
		
		public function move(){
			if ( true && GlobalInput.Right>0)
				drawObject.x += speed * GlobalInput.Right
			if (  drawObject.x > 0 && GlobalInput.Right<0)
				drawObject.x += speed * GlobalInput.Right
			if (  true   && GlobalInput.Forward >0)
				drawObject.y += speed * GlobalInput.Forward 
			if (  drawObject.y > 0  && GlobalInput.Forward <0) 
				drawObject.y += speed * GlobalInput.Forward 
				
			var vector:Array = [drawObject.x-stage.mouseX+drawObject.width/2,drawObject.y-stage.mouseY+drawObject.height/2] 	
			//trace(Math.atan2(vector[0],vector[1]) * 180/Math.PI) 
			drawObject.rotation =  Math.atan2(vector[1],vector[0]) * 180/Math.PI  -90 //这里可能是坐标轴的问题
			//我所熟悉的坐标右手为x 这里 乱 感觉在强行解释
			stage.addChild(drawObject)
		}
		
		public function Tick(){
			this.attackTime -=1
			move()
		}
	}
}

敌人类
敌人生命的 被击中的时候会调用 applydamage 这里没有多写而已。做出游戏这里是用的到的。
move 函数也是 敌人一定有他自己的移动逻辑。移动的时候 必须检测下 是否还活着,死了记得销毁对象。
这里 写的是 假销毁
this.x = -1000 this.y = -1000 移动到舞台外面就没了嘛。

package  {
	
	public class Enamy extends EnemyImage {
		
		public var _stage 
		public var healthy = 100
		public var is_live = true
		public function Enamy(_stage,x,y) {
			// constructor code
			this._stage = _stage
			this.x = x
			this.y = y
			
		}
		
		public function move()
		{
			if (healthy>0)
				_stage.addChild(this)
			else if (this.is_live)
			{
				this.x = -1000
				this.y = -1000
			}

		}
		
		public function Tick(){
			
			move()
		}
		
		public function applyDamage(num)
		{
			this.healthy -=  num
		}
		
	}
	
}

子弹类
构造函数在做这件事
速度 = 速率* 单位化的方向向量
顺便获取 发射者的位置

package  {
	import Math
	public class bullet  {
		public var  speed = 10
		public var  vector:Array  = [0,0]
		public var drawObject;
		var stage
		
		public function bullet(_stage,launcher,image,v) {  
			stage = _stage
			vector[0] =  v[0] / Math.sqrt(v[0]*v[0]+v[1]*v[1])
			vector[1] =  v[1] / Math.sqrt(v[0]*v[0]+v[1]*v[1])   
 			drawObject = image
			
			drawObject.x = launcher.drawObject.x
			drawObject.y = launcher.drawObject.y 
			//drawObject.x = launcher.drawObject.x + launcher.drawObject.width/2
			//drawObject.y = launcher.drawObject.y + launcher.drawObject.height/2
			// constructor code
		}
		
		public function setSpeed(sp)
		{
			speed = sp
		}
		
		public function move(){

			drawObject.x -= vector[0] *speed
			drawObject.y -= vector[1] *speed
			stage.addChild(drawObject)
			
		}

		public function Tick(){
			move()
		}
	}
	
}

游戏的话 自机 是需要和 敌人和子弹做碰撞检测的。
希望对大家有帮助。

相关标签: flash