一大波优化

This commit is contained in:
2026-07-05 15:33:41 +08:00
parent 4da7bdb9a4
commit 8485743cb7
115 changed files with 13467 additions and 201 deletions
+107
View File
@@ -0,0 +1,107 @@
%YAML 1.1
%TAG !u! tag:yousandi.cn,2023:
--- !u!1 &1000000000000001
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 7
m_Component:
- component: {fileID: 1000000000000002}
- component: {fileID: 1000000000000003}
- component: {fileID: 5026520723394658369}
m_Layer: 0
m_HasEditorInfo: 1
m_Name: SoulDrop
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1000000000000002
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1000000000000001}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!212 &1000000000000003
SpriteRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1000000000000001}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 0
m_RayTraceProcedural: 0
m_virtualGeometry: 0
m_virtualGeometryShadow: 0
m_ShadingRate: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 0
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 200
m_Sprite: {fileID: 21300000, guid: 26977bf2f4c1c2a439720e4ac20ed699, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 0.65, y: 0.92}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_MaskInteraction: 0
m_SpriteSortPoint: 0
--- !u!114 &5026520723394658369
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1000000000000001}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 05f5fd3b15112ea4a839e002766a56b9, type: 3}
m_Name:
m_EditorClassIdentifier:
flyDuration: 0.8
scoreValue: 1
delayMin: 0
delayMax: 0.3
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: Ci4c43mqVXLpSFSwxyzCy2YR04iF37g3Z6OFbLPfNeyhQQ8wiaslBAI=
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+21 -33
View File
@@ -126,15 +126,15 @@ MonoBehaviour:
m_EditorClassIdentifier:
lifetime: 10
damageOnContact: 1
--- !u!58 &8338025974414621740
CircleCollider2D:
fadeOutDuration: 2
soulDropPrefab: {fileID: 1000000000000001, guid: 5d3fc7696ceb3a24d9234355fee1c344, type: 3}
--- !u!135 &8338025974414621740
SphereCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6632183076166779216}
m_Enabled: 1
m_Density: 1
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
@@ -143,48 +143,36 @@ CircleCollider2D:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_ForceSendLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ForceReceiveLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ContactCaptureLayers:
serializedVersion: 2
m_Bits: 4294967295
m_CallbackLayers:
serializedVersion: 2
m_Bits: 4294967295
m_IsTrigger: 1
m_UsedByEffector: 0
m_UsedByComposite: 0
m_Offset: {x: 0, y: 0}
serializedVersion: 2
m_Radius: 0.5
--- !u!50 &8635647722604209322
Rigidbody2D:
serializedVersion: 4
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Radius: 5
m_Center: {x: 0, y: 0, z: 0}
--- !u!54 &8635647722604209322
Rigidbody:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6632183076166779216}
m_BodyType: 1
m_Simulated: 1
m_UseFullKinematicContacts: 0
m_UseAutoMass: 0
serializedVersion: 4
m_Mass: 1
m_LinearDrag: 0
m_Drag: 0
m_AngularDrag: 0.05
m_GravityScale: 1
m_Material: {fileID: 0}
m_CenterOfMass: {x: 0, y: 0, z: 0}
m_InertiaTensor: {x: 1, y: 1, z: 1}
m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_ImplicitCom: 1
m_ImplicitTensor: 1
m_UseGravity: 0
m_IsKinematic: 0
m_Interpolate: 0
m_SleepingMode: 1
m_CollisionDetection: 0
m_Constraints: 0
m_CollisionDetection: 0
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

