From 3dc5585e4e8eb2f36bebbbb40f3f8a1c8b84f71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=B8=85=27=CF=89=27=E0=B8=85?= Date: Sat, 21 Feb 2026 07:56:46 -0500 Subject: [PATCH 1/2] feat: add emotion bar - add emotion bar for individual NPC to visualize mood --- Assets/Art/Sprites/Square.png | Bin 0 -> 2097 bytes Assets/Art/Sprites/Square.png.meta | 169 ++++++++++++++ Assets/Prefabs/NPC.prefab | 230 ++++++++++++++++++- Assets/Scripts/NPCBase.cs | 37 ++- Assets/Scripts/NPCEmotionBar.cs | 76 ++++++ Assets/Scripts/NPCEmotionBar.cs.meta | 11 + Packages/packages-lock.json | 38 +-- ProjectSettings/PackageManagerSettings.asset | 6 +- ProjectSettings/ProjectVersion.txt | 4 +- README.md | 1 + 10 files changed, 539 insertions(+), 33 deletions(-) create mode 100644 Assets/Art/Sprites/Square.png create mode 100644 Assets/Art/Sprites/Square.png.meta create mode 100644 Assets/Scripts/NPCEmotionBar.cs create mode 100644 Assets/Scripts/NPCEmotionBar.cs.meta diff --git a/Assets/Art/Sprites/Square.png b/Assets/Art/Sprites/Square.png new file mode 100644 index 0000000000000000000000000000000000000000..3410c68252208bef952a5d8683a07a4a581aac8f GIT binary patch literal 2097 zcmeHI&5zSY6rb=>J_;2Q7vMCQ3l-QNJ6UHl!YoU&-9)Olt0hvG8D)-&SB4T(#SRR#Y57f>%nTmcDH{R=91&WE*IQNAu*uxxoe^PAs$?>Fx~|FXKW zeDv_C!w8|Ht!85lp%M&B=-?iBJw3MI!0S-byqY2O?eY96p*wd^AhiFKY_IF};77_; zWU)|ngf)s1KqGWvVU#ewAvErYo{W9tpWh!EScbmw^ISlJq%Qihxt)qD+beCpy}@gt zv2YPz7*QaIgl2dY4dRTBd}GW@VVqCf1|CE7hHot92Jw2Zit8#B*t3Yq32||?W;tG^ zGCzMFyTm0nsoD-PU6&G%&Xw`>GQe6IcIjH)c% z;@Ylj0>aF;V$DWooSm65G(^TznP{nEoHMeH+SI-Qo=!rDl7cqQrZRzG_J}36W05?h zF)-u>F4;^6W8)#W#Xv+N))`=(0-N-eR#{*D4|TD;%K%6l1ci-v`VvKjiA*oufH0~8Ibx?UTOxLl@lyP=RYA=B)G;E>a~|lFqHAU5PXB@86ZMqIxRn2feG!fFM#wt zc`<=ys;h@A6^lJk>mxGH2KVi}XeW`_{|$1ywxhsjaOfKOuxMBCQ8YXeLzhdTojw2U z^&5ot{LyMGwnumWe(IDEKJth>die4*Up~J7=63JJr9Yp2cPsb?KSuXX-m2{VwTqq{ oxpb%0EF<}K@~a?UJQ@BvaR1f5fA>Bno&2ZXT3Ts5xP0yQTl{2u)c^nh literal 0 HcmV?d00001 diff --git a/Assets/Art/Sprites/Square.png.meta b/Assets/Art/Sprites/Square.png.meta new file mode 100644 index 0000000..731349c --- /dev/null +++ b/Assets/Art/Sprites/Square.png.meta @@ -0,0 +1,169 @@ +fileFormatVersion: 2 +guid: 4608366a2f0b545159493509817d86e6 +TextureImporter: + internalIDToNameTable: + - first: + 213: 7482667652216324306 + second: Square + 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 + 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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 256 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: 0 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + 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 + 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: iPhone + maxTextureSize: 2048 + 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: Android + maxTextureSize: 2048 + 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: + - serializedVersion: 2 + name: Square + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 256 + height: 256 + alignment: 0 + pivot: {x: 0.5, y: 0.5} + border: {x: 0, y: 0, z: 0, w: 0} + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: 2d009a6b596c7d760800000000000000 + internalID: 7482667652216324306 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + physicsShape: + - - {x: -128, y: 128} + - {x: -128, y: -128} + - {x: 128, y: -128} + - {x: 128, y: 128} + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: + Square: 7482667652216324306 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/NPC.prefab b/Assets/Prefabs/NPC.prefab index 543ef1d..3b27f5f 100644 --- a/Assets/Prefabs/NPC.prefab +++ b/Assets/Prefabs/NPC.prefab @@ -32,7 +32,8 @@ Transform: m_LocalPosition: {x: -0.3822229, y: -0.08349733, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: [] + m_Children: + - {fileID: 4367567054083019759} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!212 &2476905963911091668 @@ -103,6 +104,9 @@ MonoBehaviour: runSpeed: 4 rainMoodPenalty: -10 puddleMoodBonus: 15 + maxEmotion: 100 + minEmotion: 0 + currentEmotion: 50 puddleShrinkAmount: 1.5 puddleDetectionRadius: 2 puddleLayer: @@ -170,3 +174,227 @@ Rigidbody2D: m_SleepingMode: 1 m_CollisionDetection: 0 m_Constraints: 0 +--- !u!1 &3397686684337667064 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3800979187013809294} + - component: {fileID: 5282190346471789721} + m_Layer: 11 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3800979187013809294 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3397686684337667064} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0.7, z: 0} + m_LocalScale: {x: 1.5, y: 0.15, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4367567054083019759} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!212 &5282190346471789721 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3397686684337667064} + 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_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + 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: 5 + m_Sprite: {fileID: 7482667652216324306, guid: 4608366a2f0b545159493509817d86e6, type: 3} + m_Color: {r: 0.2735849, g: 0.2516465, b: 0.2516465, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 1, y: 1} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 0 + m_SpriteSortPoint: 0 +--- !u!1 &5051396973743330409 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4367567054083019759} + - component: {fileID: 3541607058677874323} + m_Layer: 11 + m_Name: EmotionBar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4367567054083019759 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5051396973743330409} + 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: + - {fileID: 3800979187013809294} + - {fileID: 8671735667365070231} + m_Father: {fileID: 5221707524378300132} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3541607058677874323 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5051396973743330409} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8249d52c2d622415eabc0d064dc074c3, type: 3} + m_Name: + m_EditorClassIdentifier: + npc: {fileID: 0} + background: {fileID: 3800979187013809294} + fill: {fileID: 8671735667365070231} + fillOnly: 1 + heightOffset: 1.2 + barWidth: 1.5 + useColorGradient: 1 + colorLow: {r: 0.9, g: 0.2, b: 0.2, a: 1} + colorMid: {r: 0.95, g: 0.85, b: 0.2, a: 1} + colorHigh: {r: 0.2, g: 0.85, b: 0.3, a: 1} +--- !u!1 &7606604419182449673 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8671735667365070231} + - component: {fileID: 8183238178871403668} + m_Layer: 11 + m_Name: Fill + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8671735667365070231 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7606604419182449673} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0.7, z: 0} + m_LocalScale: {x: 1.5, y: 0.15, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4367567054083019759} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!212 &8183238178871403668 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7606604419182449673} + 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_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + 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: 6 + m_Sprite: {fileID: 7482667652216324306, guid: 4608366a2f0b545159493509817d86e6, type: 3} + m_Color: {r: 0.26500848, g: 0.735849, b: 0.18396226, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 1, y: 1} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 0 + m_SpriteSortPoint: 0 diff --git a/Assets/Scripts/NPCBase.cs b/Assets/Scripts/NPCBase.cs index ca778b3..142d794 100644 --- a/Assets/Scripts/NPCBase.cs +++ b/Assets/Scripts/NPCBase.cs @@ -13,6 +13,12 @@ public class NPCBase : MonoBehaviour [Header("Mood Impact")] public float rainMoodPenalty = -10f; public float puddleMoodBonus = 15f; + + [Header("Emotion (for head bar display)")] + [Tooltip("Per-NPC emotion value, 0=bad to 100=good")] + public float maxEmotion = 100f; + public float minEmotion = 0f; + [SerializeField] private float currentEmotion = 50f; [Header("Interactions & AI")] public float puddleShrinkAmount = 1.5f; // How much puddle size is consumed when stepped on @@ -43,6 +49,14 @@ protected virtual void Start() // Pick the first random spot to wander to PickNewWanderTarget(); + currentEmotion = Mathf.Clamp(currentEmotion, minEmotion, maxEmotion); + } + + /// Returns emotion as 0–1 for UI bars. 0 = worst, 1 = best. + public float GetEmotionRatio() + { + if (maxEmotion <= minEmotion) return 0.5f; + return Mathf.Clamp01((currentEmotion - minEmotion) / (maxEmotion - minEmotion)); } protected virtual void Update() @@ -189,10 +203,13 @@ protected virtual void GetWet() { Debug.Log($"{gameObject.name} was rained on! Global mood penalties applied."); currentState = NPCState.Fleeing; - - if (GameManager.Instance != null) - GameManager.Instance.ModifyMood(rainMoodPenalty); - + float oldEmotion = currentEmotion; + currentEmotion = Mathf.Clamp(currentEmotion + rainMoodPenalty, minEmotion, maxEmotion); + float emotionDelta = currentEmotion - oldEmotion; + + if (GameManager.Instance != null && emotionDelta != 0f) + GameManager.Instance.ModifyMood(emotionDelta); + SetEdgeTarget(); } @@ -200,17 +217,21 @@ protected virtual void StepInPuddle(Puddle puddle) { Debug.Log($"{gameObject.name} splashed in a puddle! Feeling satisfied."); currentState = NPCState.Satisfied; - + float oldEmotion = currentEmotion; + currentEmotion = Mathf.Clamp(currentEmotion + puddleMoodBonus, minEmotion, maxEmotion); + float emotionDelta = currentEmotion - oldEmotion; + // Shrink puddle puddle.ModifySize(-puddleShrinkAmount); - // Boost global mood and register satisfied score + // Global mood changes by this NPC's actual emotion change if (GameManager.Instance != null) { - GameManager.Instance.ModifyMood(puddleMoodBonus); + if (emotionDelta != 0f) + GameManager.Instance.ModifyMood(emotionDelta); GameManager.Instance.RegisterNPCSatisfied(); } - + SetEdgeTarget(); } } diff --git a/Assets/Scripts/NPCEmotionBar.cs b/Assets/Scripts/NPCEmotionBar.cs new file mode 100644 index 0000000..dbeb70d --- /dev/null +++ b/Assets/Scripts/NPCEmotionBar.cs @@ -0,0 +1,76 @@ +using UnityEngine; + +/// +/// Displays a bar above the NPC's head to visualize emotion (0–1). +/// Attach to a child of the NPC; assign Background and Fill (SpriteRenderers or RectTransforms). +/// +public class NPCEmotionBar : MonoBehaviour +{ + [Header("References")] + [Tooltip("Leave empty to use parent NPCBase")] + public NPCBase npc; + [Tooltip("Background bar (full width).")] + public Transform background; + [Tooltip("Fill bar (will be scaled by emotion).")] + public Transform fill; + + [Header("Layout")] + [Tooltip("Check to only show fill bar, hide background.")] + public bool fillOnly = false; + [Tooltip("Height above NPC pivot")] + public float heightOffset = 1.2f; + [Tooltip("Bar width in world units (used if fill pivot is center)")] + public float barWidth = 1.5f; + + [Header("Colors (optional, for SpriteRenderer only)")] + public bool useColorGradient = true; + public Color colorLow = new Color(0.9f, 0.2f, 0.2f); + public Color colorMid = new Color(0.95f, 0.85f, 0.2f); + public Color colorHigh = new Color(0.2f, 0.85f, 0.3f); + + private SpriteRenderer _fillSprite; + private float _lastRatio = -1f; + + private void Awake() + { + if (npc == null) + npc = GetComponentInParent(); + + if (fill != null) + _fillSprite = fill.GetComponent(); + + if (background != null && fillOnly) + background.gameObject.SetActive(false); + } + + private void LateUpdate() + { + if (npc == null) return; + + // Keep bar above NPC + transform.position = npc.transform.position + Vector3.up * heightOffset; + + float ratio = npc.GetEmotionRatio(); + if (fill != null) + { + float r = Mathf.Clamp01(ratio); + Vector3 scale = fill.localScale; + scale.x = r; + fill.localScale = scale; + // If fill pivot is center: shift so bar fills from left + fill.localPosition = new Vector3(-(1f - r) * (barWidth * 0.5f), 0f, 0f); + + if (useColorGradient && _fillSprite != null) + _fillSprite.color = GetColorForRatio(ratio); + + _lastRatio = ratio; + } + } + + private Color GetColorForRatio(float r) + { + if (r <= 0.5f) + return Color.Lerp(colorLow, colorMid, r * 2f); + return Color.Lerp(colorMid, colorHigh, (r - 0.5f) * 2f); + } +} diff --git a/Assets/Scripts/NPCEmotionBar.cs.meta b/Assets/Scripts/NPCEmotionBar.cs.meta new file mode 100644 index 0000000..681bf65 --- /dev/null +++ b/Assets/Scripts/NPCEmotionBar.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8249d52c2d622415eabc0d064dc074c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index fada319..f155a45 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -18,7 +18,7 @@ "com.unity.modules.animation": "1.0.0", "com.unity.modules.uielements": "1.0.0" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.2d.aseprite": { "version": "1.1.9", @@ -30,7 +30,7 @@ "com.unity.mathematics": "1.2.6", "com.unity.modules.animation": "1.0.0" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.2d.common": { "version": "8.1.0", @@ -43,7 +43,7 @@ "com.unity.modules.animation": "1.0.0", "com.unity.modules.uielements": "1.0.0" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.2d.pixel-perfect": { "version": "5.1.0", @@ -52,7 +52,7 @@ "dependencies": { "com.unity.modules.imgui": "1.0.0" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.2d.psdimporter": { "version": "8.1.0", @@ -63,7 +63,7 @@ "com.unity.2d.sprite": "1.0.0", "com.unity.2d.animation": "9.2.0" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.2d.sprite": { "version": "1.0.0", @@ -80,7 +80,7 @@ "com.unity.mathematics": "1.1.0", "com.unity.modules.physics2d": "1.0.0" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.2d.tilemap": { "version": "1.0.0", @@ -101,7 +101,7 @@ "com.unity.modules.tilemap": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.burst": { "version": "1.8.21", @@ -111,14 +111,14 @@ "com.unity.mathematics": "1.2.1", "com.unity.modules.jsonserialize": "1.0.0" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.collab-proxy": { "version": "2.11.3", "depth": 0, "source": "registry", "dependencies": {}, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.collections": { "version": "1.2.4", @@ -128,14 +128,14 @@ "com.unity.burst": "1.6.6", "com.unity.test-framework": "1.1.31" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.ext.nunit": { "version": "1.0.6", "depth": 1, "source": "registry", "dependencies": {}, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.feature.2d": { "version": "2.0.1", @@ -159,7 +159,7 @@ "dependencies": { "com.unity.ext.nunit": "1.0.6" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.ide.visualstudio": { "version": "2.0.22", @@ -168,14 +168,14 @@ "dependencies": { "com.unity.test-framework": "1.1.9" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.mathematics": { "version": "1.2.6", "depth": 1, "source": "registry", "dependencies": {}, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.render-pipelines.core": { "version": "14.0.12", @@ -213,7 +213,7 @@ "depth": 2, "source": "registry", "dependencies": {}, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.shadergraph": { "version": "14.0.12", @@ -233,7 +233,7 @@ "com.unity.modules.imgui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.textmeshpro": { "version": "3.0.7", @@ -242,7 +242,7 @@ "dependencies": { "com.unity.ugui": "1.0.0" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.timeline": { "version": "1.7.7", @@ -254,7 +254,7 @@ "com.unity.modules.animation": "1.0.0", "com.unity.modules.particlesystem": "1.0.0" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.ugui": { "version": "1.0.0", @@ -273,7 +273,7 @@ "com.unity.ugui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" }, - "url": "https://packages.unity.cn" + "url": "https://packages.unity.com" }, "com.unity.modules.ai": { "version": "1.0.0", diff --git a/ProjectSettings/PackageManagerSettings.asset b/ProjectSettings/PackageManagerSettings.asset index 61024a5..616c44f 100644 --- a/ProjectSettings/PackageManagerSettings.asset +++ b/ProjectSettings/PackageManagerSettings.asset @@ -21,7 +21,7 @@ MonoBehaviour: m_Registries: - m_Id: main m_Name: - m_Url: https://packages.unity.cn + m_Url: https://packages.unity.com m_Scopes: [] m_IsDefault: 1 m_Capabilities: 7 @@ -31,6 +31,6 @@ MonoBehaviour: m_RegistryInfoDraft: m_Modified: 0 m_ErrorMessage: - m_UserModificationsInstanceId: -834 - m_OriginalInstanceId: -836 + m_UserModificationsInstanceId: -830 + m_OriginalInstanceId: -832 m_LoadAssets: 0 diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index d87ee45..587f809 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2022.3.62f2c1 -m_EditorVersionWithRevision: 2022.3.62f2c1 (92e6e6be66dc) +m_EditorVersion: 2022.3.62f3 +m_EditorVersionWithRevision: 2022.3.62f3 (96770f904ca7) diff --git a/README.md b/README.md index f7625f7..b591ac9 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ The game fully supports both Keyboard and Gamepad inputs! - **核心游戏循环**:稳健的全局状态机防穿游戏流(主菜单/游玩/暂停/结算)。 - **实体系统**:基于时间增量的动态难度刷怪器机制、随机道具机制。 - **系统闭环**:基于 PlayerPrefs 的最高分榜单持久化、响应式的 UI 弹窗与事件总线、带边界限制的平滑跟随摄像机。 +- **NPC 情感条**:每个 NPC 有独立情感值,头顶条随被雨淋/踩水坑变化;全局情绪值按每个 NPC 的情感变化量同步增减(见 `NPCBase` / `NPCEmotionBar`)。 --- From 69aaefb39798ee4a95a22aee3e5514cdd5a7d5e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=B8=85=27=CF=89=27=E0=B8=85?= Date: Sat, 21 Feb 2026 08:41:37 -0500 Subject: [PATCH 2/2] fix: emotion bar position and scale --- Assets/Prefabs/NPC.prefab | 4 ++-- Assets/Scripts/NPCEmotionBar.cs | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Assets/Prefabs/NPC.prefab b/Assets/Prefabs/NPC.prefab index 3b27f5f..5136af7 100644 --- a/Assets/Prefabs/NPC.prefab +++ b/Assets/Prefabs/NPC.prefab @@ -307,8 +307,8 @@ MonoBehaviour: npc: {fileID: 0} background: {fileID: 3800979187013809294} fill: {fileID: 8671735667365070231} - fillOnly: 1 - heightOffset: 1.2 + fillOnly: 0 + heightOffset: 0 barWidth: 1.5 useColorGradient: 1 colorLow: {r: 0.9, g: 0.2, b: 0.2, a: 1} diff --git a/Assets/Scripts/NPCEmotionBar.cs b/Assets/Scripts/NPCEmotionBar.cs index dbeb70d..5994310 100644 --- a/Assets/Scripts/NPCEmotionBar.cs +++ b/Assets/Scripts/NPCEmotionBar.cs @@ -30,6 +30,8 @@ public class NPCEmotionBar : MonoBehaviour private SpriteRenderer _fillSprite; private float _lastRatio = -1f; + /// Cached Fill localScale.x when at "full" (1.0) so bar width matches Background. + private float _fillFullScaleX = 1f; private void Awake() { @@ -37,7 +39,10 @@ private void Awake() npc = GetComponentInParent(); if (fill != null) + { _fillSprite = fill.GetComponent(); + _fillFullScaleX = fill.localScale.x; + } if (background != null && fillOnly) background.gameObject.SetActive(false); @@ -55,10 +60,12 @@ private void LateUpdate() { float r = Mathf.Clamp01(ratio); Vector3 scale = fill.localScale; - scale.x = r; + scale.x = r * _fillFullScaleX; // same full width as Background so left/right edges align fill.localScale = scale; - // If fill pivot is center: shift so bar fills from left - fill.localPosition = new Vector3(-(1f - r) * (barWidth * 0.5f), 0f, 0f); + + Vector3 pos = fill.localPosition; + pos.x = -(1f - r) * (_fillFullScaleX * 0.5f); // left-edge align with Background (pivot center) + fill.localPosition = pos; if (useColorGradient && _fillSprite != null) _fillSprite.color = GetColorForRatio(ratio);