Bullet.ts
private _lastCheckPos:Laya.Point = new Laya.Point(0, 0); // 上次检测的位置
/**
* 检查两条线段是否相交
* 线段1: (x1, y1) -> (x2, y2)
* 线段2: (x3, y3) -> (x4, y4)
*/
isLinesIntersect(x1, y1, x2, y2, x3, y3, x4, y4) {
let denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (denom === 0) {
return false; // 平行或共线
}
let t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom;
let u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom;
return t >= 0 && t <= 1 && u >= 0 && u <= 1;
}
/**
* 检查子弹是否与怪物矩形相撞
* @param {Laya.Point} start 子弹起始位置
* @param {Laya.Point} end 子弹结束位置
* @param {Laya.Rectangle} rect 怪物矩形
* @returns {boolean} 如果相撞返回 true,否则返回 false
*/
checkBulletHit(start, end, rect) {
// 1. 检查线段的两个端点是否在矩形内部
if (rect.contains(start.x, start.y) || rect.contains(end.x, end.y)) {
return true;
}
// 2. 检查线段是否与矩形的四条边相交
// 定义矩形的四条边
let left = rect.x;
let right = rect.x + rect.width;
let top = rect.y;
let bottom = rect.y + rect.height;
// 定义线段的两个端点
let x1 = start.x;
let y1 = start.y;
let x2 = end.x;
let y2 = end.y;
// 检查线段是否与矩形的四条边相交
// 左边
if (this.isLinesIntersect(x1, y1, x2, y2, left, top, left, bottom)) return true;
// 右边
if (this.isLinesIntersect(x1, y1, x2, y2, right, top, right, bottom)) return true;
// 上边
if (this.isLinesIntersect(x1, y1, x2, y2, left, top, right, top)) return true;
// 下边
if (this.isLinesIntersect(x1, y1, x2, y2, left, bottom, right, bottom)) return true;
// 如果都不相交
return false;
}
/**
* 检查子弹是否与怪物最近的怪物相撞
* @returns {boolean} 如果相撞返回 怪物,否则返回 null
*/
checkHit(fishCtrl: FishCtrl): IFish {
if (this._hasHit) return null;
if (this._target) return null;
let nowPos = new Laya.Point(this.x, this.y);
let fishList = fishCtrl.getFishList();
let minDistance = Number.MAX_VALUE;
let targetMonster = null;
for (let fishId in fishList) {
let fish: IFish = fishList[fishId];
let hitRect = fish.getHitRect();
if (fish && fish.type != 0 && fish.canShoot && this.checkBulletHit(this._lastCheckPos, nowPos, hitRect)) {
// 计算起点到怪物中心的距离
let distance = this._lastCheckPos.distance(hitRect.x + hitRect.width / 2, hitRect.y + hitRect.height / 2);
if (distance < minDistance) {
minDistance = distance;
targetMonster = fish;
}
}
}
this._lastCheckPos = nowPos;
return targetMonster;
}
private _dirction: Vector2;
step(time: number): number {
let x = this.x + this._dirction.x * s
let y = this.y + this._dirction.y * s
this.pos(x, y, true);
}
init(uid: number, id: number, from: Vector2, to: Vector2): void {
let a: number = to.x - from.x;
let b: number = to.y - from.y;
let m: number = Math.sqrt(a * a + b * b);
this._dirction.x = a / m;
this._dirction.y = b / m;
this.pos(from.x, from.y, true);
this._lastCheckPos = new Laya.Point(from.x, from.y);
}
BulletCtrl.ts
Laya.timer.frameLoop(1, this, this.loop);
private loop() {
let now: number = getTime();
for (let i = 0; i < this._bulletList.length; i++) {
let fish: IFish, fishID: number;
let b: Bullet = this._bulletList[i];
if (b.hasHit) {
b.hit();
this._bulletList.splice(i, 1);
i = i - 1;
let count: number = this._bulletCnt[b.uid] || 0;
this._bulletCnt[b.uid] = --count;
} else {
//移动
fishID = b.step(now - this._lastTime);
}
// 检测是否击中
let fish = b.checkHit(this._fishCtrl);
if (fish) {
fishID = fish.id;
b.hit(); // 处理爆炸
this._bulletList.splice(i, 1);
i = i - 1;
let count: number = this._bulletCnt[b.uid] || 0;
this._bulletCnt[b.uid] = --count;
}
app.event(BulletCtrl.BULLET_HIT_FISH, { isrobot: b.isrobot, uid: b.uid, bullet_id: b.id, fishid: fishID, ls: [] });
}
this._lastTime = now;
}