You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.8 KiB
157 lines
4.8 KiB
|
1 week ago
|
import { _decorator, Component, Node, Vec2, Rect, Sprite, Label, CCInteger } from 'cc';
|
||
|
|
|
||
|
|
|
||
|
|
const { ccclass, property } = _decorator;
|
||
|
|
|
||
|
|
// 城墙攻击点类型
|
||
|
|
export interface WallAttackPoint {
|
||
|
|
id: string; // A, B, C, D等
|
||
|
|
position: Vec2;
|
||
|
|
isObstructed: boolean; // 是否被障碍物阻挡
|
||
|
|
health: number; // 该位置的血量
|
||
|
|
maxHealth: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
@ccclass('WallSystem')
|
||
|
|
export class WallSystem extends Component {
|
||
|
|
@property(Node)
|
||
|
|
wallNode: Node = null; // 城墙根节点
|
||
|
|
|
||
|
|
@property(CCInteger)
|
||
|
|
wallLength: number = 400; // 城墙总长度
|
||
|
|
|
||
|
|
@property(CCInteger)
|
||
|
|
attackPointCount: number = 4; // 攻击点数量 A,B,C,D
|
||
|
|
|
||
|
|
@property(CCInteger)
|
||
|
|
attackPointHealth: number = 100; // 每个攻击点的初始血量
|
||
|
|
|
||
|
|
private attackPoints: WallAttackPoint[] = [];
|
||
|
|
private wallRect: Rect = null; // 城墙碰撞区域
|
||
|
|
|
||
|
|
init() {
|
||
|
|
this.initAttackPoints();
|
||
|
|
this.initWallCollision();
|
||
|
|
}
|
||
|
|
|
||
|
|
// 初始化攻击点
|
||
|
|
private initAttackPoints() {
|
||
|
|
this.attackPoints = [];
|
||
|
|
|
||
|
|
// 计算攻击点间距
|
||
|
|
const spacing = this.wallLength / (this.attackPointCount - 1);
|
||
|
|
const startY = -this.wallLength / 2;
|
||
|
|
|
||
|
|
// 创建攻击点
|
||
|
|
for (let i = 0; i < this.attackPointCount; i++) {
|
||
|
|
const id = String.fromCharCode(65 + i); // A, B, C, D...
|
||
|
|
const position = new Vec2(
|
||
|
|
this.wallNode.position.x,
|
||
|
|
startY + i * spacing
|
||
|
|
);
|
||
|
|
|
||
|
|
this.attackPoints.push({
|
||
|
|
id,
|
||
|
|
position,
|
||
|
|
isObstructed: false,
|
||
|
|
health: this.attackPointHealth,
|
||
|
|
maxHealth: this.attackPointHealth
|
||
|
|
});
|
||
|
|
|
||
|
|
// 在场景中创建可视化攻击点标记
|
||
|
|
this.createAttackPointMarker(id, position);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 创建攻击点标记
|
||
|
|
private createAttackPointMarker(id: string, position: Vec2) {
|
||
|
|
const marker = new Node(`WallPoint_${id}`);
|
||
|
|
marker.setParent(this.wallNode);
|
||
|
|
marker.setPosition(position.x, position.y, 0);
|
||
|
|
|
||
|
|
// 添加一个小图标作为标记
|
||
|
|
const sprite = marker.addComponent(Sprite);
|
||
|
|
// 这里应该设置一个合适的精灵帧,简化处理略
|
||
|
|
|
||
|
|
// 添加ID标签
|
||
|
|
const labelNode = new Node('Label');
|
||
|
|
labelNode.setParent(marker);
|
||
|
|
const label = labelNode.addComponent(Label);
|
||
|
|
label.string = id;
|
||
|
|
labelNode.setPosition(0, 20);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 初始化城墙碰撞区域
|
||
|
|
private initWallCollision() {
|
||
|
|
// 假设城墙是一个矩形,位于左侧
|
||
|
|
this.wallRect = new Rect(
|
||
|
|
this.wallNode.position.x - 20, // x
|
||
|
|
-this.wallLength / 2, // y
|
||
|
|
40, // width
|
||
|
|
this.wallLength // height
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 检查点是否与城墙碰撞
|
||
|
|
isCollidingWithWall(point: Vec2): boolean {
|
||
|
|
return this.wallRect.contains(point);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取最近的攻击点
|
||
|
|
getNearestAttackPoint(position: Vec2): WallAttackPoint {
|
||
|
|
let nearestPoint: WallAttackPoint = null;
|
||
|
|
let minDistance = Number.MAX_VALUE;
|
||
|
|
|
||
|
|
for (const point of this.attackPoints) {
|
||
|
|
if (point.isObstructed) continue; // 跳过被阻挡的点
|
||
|
|
|
||
|
|
const distance = Vec2.distance(position, point.position);
|
||
|
|
if (distance < minDistance) {
|
||
|
|
minDistance = distance;
|
||
|
|
nearestPoint = point;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return nearestPoint;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取所有可用的攻击点(未被阻挡)
|
||
|
|
getAvailableAttackPoints(): WallAttackPoint[] {
|
||
|
|
return this.attackPoints.filter(point => !point.isObstructed);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 检查攻击点是否被障碍物阻挡
|
||
|
|
updateAttackPointObstructions(obstaclePositions: Vec2[]) {
|
||
|
|
for (const point of this.attackPoints) {
|
||
|
|
// 检查是否有障碍物在攻击点附近(例如30像素内)
|
||
|
|
point.isObstructed = obstaclePositions.some(obstaclePos =>
|
||
|
|
Vec2.distance(obstaclePos, point.position) < 30
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 处理攻击
|
||
|
|
takeDamage(pointId: string, damage: number): boolean {
|
||
|
|
const point = this.attackPoints.find(p => p.id === pointId);
|
||
|
|
if (!point) return false;
|
||
|
|
|
||
|
|
point.health -= damage;
|
||
|
|
if (point.health <= 0) {
|
||
|
|
point.health = 0;
|
||
|
|
return true; // 该点已被摧毁
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取城墙位置信息
|
||
|
|
getWallRect(): Rect {
|
||
|
|
return this.wallRect;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取所有攻击点
|
||
|
|
getAllAttackPoints(): WallAttackPoint[] {
|
||
|
|
return [...this.attackPoints];
|
||
|
|
}
|
||
|
|
}
|