feat(gameplay): 提升单位检测范围并添加法师属性

- 将所有单位的检测范围从默认值提升至100
- 为法师预制体添加护盾、等级等新属性
- 为法师添加暴击、吸血、伤害减免等战斗属性
- 更换法师弹丸预设并调整相关参数
- 添加锚点交战Z线控制功能
- 更新玩家数据中配备的召唤师技能
- 移除多余的纹理配置文件
```
This commit is contained in:
huadexuan committed 2026-10-07 23:59:17 +08:00
1 parent 6089308f66
commit 23c559d9f7
243 files changed
+150612 -1459

No files matched your search

+131 -7
View File
@@ -9,6 +9,20 @@ public class WorldHealthBar : MonoBehaviour
// 当前生命值,范围会自动限制在 0 到 maxHealth 之间。
[Min(0f)] public float currentHealth = 100f;
[Header("护盾")]
public float currentShield = 0f;
/// <summary>
/// 为单位添加护盾
/// </summary>
public void AddShield(float amount)
{
if (amount <= 0f || isDead) return;
currentShield += amount;
UpdateFill();
Debug.Log($"{gameObject.name} 获得护盾 +{amount:F1},当前护盾: {currentShield:F1}");
}
// 技能能量上限,英雄默认使用100点;没有技能的小怪可关闭能量条。
[Header("技能能量")]
public bool showEnergyBar = true;
@@ -88,8 +102,14 @@ public class WorldHealthBar : MonoBehaviour
// 血条最终使用的世界宽度。
private float worldWidth;
// 所有血条共用的圆角 Sprite。
[Header("等级显示")]
public int unitLevel = 1;
// 所有血条共用的圆角 Sprite 和圆形 Sprite。
private static Sprite roundedSprite;
private static Sprite circleSprite;
private Text levelText;
private Image levelBadgeBg;
// 防止死亡逻辑重复执行。
private bool isDead;
@@ -97,6 +117,15 @@ public class WorldHealthBar : MonoBehaviour
// 公开死亡状态供外部查询(用于胜负判定)
public bool IsDead => isDead;
public void SetLevel(int level)
{
unitLevel = Mathf.Max(1, level);
if (levelText != null)
{
levelText.text = unitLevel.ToString();
}
}
// 初始化血量和血条 UI。
private void Awake()
{
@@ -133,16 +162,16 @@ public class WorldHealthBar : MonoBehaviour
canvas.worldCamera = camera;
if (camera.gameObject.name == "Main Camera")
{
// 使用摄像机的上方向,保证血条在摄像机画面中保持水平。
// 面向摄像机背面,保证 UI 左右方向不发生镜像反转
barRect.rotation = Quaternion.LookRotation(
camera.transform.position - barRect.position,
barRect.position - camera.transform.position,
camera.transform.up);
}
else
{
// 找不到 Main Camera 时,保留原来的展示逻辑。
barRect.rotation = Quaternion.LookRotation(
camera.transform.position - barRect.position,
barRect.position - camera.transform.position,
Vector3.up);
}
}
@@ -181,12 +210,27 @@ public class WorldHealthBar : MonoBehaviour
public void TakeDamage(float amount, GameObject attacker = null)
{
bool wasDead = isDead;
SetHealth(currentHealth - amount);
if (showDamageNumbers && amount > 0f && !wasDead)
float originalDamage = amount;
// 优先消耗护盾抵扣伤害
if (currentShield > 0f && amount > 0f)
{
float absorbed = Mathf.Min(currentShield, amount);
currentShield -= absorbed;
amount -= absorbed;
Debug.Log($"{gameObject.name} 护盾吸收了 {absorbed:F1} 伤害,剩余护盾: {currentShield:F1}");
}
if (amount > 0f)
{
SetHealth(currentHealth - amount);
}
if (showDamageNumbers && originalDamage > 0f && !wasDead)
{
// 判断受击者(自己)是否是友方(Friend tag)
bool isVictimFriend = gameObject.CompareTag("Friend");
SpawnDamageNumber(amount, false, isVictimFriend);
SpawnDamageNumber(originalDamage, false, isVictimFriend);
}
}
@@ -451,6 +495,7 @@ public class WorldHealthBar : MonoBehaviour
if (!showEnergyBar)
{
energyFillImage = null;
CreateLevelBadge(barObject.transform);
return;
}
@@ -476,6 +521,8 @@ public class WorldHealthBar : MonoBehaviour
energyInner.fillMethod = Image.FillMethod.Horizontal;
energyInner.fillOrigin = 0;
energyFillImage = energyInner;
CreateLevelBadge(barObject.transform);
}
private void ApplyScaleCompensation()
@@ -539,6 +586,83 @@ public class WorldHealthBar : MonoBehaviour
return new Color(1f, 0.72f, 0.08f, 1f);
}
// 创建圆形 Sprite 用于等级徽章背景。
private static Sprite CircleSprite()
{
if (circleSprite != null) return circleSprite;
Texture2D texture = new Texture2D(64, 64, TextureFormat.RGBA32, false);
float radius = 30f;
Vector2 center = new Vector2(31.5f, 31.5f);
for (int y = 0; y < 64; y++)
{
for (int x = 0; x < 64; x++)
{
float dist = Vector2.Distance(new Vector2(x, y), center);
if (dist > radius)
{
texture.SetPixel(x, y, Color.clear);
}
else
{
float alpha = Mathf.Clamp01(radius + 0.5f - dist);
texture.SetPixel(x, y, new Color(1f, 1f, 1f, alpha));
}
}
}
texture.Apply();
circleSprite = Sprite.Create(texture, new Rect(0, 0, 64, 64), new Vector2(0.5f, 0.5f));
return circleSprite;
}
// 创建血条左侧的圆圈等级徽章
private void CreateLevelBadge(Transform parent)
{
int badgeSize = 26; // 圆圈徽章直径
GameObject badgeObj = new GameObject("LevelBadge", typeof(RectTransform));
badgeObj.transform.SetParent(parent, false);
RectTransform badgeRect = badgeObj.GetComponent<RectTransform>();
badgeRect.anchorMin = new Vector2(0f, 1f);
badgeRect.anchorMax = new Vector2(0f, 1f);
badgeRect.pivot = new Vector2(1f, 0.5f); // 右边缘切齐,紧贴血条左边缘
badgeRect.sizeDelta = new Vector2(badgeSize, badgeSize);
badgeRect.anchoredPosition = new Vector2(2f, -PixelHeight * 0.5f); // 总是对齐第一行血条中心
// 外层黑边圆圈
Image outerCircle = CreateImage("OuterCircle", badgeRect, CircleSprite(), new Color(0.05f, 0.05f, 0.05f, 0.95f));
SetFullRect(outerCircle.rectTransform);
// 内层深色底板
Image innerCircle = CreateImage("InnerCircle", outerCircle.transform, CircleSprite(), new Color(0.12f, 0.18f, 0.15f, 1f));
innerCircle.rectTransform.anchorMin = Vector2.zero;
innerCircle.rectTransform.anchorMax = Vector2.one;
innerCircle.rectTransform.offsetMin = new Vector2(2f, 2f);
innerCircle.rectTransform.offsetMax = new Vector2(-2f, -2f);
levelBadgeBg = innerCircle;
// 居中阿拉伯数字 Text
GameObject textObj = new GameObject("LevelText", typeof(RectTransform), typeof(Text));
textObj.transform.SetParent(innerCircle.transform, false);
RectTransform textRect = textObj.GetComponent<RectTransform>();
SetFullRect(textRect);
levelText = textObj.GetComponent<Text>();
levelText.text = unitLevel.ToString();
levelText.font = GetBuiltinFont();
levelText.fontSize = 18;
levelText.fontStyle = FontStyle.Bold;
levelText.alignment = TextAnchor.MiddleCenter;
levelText.color = new Color(0.95f, 0.98f, 0.95f, 1f);
// 加上外发光/描边效果
var shadow = textObj.AddComponent<Shadow>();
shadow.effectColor = new Color(0f, 0f, 0f, 0.9f);
shadow.effectDistance = new Vector2(1f, -1f);
}
// 创建一个用于边框或填充的 UI Image。
private static Image CreateImage(string name, Transform parent, Sprite sprite, Color color)
{