103
社区成员
发帖
与我相关
我的任务
分享| 这个作业属于哪个课程 | 2501_CS_SE_FZU |
|---|---|
| 这个作业要求在哪里 | 团队作业——站立式会议+α冲刺 |
| 这个作业的目标 | α冲刺Day5 |
| 其他参考文献 | 《构建之法》、Google Style Guides |


| 成员角色 | 昨日至今日日站立会安排 | 存在的问题 / 遇到的困难 | 心得体会 | 今日至明日站立会安排 |
|---|---|---|---|---|
| 陈志豪(敌人模块) | 1. 针对精英敌人的战斗节奏进行优化,将其攻击后摇时长从 0.8 秒调整至 0.6 秒,平衡战斗难度;2. 为解决敌人追击迷路问题,添加 “超出巡逻范围 10 秒后自动返回原点” 的逻辑;3. 重点测试多敌人混战场景下的 AI 行为,排查攻击动作卡顿的异常情况。 | 在多敌人混战时,由于敌人碰撞体重叠,出现 “攻击动作正常触发但无伤害判定” 的卡顿现象;普通敌人与精英敌人的攻击节奏差异不明显(仅 0.2 秒间隔差),玩家难以通过操作感知两者强度区别,降低战斗策略性。 | 敌人 AI 开发中,“碰撞体管理” 和 “差异化设计” 是提升战斗体验的核心。针对多敌人碰撞卡顿问题,通过添加 “攻击时临时忽略友方碰撞” 的逻辑,让敌人攻击时不再被同类阻挡;而普通与精英敌人的节奏差异问题,让我意识到数值设计需跳出 “功能实现” 思维,要通过明显的参数差距(如攻击间隔、伤害数值),让玩家直观区分敌人强度,进而调整战斗策略。后续开发中,需更注重 “玩家感知” 层面的设计,而非仅满足功能正确性。 | 1. 完善敌人碰撞体管理逻辑,在攻击时临时忽略友方碰撞,彻底解决混战卡顿;2. 进一步拉大普通与精英敌人的攻击间隔(普通敌人从 2 秒调整至 2.5 秒,精英敌人从 3 秒调整至 3.5 秒),强化强度差异;3. 测试敌人 “返回原点” 的路径逻辑,避免因地形阻挡导致敌人卡在半路,确保 AI 行为流畅。 |
| 胡定赟 (UI/UX 设计) | 1. 修复死亡 UI 的重生按钮状态 bug,添加 “倒计时结束后自动禁用按钮” 的逻辑,防止重复触发重生;2. 重新制作适配 2K 高分辨率的技能栏按键提示图标,解决原图标模糊问题;3. 为背包 UI 开发 “物品数量超过 99 时显示 99+” 的功能,优化信息展示。 | 背包 UI 中 “99+” 的文字与物品图标边缘重叠,信息显示不清晰;技能栏 UI 在窗口化模式切换(如从全屏切至窗口)时,按键提示图标会出现短暂位移,影响视觉稳定性。 | UI 开发中,“细节布局” 和 “状态稳定性” 是最容易被忽视却直接影响体验的环节。背包 UI 的文字重叠问题,源于前期未预留足够的文字显示空间,通过缩小文字字号(从 14 号降至 12 号)并增加与图标间距(从 5px 增至 8px)后解决;窗口化切换时的图标位移,则是因为 UI 锚点绑定了屏幕边缘而非画布中心,重新设置锚点为画布中心后,图标位置不再随窗口大小变化偏移。现在做 UI 设计时,会针对 “极端数据场景”(如 99 + 物品、超长技能名称)和 “窗口状态变化” 做专项测试,确保所有场景下的显示效果一致、清晰。 | 1. 进一步优化背包 UI“99+” 文字的布局,调整文字锚点至图标右上角,避免边缘重叠;2. 修复技能栏 UI 窗口化切换时的图标位移问题,通过绑定画布中心锚点确保位置稳定;3. 为血条 UI 添加 “受击时短暂闪烁红色” 的效果,强化玩家受击反馈,让玩家更直观感知伤害。 |
| 阮航宇 (地图与资源设计) | 1. 同步恢复泉水的粒子特效与数值飘字触发时序,确保两者同时显示,避免玩家误解恢复效果;2. 调整地图角落装饰元素(如岩石、火把)的位置,避免与地形碰撞体重叠导致视觉穿透;3. 在地图关键路径(如岔路口、隐藏区域入口)添加 “指路箭头” UI 提示,引导玩家探索方向。 | 指路箭头 UI 在玩家远离后未自动隐藏,导致地图多处箭头堆积,影响场景整洁;恢复泉水在多玩家同时使用时,存在 “恢复效果叠加” 的异常(如 2 名玩家同时触发,恢复量翻倍),违背设计预期。 | 地图交互物开发需兼顾 “多玩家场景” 和 “UI 动态管理”。针对恢复泉水叠加问题,通过添加 “同一玩家 3 秒内仅触发 1 次恢复” 的冷却逻辑,确保每位玩家的恢复频率符合设计;而指路箭头未隐藏的问题,让我意识到动态 UI 需具备 “场景适配” 能力,通过添加 “玩家距离箭头 5 米后自动隐藏” 的判断,既保留引导功能,又避免场景杂乱。后续地图设计中,需提前预判多玩家交互场景,同时通过动态 UI 管理,保持场景视觉整洁与功能引导的平衡。 | 1. 为指路箭头 UI 添加距离检测逻辑,当玩家距离超过 5 米时自动隐藏,避免场景堆积;2. 完善恢复泉水的多玩家适配,添加单玩家 3 秒触发冷却,防止恢复效果叠加;3. 在地图 Boss 区域外围添加 “战斗预警圈”(红色渐变光圈),提示玩家即将进入高强度战斗,提前做好准备。 |
| 张天荣 (攻击模块) | 1. 修复冰元素冻结敌人后的移动状态 bug,添加 “冻结结束后自动恢复移动” 的回调逻辑,避免敌人卡住;2. 优化攻击判定优先级,明确 “原攻击盒未命中时再触发 SphereCast 球形检测” 的规则,避免重复计算伤害;3. 为元素攻击添加 “属性克制提示”(如 “火克冰”“冰克雷”)的弹出文字,提升玩法策略性。 | 雷元素连锁攻击时,偶尔会误判友方单位(如玩家召唤的随从),导致对友方造成伤害;属性克制提示文字在多攻击同时触发时(如连续释放火、冰攻击),会出现文字重叠遮挡,影响信息传递。 | 元素攻击开发中,“层级过滤” 和 “视觉反馈管理” 是关键。雷元素误判友方的问题,源于碰撞检测时未过滤 “Player 层”,通过在 OverlapCircleAll 检测中添加 “仅检测 Enemy 层” 的条件,彻底解决误判;而文字重叠问题,通过为每段提示文字添加随机 Y 轴偏移(±10px),让多段文字错开显示,提升清晰度。这让我明白,攻击系统不仅要实现 “打得到、算得对”,还要通过层级过滤确保目标正确性,通过视觉反馈优化让玩家清晰感知攻击效果,进而提升战斗策略性。 | 1. 进一步优化雷元素连锁攻击的层级过滤逻辑,明确仅检测 Enemy 层,避免误判友方;2. 为属性克制提示文字添加随机 Y 轴偏移,彻底解决多文字重叠问题;3. 优化火元素燃烧效果,设计 “伤害随时间递减” 机制(第 1 秒 5 点伤害→第 2 秒 3 点→第 3 秒 2 点),让玩家可通过操作(如闪避、解控)减少后续伤害,提升玩法策略性。 |
| 汪涛(测试与性能优化、玩家模块) | 1. 修复技能释放后攻击延迟的问题,取消技能逻辑中多余的 0.3 秒输入锁定,让玩家释放技能后可立即衔接攻击;2. 调整玩家下落重力参数(从 20f 提升至 25f),解决空中飘动感,提升移动手感;3. 优化玩家受击无敌帧判定,添加 “无敌期间忽略所有伤害检测” 的逻辑,避免无敌时仍被攻击命中。 | 玩家在使用 Dash(冲刺)技能位移过程中,偶发 “物理碰撞失效” 现象,导致穿透薄墙体(如栅栏、矮墙);性能测试中发现,当 10 + 敌人同时死亡时,帧率从 60fps 降至 45fps,存在明显卡顿,经排查是敌人尸体资源未及时销毁导致的内存占用过高。 | 玩家模块开发需在 “体验流畅度” 与 “性能稳定性” 之间找到平衡。针对 Dash 技能穿透墙体问题,通过将 Rigidbody2D 的碰撞检测模式设为 “Continuous”(连续碰撞检测),让高速移动时也能精准检测碰撞,避免穿模;而帧率下降问题,通过添加 “敌人尸体生成后 2 秒自动销毁” 的逻辑,及时释放内存,帧率可回升至 58fps。这让我意识到,测试工作不仅要验证 “功能是否能用”,还要关注 “体验是否流畅”“性能是否稳定”,尤其是高负载场景(如多敌人混战、技能连发),需通过资源生命周期管理、碰撞检测优化等手段,保障游戏运行流畅。 | 1. 完善玩家 Dash 技能的碰撞检测逻辑,开启 Continuous 模式,彻底解决墙体穿透问题;2. 优化敌人尸体的资源回收机制,确保生成后 2 秒自动销毁,同时添加 “尸体淡出动画”,提升视觉过渡效果;3. 执行 “玩家 - 敌人 - 技能 - 地图” 的全流程压力测试,模拟 20 + 敌人混战、多技能连发等高负载场景,记录帧率、内存占用等性能数据,定位潜在瓶颈。 |
| 莫馥玮(技能模块) | 1. 修复 DashStab(冲刺突刺)技能的穿透敌人问题,添加 “冲刺期间开启连续碰撞检测” 的逻辑,确保位移中能精准命中敌人;2. 完善技能 MP 消耗的兜底计算逻辑,当基础消耗为 0 时默认按 1 点计算,避免异常;3. 为技能释放添加 “冷却中弹窗提示”,显示剩余冷却时间(如 “技能冷却中,剩余 2.3 秒”),提升玩家操作预期。 | DashStab 技能在斜向冲刺(如右上、左下方向)时,偶尔出现 “位移距离缩短” 的异常(正向冲刺 2 米,斜向仅 1.5 米);技能冷却弹窗在技能 CD 结束后,偶发 “弹窗未自动关闭” 的 bug,导致弹窗一直停留在屏幕上。 | 技能开发中,“位移计算精度” 和 “状态同步” 是核心。斜向冲刺距离缩短的问题,源于未对斜向速度进行归一化处理(X/Y 轴速度叠加导致实际位移速度变快,进而被截断),通过将 dashDirection 向量归一化,确保各方向冲刺距离一致(均为 2 米);而弹窗未关闭的问题,是因为缺少 “CD 结束检测”,在 Update 函数中添加 “剩余 CD≤0 时关闭弹窗” 的判断后解决。这让我明白,技能设计需兼顾 “精度” 与 “反馈”:位移精度确保操作手感,状态同步确保玩家清晰感知技能状态,两者结合才能让技能体验流畅、可控。 | 1. 优化 DashStab 技能的斜向冲刺逻辑,通过速度归一化确保各方向位移距离一致;2. 完善技能冷却弹窗的状态同步,在 CD 结束后自动关闭弹窗,避免视觉干扰;3. 为技能系统添加 “连招提示” 功能,当玩家连续释放互补技能(如 DashStab + 冰攻击)时,弹出 “连招加成!伤害 + 10%” 的提示,引导玩家探索最优技能组合。 |
玩家模块
// 修复Dash技能穿透墙体问题,开启连续碰撞检测
private void Awake()
{
rb = GetComponent<Rigidbody2D>();
if (rb != null)
{
rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous; // 开启连续碰撞检测,避免高速穿模
rb.freezeRotation = true;
}
}
// 优化受击无敌帧与重力参数
private void TriggerRespawn()
{
transform.position = spawnPoint.position;
currentHealth = maxHealth;
rb.gravityScale = 25f; // 调整下落重力,解决空中飘动感
isInvincible = false;
Debug.Log("玩家重生,碰撞检测与重力参数已更新");
}
// 修复技能释放后攻击延迟,取消输入锁定
public void OnSkillCastEnd()
{
// 取消原0.3秒输入锁定,技能释放后立即恢复攻击能力
canAttack = true;
Debug.Log("技能释放结束,立即恢复攻击响应");
}
敌人模块
// 解决多敌人混战卡顿,攻击时忽略友方碰撞
private void OnAttackStart()
{
// 攻击期间临时忽略友方碰撞(Enemy层),避免被同类阻挡
Physics2D.IgnoreLayerCollision(gameObject.layer, LayerMask.NameToLayer("Enemy"), true);
StartCoroutine(ResetEnemyCollision());
}
private IEnumerator ResetEnemyCollision()
{
yield return new WaitForSeconds(0.5f); // 攻击结束后恢复碰撞
Physics2D.IgnoreLayerCollision(gameObject.layer, LayerMask.NameToLayer("Enemy"), false);
}
// 敌人超出范围自动返回原点
private void Update()
{
if (IsChasingPlayer() && Vector2.Distance(transform.position, patrolOrigin) > chaseRange)
{
chaseTimer += Time.deltaTime;
if (chaseTimer >= 10f)
{
StopChasing();
ReturnToPatrolOrigin();
chaseTimer = 0f;
}
}
}
// 敌人尸体自动销毁,优化性能
private void OnDeath()
{
// 尸体生成后2秒自动销毁,同时播放淡出动画
StartCoroutine(FadeAndDestroy());
Debug.Log("敌人死亡,尸体将在2秒后销毁");
}
private IEnumerator FadeAndDestroy()
{
SpriteRenderer renderer = GetComponent<SpriteRenderer>();
Color originalColor = renderer.color;
// 1.5秒内逐渐淡出
for (float t = 0; t < 1.5f; t += Time.deltaTime)
{
renderer.color = new Color(originalColor.r, originalColor.g, originalColor.b, Mathf.Lerp(1f, 0f, t / 1.5f));
yield return null;
}
Destroy(gameObject);
}
攻击模块
// 修复雷元素连锁误判友方,仅检测Enemy层
private void ApplyThunderEffect(GameObject target, AttackInfo attackInfo)
{
// 仅检测Enemy层,避免误判友方单位(Player层、Ally层)
Collider2D[] nearbyEnemies = Physics2D.OverlapCircleAll(target.transform.position, thunderChainRange, enemyLayer);
int chainDamage = Mathf.RoundToInt(attackInfo.baseDamage * 0.5f);
foreach (Collider2D enemy in nearbyEnemies)
{
if (enemy.gameObject != target && enemy.gameObject != gameObject)
{
Attribute enemyAttribute = enemy.GetComponent<Attribute>();
if (enemyAttribute != null)
{
enemyAttribute.TakeDamage(chainDamage, gameObject);
Debug.Log($"雷元素连锁: {enemy.name} 受到{chainDamage}伤害");
}
}
}
}
// 属性克制提示文字添加随机偏移,避免重叠
private void ShowElementTip(string tipText)
{
GameObject tipObj = Instantiate(elementTipPrefab, transform.position + Vector3.up, Quaternion.identity);
TextMeshProUGUI tipTextComp = tipObj.GetComponent<TextMeshProUGUI>();
tipTextComp.text = tipText;
// 添加随机Y轴偏移(±10px),避免多文字重叠
Vector3 randomOffset = new Vector3(0, Random.Range(-10f, 10f), 0);
tipObj.transform.localPosition += randomOffset;
// 2秒后自动销毁提示文字
Destroy(tipObj, 2f);
}
// 火元素燃烧伤害递减
private void ApplyFireEffect(GameObject target, AttackInfo attackInfo)
{
BurnEffect burnEffect = target.GetComponent<BurnEffect>();
if (burnEffect == null) burnEffect = target.AddComponent<BurnEffect>();
// 燃烧伤害随时间递减(第1秒5点→第2秒3点→第3秒2点)
int[] burnDamages = { 5, 3, 2 };
burnEffect.StartBurning(burnDamages, fireDamageDuration, gameObject);
Debug.Log($"火元素: {target.name} 开始燃烧,伤害随时间递减");
}
技能模块
// 修复DashStab斜向冲刺距离缩短,速度归一化
private void PerformDashStab()
{
isDashing = true;
// 斜向速度归一化,确保各方向(正前、斜上、斜下)冲刺距离一致(均为2米)
Vector2 normalizedDir = dashDirection.normalized;
rb.velocity = new Vector2(normalizedDir.x * dashSpeed, normalizedDir.y * dashSpeed);
Physics2D.IgnoreLayerCollision(playerLayer, enemyLayer, false); // 开启碰撞检测,避免穿透敌人
StartCoroutine(EndDash());
}
private IEnumerator EndDash()
{
yield return new WaitForSeconds(0.3f);
isDashing = false;
rb.velocity = Vector2.zero;
}
// 技能冷却弹窗自动关闭,确保状态同步
private void Update()
{
if (skillCDPopup != null && skillCDPopup.activeSelf)
{
float remainingCD = skillCD - (Time.time - lastCastTime);
if (remainingCD <= 0)
{
skillCDPopup.SetActive(false);
Debug.Log("技能冷却结束,自动关闭弹窗");
}
else
{
// 实时更新剩余冷却时间文字
TextMeshProUGUI cdText = skillCDPopup.GetComponentInChildren<TextMeshProUGUI>();
if (cdText != null)
{
cdText.text = $"冷却中:{Mathf.Round(remainingCD)}秒";
}
}
}
}
// 技能MP消耗兜底逻辑,避免异常
private int CalculateMPCost()
{
int baseCost = skillData.baseMPCost;
// 基础消耗为0时默认按1点计算,防止MP无消耗的异常情况
if (baseCost <= 0) baseCost = 1;
return Mathf.RoundToInt(baseCost * (1 + 0.1f * skillLevel));
}
UI/UX 设计
// 背包UI“99+”文字优化,避免重叠
private void UpdateItemCountText(Item item)
{
if (item.count > 99)
{
itemCountText.text = "99+";
// 缩小字号并调整锚点,避免与图标重叠
itemCountText.fontSize = 12;
itemCountText.rectTransform.anchoredPosition = new Vector2(8, -8); // 右上角偏移
}
else
{
itemCountText.text = item.count.ToString();
itemCountText.fontSize = 14;
itemCountText.rectTransform.anchoredPosition = new Vector2(5, -5);
}
}
// 指路箭头UI距离检测,自动隐藏
private void UpdateArrowVisibility()
{
if (playerTransform == null)
{
playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
return;
}
float distanceToPlayer = Vector2.Distance(transform.position, playerTransform.position);
if (distanceToPlayer > 5f)
{
gameObject.SetActive(false);
}
else
{
gameObject.SetActive(true);
// 箭头始终朝向玩家,增强引导性
Vector2 direction = (playerTransform.position - transform.position).normalized;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0, 0, angle);
}
}
// 血条受击闪烁效果,强化反馈
public void OnPlayerTakeDamage()
{
StartCoroutine(BlinkHealthBar());
}
private IEnumerator BlinkHealthBar()
{
Color originalColor = healthFillImage.color;
healthFillImage.color = Color.red; // 受击时闪烁红色
yield return new WaitForSeconds(0.1f);
// 恢复原颜色(根据血量百分比渐变)
healthFillImage.color = GetHealthColor(currentHealth / maxHealth);
}
private Color GetHealthColor(float percentage)
{
if (percentage > 0.6f) return Color.green;
else if (percentage > 0.3f) return Color.yellow;
else return Color.red;
}
地图模块
// 恢复泉水单玩家触发冷却,避免多玩家叠加
private Dictionary<PlayerController, float> playerTriggerCooldown = new Dictionary<PlayerController, float>();
private void OnTriggerEnter2D(Collider2D other)
{
PlayerController player = other.GetComponent<PlayerController>();
if (player != null)
{
// 同一玩家3秒内仅触发1次恢复,避免叠加
if (!playerTriggerCooldown.ContainsKey(player) || Time.time - playerTriggerCooldown[player] > 3f)
{
HealPlayer(player);
playerTriggerCooldown[player] = Time.time;
}
}
}
private void HealPlayer(PlayerController player)
{
// 每2秒恢复10%生命值/MP
Attribute playerAttr = player.GetComponent<Attribute>();
if (playerAttr != null)
{
float healAmount = playerAttr.MaxHealth * 0.1f;
playerAttr.Heal(healAmount);
// 显示恢复数值飘字
ShowHealText(player.transform.position, healAmount);
// 播放恢复粒子特效
Instantiate(healEffectPrefab, player.transform.position, Quaternion.identity);
}
}
// Boss区域战斗预警圈
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
warningCircle.SetActive(true);
// 播放预警音效,强化提示
AudioSource.PlayClipAtPoint(warningSound, transform.position);
// 显示战斗预警文字
ShowWarningText("前方即将进入Boss战斗区域!");
Debug.Log("玩家进入Boss预警区域,战斗即将开始");
}
}
private void OnTriggerExit2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
warningCircle.SetActive(false);
}
}
private void ShowWarningText(string text)
{
GameObject textObj = Instantiate(warningTextPrefab, transform.position + Vector3.up * 2f, Quaternion.identity);
TextMeshProUGUI textComp = textObj.GetComponent<TextMeshProUGUI>();
textComp.text = text;
Destroy(textObj, 3f);
}