激光扫射技能,感觉还是挺酷炫的,可以应用在镭射眼、奥特曼光波、张口就来的激光攻击(比如特斯拉)等。
本篇实现方法没采用Cocos的物理引擎碰撞检测,主要用的是图形与图形是否有交集的检测
需要的东西:
1.一张可九宫格拉伸的激光射线png图片
2.CocosCreator 2.4.4
3.可被攻击的木箱
4.木箱被击碎的动画
实现方式:
首先,新建一个script,写一个cc.Component
设置一个用来控制激光的cc.Node,用property,方便拖拽赋值。
/**激光 */
@property(cc.Node)
skillNode: cc.Node = null
激光扫射嘛 一般是先直直的像金箍棒一样快速伸长,然后再进行角度变换的横扫。
考虑到快速伸长的过程也是可攻击到敌人的,换句话说就是每一单位时间都会判断一下激光的长度和箱子受击范围是否相交来决定是否销毁箱子。
假设让激光的光波先每0.05秒延长40像素,达到500像素左右开始做旋转。同时进行受击判断doSkill()
大概持续3秒左右:
代码实现
onClick(){
this.schedule(this.showLight,0.05)
this.scheduleOnce(this.doDestory,3)
}
/**释放激光射线 */
showLight(){
this.doSkill()//受击判断
this.skillNode.width += 40
if(this.skillNode.width >= 500){
this.skillNode.width = 500
}
if(this.skillNode.width > 400){
this.skillNode.angle -= 1
}
}
doDestory() {
this.schedule(this.hideSkillNode, 0)
}
/**收回激光射线 */
hideSkillNode(){
this.skillNode.width -= 100
if(this.skillNode.width <=0) {
this.skillNode.width = 0
this.unschedule(this.hideSkillNode)
}
}
受击判断
如果把激光当做一条线的话,其实就比较容易了,只需要把图片的anchor点设置在左边的高的中点,也就是Anchor属性设为(0, 0.5),以图片宽度为线段长度两点连线,再给这条线加一个旋转角就可以了。以这条线段和箱子的边框是否相交为基准判断是否销毁箱子。
这种方法比较简单,但是如果激光是光波状的,图片比较接近矩形,就比较不适合这么做了,因为达不到那种“擦着边就灰飞烟灭”的效果,得等没入光波内了才灭,那样可能又会因为被光波遮挡,看不见箱子的破碎动画,效果大打折扣。
所以这里我才用另一种方式,稍微复杂一点的把激光的线扩充成一个矩形。
首先,换算出激光相对x轴的倾斜角度angle:激光的angle / 180 * Π
取出激光this.skillNode的坐标x,y,和高h、宽w
以此算出倾斜后激光矩形的四个顶点a1,a2,a3,a4,存为数组a
代码实现
let angle = this.skillNode.angle / 180 * Math.PI
let x = this.skillNode.x
let y = this.skillNode.y
let h = this.skillNode.height / 2
let w = this.skillNode.width
let a1 = cc.v2(x + Math.cos( Math.PI/2 + angle) * (h/2), y + Math.sin(Math.PI/2 + angle) * (h/2))
let a2 = cc.v2(x + Math.cos( -Math.PI/2 + angle) * (h/2), y + Math.sin(-Math.PI/2 + angle) * (h/2))
let a3 = cc.v2(a1.x + (Math.cos(angle) * w), a1.y + Math.sin(angle) * w)
let a4 = cc.v2(a2.x + (Math.cos(angle) * w), a2.y + Math.sin(angle) * w)
let a = [a1, a2, a4, a3]
// 可1绘制出矩形a看看效果
var gra = new cc.Node().addComponent(cc.Graphics)
gra.node.parent = this.skillNode.parent
gra.moveTo(a1.x, a1.y)
gra.lineTo(a2.x, a2.y)
gra.lineTo(a4.x, a4.y)
gra.lineTo(a3.x, a3.y)
gra.close();
gra.stroke()
gra.fillColor = cc.color(255,0,0,1)
gra.fill()
接下来计算出对应的木箱quad四个顶点b1,b2,b3,b4,存为数组b
a,b通过cc.Intersection.polygonPolygon()【注:测试多边形与多边形是否相交】比对是否相交即可。返回比对结果为true就播放木箱销毁和爆破动画。
代码实现
let quad_rect = quad.node.getBoundingBox()
let b1 = cc.v2(quad_rect.xMin, quad_rect.yMin)
let b2 = cc.v2(quad_rect.xMax, quad_rect.yMin)
let b3 = cc.v2(quad_rect.xMax, quad_rect.yMax)
let b4 = cc.v2(quad_rect.xMin, quad_rect.yMax)
let b = [b1, b2, b3, b4]
var isOK = cc.Intersection.polygonPolygon(a, b)
所以,其实就是按上面的设定,每0.04秒对逐个木箱执行一次上述流程,进行比对看是否需要销毁即可。
也可以对木箱进行转换为矩阵、二维表,通过直接获取激光范围先一步进行筛选攻击范围内的木箱数组,减少比对次数。这部分后续有时间再进行另外的补充好了。