本文章主要介绍狼人杀的功能提供思路,并不能没有真正实现
一、项目整体架构与技术选型
该狼人杀游戏基于ArkTS语言开发,采用HarmonyOS的声明式UI框架,通过组件化设计将游戏逻辑与界面渲染解耦。核心架构包含三大模块:
- 状态管理模块:通过
@State
装饰器实现数据响应式,确保UI随游戏状态自动更新; - 界面渲染模块:利用
Column
、Grid
等容器组件实现分层布局,通过@Builder
修饰符封装可复用UI组件; - 游戏逻辑模块:基于状态机模式管理日夜循环、角色行动与胜负判定,通过枚举类型规范流程控制。
二、状态管理与数据模型详解
1. 核心状态变量解析
@State private players: Player[] = []; // 玩家列表,存储所有角色信息
@State private gamePhase: GamePhase = GamePhase.Night; // 游戏阶段(日夜切换)
@State private nightPhase: NightPhase = NightPhase.Wolf; // 夜间行动顺序
@State private isVoting: boolean = false; // 投票阶段标记
@State private voteResults: Map<number, number> = new Map(); // 投票结果统计
@State private witchHasAntidote: boolean = true; // 女巫解药状态
- 响应式原理:当
players
数组中玩家的isAlive
属性变更时,所有引用该数据的UI组件(如玩家卡片)会自动刷新; - 状态联动:
gamePhase
与nightPhase
配合控制界面显示内容,例如夜间阶段仅显示狼人/预言家/女巫的操作按钮。
2. 玩家模型(Player类)设计
class Player {
public isAlive: boolean = true; // 存活状态
public role: string; // 角色名称
public isWolf: boolean; // 是否为狼人
public hasUsedSkill: boolean = false; // 技能使用标记(如猎人开枪)
public index: number; // 玩家唯一索引
constructor(role: string, index: number) {
this.role = role;
this.isWolf = role === '狼人';
this.index = index;
}
public kill() {
this.isAlive = false;
this.isDead = true;
}
}
- 角色属性:通过
isWolf
字段区分阵营,role
字段存储角色名称(村民/狼人/预言家等); - 状态切换:
kill()
方法统一处理玩家死亡逻辑,确保UI与数据状态一致。
三、界面布局与组件化实现
1. 玩家列表的左右分栏布局
Scroll() {
Grid() {
// 左栏玩家(前半部分)
ForEach(this.players.slice(0, this.players.length / 2), (player, index) => {
GridItem() {
this.renderPlayer(player, index, 'left')
}
})
// 右栏玩家(后半部分)
ForEach(this.players.slice(this.players.length / 2), (player, index) => {
GridItem() {
this.renderPlayer(player, index + this.players.length / 2, 'right')
}
})
}
.columnsTemplate('1fr 1fr') // 两列等宽
.width('100%')
.height('45%')
.padding(5)
}
- 布局策略:使用
Grid
容器配合columnsTemplate('1fr 1fr')
实现左右分栏,通过slice
方法分割玩家数组; - 视觉区分:左栏玩家通过
alignItems(HorizontalAlign.Start)
靠左显示,右栏玩家靠右显示,死亡玩家卡片背景色设为#e0e0e0
并降低透明度。
2. 游戏结束弹窗组件
@Builder
renderGameOverDialog() {
Dialog() {
Column() {
Text('游戏结束!').fontSize(24).fontWeight(FontWeight.Bold)
Text(`胜利方:${this.winner}`).fontSize(18)
Scroll() {
Column() {
Text('玩家身份:').fontSize(16).fontWeight(FontWeight.Medium)
ForEach(this.players, (player) => {
Row() {
Text(`${player.role} ${player.isWolf ? '🐺' : '👤'}`)
Text(player.isAlive ? '存活' : '已淘汰')
.fontColor(player.isAlive ? '#008000' : '#FF0000')
}
})
}
.width('100%')
.padding(15)
.backgroundColor('#f0f0f0')
}
.height('200vp') // 固定弹窗内滚动区域高度
Button('重新开始').onClick(() => this.initializeGame())
}
.width('80%')
.backgroundColor('#FFFFFF')
.borderRadius(15)
}
.maskColor('#00000080') // 半透明遮罩层
.alignment(Alignment.Center)
}
- 交互设计:弹窗通过
Dialog
组件实现,半透明遮罩层maskColor
增强沉浸式体验; - 信息展示:使用
Row
布局并排显示玩家角色与存活状态,绿色/红色字体区分存活/死亡状态。
四、游戏核心逻辑与规则实现
1. 夜间行动流程控制
private confirmNightAction() {
switch (this.nightPhase) {
case NightPhase.Wolf:
// 狼人击杀逻辑
if (this.selectedPlayer !== -1 && this.players[this.selectedPlayer].isAlive) {
this.killedPlayerIndex = this.selectedPlayer;
this.addNightMessage(`狼人选择了击杀 ${this.players[this.selectedPlayer].role}`);
this.nightPhase = NightPhase.Seer; // 切换至预言家阶段
}
break;
case NightPhase.Seer:
// 预言家查验逻辑
if (this.selectedPlayer !== -1) {
const isWolf = this.players[this.selectedPlayer].isWolf;
this.addNightMessage(`预言家查验结果:${isWolf ? '狼人' : '好人'}`);
this.nightPhase = NightPhase.Witch; // 切换至女巫阶段
}
break;
case NightPhase.Witch:
// 女巫解药/毒药逻辑
if (this.selectedPlayer === this.killedPlayerIndex && this.witchHasAntidote) {
this.savedPlayerIndex = this.selectedPlayer;
this.witchHasAntidote = false;
} else if (this.witchHasPoison) {
this.poisonedPlayerIndex = this.selectedPlayer;
this.witchHasPoison = false;
}
this.endNight(); // 结束夜间,进入白天
break;
}
}
- 阶段流转:通过
nightPhase
枚举值控制行动顺序,每个阶段完成后自动切换至下一阶段; - 技能限制:女巫解药仅能救被狼人击杀的玩家,毒药不可对同一目标使用两次。
2. 投票与淘汰机制
private endVote() {
// 统计最高票数玩家
let maxVotes = 0;
let votedPlayerIndex = -1;
this.voteResults.forEach((votes, index) => {
if (votes > maxVotes) {
maxVotes = votes;
votedPlayerIndex = index;
}
});
if (votedPlayerIndex !== -1) {
this.players[votedPlayerIndex].kill(); // 淘汰玩家
this.addDayMessage(`投票结束,${this.players[votedPlayerIndex].role} 被淘汰`);
// 猎人技能触发
if (this.players[votedPlayerIndex].role === '猎人' && !this.hunterHasShot) {
const alivePlayers = this.players.filter(p => p.isAlive && p.index !== votedPlayerIndex);
if (alivePlayers.length > 0) {
const randomIndex = Math.floor(Math.random() * alivePlayers.length);
alivePlayers[randomIndex].kill(); // 随机开枪
this.addDayMessage(`猎人开枪带走了 ${alivePlayers[randomIndex].role}`);
}
}
}
}
- 票数处理:使用
Map
统计票数,支持平局判定(tiedPlayers.length > 1
时无人淘汰); - 猎人规则:猎人死亡时若未开枪,自动随机选择存活玩家带走,体现规则严谨性。
五、边界条件与性能优化
1. 胜负判定逻辑
private checkGameStatus() {
let wolfCount = 0, villagerCount = 0;
this.players.forEach(player => {
if (player.isAlive) {
wolfCount += player.isWolf ? 1 : 0;
villagerCount += !player.isWolf ? 1 : 0;
}
});
if (wolfCount === 0) {
this.winner = '好人阵营';
this.isGameOver = true;
} else if (wolfCount >= villagerCount) {
this.winner = '狼人阵营';
this.isGameOver = true;
}
}
- 实时计算:每次夜间/投票结束后触发,确保游戏状态及时更新;
- 胜利条件:狼人全灭或狼人数量≥好人时,通过
isGameOver
标记触发结束流程。
2. 操作权限控制
private canSelectPlayer(index: number): boolean {
if (!this.players[index].isAlive) return false; // 死亡玩家不可选
switch (this.nightPhase) {
case NightPhase.Wolf: return !this.players[index].isWolf; // 狼人不能杀自己
case NightPhase.Seer: return true; // 预言家可查验任意存活玩家
case NightPhase.Witch:
// 女巫救人/毒人逻辑
if (this.killedPlayerIndex === index) return this.witchHasAntidote;
return this.witchHasPoison && index !== this.killedPlayerIndex;
default: return false;
}
}
- 权限过滤:通过
canSelectPlayer
方法统一控制玩家选择权限,避免非法操作; - 阶段限制:狼人阶段不可选择其他狼人,女巫阶段根据解药/毒药状态限制目标。
六、代码可维护性与拓展性设计
- 枚举类型规范:通过
GamePhase
、NightPhase
等枚举明确状态值,避免魔法数字,提升代码可读性; - 复用组件封装:使用
@Builder
修饰符将玩家卡片、按钮组等UI元素封装为可复用组件,减少代码冗余; - 独立方法拆分:将
endNight()
、checkGameStatus()
等逻辑拆分为独立方法,保持build()
方法简洁; - 角色配置拓展:通过修改
roles
数组可快速调整初始角色分配,为添加新角色(如守卫、白痴)预留接口。
七、附:源文件
@Preview
@Component
export struct play_10 {
// 游戏状态
@State private players: Player[] = [];
@State private dayCount: number = 1;
@State private gamePhase: GamePhase = GamePhase.Night;
@State private nightPhase: NightPhase = NightPhase.Wolf;
@State private gameStatus: GameStatus = GameStatus.Playing;
@State private message: string = '游戏开始!请等待夜晚降临...';
@State private selectedPlayer: number = -1;
@State private killedPlayerIndex: number = -1;
@State private savedPlayerIndex: number = -1;
@State private poisonedPlayerIndex: number = -1;
@State private isVoting: boolean = false;
@State private voteResults: Map<number, number> = new Map();
@State private isGameOver: boolean = false;
@State private winner: string = '';
@State private currentPlayerIndex: number = -1;
@State private playerVoted: boolean = false;
@State private nightMessages: string[] = [];
@State private dayMessages: string[] = [];
// 游戏配置
private readonly roles = [
'村民', '村民', '村民',
'狼人', '狼人',
'预言家', '女巫', '猎人'
];
// 技能状态
@State private witchHasAntidote: boolean = true;
@State private witchHasPoison: boolean = true;
@State private hunterHasShot: boolean = false;
build() {
Column() {
// 游戏标题和状态(居中显示)
Column() {
Text('🐺 狼人杀游戏')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 5 })
Text(`第${this.dayCount}天 ${this.getPhaseText()}`)
.fontSize(18)
.margin({ bottom: 15 })
}
.width('100%')
.alignItems(HorizontalAlign.Center)
// 游戏消息区域(居中显示)
Scroll() {
Column() {
ForEach(this.getGameMessages(), (msg: string, index: number) => {
Text(msg)
.fontSize(14)
.margin({ bottom: 5 })
.width('90%')
.textAlign(TextAlign.Start)
})
}
.width('100%')
.padding(10)
}
.width('100%')
.height('25%')
.backgroundColor('#f5f5f5')
.borderRadius(10)
.margin({ bottom: 15 })
// 玩家列表(左右分栏显示)
Scroll() {
Grid() {
// 左栏玩家
ForEach(this.players.slice(0, this.players.length / 2), (player: Player, index: number) => {
GridItem(){
this.renderPlayer(player, index, 'left')
}
})
// 右栏玩家
ForEach(this.players.slice(this.players.length / 2), (player: Player, index: number) => {
GridItem(){
this.renderPlayer(player, index + this.players.length / 2, 'right')
}
})
}
.columnsTemplate('1fr 1fr')
.width('100%')
.height('45%')
.padding(5)
}
.width('100%')
// 操作按钮(居中显示)
if (!this.isGameOver) {
this.renderActionButtons()
} else {
this.renderGameOverScreen()
}
}
.width('100%')
.height('100%')
.padding(10)
.onAppear(() => {
this.initializeGame();
})
}
// 获取游戏消息
private getGameMessages(): string[] {
if (this.gamePhase === GamePhase.Night) {
return this.nightMessages;
} else {
return this.dayMessages;
}
}
// 渲染玩家信息(支持左右分栏)
@Builder
renderPlayer(player: Player, index: number, side: string) {
Column() {
// 玩家角色和状态
Column() {
Text(`${player.role} ${player.isWolf ? '🐺' : '👤'}`)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.margin({ bottom: 5 })
Text(player.isAlive ? '存活' : '已淘汰')
.fontSize(12)
.fontColor(player.isAlive ? '#008000' : '#FF0000')
}
.width('90%')
.alignItems(HorizontalAlign.Start)
.padding(10)
.backgroundColor(player.isAlive ? '#f0f0f0' : '#e0e0e0')
.borderRadius(10)
.margin({ bottom: 10 })
// 操作按钮(根据游戏阶段显示)
if (this.canSelectPlayer(index)) {
Button(this.getActionButtonText(index))
.onClick(() => {
this.selectPlayer(index);
})
.width('90%')
.backgroundColor(this.selectedPlayer === index ? '#007DFF' : '#f5f5f5')
.fontColor(this.selectedPlayer === index ? '#FFFFFF' : '#212121')
.margin({ top: 5 })
} else if (this.isVoting && player.isAlive) {
Button('投票')
.onClick(() => {
this.castVote(index);
})
.width('90%')
.backgroundColor(this.selectedPlayer === index ? '#007DFF' : '#f5f5f5')
.fontColor(this.selectedPlayer === index ? '#FFFFFF' : '#212121')
.margin({ top: 5 })
}
}
.width(side === 'left' ? '45%' : '45%')
.alignItems(side === 'left' ? HorizontalAlign.Start : HorizontalAlign.End)
}
// 渲染操作按钮(居中显示)
@Builder
renderActionButtons() {
Column() {
// 夜间操作按钮
if (this.gamePhase === GamePhase.Night) {
Row() {
Button('确认行动')
.onClick(() => {
this.confirmNightAction();
})
.width('40%')
.margin({ right: '5%' })
Button('跳过')
.onClick(() => {
this.skipNightAction();
})
.width('40%')
}
.width('90%')
.margin({ top: 10 })
}
// 白天操作按钮
else if (this.gamePhase === GamePhase.Day) {
if (!this.isVoting) {
Button('开始投票')
.onClick(() => {
this.startVote();
})
.width('60%')
.margin({ top: 10 })
} else {
Button('结束投票')
.onClick(() => {
this.endVote();
})
.width('60%')
.margin({ top: 10 })
}
}
}
.width('100%')
.alignItems(HorizontalAlign.Center)
}
// 渲染游戏结束界面(居中显示)
@Builder
renderGameOverScreen() {
Column() {
Text('游戏结束!')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 15 })
Text(`胜利方:${this.winner}`)
.fontSize(22)
.margin({ bottom: 20 })
// 显示所有玩家身份
Column() {
Text('玩家身份:')
.fontSize(18)
.width('60%')
.height(45)
.borderRadius(25)
.backgroundColor('#4CAF50')
.fontColor('#FFFFFF')
.onClick(() => {
this.initializeGame();
})
}
.width('80%')
.padding(20)
.borderRadius(16)
.backgroundColor('#FFFFFF')
.shadow({ color: '#00000020', radius: 10, offsetX: 0, offsetY: 4 }) // 添加阴影效果
.alignItems(HorizontalAlign.Center)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
// 初始化游戏
private initializeGame() {
this.players = [];
this.dayCount = 1;
this.gamePhase = GamePhase.Night;
this.nightPhase = NightPhase.Wolf;
this.gameStatus = GameStatus.Playing;
this.message = '游戏开始!请等待夜晚降临...';
this.selectedPlayer = -1;
this.killedPlayerIndex = -1;
this.savedPlayerIndex = -1;
this.poisonedPlayerIndex = -1;
this.isVoting = false;
this.voteResults = new Map();
this.isGameOver = false;
this.winner = '';
this.currentPlayerIndex = -1;
this.playerVoted = false;
this.nightMessages = ['游戏开始!请等待夜晚降临...'];
this.dayMessages = [];
// 重置技能状态
this.witchHasAntidote = true;
this.witchHasPoison = true;
this.hunterHasShot = false;
// 随机分配角色
this.roles.forEach((role,index) => {
this.players.push(new Player(role,index));
});
// 随机打乱玩家顺序
this.players.sort(() => Math.random() - 0.5);
// 开始第一个夜晚
this.addNightMessage('夜晚降临,请闭眼...');
}
// 添加夜间消息
private addNightMessage(message: string) {
this.nightMessages.push(message);
this.message = message;
}
// 添加白天消息
private addDayMessage(message: string) {
this.dayMessages.push(message);
this.message = message;
}
// 确认夜间行动
private confirmNightAction() {
// 根据当前夜间阶段处理行动
switch (this.nightPhase) {
case NightPhase.Wolf:
if (this.selectedPlayer !== -1 && this.players[this.selectedPlayer].isAlive) {
this.killedPlayerIndex = this.selectedPlayer;
this.addNightMessage(`狼人选择了击杀 ${this.players[this.selectedPlayer].role}`);
this.selectedPlayer = -1;
this.nightPhase = NightPhase.Seer;
} else {
this.addNightMessage('请选择要击杀的玩家!');
}
break;
case NightPhase.Seer:
if (this.selectedPlayer !== -1 && this.players[this.selectedPlayer].isAlive) {
const isWolf = this.players[this.selectedPlayer].isWolf;
this.addNightMessage(`预言家查验 ${this.players[this.selectedPlayer].role} 是 ${isWolf ? '狼人' : '好人'}`);
this.selectedPlayer = -1;
this.nightPhase = NightPhase.Witch;
} else {
this.addNightMessage('请选择要查验的玩家!');
}
break;
case NightPhase.Witch:
// 女巫可以救人或毒人
if (this.selectedPlayer !== -1 && this.players[this.selectedPlayer].isAlive) {
// 检查是否是被击杀的玩家
if (this.selectedPlayer === this.killedPlayerIndex && this.witchHasAntidote) {
this.savedPlayerIndex = this.selectedPlayer;
this.witchHasAntidote = false;
this.addNightMessage(`女巫使用了解药,救活了 ${this.players[this.selectedPlayer].role}`);
} else if (this.selectedPlayer !== this.killedPlayerIndex && this.witchHasPoison) {
this.poisonedPlayerIndex = this.selectedPlayer;
this.witchHasPoison = false;
this.addNightMessage(`女巫使用了毒药,毒死了 ${this.players[this.selectedPlayer].role}`);
}
}
this.selectedPlayer = -1;
// 结束夜晚,进入白天
this.endNight();
break;
}
}
// 跳过夜间行动
private skipNightAction() {
switch (this.nightPhase) {
case NightPhase.Wolf:
this.addNightMessage('狼人今晚没有行动');
this.nightPhase = NightPhase.Seer;
break;
case NightPhase.Seer:
this.addNightMessage('预言家今晚没有查验');
this.nightPhase = NightPhase.Witch;
break;
case NightPhase.Witch:
// 直接结束夜晚
this.endNight();
break;
}
this.selectedPlayer = -1;
}
// 结束夜晚,进入白天
private endNight() {
// 处理夜间结果
let nightResult = `天亮了,昨晚`;
// 处理女巫的解药
if (this.savedPlayerIndex !== -1) {
nightResult += '平安夜';
} else {
// 处理击杀和毒杀
const killedPlayers: number[] = [];
if (this.killedPlayerIndex !== -1) {
killedPlayers.push(this.killedPlayerIndex);
}
if (this.poisonedPlayerIndex !== -1 && this.poisonedPlayerIndex !== this.killedPlayerIndex) {
killedPlayers.push(this.poisonedPlayerIndex);
}
if (killedPlayers.length > 0) {
nightResult += '死亡的是:';
killedPlayers.forEach(index => {
this.players[index].kill();
nightResult += `${this.players[index].role} `;
});
} else {
nightResult += '平安夜';
}
}
this.addDayMessage(nightResult);
// 重置夜间状态
this.gamePhase = GamePhase.Day;
this.nightPhase = NightPhase.Wolf;
this.killedPlayerIndex = -1;
this.savedPlayerIndex = -1;
this.poisonedPlayerIndex = -1;
// 检查游戏是否结束
this.checkGameStatus();
}
// 开始投票
private startVote() {
this.isVoting = true;
this.addDayMessage('开始投票,请选择要投票的玩家');
this.voteResults.clear();
this.playerVoted = false;
}
// 投票
private castVote(playerIndex: number) {
if (this.players[playerIndex].isAlive && !this.playerVoted) {
this.selectedPlayer = playerIndex;
this.playerVoted = true;
// 记录投票结果
if (this.voteResults.has(playerIndex)) {
this.voteResults.set(playerIndex, this.voteResults.get(playerIndex)! + 1);
} else {
this.voteResults.set(playerIndex, 1);
}
this.addDayMessage(`你投票给了 ${this.players[playerIndex].role}`);
}
}
// 结束投票
private endVote() {
if (this.voteResults.size === 0) {
this.addDayMessage('没有人被投票,白天结束');
} else {
// 找出得票最多的玩家
let maxVotes = 0;
let votedPlayerIndex = -1;
let tiedPlayers: number[] = [];
this.voteResults.forEach((votes, index) => {
if (votes > maxVotes) {
maxVotes = votes;
votedPlayerIndex = index;
tiedPlayers = [index];
} else if (votes === maxVotes) {
tiedPlayers.push(index);
}
});
// 处理投票结果
if (tiedPlayers.length > 1) {
this.addDayMessage('投票平局,没有人被淘汰');
} else if (votedPlayerIndex !== -1) {
this.players[votedPlayerIndex].kill();
this.addDayMessage(`投票结束,${this.players[votedPlayerIndex].role} 被投票出局`);
// 处理猎人技能
if (this.players[votedPlayerIndex].role === '猎人' && !this.hunterHasShot) {
this.hunterHasShot = true;
// 随机选择一名存活玩家开枪
const alivePlayers = this.players.filter(p => p.isAlive && p.index !== votedPlayerIndex);
if (alivePlayers.length > 0) {
const randomIndex = Math.floor(Math.random() * alivePlayers.length);
const shotPlayer = alivePlayers[randomIndex];
shotPlayer.kill();
this.addDayMessage(`猎人开枪带走了 ${shotPlayer.role}`);
} else {
this.addDayMessage('猎人没有可开枪的目标');
}
}
}
}
this.isVoting = false;
this.selectedPlayer = -1;
this.playerVoted = false;
// 检查游戏是否结束
this.checkGameStatus();
// 如果游戏继续,进入下一个夜晚
if (this.gameStatus === GameStatus.Playing) {
this.dayCount++;
this.gamePhase = GamePhase.Night;
this.nightMessages = [];
this.addNightMessage(`第${this.dayCount}天夜晚降临,请闭眼...`);
}
}
// 检查游戏状态
private checkGameStatus() {
// 计算存活的狼人和好人数量
let wolfCount = 0;
let villagerCount = 0;
this.players.forEach(player => {
if (player.isAlive) {
if (player.isWolf) {
wolfCount++;
} else {
villagerCount++;
}
}
});
// 判断胜利条件
if (wolfCount === 0) {
this.gameStatus = GameStatus.VillagersWin;
this.winner = '好人阵营';
this.isGameOver = true;
} else if (wolfCount >= villagerCount) {
this.gameStatus = GameStatus.WolvesWin;
this.winner = '狼人阵营';
this.isGameOver = true;
}
}
// 选择玩家
private selectPlayer(index: number) {
this.selectedPlayer = index;
}
// 判断是否可以选择玩家
private canSelectPlayer(index: number): boolean {
if (!this.players[index].isAlive) {
return false;
}
switch (this.nightPhase) {
case NightPhase.Wolf:
return !this.players[index].isWolf;
case NightPhase.Seer:
return true;
case NightPhase.Witch:
// 女巫可以救被击杀的玩家(如果有解药)或毒其他玩家(如果有毒药)
if (this.killedPlayerIndex !== -1 && index === this.killedPlayerIndex) {
return this.witchHasAntidote;
}
return this.witchHasPoison && index !== this.killedPlayerIndex;
default:
return false;
}
}
// 获取行动按钮文本
private getActionButtonText(index: number): string {
switch (this.nightPhase) {
case NightPhase.Wolf:
return '击杀';
case NightPhase.Seer:
return '查验';
case NightPhase.Witch:
// 如果是被击杀的玩家,显示"救",否则显示"毒"
if (this.killedPlayerIndex !== -1 && index === this.killedPlayerIndex) {
return '救';
}
return '毒';
default:
return '选择';
}
}
// 获取当前阶段文本
private getPhaseText(): string {
if (this.isGameOver) {
return '游戏结束';
}
if (this.gamePhase === GamePhase.Night) {
switch (this.nightPhase) {
case NightPhase.Wolf:
return '狼人行动';
case NightPhase.Seer:
return '预言家行动';
case NightPhase.Witch:
return '女巫行动';
default:
return '夜晚';
}
} else {
if (this.isVoting) {
return '投票阶段';
}
return '白天讨论';
}
}
}
// 玩家类
class Player {
public isAlive: boolean = true;
public isDead: boolean = false;
public role: string;
public isWolf: boolean;
public hasUsedSkill: boolean = false; // 技能是否已使用(如猎人的枪)
public index: number; // 玩家索引
constructor(role: string, index: number) {
this.role = role;
this.isWolf = role === '狼人';
this.index = index;
}
public kill() {
this.isAlive = false;
this.isDead = true;
}
}
// 游戏阶段枚举
enum GamePhase {
Night,
Day
}
// 夜间阶段枚举
enum NightPhase {
Wolf,
Seer,
Witch
}
// 游戏状态枚举
enum GameStatus {
Playing,
VillagersWin,
WolvesWin
}