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

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

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

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

【flash】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

相关标签: flash 游戏开发