基于鸿蒙OS开发打飞机小游戏(24)-防护墙技能
基于鸿蒙OS开发打飞机小游戏(24)-防护墙技能
一、防护墙系统总览

在EmojiShooter的Boss技能体系中,防护墙技能(hasWall)是最复杂的空间控制机制。它不仅通过物理障碍限制玩家的移动空间,还通过"掏兜"动画提供战术预警,通过弹飞机制改变玩家的位置,甚至通过屏幕外死亡判定创造了一种全新的致死模式。
防护墙系统包含以下子系统:
| 子系统 | 核心功能 | 设计意图 |
|---|---|---|
| 掏兜动画 | 墙壁生成前的视觉预警 | 提供可读的战术信息 |
| 表情砌墙 | 生成物理障碍限制空间 | 空间否定与路径控制 |
| 子弹↔墙碰撞 | 墙壁阻挡玩家子弹 | 保护Boss免受伤害 |
| 墙↔玩家碰撞 | 墙壁弹飞玩家 | 位置改变+生命损失 |
| 屏幕外死亡 | 弹飞后飞出屏幕=死亡 | 弹飞→死亡的连锁 |
| 护盾抗弹飞 | 护盾消耗一次弹飞 | 提供一线生机 |
这些子系统协同工作,创造了一个"空间博弈"的战斗环境——玩家不仅要回避弹幕和射击Boss,还要管理自己的空间位置,避免被墙壁包围和弹飞。
二、掏兜动画系统
2.1 掏兜计时器逻辑
掏兜动画的核心计时器逻辑(Index.ets:1431-1556):
wallPocketTimer++;
threshold = aliveCount === 0 ? wallPocketInterval : wallPocketInterval + 120;
if (wallPocketTimer >= threshold) {
wallPocketActive = true;
wallPocketAnimTime = wallPocketAnimMax; // 60
}
关键参数:
| 参数 | 值 | 说明 |
|---|---|---|
| wallPocketInterval | 240帧 | 基础掏兜间隔 |
| wallPocketAnimMax | 60帧 | 掏兜动画持续帧数 |
| wallPocketTimer | 帧计数器 | 掏兜计时器 |
| wallPocketActive | 布尔值 | 掏兜动画是否激活 |
| wallPocketAnimTime | 帧计数器 | 动画倒计时 |
2.2 阈值的动态调整
掏兜触发的阈值根据当前墙壁存活数量动态调整:
| 条件 | 阈值 | 间隔时间(60FPS) | 说明 |
|---|---|---|---|
| aliveCount === 0 | 240帧 | 4秒 | 无墙时快速生成 |
| aliveCount > 0 | 240+120=360帧 | 6秒 | 有墙时慢速扩展 |
这种动态调整的逻辑是:
- 无墙时快速生成——确保场地上始终有墙壁存在,维持空间压力
- 有墙时慢速扩展——给玩家喘息时间,避免墙壁过快覆盖全场
阈值差异为120帧(2秒),这意味着:
- 拆除所有墙壁后,2秒后就会开始生成新墙壁
- 保留部分墙壁,4秒后才会扩展
这创造了一个策略选择:快速拆墙可以获得2秒的额外无墙时间,但需要投入射击资源。
2.3 掏兜动画的时序
当wallPocketTimer达到阈值时,掏兜动画开始:
| 帧数 | wallPocketAnimTime | 事件 | 视觉效果 |
|---|---|---|---|
| 0 | 60 | 动画开始 | 🤚手从Boss位置伸出 |
| 1-30 | 59→30 | 动画中期 | 手逐渐伸长+emoji开始出现 |
| 31-59 | 29→1 | 动画后期 | emoji飞向目标位置 |
| 60 | 0 | 动画结束 | 墙壁方块生成 |
60帧的动画时长(1秒)提供了足够的预警时间。在动画的前30帧,玩家可以看到手伸出的方向和emoji的初始轨迹,推断墙壁将出现在哪里。在后30帧,emoji已经飞向目标位置,玩家可以看到墙壁的最终位置。
2.4 掏兜动画作为电报系统
在游戏设计术语中,“电报”(telegraph)是指敌人在发动攻击前的可视化预警。掏兜动画就是一个电报系统——它告诉玩家"墙壁即将出现在某个位置",给玩家时间做出反应。
电报系统的设计遵循以下原则:
原则1:可读性
- 动画必须足够明显,不会被弹幕或其他特效掩盖
- 🤚手的视觉效果应该突出且清晰
原则2:可预测性
- 玩家应该能从动画推断攻击的结果
- emoji飞向的方向=墙壁出现的位置
原则3:可应对性
- 预警时间必须足够玩家做出反应
- 60帧(1秒)的动画时长给了玩家移动或射击的时间
| 电报属性 | 掏兜动画 | 评价 |
|---|---|---|
| 可读性 | 🤚手+emoji飞行 | 高 |
| 可预测性 | 飞行方向=墙壁位置 | 高 |
| 可应对性 | 60帧预警时间 | 中高 |
| 一致性 | 每次掏兜都有相同动画 | 高 |
2.5 掏兜动画的视觉元素
根据代码,掏兜动画包含以下视觉元素:
元素1:危险光环(红色圆圈)
- 位置:Boss周围
- 效果:红色的圆形危险指示
- 作用:提示Boss即将执行墙壁技能
元素2:🤚手动画
- 位置:从Boss位置伸出
- 效果:手逐渐伸出+在70%计时器时出现
- 作用:视觉预警+方向指示
元素3:emoji生成
- 位置:从手中飞出
- 效果:emoji飞向目标位置
- 作用:显示墙壁的类型和位置
这些元素的时序关系:
| 计时器比例 | 视觉效果 | 信息量 |
|---|---|---|
| 0-50% | 危险光环+手伸出 | 低(只知道"有东西要发生") |
| 50-70% | 手伸长+准备 | 中(可以看到方向) |
| 70-100% | emoji飞出 | 高(可以看到目标位置) |
| 100% | 墙壁生成 | 完整(墙壁已就位) |
2.6 手动画的70%阈值
手的出现在计时器达到70%时(即wallPocketTimer/wallPocketInterval > 0.7且无活跃掏兜时)。这个阈值的设计意义:
- 70%之前:玩家只知道"掏兜即将发生",但不知道方向
- 70%之后:玩家可以看到手的方向,推断墙壁位置
- 70% = 168帧(无墙时)或252帧(有墙时):即2.8秒或4.2秒后手出现
70%的阈值给了玩家约30%的周期(72帧或108帧≈1.2-1.8秒)来看到手并做出反应。这个时间窗口虽然不长,但足以让玩家移动位置或准备射击新生成的墙壁。
三、表情砌墙系统
3.1 addWallBlocks逻辑
当掏兜动画完成(wallPocketAnimTime=0)时,addWallBlocks函数被调用,根据当前墙壁数量决定生成策略:
if (existingCount === 0) {
// 生成5-block初始环形
生成5个方块,半径80x/60y
} else if (existingCount < 20) {
// 扩展+5个方块
在现有环形基础上增加5个
} else if (existingCount >= 20) {
// 修复+3个方块
修复已死亡的墙壁+新增3个
}
三种生成策略的对比:
| 条件 | 生成数量 | 布局 | 说明 |
|---|---|---|---|
| existingCount=0 | 5 | 环形(半径80x/60y) | 初始墙壁环 |
| 0<existingCount<20 | +5 | 扩展环形 | 逐步扩展 |
| existingCount≥20 | +3 | 修复/补充 | 维持+修复 |
3.2 初始环形墙壁
初始环形墙壁的参数:
| 参数 | 值 | 说明 |
|---|---|---|
| 方块数量 | 5 | 环形中的方块数 |
| X方向半径 | 80px | 环形在X方向的半径 |
| Y方向半径 | 60px | 环形在Y方向的半径 |
| 中心位置 | Boss中心 | 环形围绕Boss中心 |
5个方块均匀分布在椭圆形上,角度间隔为72度(360/5):
| 方块编号 | 角度 | X偏移 | Y偏移 | 相对位置 |
|---|---|---|---|---|
| 0 | 0° | +80 | 0 | 右侧 |
| 1 | 72° | +25 | -57 | 右上 |
| 2 | 144° | -65 | -35 | 左上 |
| 3 | 216° | -65 | +35 | 左下 |
| 4 | 288° | +25 | +57 | 右下 |
这个环形布局创造了一个"保护圈"——Boss在中心,5个方块围绕Boss形成一个椭圆形的屏障。玩家必须穿过或绕过这个屏障才能射击Boss。
3.3 扩展策略
当已有1-19个墙壁方块时,每次扩展增加5个:
| 扩展次数 | 总方块数 | 累计扩展角度覆盖 | 密度变化 |
|---|---|---|---|
| 初始 | 5 | 环形 | 基础 |
| +1 | 10 | 环形扩展 | 密度增加 |
| +2 | 15 | 双环 | 更密集 |
| +3 | 20 | 多环 | 非常密集 |
每次扩展的5个方块可能添加在:
- 现有环形的外圈(扩大半径)
- 现有环形的间隙(填充空隙)
- 新的同心环(多层防御)
3.4 修复策略
当方块数≥20时,改为修复+3策略:
| 修复行为 | 条件 | 效果 |
|---|---|---|
| 修复已死亡方块 | 有alive=false的方块 | 将其alive设为true, hp恢复 |
| 新增方块 | 所有方块都alive | 新增3个方块 |
修复策略确保了墙壁的完整性——即使玩家拆掉了一些方块,它们会在下一次掏兜时被修复。这使得"拆墙"策略的长期效果有限——除非玩家能在修复前利用无墙间隙对Boss造成足够伤害。
3.5 wallEmojis列表
墙壁方块的emoji列表:
wallEmojis = [🧱📦🔩⛓🛡🔨🚪🏰🧱📦]
| 索引 | emoji | 含义 | 视觉特征 |
|---|---|---|---|
| 0 | 🧱 | 砖块 | 红色方块 |
| 1 | 📦 | 包裹 | 棕色立方体 |
| 2 | 🔩 | 螺栓 | 金属质感 |
| 3 | ⛓ | 锁链 | 连接感 |
| 4 | 🛡 | 盾牌 | 防御象征 |
| 5 | 🔨 | 锤子 | 攻击/建造 |
| 6 | 🚪 | 门 | 通道/入口 |
| 7 | 🏰 | 城堡 | 建筑象征 |
| 8 | 🧱 | 砖块 | 红色方块(重复) |
| 9 | 📦 | 包裹 | 棕色立方体(重复) |
这些emoji的选择遵循了"建筑/防御"主题——砖块、包裹、螺栓、锁链、盾牌、锤子、门、城堡——都与建造和防御相关。这增强了墙壁系统的视觉叙事:Boss在"建造"防御工事。
四、WallBlock数据结构
4.1 WallBlock属性
每个WallBlock(墙壁方块)有以下属性:
| 属性 | 类型 | 初始值 | 说明 |
|---|---|---|---|
| hp | number | 3 | 当前生命值 |
| maxHp | number | 3 | 最大生命值 |
| size | number | 22 | 方块大小(px) |
| alive | boolean | true | 是否存活 |
| x | number | - | X坐标 |
| y | number | - | Y坐标 |
| emoji | string | - | 显示的emoji |
4.2 HP系统
墙壁方块的HP系统简单明了:
| HP值 | 状态 | 视觉表现 |
|---|---|---|
| 3 | 完好 | 正常显示emoji |
| 2 | 轻微损伤 | 可能显示裂纹 |
| 1 | 严重损伤 | 可能显示严重裂纹 |
| 0 | 破坏 | alive=false, 不再显示 |
3HP的设计意味着每个方块需要3发子弹才能击毁。这在子弹资源上是一个显著的成本——5个初始方块需要15发子弹才能全部清除。
4.3 碰撞半径
碰撞检测基于size参数:
子弹↔墙碰撞: dist < size * 0.9 = 22 * 0.9 = 19.8px
墙↔玩家碰撞: dist < size + player.width/2
0.9的系数使墙壁的碰撞区域略小于视觉区域,这是一个常见的游戏设计技巧——让碰撞区域略小于显示区域,避免"明明没碰到却被弹"的挫败感。
五、子弹↔墙壁碰撞
5.1 碰撞检测逻辑
在updateBossWall函数中,子弹与墙壁的碰撞检测:
for each bullet:
for each wallBlock (alive=true):
dist = distance(bullet, wallBlock)
if (dist < wallBlock.size * 0.9):
bullet.alive = false // 子弹被墙壁阻挡
wallBlock.hp-- // 墙壁受损
if (wallBlock.hp <= 0):
wallBlock.alive = false // 墙壁被击毁
5.2 子弹被阻挡的战术影响
子弹被墙壁阻挡意味着:
- 墙壁保护Boss——在墙壁后面的Boss不会被子弹击中
- 射击效率降低——部分子弹被墙壁吸收,到达Boss的子弹减少
- 需要拆墙——必须先击毁阻挡视线的墙壁
子弹被阻挡的效率损失:
| 墙壁数量 | 子弹通过率 | 说明 |
|---|---|---|
| 0 | 100% | 无墙壁 |
| 5 | ~60-80% | 初始环形,有间隙 |
| 10 | ~40-60% | 扩展后,间隙缩小 |
| 15 | ~20-40% | 密集,少量间隙 |
| 20+ | ~10-20% | 几乎完全封锁 |
通过率取决于射击角度和墙壁布局。初始的5方块环形有较大的间隙(72度间隔),约60-80%的子弹可以通过。但随着墙壁扩展,间隙被填满,通过率急剧下降。
5.3 拆墙的成本-收益分析
拆墙需要消耗子弹(每个方块3发),但可以恢复射击通道。成本-收益分析:
| 方块HP | 击毁所需子弹 | 恢复的射击通道 | 净收益 |
|---|---|---|---|
| 3→0 | 3发 | 该方向的射击通道 | 正(如果该方向有Boss部件) |
| 3→0 | 3发 | 无(该方向无Boss部件) | 负(浪费子弹) |
最优策略是只拆掉阻挡射击Boss关键部件的墙壁,而不是全部拆除。但考虑到墙壁会在修复阶段被恢复,拆墙的收益是暂时的。
5.4 墙壁作为"子弹吸收器"
从Boss的角度看,墙壁不仅是物理屏障,更是"子弹吸收器"——它们消耗玩家的子弹资源,降低玩家的有效DPS。
假设玩家射速为每6帧1发(10发/秒),Boss的射击间隔为100帧(6发/秒):
| 墙壁状态 | 玩家子弹分配 | 到达Boss的子弹 | 有效DPS |
|---|---|---|---|
| 无墙 | 全部射向Boss | 10发/秒 | 100% |
| 5墙(拆2) | 6发拆墙+4发射Boss | 4发/秒 | 40% |
| 5墙(不拆) | 全部被吸收 | 2发/秒(间隙通过) | 20% |
| 10墙 | 大部分被吸收 | 1-2发/秒 | 10-20% |
墙壁对DPS的衰减是显著的。5个初始环形墙就能将有效DPS降低到40%(如果拆墙)或20%(如果不拆)。10个扩展墙更是将DPS降到10-20%。
六、墙↔玩家碰撞:弹飞机制
6.1 碰撞检测逻辑
checkWallPlayerCollision函数检测玩家与墙壁的碰撞:
for each wallBlock (alive=true):
dist = distance(player, wallBlock)
if (dist < wallBlock.size + player.width/2):
// 弹飞玩家
knockForce = 18
direction = (player - wallBlock) / dist // 方向:从墙到玩家
player.knockbackVx = direction.x * knockForce
player.knockbackVy = direction.y * knockForce
// 护盾检查
if (player.shield > 0):
player.shield = 0 // 消耗护盾
// 不扣生命
else:
lives -= 1 // 扣1条生命
6.2 弹飞力学
弹飞的力学参数:
| 参数 | 值 | 说明 |
|---|---|---|
| knockForce | 18 | 弹飞力度 |
| knockbackVx | direction.x × 18 | X方向弹飞速度 |
| knockbackVy | direction.y × 18 | Y方向弹飞速度 |
| 衰减系数 | 0.92 | 每帧速度衰减 |
| 停止阈值 | 0.3 | 速度低于此值停止弹飞 |
弹飞方向是从墙壁指向玩家的单位向量×力度。这意味着玩家被"推离"墙壁——无论从哪个方向接触墙壁,都会被推向相反方向。
6.3 弹飞速度的帧级衰减
弹飞速度每帧衰减8%(乘以0.92):
| 帧数 | 速度 | 位移(帧) | 累计位移 |
|---|---|---|---|
| 0 | 18.0 | 18.0 | 18.0 |
| 1 | 16.56 | 16.56 | 34.56 |
| 2 | 15.24 | 15.24 | 49.80 |
| 3 | 14.02 | 14.02 | 63.82 |
| 4 | 12.90 | 12.90 | 76.72 |
| 5 | 11.87 | 11.87 | 88.59 |
| 10 | 7.73 | 7.73 | 136.56 |
| 15 | 5.04 | 5.04 | 166.42 |
| 20 | 3.28 | 3.28 | 185.10 |
| 25 | 2.14 | 2.14 | 196.76 |
| 30 | 1.39 | 1.39 | 204.27 |
| 35 | 0.91 | 0.91 | 209.01 |
| 40 | 0.59 | 0.59 | 212.15 |
| 45 | 0.39 | 0.39 | 214.12 |
| 50 | 0.25 | 停止 | 215.50 |
弹飞的总位移约为215px,持续约50帧(0.83秒)。这个位移足以将玩家从墙壁附近推到屏幕边缘甚至屏幕外。
6.4 弹飞方向分析
弹飞方向取决于玩家接触墙壁的位置:
| 接触位置 | 弹飞方向 | 结果 |
|---|---|---|
| 墙壁左侧 | 向左弹飞 | 可能飞向左屏幕外 |
| 墙壁右侧 | 向右弹飞 | 可能飞向右屏幕外 |
| 墙壁上方 | 向上弹飞 | 可能飞向上屏幕外 |
| 墙壁下方 | 向下弹飞 | 可能飞向下屏幕外 |
| 墙壁角落 | 对角弹飞 | 可能飞向角落屏幕外 |
弹飞方向是从墙壁中心指向玩家中心的方向。这意味着:
- 如果玩家在墙壁左边碰到,被推向更左
- 如果玩家在墙壁上方碰到,被推向更上
- 如果玩家被多个墙壁包围,可能被反复弹飞
6.5 连续弹飞的灾难性场景
当玩家被弹飞后,如果弹飞路径上还有其他墙壁,就会发生连续弹飞:
玩家碰到墙A → 被弹飞 → 飞向墙B → 碰到墙B → 被再次弹飞 → 飞向墙C → ...
每次碰撞都会:
- 重置弹飞速度为18(方向改变)
- 扣1条生命(或消耗护盾)
- 改变弹飞方向
如果玩家被3面墙壁包围,可能发生3次连续弹飞,损失3条生命,最终被弹向屏幕外。
| 碰撞次数 | 生命损失 | 累计位移方向 | 结果 |
|---|---|---|---|
| 1 | -1 | 向外1次 | 可能安全 |
| 2 | -2 | 向外2次 | 危险 |
| 3 | -3 | 向外3次 | 极可能屏幕外 |
| 4+ | -4+ | 不确定 | 几乎必然屏幕外 |
连续弹飞是防护墙系统最致命的组合——一次失误可能导致连锁反应,瞬间损失多条生命。
七、屏幕外死亡机制
7.1 死亡判定条件
在updatePlayer函数中,屏幕外死亡的判定:
if (player.x < -player.width || player.x > canvasWidth + player.width ||
player.y < -player.height || player.y > canvasHeight + player.height) {
// 屏幕外死亡
lives -= 1; // 或直接game over
}
判定条件:玩家中心超出画布边界一个玩家宽度的距离。
| 方向 | 死亡边界 | 说明 |
|---|---|---|
| 左 | x < -width | 飞出左边界 |
| 右 | x > canvasWidth + width | 飞出右边界 |
| 上 | y < -height | 飞出上边界 |
| 下 | y > canvasHeight + height | 飞出下边界 |
7.2 弹飞→屏幕外死亡的数学分析
弹飞的总位移约为215px。画布尺寸假设为400×700px。玩家初始位置假设在画布中心(200, 350)。
| 弹飞方向 | 到边界的距离 | 是否致死(215px位移) |
|---|---|---|
| 向左 | 200+width/2≈220 | 是(215≈220) |
| 向右 | 200+width/2≈220 | 是(215≈220) |
| 向上 | 350+height/2≈370 | 否(215<370) |
| 向下 | 350+height/2≈370 | 否(215<370) |
在画布中心位置,水平弹飞(215px)几乎刚好到达屏幕边缘(220px),可能致死;垂直弹飞(215px)不足以到达边缘(370px),通常不致死。
但如果玩家已经靠近边缘:
| 玩家位置 | 弹飞方向 | 到边界距离 | 是否致死 |
|---|---|---|---|
| 中心(200,350) | 左 | 220 | 边缘(可能) |
| 偏左(100,350) | 左 | 120 | 是 |
| 偏右(300,350) | 右 | 120 | 是 |
| 偏上(200,150) | 上 | 170 | 是 |
| 边角(50,50) | 左上 | 70/70 | 是(两个方向) |
结论:玩家越靠近屏幕边缘,弹飞致死的风险越高。 墙壁的存在迫使玩家在有限的区域内移动,而区域边缘就是死亡陷阱。
7.3 屏幕外死亡与弹幕回避的矛盾
屏幕外死亡创造了一个新的回避维度:
| 回避类型 | 方向 | 风险 |
|---|---|---|
| 弹幕回避 | 向弹幕稀疏区域移动 | 可能靠近墙壁→被弹飞 |
| 墙壁回避 | 远离墙壁 | 可能靠近弹幕→被击中 |
| 边界回避 | 远离屏幕边缘 | 被压缩到中心区域→空间更小 |
三种回避方向可能互相矛盾——回避弹幕可能靠近墙壁,回避墙壁可能靠近弹幕,回避边界可能被压缩到中心。这种三重矛盾是防护墙系统创造的核心空间博弈。
八、护盾抗弹飞机制
8.1 护盾消耗逻辑
当玩家拥有护盾(shield > 0)时,墙壁弹飞可以被护盾抵挡:
if (player.shield > 0):
player.shield = 0 // 消耗护盾
// 不扣生命
// 但弹飞仍然发生
注意:护盾只抵消生命损失,不抵消弹飞效果。玩家仍然会被弹飞,只是不扣生命。
8.2 护盾的价值评估
护盾在防护墙Boss战中的价值极高:
| 场景 | 无护盾 | 有护盾 | 差异 |
|---|---|---|---|
| 碰到1面墙 | -1生命 | 0生命(消耗护盾) | 1条生命 |
| 碰到2面墙(连续) | -2生命 | -1生命(第1次消耗护盾) | 1条生命 |
| 碰到3面墙(连续) | -3生命 | -2生命 | 1条生命 |
护盾只抵消第一次碰撞的生命损失,后续碰撞仍然正常扣生命。但这1条生命的差距可能是生死之别——如果护盾让玩家在lives=1时免于死亡,那就是从"游戏结束"到"继续战斗"的区别。
8.3 护盾使用策略
面对防护墙Boss,护盾的使用策略:
策略1:保守使用
- 保留护盾到最危急时刻
- 平时通过走位避免碰墙
- 护盾作为最后的保险
策略2:主动使用
- 有护盾时更积极地接近Boss射击
- 碰墙时用护盾抵消,换取更好的射击位置
- 护盾作为进攻资源
策略3:循环获取
- 如果击败Boss可以获得护盾,则可以循环使用
- 每次Boss被击败→获得护盾→下次碰墙消耗→再击败Boss…
策略2在防护墙Boss战中可能更有效——因为墙壁限制了射击角度,有时必须靠近Boss才能射击。有护盾时可以更自由地移动,不受墙壁碰撞的恐惧制约。
九、防护墙的空间否定分析
9.1 空间否定的概念
“空间否定”(Spatial Denial)是游戏设计中的一个核心概念——通过放置障碍物或危险区域,使某些空间变得不可进入或不可通过。防护墙系统是一个典型的空间否定机制。
| 空间状态 | 可用性 | 原因 |
|---|---|---|
| 无墙区域 | 完全可用 | 可以自由移动和射击 |
| 墙壁位置 | 不可进入 | 碰到墙壁→弹飞+生命损失 |
| 墙壁后方 | 部分可用 | 可以射击但子弹被阻挡 |
| 墙壁包围区域 | 极度危险 | 可能被连续弹飞 |
9.2 空间压缩的动态过程
随着墙壁数量增加,可用空间逐步压缩:
| 阶段 | 墙壁数量 | 可用空间比例 | 移动自由度 |
|---|---|---|---|
| 初始 | 0 | 100% | 完全自由 |
| 5墙 | 5 | ~85% | 大部分自由 |
| 10墙 | 10 | ~70% | 受限 |
| 15墙 | 15 | ~55% | 严重受限 |
| 20墙 | 20 | ~40% | 极度受限 |
| 25墙 | 25 | ~30% | 几乎无法移动 |
可用空间的压缩直接影响玩家的回避能力——空间越小,回避弹幕的余地越小。这创造了一种"空间绞杀"效应:墙壁逐步压缩空间,弹幕密度不变但回避空间减少,等效于弹幕密度增加。
9.3 空间否定的双重性
防护墙的空间否定具有双重性——它同时否定了玩家的移动空间和射击空间:
移动空间否定:
- 墙壁占据的区域不可进入
- 墙壁之间的通道变窄
- 被弹飞的风险增加
射击空间否定:
- 墙壁阻挡子弹
- 射击角度被限制
- 必须通过间隙射击Boss
这两个否定协同工作——移动空间减少意味着玩家更难找到好的射击角度,射击空间减少意味着玩家更难对Boss造成伤害。
十、Boss14的技能组合分析
10.1 Boss14综合参数
| 参数 | 值 | 说明 |
|---|---|---|
| hasWall | true | 拥有防护墙技能 |
| wallPocketInterval | 240 | 掏兜间隔 |
| wallEmojis | [🧱📦🔩⛓🛡🔨🚪🏰🧱📦] | 墙壁emoji列表 |
| vx | 0.8 | 水平移动速度 |
| shootInterval | 100 | 射击间隔 |
10.2 墙壁+射击的协同效应
Boss14同时拥有防护墙和射击技能,两者产生协同效应:
协同1:墙壁保护Boss
- 玩家的子弹被墙壁阻挡
- Boss在墙壁后面安全射击
- 相当于Boss拥有"物理护盾"
协同2:墙壁压缩空间+弹幕覆盖空间
- 墙壁减少了可用移动空间
- 弹幕覆盖了剩余空间
- 玩家的回避选择越来越少
协同3:弹飞+弹幕的双重威胁
- 被弹飞后,玩家处于失控状态
- 在失控期间无法回避弹幕
- 可能被弹幕击中+弹飞的双重伤害
10.3 Boss14的战斗节奏
Boss14的战斗节奏由掏兜周期决定:
| 时间 | 事件 | 墙壁数量 | 威胁等级 |
|---|---|---|---|
| 0-4s | 首次掏兜预警 | 0→5 | 低→中 |
| 4-10s | 5墙阶段 | 5 | 中 |
| 10-14s | 扩展掏兜 | 5→10 | 中→高 |
| 14-20s | 10墙阶段 | 10 | 高 |
| 20-24s | 扩展掏兜 | 10→15 | 高→极高 |
| 24-30s | 15墙阶段 | 15 | 极高 |
| 30-34s | 扩展掏兜 | 15→20 | 极高 |
| 34+ | 修复阶段 | 20(修复) | 极高 |
如果不拆墙,约30秒后墙壁数量达到20,进入修复阶段。此时可用空间仅约40%,战斗变得极其困难。
10.4 拆墙vs射击Boss的策略权衡
玩家面临的核心策略权衡:拆墙还是射击Boss?
| 策略 | 子弹分配 | 优点 | 缺点 |
|---|---|---|---|
| 全力拆墙 | 100%拆墙 | 恢复空间和射击通道 | Boss不受伤害 |
| 全力射击Boss | 100%射Boss | BossHP下降 | 墙壁越来越多 |
| 平衡分配 | 50%拆墙+50%射Boss | 兼顾空间和伤害 | 两边都不够 |
最优策略可能是"阶段性切换":
- 墙壁少时(0-5个):全力射击Boss
- 墙壁中等时(5-10个):拆关键墙壁+射击Boss
- 墙壁多时(10+个):优先拆墙恢复空间
- 墙壁极多时(20+个):全力拆墙,避免空间绞杀
十一、掏兜动画的视觉设计深度分析
11.1 掏兜的叙事含义
“掏兜”(Pocket Pull)动画的叙事含义非常直观——Boss从"口袋"中掏出建筑材料来建造墙壁。这个动画有以下叙事功能:
- 赋予Boss"建造者"的身份——Boss不是凭空生成墙壁,而是从口袋中取出材料
- 提供视觉逻辑——墙壁的来源有了可视化的解释
- 增加Boss的拟人化——“掏兜"是一个人类的动作,使Boss更有"角色感”
11.2 🤚手的动画设计
🤚手动画在70%计时器时出现,这是一个精心设计的时机:
| 计时器阶段 | 手的状态 | 信息揭示 |
|---|---|---|
| 0-70% | 无手 | 只有危险光环,不知道方向 |
| 70-85% | 手伸出 | 可以看到大致方向 |
| 85-95% | 手完全伸出 | 方向明确 |
| 95-100% | emoji从手中飞出 | 目标位置确定 |
70%的出现时机确保了:
- 早期不确定——0-70%期间玩家只知道"有东西要发生",但不知道是什么方向
- 后期可预测——70-100%期间玩家可以看到手的方向和emoji的飞行轨迹
- 总预警时间约1.2-1.8秒——30%的周期(72-108帧)是可见预警时间
11.3 emoji飞行动画
emoji从手中飞向目标位置的动画有以下功能:
- 显示墙壁类型——emoji的样式暗示了墙壁的emoji(🧱、📦等)
- 显示目标位置——emoji飞向的方向=墙壁出现的位置
- 增加动态感——飞行的emoji增加了视觉趣味性
- 提供最后预警——emoji到达目标前的几帧是最后的移动机会
11.4 危险光环(红色圆圈)
危险光环在掏兜预警期间出现:
| 属性 | 值 | 说明 |
|---|---|---|
| 颜色 | 红色 | 危险/警告色 |
| 形状 | 圆形 | 围绕Boss |
| 透明度 | 可能随计时器变化 | 早期低,后期高 |
| 持续时间 | 整个预警期 | 从70%计时器到掏兜触发 |
危险光环的作用是"全局预警"——即使玩家没有注意到手的动画,红色光环也能吸引注意力,提示"Boss正在准备什么"。
十二、墙壁布局的空间分析
12.1 初始环形的战术空间
5方块初始环形创造了一个椭圆形的保护区域:
[方块2]
[方块3] Boss [方块1]
[方块4]
[方块0]
从玩家的视角,这个环形的影响:
| 方向 | 墙壁阻挡 | 间隙 | 可射击角度 |
|---|---|---|---|
| 右侧 | 方块0 | 无 | 被完全阻挡 |
| 右上 | 方块1 | 少量 | 大部分阻挡 |
| 左上 | 方块2 | 少量 | 大部分阻挡 |
| 左下 | 方块3 | 少量 | 大部分阻挡 |
| 右下 | 方块4 | 少量 | 大部分阻挡 |
72度的间隔意味着每个间隙约72度宽,但间隙的宽度取决于距离——距离Boss越远,间隙越宽。
12.2 环形半径的影响
80x/60y的椭圆半径决定了环形的大小:
| 半径方向 | 值 | 到Boss中心的距离 | 间隙宽度(72°间隔) |
|---|---|---|---|
| X方向 | 80px | 80px | ~100px(2×80×sin36°) |
| Y方向 | 60px | 60px | ~75px(2×60×sin36°) |
X方向的间隙(100px)比Y方向(75px)更宽,这意味着从左右方向射击更容易通过间隙。
12.3 多层环形的嵌套
当墙壁扩展到10个以上时,可能形成多层环形:
外环: [方块5][方块6][方块7][方块8][方块9]
内环: [方块0][方块1][方块2][方块3][方块4]
Boss
双层环形的间隙对齐情况:
| 情况 | 内外环间隙对齐 | 射击通道 |
|---|---|---|
| 完全对齐 | 内外间隙重叠 | 有直通通道 |
| 部分对齐 | 间隙部分重叠 | 有狭窄通道 |
| 完全错位 | 内外间隙不重叠 | 无直通通道 |
如果扩展时新方块恰好填充了内环的间隙,则双层环形几乎没有射击通道。这要求玩家必须在扩展前拆除关键墙壁,维持射击通道。
十三、弹飞与屏幕外死亡的连锁分析
13.1 弹飞→弹幕→死亡的连锁
弹飞后的连锁效应:
碰到墙壁 → 被弹飞(失控0.83秒) → 无法回避弹幕 → 被弹幕击中(-1生命) → 弹飞结束(可能在屏幕边缘) → 碰到另一面墙 → 再次弹飞 → 屏幕外 → 死亡
这个连锁的每个环节都有概率发生,整体致死概率:
| 连锁环节 | 发生概率 | 累计概率 |
|---|---|---|
| 碰到墙壁 | 取决于位置 | 变量 |
| 弹飞期间被弹幕击中 | ~30%(假设) | P×0.3 |
| 弹飞后碰到另一面墙 | ~40%(假设) | P×0.3×0.4 |
| 第二次弹飞后屏幕外 | ~50%(假设) | P×0.3×0.4×0.5 |
假设初始碰到墙壁的概率为P=0.5,则完整连锁的概率约为0.5×0.3×0.4×0.5=3%。虽然概率不高,但一旦发生就是灾难性的——从1次墙壁碰撞到死亡,中间可能损失2-3条生命。
13.2 墙壁包围的致死陷阱
当玩家被墙壁包围时,致死概率急剧上升:
[墙][墙][墙]
[墙] 玩家 [墙]
[墙][墙][墙]
在这种布局中,任何方向的弹飞都会碰到另一面墙,产生连续弹飞。每次碰撞-1生命,3次碰撞后lives可能归零。
| 包围程度 | 可逃出方向 | 连续弹飞概率 | 致死风险 |
|---|---|---|---|
| 半包围(3面) | 1-2个方向 | 中 | 中高 |
| 大半包围(4面) | 1个方向 | 高 | 高 |
| 完全包围(5+面) | 0个方向 | 极高 | 极高 |
完全包围是一个"死亡陷阱"——玩家无法通过正常移动逃脱,每次碰墙都被弹飞到另一面墙,形成无限循环直到死亡。
13.3 护盾在连锁中的关键作用
护盾在弹飞连锁中的作用是"断链"——消耗一次护盾,避免1次生命损失:
| 连锁状态 | 无护盾 | 有护盾 | 差异 |
|---|---|---|---|
| 第1次碰墙 | -1生命 | 0(消耗护盾) | 1条生命 |
| 第2次碰墙 | -1生命 | -1生命 | 0 |
| 第3次碰墙 | -1生命 | -1生命 | 0 |
护盾只在第1次碰撞时有效,但这次"断链"可能打破连锁——如果第1次弹飞后的位置不在其他墙壁附近,连锁就此终止。
十四、防护墙与Boss的协同战术
14.1 墙壁保护Boss的效率
墙壁保护Boss的效率取决于墙壁的布局和玩家的射击角度:
| 射击角度 | 墙壁阻挡数 | 到达Boss的子弹比例 | 保护效率 |
|---|---|---|---|
| 正面(0°) | 1-2 | 30-50% | 中 |
| 侧面(45°) | 0-1 | 60-80% | 低 |
| 对角(90°) | 1-2 | 30-50% | 中 |
| 后方(180°) | 2-3 | 10-30% | 高 |
后方射击(从Boss背后射击)的保护效率最高,因为墙壁通常集中在Boss前方。但如果Boss面向玩家,后方射击通常不可行。
14.2 Boss在墙壁保护下的射击
Boss在墙壁后面持续射击,创造了一种"堡垒"战术:
[弹幕] [弹幕] [弹幕]
↓ ↓ ↓
[墙][墙][Boss][墙][墙]
Boss从墙壁间隙中发射弹幕,同时墙壁保护Boss不受子弹伤害。这种"堡垒"布局使Boss在安全输出弹幕的同时,玩家难以有效反击。
14.3 反堡垒策略
面对Boss的堡垒战术,玩家可以采用以下反制策略:
策略1:拆墙开缺口
- 集中火力拆除一面墙壁
- 通过缺口射击Boss
- 优点:创造持久的射击通道
- 缺点:拆墙耗时,期间Boss持续输出
策略2:绕墙射击
- 移动到墙壁间隙的正对方向
- 通过间隙射击Boss
- 优点:不需要拆墙
- 缺点:间隙可能很窄,命中率低
策略3:穿墙弹幕
- 如果有穿墙武器或技能
- 直接穿过墙壁射击Boss
- 优点:无视墙壁
- 缺点:可能不存在此类武器
策略4:引诱Boss移动
- 通过移动引诱Boss改变位置
- 利用Boss移动时墙壁滞后的时间窗口
- 优点:利用动态间隙
- 缺点:需要精确的移动控制
十五、防护墙系统的代码实现详解
15.1 掏兜计时器逻辑(Index.ets:1431-1456)
if (boss.hasWall) {
boss.wallPocketTimer++;
let threshold = aliveWallCount === 0 ?
boss.wallPocketInterval : boss.wallPocketInterval + 120;
if (boss.wallPocketTimer >= threshold) {
boss.wallPocketActive = true;
boss.wallPocketAnimTime = boss.wallPocketAnimMax; // 60
}
if (boss.wallPocketActive) {
boss.wallPocketAnimTime--;
if (boss.wallPocketAnimTime <= 0) {
boss.wallPocketActive = false;
addWallBlocks(boss);
}
}
}
15.2 addWallBlocks函数
function addWallBlocks(boss) {
let existingCount = boss.wallBlocks.filter(w => w.alive).length;
if (existingCount === 0) {
// 5-block环形
for (let i = 0; i < 5; i++) {
let angle = (i / 5) * Math.PI * 2;
boss.wallBlocks.push({
x: boss.x + Math.cos(angle) * 80,
y: boss.y + Math.sin(angle) * 60,
hp: 3, maxHp: 3, size: 22, alive: true,
emoji: boss.wallEmojis[i % boss.wallEmojis.length]
});
}
} else if (existingCount < 20) {
// 扩展+5
for (let i = 0; i < 5; i++) {
let angle = (i / 5) * Math.PI * 2 + offset;
let radius = 80 + layer * 20;
boss.wallBlocks.push({
x: boss.x + Math.cos(angle) * radius,
y: boss.y + Math.sin(angle) * (radius * 0.75),
hp: 3, maxHp: 3, size: 22, alive: true,
emoji: boss.wallEmojis[i % boss.wallEmojis.length]
});
}
} else {
// 修复+3
let deadWalls = boss.wallBlocks.filter(w => !w.alive);
for (let i = 0; i < Math.min(3, deadWalls.length); i++) {
deadWalls[i].alive = true;
deadWalls[i].hp = deadWalls[i].maxHp;
}
// 如果所有都存活,新增3个
if (deadWalls.length < 3) {
for (let i = 0; i < 3 - deadWalls.length; i++) {
// 新增方块...
}
}
}
}
15.3 子弹↔墙碰撞(updateBossWall函数)
for (let bullet of bullets) {
if (!bullet.alive) continue;
for (let wall of boss.wallBlocks) {
if (!wall.alive) continue;
let dist = distance(bullet, wall);
if (dist < wall.size * 0.9) {
bullet.alive = false;
wall.hp--;
if (wall.hp <= 0) {
wall.alive = false;
}
break; // 一颗子弹只碰一面墙
}
}
}
15.4 墙↔玩家碰撞(checkWallPlayerCollision函数)
for (let wall of boss.wallBlocks) {
if (!wall.alive) continue;
let dist = distance(player, wall);
if (dist < wall.size + player.width / 2) {
let knockForce = 18;
let dx = player.x - wall.x;
let dy = player.y - wall.y;
let len = Math.sqrt(dx * dx + dy * dy);
player.knockbackVx = (dx / len) * knockForce;
player.knockbackVy = (dy / len) * knockForce;
if (player.shield > 0) {
player.shield = 0;
} else {
lives -= 1;
}
break; // 一次只碰一面墙
}
}
15.5 弹飞衰减(updatePlayer函数)
if (player.knockbackVx !== 0 || player.knockbackVy !== 0) {
player.x += player.knockbackVx;
player.y += player.knockbackVy;
player.knockbackVx *= 0.92;
player.knockbackVy *= 0.92;
if (Math.abs(player.knockbackVx) < 0.3) player.knockbackVx = 0;
if (Math.abs(player.knockbackVy) < 0.3) player.knockbackVy = 0;
}
15.6 屏幕外死亡判定
if (player.x < -player.width || player.x > canvasWidth + player.width ||
player.y < -player.height || player.y > canvasHeight + player.height) {
// 屏幕外死亡
lives -= 1;
// 或 game over
}
十六、防护墙系统的数值参考表
16.1 核心参数
| 参数 | 值 | 单位 | 说明 |
|---|---|---|---|
| wallPocketInterval | 240 | 帧 | 基础掏兜间隔 |
| wallPocketAnimMax | 60 | 帧 | 动画持续帧数 |
| WallBlock.hp | 3 | HP | 方块生命值 |
| WallBlock.maxHp | 3 | HP | 方块最大生命值 |
| WallBlock.size | 22 | px | 方块大小 |
| knockForce | 18 | px/帧 | 弹飞力度 |
| 衰减系数 | 0.92 | - | 每帧速度衰减 |
| 停止阈值 | 0.3 | px/帧 | 弹飞停止速度 |
16.2 时间参数
| 参数 | 帧数 | 秒数(60FPS) | 说明 |
|---|---|---|---|
| 无墙掏兜间隔 | 240 | 4.0 | 无墙时的间隔 |
| 有墙掏兜间隔 | 360 | 6.0 | 有墙时的间隔 |
| 掏兜动画 | 60 | 1.0 | 动画时长 |
| 手出现时机 | 70%计时器 | 变化 | 预警开始 |
| 弹飞持续 | ~50 | ~0.83 | 弹飞持续时间 |
| 墙壁生成到修复 | ~30s | 30 | 达到20墙的时间 |
16.3 空间参数
| 参数 | 值 | 说明 |
|---|---|---|
| 初始环形X半径 | 80px | 椭圆X方向 |
| 初始环形Y半径 | 60px | 椭圆Y方向 |
| 方块碰撞半径 | 19.8px | size×0.9 |
| 弹飞总位移 | ~215px | 单次弹飞 |
| 弹飞最大速度 | 18px/帧 | 初始弹飞速度 |
16.4 Boss14综合参数
| 参数 | 值 | 说明 |
|---|---|---|
| hasWall | true | 拥有防护墙技能 |
| wallPocketInterval | 240 | 掏兜间隔 |
| wallEmojis | [🧱📦🔩⛓🛡🔨🚪🏰🧱📦] | 墙壁emoji |
| vx | 0.8 | 水平移动速度 |
| shootInterval | 100 | 射击间隔 |
十七、防护墙系统的设计哲学
17.1 空间作为资源
防护墙系统将"空间"从免费的背景资源转化为有限的、可消耗的战斗资源。在没有墙壁的情况下,玩家的移动空间是"无限的"(受画布边界限制),可以自由选择任何位置。但墙壁的存在使空间变成了需要管理和保护的资源。
这种"空间资源化"的设计增加了游戏的策略深度:
- 空间不足时,玩家的选择减少
- 拆墙可以回收空间,但消耗子弹
- 不拆墙会导致空间持续压缩
- 空间管理成为除回避和射击外的第三维策略
17.2 物理障碍的情感效应
物理障碍(墙壁)比弹幕(投射物)产生更强的心理压迫:
| 威胁类型 | 心理效应 | 持续性 | 对抗方式 |
|---|---|---|---|
| 弹幕 | 即时威胁 | 短暂(飞过后消失) | 回避 |
| 墙壁 | 持续威胁 | 持久(直到被击毁) | 拆除 |
| 弹飞 | 位置威胁 | 中等(0.83秒) | 无法对抗(已发生后) |
弹幕是"流动的威胁"——它们经过后就不会再造成伤害。墙壁是"固定的威胁"——它们一直在那里,持续影响玩家的移动和射击。这种持续性使墙壁的心理压迫更加持久。
17.3 掏兜动画的"公平警告"哲学
掏兜动画体现了游戏设计中"公平警告"(Fair Warning)的哲学——任何对玩家有重大影响的事件都应该有可读的预警。
| 没有预警 | 有预警 |
|---|---|
| 墙壁突然出现 | 掏兜动画60帧后墙壁出现 |
| 玩家感到不公平 | 玩家有反应时间 |
| 死亡感觉随机 | 死亡感觉是可避免的 |
| 游戏体验差 | 游戏体验好 |
60帧的掏兜动画+70%计时器时的手出现,确保了玩家有1-1.8秒的预警时间。这足以让玩家移动位置或准备射击新生成的墙壁。
十八、总结与核心要点
防护墙技能是EmojiShooter中最复杂、最多层次的空间控制机制。它通过物理障碍、弹飞力学、屏幕外死亡和护盾抗弹飞四个子系统,创造了一个完整的"空间博弈"战斗环境。
核心要点:
- 掏兜动画作为电报系统——60帧动画+70%计时器手出现,提供1-1.8秒预警
- 动态间隔——无墙240帧/有墙360帧,引导拆墙或保留的策略选择
- 三种砌墙策略——初始5环/扩展+5/修复+3,根据墙壁数量动态调整
- WallBlock——3HP/22px,每方块需3发子弹击毁
- 子弹↔墙碰撞——子弹被阻挡+墙壁受伤,墙壁作为Boss的物理护盾
- 弹飞力学——力度18/衰减0.92/总位移215px/持续50帧
- 屏幕外死亡——弹飞后飞出画布=死亡,创造弹飞→死亡的连锁
- 连续弹飞——碰到多面墙的连锁反应,可能瞬间损失多条生命
- 护盾抗弹飞——消耗护盾抵消1次生命损失,但不抵消弹飞效果
- 空间否定——墙壁同时否定移动空间和射击空间,创造"空间绞杀"
- 墙壁+射击协同——墙壁保护Boss+弹幕覆盖剩余空间+弹飞使玩家失控
- 拆墙vs射击Boss的策略权衡——资源分配的核心决策
- 修复机制——20墙后修复死亡方块,使拆墙的长期效果有限
- 建筑主题emoji——🧱📦🔩⛓🛡🔨🚪🏰增强视觉叙事
- 公平警告哲学——掏兜动画确保玩家有反应时间,避免不公平感
防护墙系统的设计体现了EmojiShooter对"空间博弈"的深刻理解——它不仅是一个障碍物系统,更是一个完整的空间经济学模型,将空间从背景资源转化为需要管理的战斗资源,将弹幕游戏从"回避+射击"的二维模式推向"回避+射击+空间管理"的三维模式。
更多推荐



所有评论(0)