[Player][Interactions] Pulver moves to item and goes back. Item disappears, but in wrong order

This commit is contained in:
Michal Pikulski
2025-09-04 00:00:46 +02:00
parent 97c5edf619
commit 0c930d09a4
18 changed files with 455 additions and 43 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fcd99d46037b3e44abe09d64d0fa2e47
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e4ec438b455a4044957501c2c66a6f4b, type: 3}
m_Name: DefaultSettings
m_EditorClassIdentifier:
playerStopDistance: 10
followerPickupDelay: 0.2

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 924922151a72ae8439be5090a3feaef9
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -13,7 +13,7 @@ GameObject:
- component: {fileID: 3435632802124758411}
m_Layer: 8
m_Name: PulverCharacter
m_TagString: Untagged
m_TagString: Pulver
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0

View File

@@ -13,7 +13,7 @@ GameObject:
- component: {fileID: 3070149615425714466}
- component: {fileID: 7616859841301711022}
- component: {fileID: 592045584872845087}
m_Layer: 6
m_Layer: 0
m_Name: BasePickup
m_TagString: Untagged
m_Icon: {fileID: 0}

View File

@@ -13,7 +13,7 @@ GameObject:
- component: {fileID: 841695541655102207}
- component: {fileID: 4981092805118965486}
- component: {fileID: 1397300447834037203}
m_Layer: 6
m_Layer: 0
m_Name: BaseLevelSwitch
m_TagString: Untagged
m_Icon: {fileID: 0}

View File

@@ -488,6 +488,81 @@ PrefabInstance:
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: b5fc01af35233eb4cbeede05e50a7c34, type: 3}
--- !u!1 &416453392 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 1102400833121127473, guid: 8ac0210dbf9d7754e9526d6d5c214f49, type: 3}
m_PrefabInstance: {fileID: 1950557796102186365}
m_PrefabAsset: {fileID: 0}
--- !u!114 &416453396
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 416453392}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f6eb1402c17e84a9282a7f0f62eb584f, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 5
radius: 2
height: 2
canMove: 1
maxSpeed: 15
gravity: {x: NaN, y: NaN, z: NaN}
groundMask:
serializedVersion: 2
m_Bits: 4294967295
centerOffsetCompatibility: NaN
repathRateCompatibility: NaN
canSearchCompability: 0
orientation: 1
enableRotation: 0
autoRepath:
mode: 2
interval: 0.5
sensitivity: 10
maximumInterval: 2
visualizeSensitivity: 0
targetCompatibility: {fileID: 0}
maxAcceleration: -2.5
rotationSpeed: 360
slowdownDistance: 3
pickNextWaypointDist: 2
endReachedDistance: 0.5
alwaysDrawGizmos: 0
slowWhenNotFacingTarget: 1
whenCloseToDestination: 0
constrainInsideGraph: 0
--- !u!114 &416453397
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 416453392}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 373b52eb9bf8c40f785bb6947a1aee66, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 1
drawGizmos: 1
detailedGizmos: 0
startEndModifier:
addPoints: 0
exactStartPoint: 3
exactEndPoint: 3
useRaycasting: 0
mask:
serializedVersion: 2
m_Bits: 4294967295
useGraphRaycasting: 0
traversableTags: -1
tagPenalties: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
graphMask:
value: -1
--- !u!1001 &448642088
PrefabInstance:
m_ObjectHideFlags: 0
@@ -633,6 +708,7 @@ Transform:
- {fileID: 954512636}
- {fileID: 535638824}
- {fileID: 189988800}
- {fileID: 2027860879}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!4 &754397347 stripped
@@ -22942,6 +23018,51 @@ Tilemap:
e31: 0
e32: 0
e33: 1
--- !u!1 &2027860878
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2027860879}
- component: {fileID: 2027860880}
m_Layer: 0
m_Name: GameManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2027860879
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2027860878}
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: 638340961}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &2027860880
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2027860878}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b9333cd9ca0e44769ef1913d10231047, type: 3}
m_Name:
m_EditorClassIdentifier:
gameSettings: {fileID: 11400000, guid: 924922151a72ae8439be5090a3feaef9, type: 2}
--- !u!4 &2102167558 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 2844046668579196942, guid: b5fc01af35233eb4cbeede05e50a7c34, type: 3}
@@ -23002,7 +23123,13 @@ PrefabInstance:
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 1102400833121127473, guid: 8ac0210dbf9d7754e9526d6d5c214f49, type: 3}
insertIndex: -1
addedObject: {fileID: 416453397}
- targetCorrespondingSourceObject: {fileID: 1102400833121127473, guid: 8ac0210dbf9d7754e9526d6d5c214f49, type: 3}
insertIndex: -1
addedObject: {fileID: 416453396}
m_SourcePrefab: {fileID: 100100000, guid: 8ac0210dbf9d7754e9526d6d5c214f49, type: 3}
--- !u!1001 &8865498003578620591
PrefabInstance:

