92 lines
2.4 KiB
TypeScript
92 lines
2.4 KiB
TypeScript
|
|
import {
|
||
|
|
_decorator,
|
||
|
|
Component,
|
||
|
|
Sprite,
|
||
|
|
SpriteFrame,
|
||
|
|
UITransform,
|
||
|
|
Size,
|
||
|
|
CircleCollider2D,
|
||
|
|
Contact2DType,
|
||
|
|
IPhysics2DContact,
|
||
|
|
RigidBody2D,
|
||
|
|
Vec2,
|
||
|
|
Node,
|
||
|
|
} from "cc";
|
||
|
|
import { FRUITS, MAX_LEVEL } from "./FruitConfig";
|
||
|
|
import { GameManager } from "./GameManager";
|
||
|
|
const { ccclass, property } = _decorator;
|
||
|
|
|
||
|
|
@ccclass("Fruit")
|
||
|
|
export class Fruit extends Component {
|
||
|
|
@property
|
||
|
|
level = 1; // 1..MAX_LEVEL
|
||
|
|
|
||
|
|
@property(Sprite)
|
||
|
|
sprite!: Sprite;
|
||
|
|
|
||
|
|
game!: GameManager;
|
||
|
|
collider!: CircleCollider2D;
|
||
|
|
body!: RigidBody2D;
|
||
|
|
|
||
|
|
// 防止同一对重复合成
|
||
|
|
merging = false;
|
||
|
|
removed = false;
|
||
|
|
|
||
|
|
init(level: number, spriteFrame: SpriteFrame, game: GameManager) {
|
||
|
|
this.level = level;
|
||
|
|
this.game = game;
|
||
|
|
if (!this.sprite) this.sprite = this.getComponent(Sprite)!;
|
||
|
|
this.sprite.spriteFrame = spriteFrame;
|
||
|
|
|
||
|
|
const def = FRUITS[this.level - 1];
|
||
|
|
const ui = this.getComponent(UITransform)!;
|
||
|
|
ui.setContentSize(new Size(def.radius * 2, def.radius * 2));
|
||
|
|
|
||
|
|
this.collider = this.getComponent(CircleCollider2D)!;
|
||
|
|
this.collider.radius = def.radius;
|
||
|
|
|
||
|
|
this.body = this.getComponent(RigidBody2D)!;
|
||
|
|
this.body.enabled = true;
|
||
|
|
|
||
|
|
this.merging = false;
|
||
|
|
this.removed = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
onEnable() {
|
||
|
|
const col = this.getComponent(CircleCollider2D);
|
||
|
|
if (col) col.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
||
|
|
}
|
||
|
|
|
||
|
|
onDisable() {
|
||
|
|
const col = this.getComponent(CircleCollider2D);
|
||
|
|
if (col) col.off(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
||
|
|
}
|
||
|
|
|
||
|
|
private onBeginContact(
|
||
|
|
selfCol: CircleCollider2D,
|
||
|
|
otherCol: CircleCollider2D,
|
||
|
|
_contact: IPhysics2DContact | null
|
||
|
|
) {
|
||
|
|
if (this.removed || this.merging) return;
|
||
|
|
const otherNode = otherCol.node as Node;
|
||
|
|
const otherFruit = otherNode.getComponent(Fruit);
|
||
|
|
if (!otherFruit || otherFruit.removed || otherFruit.merging) return;
|
||
|
|
|
||
|
|
// 仅同级可合成,且不能超过最大级
|
||
|
|
if (otherFruit.level !== this.level || this.level >= MAX_LEVEL) return;
|
||
|
|
|
||
|
|
// 为避免两者都合成,使用 uuid 决定触发者(只让“较小”的触发)
|
||
|
|
if (this.node.uuid > otherNode.uuid) return;
|
||
|
|
|
||
|
|
this.merging = true;
|
||
|
|
otherFruit.merging = true;
|
||
|
|
|
||
|
|
// 合成到下一级
|
||
|
|
const nextLevel = this.level + 1;
|
||
|
|
const wpA = this.node.worldPosition;
|
||
|
|
const wpB = otherNode.worldPosition;
|
||
|
|
const mid = wpA.clone().add(wpB).multiplyScalar(0.5);
|
||
|
|
this.game.spawnMerged(nextLevel, mid, this, otherFruit);
|
||
|
|
}
|
||
|
|
}
|