实现效果: 子弹在发射之前提前把轨迹绘制出来.类似愤怒小鸟子弹的运动轨迹.
实现步骤分3步: 1 子弹的发射; 2 子弹运动过程中角度的变化; 3 辅助线的绘制.
开发工具: CocosCreator, VsCode
场景介绍: 场景是自己随便搭的, 比较简陋. 1:代表子弹, 2:代表炮台. 6, 7 为子弹和辅助线的预制体. 5: Gunmgr挂载在Canvas下.
实现思路: 1点击鼠标炮台向上开始旋转,松手后, 给子弹添加一个力, applyForceToCente(x,y). 用到了Creator提供的物理引擎
2 在炮台旋转的同时, 通过这个力, 每隔固定的时间间隔(比如0.06s)把位置计算出来, 确定x,y坐标后生成一个小圆点. 重复此步骤,生成若干个小圆点, 模拟轨迹.
组件添加:
子弹上挂载 PhySicsBoxCollider, (RigidBody会自动挂载), Bullet脚本用来检测当触碰到地面后, 停止炮台角度的旋转.及碰到地面或敌人相应的逻辑操作. ground地面也要挂载 PhySicsBoxCollider
相关代码:
GunMgr, 挂载在Canvs下
在onEventEnd阶段, 会根据当前位置和上一帧的 位置, 计算出子弹的旋转角度.
const {ccclass, property} = cc._decorator;
@ccclass
export default class GunMgr extends cc.Component {
@property(cc.Node)
gunNode = null;
@property(cc.Node)
bulletNode = null;
@property(cc.Prefab)
pointPrefab = null;
// LIFE-CYCLE CALLBACKS:
_curAngle =0;
gunSchedule = null;
bulletfun = null;
xLi:number = 12000;
g:number = 600;
chongX:number =0;
chongY:number =0;
onLoad () {
cc.director.getPhysicsManager().enabled = true;
cc.director.getPhysicsManager().gravity = cc.v2(0, -this.g);
var manager = cc.director.getCollisionManager();
manager.enabled = true;
this.bulletNode.active = false;
}
start () {
this.node.on(cc.Node.EventType.TOUCH_START, this.onEventStart, this);
this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onEventMove, this);
this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onEventCancel, this);
this.node.on(cc.Node.EventType.TOUCH_END, this.onEventEnd, this);
console.log('AAS: ', cc.PhysicsManager.PTM_RATIO);
}
update (dt) {
}
onEventStart()
{
console.log('nodePos: ', this.gunNode.position);
this._curAngle = 0;
this.chongX = this.xLi;
//通过角度计算力度
this.chongY = this.chongX * Math.tan(Math.abs(this._curAngle) * (Math.PI / 180));
this.gunSchedule = function(){
if (this._curAngle < 90){
this._curAngle -= 1;
this.updateLine();
this.gunNode.rotation = this._curAngle;
}
};
this.schedule(this.gunSchedule, 0.02);
}
onEventMove()
{
}
onEventCancel()
{
}
onEventEnd()
{
for(let i =1; i< this.gunNode.childrenCount; i++){
this.gunNode.children[i].destroy();
}
this.bulletNode.position = cc.v2(0,0)
this.bulletNode.getComponent('Bullet').init(this);
this.unschedule(this.gunSchedule);
this.bulletNode.active = true;
this.chongX = this.xLi;
//通过角度计算力度
this.chongY = this.chongX * Math.tan(Math.abs(this._curAngle) * (Math.PI / 180));
//给子弹设置冲量
console.log('chongX: ', this.chongX);
console.log('chongY: ', this.chongY);
console.log('bulletNodeM: ', this.bulletNode.getComponent(cc.RigidBody).getMass());
this.bulletNode.getComponent(cc.RigidBody).applyForceToCenter(cc.v2(this.chongX, this.chongY));
let curPos = this.bulletNode.position;
let lastPos = curPos;
this.bulletfun = function(){
curPos = this.bulletNode.position;
//计算角度
let lenX = curPos.x - lastPos.x;
let lenY = 0;
let r = 0;
if(curPos.y < lastPos.y){ //向上运动
lenY = curPos.y - lastPos.y;
r = Math.atan2(lenY, lenX) * 180 / Math.PI;
}
else{ //向下运动
lenY = lastPos.y - curPos.y;
r = -1 * Math.atan2(lenY, lenX) * 180 / Math.PI;
}
lastPos = curPos;
this.bulletNode.rotation = -r;
};
this.schedule(this.bulletfun, 0.1);
}
insPoint()
{
let pointNode = cc.instantiate(this.pointPrefab);
pointNode.active = true;
return pointNode;
}
updateLine()
{
for(let i =1; i< this.gunNode.childrenCount; i++){
this.gunNode.children[i].destroy();
}
let timer =0;
for(let i=0; i < 15; i++){
let temp:cc.Node = this.insPoint();
temp.setParent(this.gunNode);
timer += 0.06;
let x = this.chongX/16.1 * timer;
let y = this.chongY/16.1 * timer - 0.5 * this.g * timer * timer;
console.log('x, y', x,y);
temp.setPosition(x, y);
}
}
stopSchedule()
{
this.unschedule(this.bulletfun);
}
}
Bullet
import GunMgr from "./GunMgr";
const {ccclass, property} = cc._decorator;
@ccclass
export default class Bullet extends cc.Component {
gunMgrTs = null;
// LIFE-CYCLE CALLBACKS:
onLoad () {
this.node.getComponent(cc.RigidBody).enabledContactListener = true;
}
start () {
}
init( gunMgrTs:GunMgr)
{
this.gunMgrTs = gunMgrTs;
}
// update (dt) {}
onBeginContact(contact, selfCollider, otherCollider)
{
console.log('other: ', otherCollider);
console.log('self: ', selfCollider);
if(otherCollider.node.name == 'ground'){
this.gunMgrTs.stopSchedule();
console.log('Pos: ', this.node.position);
}
}
}