《星辰战机》使用P2物理引擎

(该游戏并不需要模拟物理,这里有些大材小用,只用来检测碰撞,哈哈哈)

1、首先初始化p2 world:

this.world = new p2.World({ gravity: [0, 0] });    // 不需要重力


2、更新物理计算

egret.startTick(this.updateWorld, this);

/**
 * 更新世界
 */
private updateWorld(ts: number): boolean {
    var timeStep = ts / 1000;
    this.world.step(timeStep);
    var bodys = this.world.bodies;
    var len: number = bodys.length;
    for (var i: number = 0; i < len; i++) {
        var body: p2.Body = bodys[i];
        if (body.userData && body.userData.skin) {
            // 更新素材的坐标和角度
            var skin: egret.DisplayObject = body.userData.skin;
            skin.x = body.position[0];
            skin.y = body.position[1];
            skin.rotation = body.angle * 180 / Math.PI;
        }
    }
    return true;
}


3、给需要检测的对象加上刚体

比如玩家操作的飞机:

let points = [[0, 100], [40, 0], [80, 100]];
let body = new p2.Body({ mass: 0 });
body.type = p2.Body.DYNAMIC;
body.userData = {};
body.fromPolygon(points, { optimalDecomp: false });
this.world.addBody(body);


4、为每个碰撞对象进行分组

比如玩家操作的飞机:

this.body.userData[emBodyType.Player] = true;
for (let i = 0; i < this.body.shapes.length; i++) {
	this.body.shapes[i].collisionGroup = emCollisionGroup.Player;
	this.body.shapes[i].collisionMask = emCollisionGroup.Enemy | emCollisionGroup.BOSSBullet | emCollisionGroup.Devil;
}


5、监听碰撞事件并处理对应的逻辑:

this.world.on("beginContact", this.CheckCollisionP2.bind(this));

/**
 * p2碰撞检测
 */
private CheckCollisionP2(event): void {
	var bodyA: p2.Body = event.bodyA;
	var bodyB: p2.Body = event.bodyB;
	if (bodyA.userData[emBodyType.Player] || bodyB.userData[emBodyType.Player]) {
		// 玩家碰撞
		this.CheckCollisionPlayerP2(bodyA, bodyB);
	} else if (bodyA.userData[emBodyType.Bullet] || bodyB.userData[emBodyType.Bullet]) {
		// 玩家子弹碰撞
		this.CheckCollisionBulletP2(bodyA, bodyB);
	}
	return;
}

/**
 * 玩家碰撞
 */
private CheckCollisionPlayerP2(bodyA: p2.Body, bodyB: p2.Body): void {
	// 玩家与敌机或BOSS子弹碰撞
	let isAPlayer = bodyA.userData[emBodyType.Player];	// A 是否是玩家
	if (bodyA.userData[emBodyType.Enemy] || bodyB.userData[emBodyType.Enemy]) {
		let enemy = isAPlayer ? bodyB : bodyA;
		// 玩家与敌机碰撞
		this.CheckCollisionPlayerEnemyP2(bodyA, bodyB);
	} else if (bodyA.userData[emBodyType.BOSSBullet] || bodyB.userData[emBodyType.BOSSBullet]) {
		// 玩家与BOSS子弹碰撞
		this.CheckCollisionBossBulletP2(bodyA, bodyB);
	} else if (bodyA.userData[emBodyType.Devil] || bodyB.userData[emBodyType.Devil]) {
		// 玩家与陷阱碰撞
		this.CheckCollisionDevilP2(bodyA, bodyB);
	}
	return;
}

/**
 * 玩家与敌机碰撞
 */
private CheckCollisionPlayerEnemyP2(bodyA: p2.Body, bodyB: p2.Body): void {
	let enemy: EnemyPlane = (bodyA.userData[emBodyType.Enemy] ? bodyA : bodyB).userData["self"];
	if (gameInfo.player.CheckBuff(emItemType.Shield)) {
		gameInfo.RemoveEnemy(enemy);
	} else {
		gameInfo.gameState = emGameState.GameOver;
	}

	return;
}

/**
 * 玩家与BOSS子弹碰撞
 */
private CheckCollisionBossBulletP2(bodyA: p2.Body, bodyB: p2.Body): void {
	let bullet: BossBullet = (bodyA.userData[emBodyType.BOSSBullet] ? bodyA : bodyB).userData["self"];
	if (gameInfo.lastBossDeadScore != -1)
		return;
	if (gameInfo.player.CheckBuff(emItemType.Shield)) {
		gameInfo.RemoveBossBullets(bullet);
	} else {
		gameInfo.gameState = emGameState.GameOver;
	}
	return;
}

/**
 * 玩家与陷阱碰撞
 */
private CheckCollisionDevilP2(bodyA: p2.Body, bodyB: p2.Body): void {
	let devil: Devil = (bodyA.userData[emBodyType.Devil] ? bodyA : bodyB).userData["self"];
	devil.RemoveDevil();
	if (!gameInfo.player.CheckBuff(emItemType.Shield)) {
		// 玩家沒有防护罩则游戏结束
		gameInfo.gameState = emGameState.GameOver;
	}

	return;
}

/**
 * 子弹碰撞
 */
private CheckCollisionBulletP2(bodyA: p2.Body, bodyB: p2.Body): void {
	if (bodyA.userData[emBodyType.Enemy] || bodyB.userData[emBodyType.Enemy]) {
		// 子弹和敌机碰撞
		this.CheckCollisionEnemyP2(bodyA, bodyB);
	} else if (bodyA.userData[emBodyType.BOSS] || bodyB.userData[emBodyType.BOSS]) {
		// 子弹和BOSS碰撞
		this.CheckCollisionBOSSP2(bodyA, bodyB);
	} else if (bodyA.userData[emBodyType.Coin] || bodyB.userData[emBodyType.Coin]) {
		// 子弹和金币碰撞
		this.CheckCollisionCoinP2(bodyA, bodyB);
	} else if (bodyA.userData[emBodyType.Item] || bodyB.userData[emBodyType.Item]) {
		// 子弹和道具碰撞
		this.CheckCollisionItemP2(bodyA, bodyB);
	}
	return;
}

……


6、回收对象,也要记得移除对应的刚体!

if (body.userData && body.userData.skin) {
    skin = body.userData.skin;
    if (skin.parent != null) {
        //skin.parent.removeChild(skin);
    }
    body.userData = null;
}
this.world.removeBody(body);