【flash】FPS游戏枪的后坐力制作 准星的抖动

游戏里的准星抖动 大体思路是这样子的。所谓的手感 也不过是 函数产生的 偏移大小而已。
代码下载在最下面
效果
不压枪
在这里插入图片描述
是一个7字
压枪 哎算了 好久就没打fps 压了个寂寞
在这里插入图片描述
废话不说 上代码
先分析下
Fps里面 枪的后坐力是怎么回事。

在这里插入图片描述

射击点 其实不是中心,而是十字准星 之间的一个范围产生了一个随机落点。 [这也就是为什么你 走路 准星会变大 蹲下准星会变小的原因。( 然后对这个落点 进行射线检测(3维 里射线检测是 检测这个点 和前方是都会碰撞到敌人)
后坐力 后坐力在3维游戏里的表现是 镜头的抖动。
这里是2d的 也就是 准星变化。
这个变化 包括 准星位置x,y 准星大小
他们都是基于随机数完成的。

实现的思路

鼠标按下 --射击 准星抖动

鼠标松开 准星回正

射击
射击是的随机落点
首先获得准星中心坐标。
然后在这个中心坐标产生随机数。或者最后的坐标。
当然这个随机数应该是 根据准星的大小来变化的。准星越大 这个数字产生的范围越高
x0 = x+随机数
y0 = y+随机数

准星的抖动
应该用一个数组来储存 准星的偏移量。例如 shakeValue=[0,0]
当你按下鼠标 每射击一次 他就自增一个随机数。
准星的最终坐标 应该是由 抖动数组鼠标坐标得到的。
同时 他应该有一个最大的抖动值。当抖动数组的值超过一个阈值的时候 他就会应该再抖动。

准星 大小变化也是同理。

准星回正
鼠标松开
我们一个 吧shakevalue 的数字归0
让他向0靠近。

代码

时间轴的主函数

第1帧

import flash.events.*;
//  接收输入    吧输入的数据储存在 类里面
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
stage.addEventListener(MouseEvent.MOUSE_UP,mouseUpHandler)
stage.addEventListener(MouseEvent.MOUSE_MOVE,mouseMoveHandler)

function mouseDownHandler(e:MouseEvent):void{
		GlobalInput.mouseDown = true;
}

function mouseUpHandler(e:MouseEvent):void{
		GlobalInput.mouseDown = false;
}
function mouseMoveHandler(e:MouseEvent):void{
		GlobalInput.mousePos[0] = e.stageX
		GlobalInput.mousePos[1] = e.stageY
}

// 产生准星 
var taget = new Sight(this)   
addChild(taget)

第3帧

taget.Tick() 
 gotoAndPlay(2)

每帧调用 准星的 taget 函数
Tick() 函数可以看成是 taget的主函数 看代码逻辑看他就行了

接收输入的类
静态类

package  {
	
	public class GlobalInput {
		public static var mousePos:Array=[0,0]   // 鼠标坐标
		public static var mouseDown:Boolean=false;  //  鼠标是否按下
	}
}

准星类

关于准星所有的东西都在这里,太长了 看起来费劲,代码解析 在这下面

package  {
	import Math
	public class Sight extends sight {
		var stage_
		var shakeYMax = 110     
		var shakeXMax = 40	    //X Y 最大偏移
		var shakeValue = [0,0]  //准星偏移  
		var _scale = 1         
		var max_scale = 2      //准❤最大缩放
		var range = 2         //子弹落点偏移
		public function Sight(stage) {
			this.stage_ = stage
		}


	public function Tick(){
		if (GlobalInput.mouseDown){
			shake()  // 枪口抖动,抖动的范围 应该是一个 
			fire()
		}
		else 
			correction()

		
		this.stage_.addChild(this)
	}
	
	 function shake(){
		if (Math.abs(shakeValue[0])< shakeXMax ){
			this.shakeValue[0]+= randint(0,10)* [1,-1][randint(0,1)] 
			}
		else if (shakeValue[0]>0){
			this.shakeValue[0]+= randint(0,10)*-1
			
		}
		else if (shakeValue[0]<0)
		{
			this.shakeValue[0]+= randint(0,10)*1
		}
		 
		if (Math.abs(shakeValue[1])< shakeYMax ){  //y抖动
			this.shakeValue[1]+= randint(0,10)*-1 
			}
		else
			this.shakeValue[1]-= randint(0,3)*-1 
			
		if (this._scale < this.max_scale)
			this._scale += Math.random()/30+0.01
		else 
			this._scale -= Math.random()/80+0.01

		
		this.scaleX =this._scale
		this.scaleY =this._scale
		this.x = GlobalInput.mousePos[0] + this.shakeValue[0]
		this.y = GlobalInput.mousePos[1] + this.shakeValue[1]
	} 
	
	 function correction(){
		if  (this.shakeValue[1] <  0)
			this.shakeValue[1]+= randint(20,30) 
		else
			this.shakeValue[1] = 0
			
		if (this.shakeValue[0] != 0){
			if (Math.abs(this.shakeValue[0]) < 3)
				this.shakeValue[0] = 0
			
			if (this.shakeValue[0] > 0)
				this.shakeValue[0] -=randint(3,6)
			else if (this.shakeValue[0] < 0)
				this.shakeValue[0] +=randint(3,6)
		}
			
			
		if (this._scale > 1)
		{
			this._scale -= this._scale += Math.random()/20
		}
		else
			this._scale = 1
 		
		this.scaleX =  this._scale
		this.scaleY =  this._scale
		this.x = GlobalInput.mousePos[0] + this.shakeValue[0]
		this.y = GlobalInput.mousePos[1] + this.shakeValue[1]
	}
	
	 function fire(){
		var spawnPos:Array =   [0,0]
		spawnPos[0] = randfloat(0,this.range * this._scale*3 ) * [1,-1][randint(0,1)] 
		spawnPos[1] = randfloat(0,this.range * this._scale*3 ) * [1,-1][randint(0,1)] 
		
		var b = new bullte()
		b.x =  this.x + spawnPos[0]
		b.y =  this.y + spawnPos[1]
		this.stage_.addChild(b)
	}
	
	 function randint(min,max):int{
		return   Math.round(Math.random()*(max-min))+min
	}
	
	 function randfloat(min,max):Number{
		return   Math.random()*(max-min)+min
	} 
	}
}

工具函数
randint 产生一个 min,max 的随机整数
randfloat 产生一个min 到 max 的随机小数
这2个用来求抖动用的。

	 function randint(min,max):int{
		return   Math.round(Math.random()*(max-min))+min
	}
	
	 function randfloat(min,max):Number{
		return   Math.random()*(max-min)+min
	} 

类的属性 用到的一些数据
stage_ 构造函传入的舞台,为了获得舞台上的一些参数
shakeValue 准星的偏移数组。关于准星的偏移数据都存在这里
shakeYMax shakeXMax 抖动的最大值。当偏移数组的知道大于这个 就不会再抖动
range 子弹的落点范围。以准星中心为坐标,半径为range 产生随机落点。

_scale 准星的真正比例
max_scale 准星的最大缩放抖动的时候 超过这个就不会继续放大。
this.x this.y 是准星的真正位置

		var stage_
		var shakeYMax = 110     
		var shakeXMax = 40	    //X Y 最大偏移
		var shakeValue = [0,0]  //准星偏移  
		var _scale = 1         
		var max_scale = 2      //准❤最大缩放
		var range = 2         //子弹落点偏移

主函数 和 主要功能实现

主函数
如果 鼠标按下就
开火+抖动
否则 就执行 准星修正

	public function Tick(){
		if (GlobalInput.mouseDown){
			shake()  // 枪口抖动,抖动的范围 应该是一个 
			fire()
		}
		else 
			correction()
		this.stage_.addChild(this)
	}

准星抖动

准星的抖动 我分成了3部分 x方向上的抖动 y 方向上的抖动 和缩放
x方向上的抖动
[1,-1][randint(0,1)] 这一段可能有人看不懂,我分解下
var lis1 = [1,-1],index = randint(0,1)
得到一个值 list1[index] 实际上就是从[1,-1]随机选择一个出来。
x的抖动是分左右的。
逻辑
if (x方向上准星偏移绝对值 < 最大值)
准星的x偏移+= 一个随机数 * 1或者-1 (1代表右边 -1代表左边)
else if 已经到达最大值 且 在右边
让准星往左边偏移一点
else if 已经到最大值且 准星在坐标
让准星往右边偏移一点

为什么要处理边界呢?假设你准星偏移到边界,你不继续偏移了。他就会卡在那里不动 很傻。

y抖动
if (y方向上准星偏移 < 最大值)
准星的y偏移+= 一个随机数
else if 已经到达最大值
让他往下偏移一点点

缩放
if 缩放值<缩放最大值
缩放值 随机的变大
else 已经达到追到
缩放值变小了一点点’

为什么要处理边界 上面的x有说。
接着 我们求完偏移数组,和准星缩放 应该让他 赋值给 真正的准星位置上。

this.scaleX 是准星影片剪辑的属性。他决定了准星的大小
this.scaleX =this._scale
this.scaleY =this._scale
this.x 不用说了 他就决定了准星显示的真正坐标。
解释下
this.x = 鼠标的x位置 + 准星的x偏移
this.x = GlobalInput.mousePos[0] + this.shakeValue[0]
this.y = GlobalInput.mousePos[1] + this.shakeValue[1]

		if (Math.abs(shakeValue[0])< shakeXMax ){
			this.shakeValue[0]+= randint(0,10)* [1,-1][randint(0,1)] 
		else if (shakeValue[0]>0)
			this.shakeValue[0]+= randint(0,10)*-1
		else if (shakeValue[0]<0)
			this.shakeValue[0]+= randint(0,10)*1
	
		 
		if (Math.abs(shakeValue[1])< shakeYMax ) //y抖动
			this.shakeValue[1]+= randint(0,10)*-1 
		else
			this.shakeValue[1]-= randint(0,3)*-1 
			
		if (this._scale < this.max_scale)
			this._scale += Math.random()/30+0.01
		else 
			this._scale -= Math.random()/80+0.01

		
		this.scaleX =this._scale
		this.scaleY =this._scale
		this.x = GlobalInput.mousePos[0] + this.shakeValue[0]
		this.y = GlobalInput.mousePos[1] + this.shakeValue[1]

开火函数

开火函数 实现了 对开火坐标的确定 和 子弹的产生。
[1,-1][randint(0,1)] 上面有解释 自己看。
spawnPos 是产生子弹最终目标 x y
首先我们确定 子弹是在准星中心 附近 产生的。而且 随着准星增大范围越大。
计算公式 = 基准范围 * 缩放比例 * 方向
randfloat(0,this.range * this._scale* 3 ) 求的就是 基准范围 * 缩放比例
[1,-1][randint(0,1)] 是方向

b的位置的确定,为什么是 this.x呢?==
主函数调用的顺序是 先抖动后fire()
因为 this.x y 就是准星的真正的中心位置
b.x = this.x + spawnPos[0]
b.y = this.y + spawnPos[1]

	 function fire(){
		var spawnPos:Array =   [0,0]
		spawnPos[0] = randfloat(0,this.range * this._scale*3 ) * [1,-1][randint(0,1)] 
		spawnPos[1] = randfloat(0,this.range * this._scale*3 ) * [1,-1][randint(0,1)] 
		
		var b = new bullte()
		b.x =  this.x + spawnPos[0]
		b.y =  this.y + spawnPos[1]
		this.stage_.addChild(b)
	}

回正函数

分为 x y 修正 和 比例修正
x y 主要是吧 偏移数组归为1
scale 主要是 吧他变为1

注意在x 修正的时候需要注意方向问题。
这里说一下y的修正
啊 忘记说了 这里y偏移是 负数。因为 y坐标轴是向下的。
if (如果y偏移 小于0)
y偏移 +=一个随机数
else(如果大于0 说明修正过头了)
y 偏移 = 0
同理 修正 需要检测是否修正过头,过头了 就把他变成 最终值。
scale的最终值是1
x y 偏移的最终值是0

最后是吧计算出来的修正值赋值给准星

	this.scaleX =  this._scale
	this.scaleY =  this._scale
	this.x = GlobalInput.mousePos[0] + this.shakeValue[0]
	this.y = GlobalInput.mousePos[1] + this.shakeValue[1]
	 function correction(){
		if  (this.shakeValue[1] <  0)
			this.shakeValue[1]+= randint(20,30) 
		else
			this.shakeValue[1] = 0
			
		if (this.shakeValue[0] != 0){
			if (Math.abs(this.shakeValue[0]) < 3)
				this.shakeValue[0] = 0
			
			if (this.shakeValue[0] > 0)
				this.shakeValue[0] -=randint(3,6)
			else if (this.shakeValue[0] < 0)
				this.shakeValue[0] +=randint(3,6)
		}
			
			
		if (this._scale > 1){
			this._scale -= this._scale += Math.random()/20
		}
		else
			this._scale = 1
 		
		this.scaleX =  this._scale
		this.scaleY =  this._scale
		this.x = GlobalInput.mousePos[0] + this.shakeValue[0]
		this.y = GlobalInput.mousePos[1] + this.shakeValue[1]
	}
	


抓住主要矛盾
if 按下
准星偏移
开火
else
准星回正

这个只是基本效果,真正玩游戏的时候 你会发现一开始的几枪 一般是不会偏的 比如MP5 。 这时候需要多加点判断喽
例如一个count 当他是1-3 的时候 不执行准星抖动
可以感觉到 游戏机制 的背后还是算法,和数据的计算 和语言没多大关系

个人的总结,废话有点多。见谅
如果有说错的地方 请大佬斧正

代码链接
链接:https://pan.baidu.com/s/1q70GL2bZ92CGBP1YRTCspg
提取码:eps9

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值