View File

@@ -27,6 +27,9 @@ public class FollowerController : MonoBehaviour
public float thresholdNear = 0.5f;
public float stopThreshold = 0.1f; // Stop moving when within this distance
private float playerMaxSpeed = 5f;
private const float followerSpeedMultiplier = 1.2f;
private float followerMaxSpeed = 6f; // Default, will be set from player
private float defaultFollowerMaxSpeed = 6f; // Default fallback value
private Animator animator;
private Transform artTransform;
@@ -72,6 +75,8 @@ public class FollowerController : MonoBehaviour
if (playerAIPath != null)
{
playerMaxSpeed = playerAIPath.maxSpeed;
defaultFollowerMaxSpeed = playerMaxSpeed;
followerMaxSpeed = playerMaxSpeed * followerSpeedMultiplier;
}
}
else
@@ -95,27 +100,29 @@ public class FollowerController : MonoBehaviour
if (playerTransform == null)
return; // Still missing, skip update
}
// Determine direction: use player's velocity if available, else lastMoveDir
Vector3 playerPos = playerTransform.position;
Vector3 moveDir = Vector3.zero;
if (playerAIPath != null && playerAIPath.velocity.magnitude > 0.01f)
if (isManualFollowing)
{
moveDir = playerAIPath.velocity.normalized;
lastMoveDir = moveDir; // Update last valid direction
}
else
{
moveDir = lastMoveDir; // Use last direction if stationary
}
// Calculate target point behind player
targetPoint = playerPos - moveDir * followDistance;
targetPoint.z = 0; // For 2D
// Determine direction: use player's velocity if available, else lastMoveDir
Vector3 playerPos = playerTransform.position;
Vector3 moveDir = Vector3.zero;
if (playerAIPath != null && playerAIPath.velocity.magnitude > 0.01f)
{
moveDir = playerAIPath.velocity.normalized;
lastMoveDir = moveDir; // Update last valid direction
}
else
{
moveDir = lastMoveDir; // Use last direction if stationary
}
// Calculate target point behind player
targetPoint = playerPos - moveDir * followDistance;
targetPoint.z = 0; // For 2D
// Always use manual following unless GoToPoint is called
isManualFollowing = true;
if (aiPath != null)
{
aiPath.enabled = false;
// Only disable aiPath if in manual mode
if (aiPath != null)
{
aiPath.enabled = false;
}
}
}
@@ -139,14 +146,17 @@ public class FollowerController : MonoBehaviour
// Manual movement logic with acceleration/deceleration and stop threshold
if (isManualFollowing)
{
float dist = Vector3.Distance(transform.position, targetPoint);
// 2D distance calculation (ignore z)
Vector2 current2D = new Vector2(transform.position.x, transform.position.y);
Vector2 target2D = new Vector2(targetPoint.x, targetPoint.y);
float dist = Vector2.Distance(current2D, target2D);
if (dist > stopThreshold)
{
float desiredSpeed = playerMaxSpeed;
float desiredSpeed = followerMaxSpeed;
if (dist > thresholdFar)
{
// Accelerate to player's max speed
desiredSpeed = Mathf.Min(currentSpeed + acceleration * Time.deltaTime, playerMaxSpeed);
// Accelerate to follower's max speed
desiredSpeed = Mathf.Min(currentSpeed + acceleration * Time.deltaTime, followerMaxSpeed);
}
else if (dist <= thresholdNear && dist > stopThreshold)
{
@@ -155,8 +165,8 @@ public class FollowerController : MonoBehaviour
}
else
{
// Maintain player's max speed
desiredSpeed = playerMaxSpeed;
// Maintain follower's max speed
desiredSpeed = followerMaxSpeed;
}
currentSpeed = desiredSpeed;
Vector3 dir = (targetPoint - transform.position).normalized;
@@ -176,12 +186,12 @@ public class FollowerController : MonoBehaviour
if (isManualFollowing)
{
// Use currentSpeed for manual following
normalizedSpeed = currentSpeed / playerMaxSpeed;
normalizedSpeed = currentSpeed / followerMaxSpeed;
}
else if (aiPath != null)
{
// Use aiPath velocity for pathfinding mode
normalizedSpeed = aiPath.velocity.magnitude / playerMaxSpeed;
normalizedSpeed = aiPath.velocity.magnitude / followerMaxSpeed;
}
animator.SetFloat("Speed", Mathf.Clamp01(normalizedSpeed));
}
@@ -194,10 +204,64 @@ public class FollowerController : MonoBehaviour
if (aiPath != null)
{
aiPath.enabled = true;
aiPath.maxSpeed = followerMaxSpeed;
aiPath.destination = new Vector3(worldPosition.x, worldPosition.y, 0);
}
}
public delegate void FollowerPickupHandler();
public event FollowerPickupHandler OnPickupArrived;
public event FollowerPickupHandler OnPickupReturned;
private Coroutine pickupCoroutine;
// Command follower to go to a specific point and return to player
public void GoToPointAndReturn(Vector2 itemPosition, Transform playerTransform)
{
if (pickupCoroutine != null)
StopCoroutine(pickupCoroutine);
if (aiPath != null)
aiPath.maxSpeed = followerMaxSpeed;
pickupCoroutine = StartCoroutine(PickupSequence(itemPosition, playerTransform));
}
private System.Collections.IEnumerator PickupSequence(Vector2 itemPosition, Transform playerTransform)
{
isManualFollowing = false;
if (aiPath != null)
{
aiPath.enabled = true;
aiPath.maxSpeed = followerMaxSpeed;
aiPath.destination = new Vector3(itemPosition.x, itemPosition.y, 0);
}
// Wait until follower reaches item (2D distance)
while (Vector2.Distance(new Vector2(transform.position.x, transform.position.y), new Vector2(itemPosition.x, itemPosition.y)) > stopThreshold)
{
yield return null;
}
OnPickupArrived?.Invoke();
// Wait briefly, then return to player
yield return new WaitForSeconds(0.2f);
if (aiPath != null && playerTransform != null)
{
aiPath.maxSpeed = followerMaxSpeed;
aiPath.destination = playerTransform.position;
}
// Wait until follower returns to player (2D distance)
while (playerTransform != null && Vector2.Distance(new Vector2(transform.position.x, transform.position.y), new Vector2(playerTransform.position.x, playerTransform.position.y)) > stopThreshold)
{
yield return null;
}
OnPickupReturned?.Invoke();
// Reset follower speed to normal after pickup
followerMaxSpeed = defaultFollowerMaxSpeed;
if (aiPath != null)
aiPath.maxSpeed = followerMaxSpeed;
isManualFollowing = true;
if (aiPath != null)
aiPath.enabled = false;
pickupCoroutine = null;
}
void OnDrawGizmos()
{
if (debugDrawTarget && Application.isPlaying)

View File

@@ -0,0 +1,36 @@
using UnityEngine;
public class GameManager : MonoBehaviour
{
private static GameManager _instance;
public static GameManager Instance
{
get
{
if (_instance == null)
{
_instance = FindAnyObjectByType<GameManager>();
if (_instance == null)
{
var go = new GameObject("GameManager");
_instance = go.AddComponent<GameManager>();
DontDestroyOnLoad(go);
}
}
return _instance;
}
}
[Header("Game Settings")]
public GameSettings gameSettings;
void Awake()
{
_instance = this;
DontDestroyOnLoad(gameObject);
}
public float PlayerStopDistance => gameSettings != null ? gameSettings.playerStopDistance : 1.0f;
public float FollowerPickupDelay => gameSettings != null ? gameSettings.followerPickupDelay : 0.2f;
// Add more accessors as needed
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b9333cd9ca0e44769ef1913d10231047
timeCreated: 1756933142

View File

@@ -0,0 +1,11 @@
using UnityEngine;
[CreateAssetMenu(fileName = "GameSettings", menuName = "AppleHills/GameSettings", order = 1)]
public class GameSettings : ScriptableObject
{
[Header("Interactions")]
public float playerStopDistance = 6.0f;
public float followerPickupDelay = 0.2f;
// Add other settings here as needed
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e4ec438b455a4044957501c2c66a6f4b
timeCreated: 1756933137

View File

@@ -7,8 +7,12 @@ public class LevelSwitch : MonoBehaviour
public SpriteRenderer iconRenderer;
private Interactable interactable;
private bool _isActive = true;
void Awake()
{
_isActive = true;
if (iconRenderer == null)
iconRenderer = GetComponent<SpriteRenderer>();
@@ -51,11 +55,12 @@ public class LevelSwitch : MonoBehaviour
private async void OnInteracted()
{
Debug.Log($"LevelSwitch.OnInteracted: Switching to level {switchData?.targetLevelSceneName}");
if (switchData != null && !string.IsNullOrEmpty(switchData.targetLevelSceneName))
if (switchData != null && !string.IsNullOrEmpty(switchData.targetLevelSceneName) && _isActive)
{
// Optionally: show loading UI here
var progress = new Progress<float>(p => Debug.Log($"Loading progress: {p * 100:F0}%"));
await SceneManagerService.Instance.SwitchSceneAsync(switchData.targetLevelSceneName, progress);
_isActive = false;
// Optionally: hide loading UI here
}
}

View File

@@ -6,6 +6,8 @@ public class Pickup : MonoBehaviour
public SpriteRenderer iconRenderer;
private Interactable interactable;
private bool pickupInProgress = false;
void Awake()
{
if (iconRenderer == null)
@@ -33,6 +35,23 @@ public class Pickup : MonoBehaviour
iconRenderer = GetComponent<SpriteRenderer>();
ApplyItemData();
}
void OnDrawGizmos()
{
// Get stop distance from GameManager or default
float playerStopDistance = GameManager.Instance != null ? GameManager.Instance.PlayerStopDistance : 1.0f;
// Draw stop distance circle around pickup
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, playerStopDistance);
// Draw stop point (where player is told to move)
GameObject playerObj = GameObject.FindGameObjectWithTag("Player");
if (playerObj != null)
{
Vector3 stopPoint = transform.position + (playerObj.transform.position - transform.position).normalized * playerStopDistance;
Gizmos.color = Color.cyan;
Gizmos.DrawSphere(stopPoint, 0.15f);
}
}
#endif
public void ApplyItemData()
@@ -48,8 +67,56 @@ public class Pickup : MonoBehaviour
private void OnInteracted()
{
Debug.Log($"[Pickup] OnInteracted: Picked up {itemData?.itemName}");
// TODO: Add item to inventory manager here
Destroy(gameObject);
if (pickupInProgress) return;
pickupInProgress = true;
// Find player and follower controllers
var playerObj = GameObject.FindGameObjectWithTag("Player");
var followerObj = GameObject.FindGameObjectWithTag("Pulver");
if (playerObj == null || followerObj == null)
{
Debug.LogWarning("Pickup: Player or Follower not found.");
pickupInProgress = false;
return;
}
var playerController = playerObj.GetComponent<PlayerTouchController>();
var followerController = followerObj.GetComponent<FollowerController>();
if (playerController == null || followerController == null)
{
Debug.LogWarning("Pickup: PlayerTouchController or FollowerController missing.");
pickupInProgress = false;
return;
}
// Get settings from GameManager
float playerStopDistance = GameManager.Instance != null ? GameManager.Instance.PlayerStopDistance : 1.0f;
float followerPickupDelay = GameManager.Instance != null ? GameManager.Instance.FollowerPickupDelay : 0.2f;
// Subscribe to player arrival event
void OnPlayerArrived()
{
playerController.OnArrivedAtTarget -= OnPlayerArrived;
// After player arrives, dispatch follower after delay
StartCoroutine(DispatchFollower());
}
System.Collections.IEnumerator DispatchFollower()
{
yield return new WaitForSeconds(followerPickupDelay);
// Subscribe to follower events
followerController.OnPickupArrived += OnFollowerArrived;
followerController.OnPickupReturned += OnFollowerReturned;
followerController.GoToPointAndReturn(transform.position, playerObj.transform);
}
void OnFollowerArrived()
{
followerController.OnPickupArrived -= OnFollowerArrived;
// Optionally: play pickup animation, etc.
}
void OnFollowerReturned()
{
followerController.OnPickupReturned -= OnFollowerReturned;
pickupInProgress = false;
Destroy(gameObject);
}
playerController.OnArrivedAtTarget += OnPlayerArrived;
Vector3 stopPoint = transform.position + (playerObj.transform.position - transform.position).normalized * playerStopDistance;
playerController.MoveToAndNotify(stopPoint);
}
}

View File

@@ -21,6 +21,11 @@ public class PlayerTouchController : MonoBehaviour, ITouchInputConsumer
private Animator animator;
private Transform artTransform;
public delegate void ArrivedAtTargetHandler();
public event ArrivedAtTargetHandler OnArrivedAtTarget;
private Coroutine moveToCoroutine;
private bool interruptMoveTo = false;
void Awake()
{
rb3d = GetComponent<Rigidbody>();
@@ -56,6 +61,8 @@ public class PlayerTouchController : MonoBehaviour, ITouchInputConsumer
public void OnTouchPress(Vector2 worldPosition)
{
// If moving to pickup, interrupt
InterruptMoveTo();
Debug.Log($"PlayerTouchController.OnTouchPress received worldPosition: {worldPosition}");
SetTargetPosition(worldPosition);
}
@@ -93,4 +100,48 @@ public class PlayerTouchController : MonoBehaviour, ITouchInputConsumer
}
// Remove FixedUpdate and MoveTowardsTarget, as AIPath handles movement
// Move to a target position, notify when arrived
public void MoveToAndNotify(Vector3 target)
{
if (moveToCoroutine != null)
{
StopCoroutine(moveToCoroutine);
}
interruptMoveTo = false;
moveToCoroutine = StartCoroutine(MoveToTargetCoroutine(target));
}
public void InterruptMoveTo()
{
interruptMoveTo = true;
}
private System.Collections.IEnumerator MoveToTargetCoroutine(Vector3 target)
{
hasTarget = true;
targetPosition = target;
if (aiPath != null)
{
aiPath.destination = target;
}
while (!interruptMoveTo)
{
// 2D distance calculation (ignore z)
Vector2 current2D = new Vector2(transform.position.x, transform.position.y);
Vector2 target2D = new Vector2(target.x, target.y);
float dist = Vector2.Distance(current2D, target2D);
if (dist <= stopDistance + 0.2f)
{
break;
}
yield return null;
}
hasTarget = false;
moveToCoroutine = null;
if (!interruptMoveTo)
{
OnArrivedAtTarget?.Invoke();
}
}
}

View File

@@ -6,7 +6,24 @@ using UnityEngine.SceneManagement;
public class SceneManagerService : MonoBehaviour
{
public static SceneManagerService Instance { get; private set; }
private static SceneManagerService _instance;
public static SceneManagerService Instance
{
get
{
if (_instance == null)
{
_instance = FindAnyObjectByType<SceneManagerService>();
if (_instance == null)
{
var go = new GameObject("SceneManagerService");
_instance = go.AddComponent<SceneManagerService>();
DontDestroyOnLoad(go);
}
}
return _instance;
}
}
// Events for scene lifecycle
public event Action<string> SceneLoadStarted;
@@ -21,12 +38,7 @@ public class SceneManagerService : MonoBehaviour
void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
_instance = this;
DontDestroyOnLoad(gameObject);
}

View File

@@ -53,4 +53,4 @@ Physics2DSettings:
m_ReuseCollisionCallbacks: 1
m_AutoSyncTransforms: 0
m_GizmoOptions: 10
m_LayerCollisionMatrix: fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff7fffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
m_LayerCollisionMatrix: fffffffffffffffffffffffffffffffffffffffffffffffffffefffffffcffff3fffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

View File

@@ -5,6 +5,7 @@ TagManager:
serializedVersion: 3
tags:
- CharacterArt
- Pulver
layers:
- Default
- TransparentFX