最近在做小游戏时遇到个物体沿着抛物线运动,并且要显示抛物线轨迹。由于第一次弄CocosCreate3D 引擎开发,查了网上好多资料发现都是在2d下实现没有3d。因为我一直是unity引擎开发,所以将以前写的代码改变,用到Create3D中来实现功能。下面我直接将代码贴出来做个记录。
1:抛物线具体实现方法
import { _decorator, Vec3,} from "cc";
const { ccclass, property } = _decorator;
@ccclass("PhysicsUtil")
export class PhysicsUtil {
private m_start:Vec3
private m_end:Vec3
private m_height:number
private m_gravity:number
private m_upTime:number
private m_downTime:number
private m_totalTime:number
private m_velocityStart:Vec3
private m_position:Vec3
private m_time:number
/// <summary> 起点 </summary>
public get start():Vec3{return this.m_start}
/// <summary> 终点 </summary>
public get end():Vec3 {return this.m_end}
/// <summary> 目标高度 </summary>
public get height():number {return this.m_height}
/// <summary> 重力加速度 </summary>
public get gravity():number { return this.m_gravity}
/// <summary> 上升时间 </summary>
public get upTime():number {return this.m_upTime}
/// <summary> 下降时间 </summary>
public get downTime():number {return this.m_downTime}
/// <summary> 总运动时间 </summary>
public get totalTime():number {return this.m_totalTime}
/// <summary> 顶点 </summary>
public get top():Vec3 {return this.GetPosition(this.m_upTime)}
/// <summary> 初始速度 </summary>
public get velocityStart():Vec3 {return this.m_velocityStart}
/// <summary> 当前位置 </summary>
public get position():Vec3 {return this.m_position}
/// <summary> 当前速度 </summary>
public get velocity():Vec3 {return this.GetVelocity(this.m_time)}
/// <summary> 当前时间 </summary>
public get time() {return this.m_time;}
public set time(val) {
this.m_time = val;
this.m_position = this.GetPosition(this.m_time);
}
/// <summary> 初始化抛物线运动轨迹 </summary>
/// <param name="start">起点</param>
/// <param name="end">终点</param>
/// <param name="height">高度(相对于两个点的最高位置 高出多少)</param>
/// <param name="gravity">重力加速度(负数)</param>
init(start:Vec3,end:Vec3,height:number=10,gravity:number=-9.8)
{
let topY:number = Math.max(start.y, end.y) + height;
let d1:number = topY - start.y;
let d2:number = topY - end.y;
let g2:number = 2 / -gravity;
let t1:number = Math.sqrt(g2 * d1);
let t2:number = Math.sqrt(g2 * d2);
let t:number = t1 + t2;
let vX:number = (end.x - start.x) / t;
let vZ:number = (end.z - start.z) / t;
let vY:number = -gravity * t1;
this.m_start = start;
this.m_end = end;
this.m_height = height;
this.m_gravity = gravity;
this.m_upTime = t1;
this.m_downTime = t2;
this.m_totalTime = t;
this.m_velocityStart = new Vec3(vX, vY, vZ);
this.m_position = this.m_start;
this.m_time = 0;
}
/// <summary> 获取某个时间点的位置 </summary>
public GetPosition(time:number):Vec3
{
if (time == 0) {
return this.m_start;
}
if (time == this.m_totalTime) {
return this.m_end;
}
let dY:number = 0.5 * this.m_gravity * time * time;
let vector3:Vec3= new Vec3(this.m_velocityStart.x*time,this.m_velocityStart.y*time,this.m_velocityStart.z*time)
let dYVec3:Vec3=new Vec3(0+this.m_start.x+vector3.x, dY+this.m_start.y+vector3.y, (0+this.m_start.z+vector3.z))
return dYVec3
}
/// <summary> 获取某个时间点的速度 </summary>
public GetVelocity(time:number):Vec3
{
if (time == 0) return this.m_velocityStart;
let dYVec3=new Vec3(0+this.m_velocityStart.x, this.m_velocityStart.y +this.m_velocityStart.y + (this.m_gravity * time), this.m_velocityStart.z)
return dYVec3
}
}
2:抛物线调用
import { _decorator, Component, Node,Vec3,instantiate, Prefab } from "cc";
import {PhysicsUtil} from "./PhysicsUtil"
const { ccclass, property } = _decorator;
@ccclass("Missile")
export class Missile extends Component {
lineList: { [key: number]: Node } = {};
_Physics:PhysicsUtil //抛物线运动轨迹
@property(Node)
play:Node = null // 飞行对象
@property(Node)
target:Node = null // 目标
@property
height:number=16 // 高度
@property
gravity:number = -9.8; // 重力加速度
@property(Prefab)
pointPrefab:Prefab = null;
@property
segmentCount:number=20 //抛物线预测计数
private playPos:Vec3 = null // 飞行对象位置点
private targetPos:Vec3 = null // 目标位置点
isStart:boolean = false
isLine:boolean=false
_deltaTime:number
start () {
this.CreateLine()
this._Physics = new PhysicsUtil();
this.isLine=true
}
//控制物体开始移动
SetStart()
{
this.isLine=false
this.isStart=true
}
update (deltaTime: number) {
this._deltaTime=deltaTime
if(this.isStart)
{
this.StartMove()
}
if(this.isLine)
{
this.DrawLine()
}
}
//创建虚拟轨迹线
CreateLine()
{
this.lineList=[]
let scene = cc.director.getScene()
let mNode:Node=scene.getChildByName('Node')
mNode.removeAllChildren()
for(let i=0;i<this.segmentCount;i++)
{
let pointNode:Node =instantiate(this.pointPrefab);
pointNode.setParent(mNode)
pointNode.setPosition(Vec3.ZERO)
this.lineList[i]=pointNode
pointNode.active=false
}
}
//根据目标点画轨迹线
DrawLine()
{
this.playPos=this.play.position.clone()
this.targetPos=this.target.position.clone()
this._Physics.init(this.playPos,this.targetPos,this.height, this.gravity)
this.play.lookAt(this._Physics.GetPosition(this._Physics.time + this._deltaTime));
let timeStep = this._Physics.totalTime/this.segmentCount
if(this.lineList!=null)
{
for(let i=0;i<this.segmentCount;i++)
{
let pointNode:Node = this.lineList[i]
pointNode.active=true
let pos = this._Physics.GetPosition(timeStep*i)
pointNode.setPosition(pos)
}
}
}
//物体沿着抛物线轨迹开始移动
StartMove()
{
//隐藏轨迹线
for(let i=0;i<this.segmentCount;i++)
{
let pointNode:Node = this.lineList[i]
pointNode.active=false
}
this._Physics.time=this._Physics.time+this._deltaTime
this.play.position = this._Physics.position;
this.playPos=this.play.position.clone()
// 计算转向
this.play.lookAt(this._Physics.GetPosition(this._Physics.time + this._deltaTime));
// 简单模拟一下碰撞检测
if (this._Physics.time >= this._Physics.totalTime)
{
this.play.position=this.target.position
this.play.rotation=this.target.rotation
console.log("==简单模拟一下碰撞检测==")
this.isStart=false
this.isLine=true
}
}
}