chore: remove Unity AI Toolkit packages to fix enum warnings
- Remove com.unity.ai.assistant, com.unity.ai.generators, com.unity.ai.inference - Update packages-lock.json - Additional Phase 19 visual polish updates 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -83,6 +83,9 @@ namespace TheIsland.Visual
|
||||
private bool _isMoving;
|
||||
private float _moveSpeed = 3f;
|
||||
private Vector3 _lastPosition;
|
||||
private GameObject _shadowObj;
|
||||
private SpriteRenderer _shadowRenderer;
|
||||
private float _footstepTimer;
|
||||
|
||||
// UI Smoothing (Phase 19)
|
||||
private float _currentHpPercent;
|
||||
@@ -110,9 +113,40 @@ namespace TheIsland.Visual
|
||||
if (_animator == null) _animator = gameObject.AddComponent<AgentAnimator>();
|
||||
|
||||
CreateVisuals();
|
||||
CreateShadow();
|
||||
_lastPosition = transform.position;
|
||||
}
|
||||
|
||||
private void CreateShadow()
|
||||
{
|
||||
_shadowObj = new GameObject("Shadow");
|
||||
_shadowObj.transform.SetParent(transform);
|
||||
_shadowObj.transform.localPosition = new Vector3(0, 0.05f, 0); // Slightly above ground
|
||||
_shadowObj.transform.localRotation = Quaternion.Euler(90, 0, 0); // Flat on ground
|
||||
|
||||
_shadowRenderer = _shadowObj.AddComponent<SpriteRenderer>();
|
||||
_shadowRenderer.sprite = CreateBlobShadowSprite();
|
||||
_shadowRenderer.color = new Color(0, 0, 0, 0.3f);
|
||||
_shadowRenderer.sortingOrder = 1; // Just above ground
|
||||
}
|
||||
|
||||
private Sprite CreateBlobShadowSprite()
|
||||
{
|
||||
int size = 32;
|
||||
Texture2D tex = new Texture2D(size, size);
|
||||
for (int y = 0; y < size; y++)
|
||||
{
|
||||
for (int x = 0; x < size; x++)
|
||||
{
|
||||
float dist = Vector2.Distance(new Vector2(x, y), new Vector2(size / 2f, size / 2f)) / (size / 2f);
|
||||
float alpha = Mathf.Exp(-dist * 4f);
|
||||
tex.SetPixel(x, y, new Color(1, 1, 1, alpha));
|
||||
}
|
||||
}
|
||||
tex.Apply();
|
||||
return Sprite.Create(tex, new Rect(0, 0, size, size), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!IsAlive) return;
|
||||
@@ -169,10 +203,42 @@ namespace TheIsland.Visual
|
||||
FaceInteractionTarget();
|
||||
}
|
||||
|
||||
// Phase 19-F: AAA Grounding (Shadow & Footsteps)
|
||||
UpdateGrounding();
|
||||
|
||||
// Phase 19-F: Random emotion trigger test (Optional, for demo)
|
||||
if (Random.value < 0.001f) ShowEmotion("!");
|
||||
|
||||
// Phase 19: Smooth UI Bar Transitions
|
||||
UpdateSmoothBars();
|
||||
}
|
||||
|
||||
private void UpdateGrounding()
|
||||
{
|
||||
if (_shadowObj != null)
|
||||
{
|
||||
// Shadow follows but stays on ground (assuming Y=0 is ground level or character is at Y=0)
|
||||
// For simplicity, we just keep it at local zero.
|
||||
// If the character bops up, the shadow should shrink slightly
|
||||
float bopY = (_spriteRenderer != null) ? _spriteRenderer.transform.localPosition.y : 0;
|
||||
float shadowScale = Mathf.Clamp(1.0f - (bopY * 0.5f), 0.5f, 1.2f);
|
||||
_shadowObj.transform.localScale = new Vector3(1.2f * shadowScale, 0.6f * shadowScale, 1f);
|
||||
}
|
||||
|
||||
if (_isMoving)
|
||||
{
|
||||
_footstepTimer += Time.deltaTime;
|
||||
if (_footstepTimer > 0.35f) // Approximate footstep interval
|
||||
{
|
||||
_footstepTimer = 0;
|
||||
if (TheIsland.Visual.VisualEffectsManager.Instance != null)
|
||||
{
|
||||
TheIsland.Visual.VisualEffectsManager.Instance.SpawnFootstepDust(transform.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FaceInteractionTarget()
|
||||
{
|
||||
// If the agent is talking or near others, turn to face them
|
||||
@@ -202,6 +268,74 @@ namespace TheIsland.Visual
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowEmotion(string type)
|
||||
{
|
||||
var bubble = new GameObject("EmotionBubble");
|
||||
bubble.transform.SetParent(transform);
|
||||
bubble.transform.localPosition = new Vector3(0, 2.5f, 0); // Above head
|
||||
|
||||
var sprite = bubble.AddComponent<SpriteRenderer>();
|
||||
sprite.sprite = CreateEmotionSprite(type);
|
||||
sprite.sortingOrder = 110; // Top layer
|
||||
bubble.AddComponent<Billboard>();
|
||||
|
||||
StartCoroutine(AnimateEmotion(bubble));
|
||||
}
|
||||
|
||||
private Sprite CreateEmotionSprite(string type)
|
||||
{
|
||||
int size = 32;
|
||||
Texture2D tex = new Texture2D(size, size);
|
||||
Color bgColor = Color.white;
|
||||
Color iconColor = type == "!" ? Color.red : (type == "?" ? Color.blue : Color.black);
|
||||
|
||||
for (int y = 0; y < size; y++)
|
||||
{
|
||||
for (int x = 0; x < size; x++)
|
||||
{
|
||||
float d = Vector2.Distance(new Vector2(x, y), new Vector2(size / 2f, size / 2f)) / (size / 2.2f);
|
||||
bool isBorder = d > 0.85f && d < 1.0f;
|
||||
bool isBg = d <= 0.85f;
|
||||
|
||||
if (isBorder) tex.SetPixel(x, y, Color.black);
|
||||
else if (isBg) tex.SetPixel(x, y, bgColor);
|
||||
else tex.SetPixel(x, y, new Color(0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
// Simple "!" or "?" pixel art logic could go here, but for now just a red dot for "!"
|
||||
if (type == "!") {
|
||||
for (int y = 10; y < 24; y++) tex.SetPixel(16, y, iconColor);
|
||||
tex.SetPixel(16, 8, iconColor);
|
||||
}
|
||||
|
||||
tex.Apply();
|
||||
return Sprite.Create(tex, new Rect(0, 0, size, size), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
|
||||
private IEnumerator AnimateEmotion(GameObject bubble)
|
||||
{
|
||||
float elapsed = 0;
|
||||
float duration = 1.5f;
|
||||
Vector3 startScale = Vector3.zero;
|
||||
Vector3 peakScale = Vector3.one * 0.8f;
|
||||
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = elapsed / duration;
|
||||
float scale = (t < 0.2f) ? (t / 0.2f) : (1f - (t - 0.2f) / 0.8f);
|
||||
bubble.transform.localScale = peakScale * (Mathf.Sin(t * Mathf.PI * 1.5f) * 0.2f + 0.8f);
|
||||
bubble.transform.localPosition += Vector3.up * Time.deltaTime * 0.2f;
|
||||
|
||||
if (t > 0.8f) {
|
||||
var s = bubble.GetComponent<SpriteRenderer>();
|
||||
s.color = new Color(1, 1, 1, (1f - t) / 0.2f);
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
Destroy(bubble);
|
||||
}
|
||||
|
||||
private Vector3 CalculateRepulsion()
|
||||
{
|
||||
Vector3 force = Vector3.zero;
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace TheIsland
|
||||
public float moveBopAmount = 0.1f;
|
||||
public float moveTiltAmount = 10f;
|
||||
public float bankingAmount = 15f;
|
||||
public float jiggleIntensity = 0.15f;
|
||||
|
||||
private SpriteRenderer _spriteRenderer;
|
||||
private Vector3 _originalScale;
|
||||
@@ -27,7 +28,8 @@ namespace TheIsland
|
||||
private Vector3 _currentVelocity;
|
||||
private float _velocityPercentage; // 0 to 1
|
||||
private bool _isMoving;
|
||||
private float _transitionTimer;
|
||||
private float _jiggleOffset;
|
||||
private float _jiggleVelocity;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -50,20 +52,21 @@ namespace TheIsland
|
||||
public void SetMovement(Vector3 velocity, float maxVelocity = 3f)
|
||||
{
|
||||
_currentVelocity = velocity;
|
||||
_velocityPercentage = Mathf.Clamp01(velocity.magnitude / Mathf.Max(0.1f, maxVelocity));
|
||||
float targetVelPct = Mathf.Clamp01(velocity.magnitude / Mathf.Max(0.1f, maxVelocity));
|
||||
|
||||
bool nowMoving = _velocityPercentage > 0.05f;
|
||||
bool nowMoving = targetVelPct > 0.05f;
|
||||
if (nowMoving && !_isMoving)
|
||||
{
|
||||
// Anticipation: Squash when starting to move
|
||||
TriggerAnticipation();
|
||||
_jiggleVelocity = -2f; // Initial kickback
|
||||
}
|
||||
else if (!nowMoving && _isMoving)
|
||||
{
|
||||
// Overshoot: Rebound when stopping
|
||||
TriggerOvershoot();
|
||||
_jiggleVelocity = 2f; // Snap forward
|
||||
}
|
||||
|
||||
_velocityPercentage = targetVelPct;
|
||||
_isMoving = nowMoving;
|
||||
}
|
||||
|
||||
@@ -93,6 +96,14 @@ namespace TheIsland
|
||||
{
|
||||
if (_spriteRenderer == null) return;
|
||||
|
||||
// Phase 19-F: Secondary Jiggle Physics (Simple Spring)
|
||||
float jiggleStrength = 150f;
|
||||
float jiggleDamping = 10f;
|
||||
float force = -jiggleStrength * _jiggleOffset;
|
||||
_jiggleVelocity += (force * Time.deltaTime);
|
||||
_jiggleVelocity -= _jiggleVelocity * jiggleDamping * Time.deltaTime;
|
||||
_jiggleOffset += _jiggleVelocity * Time.deltaTime;
|
||||
|
||||
if (_isMoving)
|
||||
{
|
||||
AnimateMove();
|
||||
@@ -105,9 +116,12 @@ namespace TheIsland
|
||||
// Smoothly apply transforms
|
||||
float lerpSpeed = 12f;
|
||||
var t = _spriteRenderer.transform;
|
||||
t.localPosition = Vector3.Lerp(t.localPosition, _targetLocalPos, Time.deltaTime * lerpSpeed);
|
||||
t.localRotation = Quaternion.Slerp(t.localRotation, _targetLocalRot, Time.deltaTime * lerpSpeed);
|
||||
t.localScale = Vector3.Lerp(t.localScale, _targetScale, Time.deltaTime * lerpSpeed);
|
||||
t.localPosition = Vector3.Lerp(t.localPosition, _targetLocalPos + new Vector3(0, _jiggleOffset * 0.1f, 0), Time.deltaTime * lerpSpeed);
|
||||
t.localRotation = Quaternion.Slerp(t.localRotation, _targetLocalRot * Quaternion.Euler(0, 0, _jiggleOffset * 2f), Time.deltaTime * lerpSpeed);
|
||||
|
||||
// Apply scale with jiggle squash/stretch
|
||||
Vector3 jiggleScale = new Vector3(1f + _jiggleOffset, 1f - _jiggleOffset, 1f);
|
||||
t.localScale = Vector3.Lerp(t.localScale, Vector3.Scale(_targetScale, jiggleScale), Time.deltaTime * lerpSpeed);
|
||||
}
|
||||
|
||||
private void AnimateIdle()
|
||||
|
||||
@@ -222,6 +222,55 @@ namespace TheIsland.Visual
|
||||
return Sprite.Create(tex, new Rect(0, 0, size, size), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
|
||||
public void SpawnFootstepDust(Vector3 position)
|
||||
{
|
||||
var dust = new GameObject("FootstepDust");
|
||||
dust.transform.position = position;
|
||||
var sprite = dust.AddComponent<SpriteRenderer>();
|
||||
sprite.sprite = CreateDustSprite();
|
||||
sprite.color = new Color(0.9f, 0.8f, 0.6f, 0.4f);
|
||||
sprite.sortingOrder = 5; // Behind agents usually or just low
|
||||
dust.AddComponent<Billboard>();
|
||||
StartCoroutine(AnimateDust(dust));
|
||||
}
|
||||
|
||||
private Sprite CreateDustSprite()
|
||||
{
|
||||
int size = 16;
|
||||
Texture2D tex = new Texture2D(size, size);
|
||||
for (int y = 0; y < size; y++)
|
||||
{
|
||||
for (int x = 0; x < size; x++)
|
||||
{
|
||||
float d = Vector2.Distance(new Vector2(x, y), new Vector2(size / 2f, size / 2f)) / (size / 2f);
|
||||
float alpha = Mathf.Max(0, 1.0f - d);
|
||||
tex.SetPixel(x, y, new Color(1, 1, 1, alpha * alpha));
|
||||
}
|
||||
}
|
||||
tex.Apply();
|
||||
return Sprite.Create(tex, new Rect(0, 0, size, size), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
|
||||
private IEnumerator AnimateDust(GameObject dust)
|
||||
{
|
||||
float elapsed = 0;
|
||||
float duration = 0.8f;
|
||||
Vector3 startScale = Vector3.one * 0.2f;
|
||||
Vector3 endScale = Vector3.one * 1.5f;
|
||||
var sprite = dust.GetComponent<SpriteRenderer>();
|
||||
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = elapsed / duration;
|
||||
dust.transform.localScale = Vector3.Lerp(startScale, endScale, t);
|
||||
sprite.color = new Color(0.9f, 0.8f, 0.6f, 0.4f * (1f - t));
|
||||
dust.transform.position += Vector3.up * Time.deltaTime * 0.5f;
|
||||
yield return null;
|
||||
}
|
||||
Destroy(dust);
|
||||
}
|
||||
|
||||
private IEnumerator AnimateFirefly(GameObject firefly)
|
||||
{
|
||||
Vector3 startPos = firefly.transform.position;
|
||||
|
||||
Reference in New Issue
Block a user