+133
View File
@@ -0,0 +1,133 @@
fileFormatVersion: 2
guid: DXwWsi3/BXk7uR1eMmEfbbF3pQH8K3u2VIV9GkCRR1J/An4VNoLdwm4=
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
webStreaming: 0
priorityLevel: 0
uploadedMode: 2
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
maxPlaceholderSize: 32
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
maxPlaceholderSize: 32
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
maxPlaceholderSize: 32
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:
+114
View File
@@ -0,0 +1,114 @@
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
namespace GameFramework
{
/// <summary>
/// 魂灵掉落物 —— 敌人被灵灯击杀后掉落。
/// 从敌人位置飞向 HUD 魂灵计数图标,到达后加分并自毁。
/// </summary>
public class SoulDrop : MonoBehaviour
{
[Header("飞行参数")]
[Tooltip("飞向 HUD 的飞行时间(秒)")]
[SerializeField] private float flyDuration = 0.8f;
[Tooltip("每个掉落物的分数")]
[SerializeField] private int scoreValue = 1;
[Header("延迟")]
[Tooltip("出生后的随机延迟范围(秒),避免所有掉落物同时起飞")]
[SerializeField] private float delayMin = 0f;
[SerializeField] private float delayMax = 0.3f;
private RectTransform _targetUI;
private SpriteRenderer _sr;
private void Awake()
{
_sr = GetComponent<SpriteRenderer>();
}
/// <summary>
/// 初始化掉落物:设置目标 UI 并启动飞行协程。
/// </summary>
public void Initialize(RectTransform targetUI)
{
_targetUI = targetUI;
StartCoroutine(DelayedFly());
}
private IEnumerator DelayedFly()
{
// 随机延迟,让掉落物有先后起飞的效果
float delay = Random.Range(delayMin, delayMax);
if (delay > 0f)
yield return new WaitForSeconds(delay);
yield return StartCoroutine(FlyToHUD());
}
private IEnumerator FlyToHUD()
{
Vector3 startPos = transform.position;
Camera cam = Camera.main;
if (cam == null || _targetUI == null)
{
// 降级处理:直接加分
AddScoreAndDestroy();
yield break;
}
// 目标:HUD 魂灵图标的屏幕位置
Vector3 targetScreenPos = _targetUI.position;
// 保持深度一致,避免转换出错
float depth = Mathf.Abs(cam.WorldToScreenPoint(startPos).z);
targetScreenPos.z = depth;
Vector3 targetWorldPos = cam.ScreenToWorldPoint(targetScreenPos);
float elapsed = 0f;
while (elapsed < flyDuration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / flyDuration);
// 带弧度的飞行轨迹(先高后低)
float arc = Mathf.Sin(t * Mathf.PI) * 0.5f;
Vector3 pos = Vector3.Lerp(startPos, targetWorldPos, t);
pos.y += arc;
transform.position = pos;
// 逐渐缩小 + 旋转
float scale = Mathf.Lerp(1f, 0.3f, t);
transform.localScale = Vector3.one * scale;
transform.Rotate(0, 0, 360f * Time.deltaTime);
// 渐隐效果(最后 30% 开始变淡)
if (_sr != null && t > 0.7f)
{
float fadeT = (t - 0.7f) / 0.3f;
_sr.color = new Color(_sr.color.r, _sr.color.g, _sr.color.b, 1f - fadeT);
}
yield return null;
}
AddScoreAndDestroy();
}
private void AddScoreAndDestroy()
{
// 确保 ScoreManager 存在(直接从 Gameplay 场景启动时可能没有)
if (ScoreManager.Instance == null)
{
var go = new GameObject("ScoreManager");
go.AddComponent<ScoreManager>();
Debug.Log("[SoulDrop] 自动创建 ScoreManager");
}
Debug.Log($"[SoulDrop] 加分 +{scoreValue},当前总分: {ScoreManager.Instance.CurrentScore + scoreValue}");
ScoreManager.Instance.AddScore(scoreValue);
Destroy(gameObject);
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: D39JsHz5UCnBU6cE/ziIfIKIuVF1r+F2bQjvK7afzo4asq+9jP9uAW4=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+112 -21
View File
@@ -1,19 +1,20 @@
using System;
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using GameFramework;
namespace IndianOceanAssets.Engine2_5D
{
/// <summary>
/// 单个灵灯的行为组件 —— 挂在灵灯 Prefab 上。
/// 放置后照亮周围区域(通过 LightSource),
/// 怪物碰触时扣 1 点血并自毁回收
/// 存在时间到期后自动回收
/// 只伤害第一个碰触的怪物,触发 2s 渐隐消失流程
/// 怪物死亡后掉落魂灵飞向 HUD
///
/// 【碰撞检测说明】
/// 灵灯自身持有 CircleCollider2D (isTrigger=true),是主动检测方。
/// 当怪物的 Collider2D 进入灵灯的触发区域时,OnTriggerEnter2D 被调用
/// 需确保 Physics2D 碰撞矩阵中,灵灯所在 Layer 与怪物 Layer 可互相触发。
/// 灵灯不依赖 whatIsEnemy LayerMask,而是直接用 Tag/Component 判定目标。
/// 灵灯自身持有 SphereCollider (isTrigger=true),是主动检测方。
/// 使用 3D 物理系统以匹配敌人的 CapsuleCollider3D
/// </summary>
public class SpiritLantern : MonoBehaviour
{
@@ -25,6 +26,14 @@ namespace IndianOceanAssets.Engine2_5D
[Tooltip("怪物碰触灵灯时受到的伤害")]
[SerializeField] private int damageOnContact = 1;
[Header("渐隐")]
[Tooltip("碰触后灵灯渐隐消失的时间(秒)")]
[SerializeField] private float fadeOutDuration = 2f;
[Header("魂灵掉落")]
[Tooltip("魂灵掉落物预制体")]
[SerializeField] private GameObject soulDropPrefab;
/// <summary>灵灯被回收时触发(被 SpiritLanternSystem 订阅)</summary>
public event Action OnLanternRecalled;
@@ -40,58 +49,140 @@ namespace IndianOceanAssets.Engine2_5D
_ownerSystem = system;
}
private void Awake()
{
// 确保 Rigidbody 为运动学模式,不受重力和物理影响
var rb = GetComponent<Rigidbody>();
if (rb != null)
{
rb.isKinematic = true;
rb.useGravity = false;
}
}
private void Update()
{
// 存在时间倒计时
lifetime -= Time.deltaTime;
if (lifetime <= 0f)
{
Recall();
StartRecallSequence();
}
}
/// <summary>
/// 怪物碰触灵灯时触发:扣血 + 回收灵灯
/// 灵灯的 Trigger 主动检测进入的碰撞体,排除玩家后对怪物造成伤害
/// 怪物碰触灵灯时触发:只伤害第一个碰到的敌人
/// 已触发回收后不再响应后续碰撞
/// </summary>
private void OnTriggerEnter2D(Collider2D other)
private void OnTriggerEnter(Collider other)
{
// 排除玩家(玩家 Tag 为 "Player"),避免放置时与玩家碰撞体误触发
if (other.CompareTag("Player"))
return;
// 已触发则忽略后续碰撞
if (_recalled) return;
// 排除玩家
if (other.CompareTag("Player")) return;
// 尝试获取怪物的 HealthSystem
HealthSystem health = other.GetComponent<HealthSystem>();
if (health != null)
{
// 在伤害前记录信息(用于掉落,因为 Die() 会 Destroy gameObject
Vector3 deathPos = other.transform.position;
int enemyMaxHp = health.MaxHealth;
health.Damage(damageOnContact);
Recall();
// 如果敌人死亡,生成魂灵掉落
if (health.IsDead && soulDropPrefab != null)
{
Debug.Log($"[SpiritLantern] 敌人死亡! maxHp={enemyMaxHp}, 准备生成魂灵掉落");
SpawnSoulDrops(deathPos, enemyMaxHp);
}
else if (health.IsDead)
{
Debug.LogWarning("[SpiritLantern] 敌人死亡但 soulDropPrefab 未配置!");
}
// 开始渐隐消失流程
StartRecallSequence();
}
}
/// <summary>
/// 回收灵灯:显式取消事件订阅 → 触发通知 → 销毁 GameObject
/// 使用 _recalled 标志防止重复触发。
/// 开始回收流程:立即通知系统回收名额 → 禁用碰撞 → 2s 渐隐 → 销毁
/// </summary>
private void Recall()
private void StartRecallSequence()
{
if (_recalled) return;
_recalled = true;
// 1. 先通过 System 显式取消事件订阅,防止内存泄漏
// 1. 立即取消事件订阅 + 通知系统(回收灵灯名额)
if (_ownerSystem != null)
{
_ownerSystem.UnregisterLantern(this);
}
// 2. 通知其他可能的订阅者(如 UI 等)
OnLanternRecalled?.Invoke();
OnLanternRecalled = null;
// 3. 销毁灵灯 GameObject
// 2. 禁用碰撞体,开始渐隐
var col = GetComponent<Collider>();
if (col != null) col.enabled = false;
StartCoroutine(FadeOutAndDestroy(fadeOutDuration));
}
/// <summary>
/// 渐隐协程:SpriteRenderer alpha 和 LightSource intensity 同步归零后销毁。
/// </summary>
private IEnumerator FadeOutAndDestroy(float duration)
{
var sr = GetComponent<SpriteRenderer>();
var light = GetComponent<LightSource>();
float startAlpha = sr != null ? sr.color.a : 1f;
float startIntensity = light != null ? light.Intensity : 1f;
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
if (sr != null)
sr.color = new Color(sr.color.r, sr.color.g, sr.color.b, Mathf.Lerp(startAlpha, 0f, t));
if (light != null)
light.SetIntensity(Mathf.Lerp(startIntensity, 0f, t));
yield return null;
}
Destroy(gameObject);
}
/// <summary>
/// 在敌人死亡位置生成魂灵掉落物,飞向 HUD 魂灵计数。
/// 数量 = 敌人最大血量 × 2~5 倍。
/// </summary>
private void SpawnSoulDrops(Vector3 position, int enemyMaxHp)
{
int count = enemyMaxHp * UnityEngine.Random.Range(2, 6); // 2~5 倍
RectTransform hudTarget = GameHUD.SoulIconRect;
Debug.Log($"[SpiritLantern] SpawnSoulDrops: count={count}, hudTarget={(hudTarget != null ? hudTarget.name : "NULL")}");
for (int i = 0; i < count; i++)
{
Vector3 offset = new Vector3(
UnityEngine.Random.Range(-0.3f, 0.3f),
UnityEngine.Random.Range(0f, 0.3f),
UnityEngine.Random.Range(-0.3f, 0.3f)
);
GameObject drop = Instantiate(soulDropPrefab, position + offset, Quaternion.identity);
SoulDrop soul = drop.GetComponent<SoulDrop>();
if (soul != null)
soul.Initialize(hudTarget);
}
}
/// <summary>
/// 安全网:如果灵灯被非正常销毁(场景卸载、外部 Destroy 等),
/// 确保事件仍然触发,避免 SpiritLanternSystem 的灵灯计数永久丢失。