上篇讲述了如何结合绘制组件和物理组件,来使线条具备刚体属性。本篇将讲述如何对线添加一个方向力,以便可以将画出来的线抬起来,先看效果图:
去掉上方方块后:
原理
蜜蜂相连的两帧的的位置分别为startPos和endPos, 以startPos为起点,以endPos为终点发射一条射线
通过PhysicsSystem2D.instance.raycast
接口,找出所画线与射线相交的第一个刚体
typescript
/** 检测碰撞 */
private checkRayCast(startPos: math.IVec2Like, endPos: math.IVec2Like): boolean {
const result = PhysicsSystem2D.instance.raycast(startPos, endPos, ERaycast2DType.Closest) as RaycastResult2D[];
if (result.length === 0) {
return false;
} else {
// 找出第一个碰撞到的刚体
if (!this._lineRigidBody) {
this._lineRigidBody = result[0].collider.node.getComponent(RigidBody2D);
}
return true;
}
}
对检测出的刚体施加一个方向向量,通过刚体applyLinearImpulseToCenter
方法,来对刚体施加方向力
typescript
...
_endPos: math.Vec2 = math.Vec2.ZERO;
/** 移动 */
public onMove(dt) {
let dir = this._target.getPosition().subtract(this.node.getPosition()).normalize();
const startPos = this.node.getPosition();
this._rigidBody.linearVelocity = v2(dir.x, dir.y).multiplyScalar(this._speed);
this._endPos.set(startPos.x + this._rigidBody.linearVelocity.x, startPos.y + this._rigidBody.linearVelocity.y);
if (this.checkRayCast(startPos, this._endPos)) {
// 检测到碰撞,施加力
const forceVector = v2(dir.x * this._speed, dir.y * this._speed);
this._lineRigidBody.applyLinearImpulseToCenter(forceVector, true);
}
}
蜜蜂组件的完整代码如下:
typescript
export default class Enemy extends Component {
/** 攻击对象 */
private _target: Node = null;
public set target(value: Node) {
this._target = value;
this.node.scale.set(this.node.getPosition().x < this._target.getPosition().x ? -0.5 : 0.5, 0.5);
}
public get target(): Node {
return this._target;
}
/** 线刚体 */
private _lineRigidBody: RigidBody2D = null;
public set lineRigidBody(value: RigidBody2D) {
this._lineRigidBody = value;
}
/** 速度 */
private _speed: number = 20;
/** 自身刚体 */
private _rigidBody: RigidBody2D = null;
protected onLoad(): void {
this._rigidBody = this.node.getComponent(RigidBody2D);
}
/** 检测碰撞 */
private checkRayCast(startPos: math.IVec2Like, endPos: math.IVec2Like): boolean {
const result = PhysicsSystem2D.instance.raycast(startPos, endPos, ERaycast2DType.Closest) as RaycastResult2D[];
if (result.length === 0) {
return false;
} else {
// 找出第一个碰撞到的刚体
if (!this._lineRigidBody) {
this._lineRigidBody = result[0].collider.node.getComponent(RigidBody2D);
}
return true;
}
}
_endPos: math.Vec2 = math.Vec2.ZERO;
/** 移动 */
public onMove(dt) {
let dir = this._target.getPosition().subtract(this.node.getPosition()).normalize();
const startPos = this.node.getPosition();
this._rigidBody.linearVelocity = v2(dir.x, dir.y).multiplyScalar(this._speed);
this._endPos.set(startPos.x + this._rigidBody.linearVelocity.x, startPos.y + this._rigidBody.linearVelocity.y);
if (this.checkRayCast(startPos, this._endPos)) {
// 检测到碰撞,施加力
const forceVector = v2(dir.x * this._speed, dir.y * this._speed);
this._lineRigidBody.applyLinearImpulseToCenter(forceVector, true);
}
}
/** 更新 */
public update(dt: number) {
this.onMove(dt);
}
}
当画完线后,直接创建蜜蜂节点,将Enemy
组件挂在蜜蜂节点上,并设置攻击目标_target
后,蜜蜂就会自动飞向主角,之后就可以看到开篇中蜜蜂推线或者抬线的效果。