Add checkpoint and respawn system; implement player respawn logic; added death animation for enemies

This commit is contained in:
Данил Ярош 2025-10-17 11:19:17 +03:00
parent 56a9c4af42
commit 9e5cc56d87
34 changed files with 8981 additions and 16195 deletions

View File

@ -43,13 +43,13 @@ AnimatorStateMachine:
m_Position: {x: 30, y: 240, z: 0}
- serializedVersion: 1
m_State: {fileID: -5973356747398055219}
m_Position: {x: 350, y: 180, z: 0}
m_Position: {x: 290, y: 180, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 800, y: 70, z: 0}
m_AnyStatePosition: {x: 310, y: 120, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
@ -81,6 +81,18 @@ AnimatorState:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!114 &-1012567705025105187
MonoBehaviour:
m_ObjectHideFlags: 1
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: 11f68d06feee61e40b41c1ae62936f6a, type: 3}
m_Name:
m_EditorClassIdentifier: '::'
--- !u!1101 &-424060727579301142
AnimatorStateTransition:
m_ObjectHideFlags: 1

View File

@ -598,7 +598,7 @@ AnimationClip:
m_Curve:
- serializedVersion: 3
time: 0
value: {x: 0, y: 0, z: 0}
value: {x: 0, y: 180, z: 0}
inSlope: {x: 0, y: 0, z: 0}
outSlope: {x: 0, y: 0, z: 0}
tangentMode: 0
@ -607,7 +607,7 @@ AnimationClip:
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
- serializedVersion: 3
time: 0.11666667
value: {x: 0, y: 0, z: 0}
value: {x: 0, y: 180, z: 0}
inSlope: {x: 0, y: 0, z: 150.00002}
outSlope: {x: 0, y: 0, z: 150.00002}
tangentMode: 0
@ -616,7 +616,7 @@ AnimationClip:
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
- serializedVersion: 3
time: 0.41666666
value: {x: 0, y: 0, z: 90}
value: {x: 0, y: 180, z: 90}
inSlope: {x: 0, y: 0, z: 0}
outSlope: {x: 0, y: 0, z: 0}
tangentMode: 0
@ -625,7 +625,7 @@ AnimationClip:
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
- serializedVersion: 3
time: 0.81666666
value: {x: 0, y: 0, z: 90}
value: {x: 0, y: 180, z: 90}
inSlope: {x: 0, y: 0, z: 0}
outSlope: {x: 0, y: 0, z: 0}
tangentMode: 0
@ -643,15 +643,15 @@ AnimationClip:
- serializedVersion: 3
time: 0
value: {x: 0.01, y: 2.41, z: 0}
inSlope: {x: 0, y: -0.6857157, z: 0}
outSlope: {x: 0, y: -0.6857157, z: 0}
inSlope: {x: 8.485714, y: -0.6857157, z: 0}
outSlope: {x: 8.485714, y: -0.6857157, z: 0}
tangentMode: 0
weightedMode: 0
inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
- serializedVersion: 3
time: 0.11666667
value: {x: 0.01, y: 2.33, z: 0}
value: {x: 1, y: 2.33, z: 0}
inSlope: {x: 0, y: 0, z: 0}
outSlope: {x: 0, y: 0, z: 0}
tangentMode: 0
@ -660,7 +660,7 @@ AnimationClip:
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
- serializedVersion: 3
time: 0.41666666
value: {x: -4.93, y: 1.83, z: 0}
value: {x: 1.83, y: 2, z: 0}
inSlope: {x: 0, y: 0, z: 0}
outSlope: {x: 0, y: 0, z: 0}
tangentMode: 0
@ -669,7 +669,7 @@ AnimationClip:
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
- serializedVersion: 3
time: 0.6166667
value: {x: -5.325947, y: 2.31, z: 0}
value: {x: 2, y: 2.31, z: 0}
inSlope: {x: 0, y: 0, z: 0}
outSlope: {x: 0, y: 0, z: 0}
tangentMode: 0
@ -678,7 +678,7 @@ AnimationClip:
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
- serializedVersion: 3
time: 0.81666666
value: {x: -5.65, y: 2.09, z: 0}
value: {x: 2, y: 2.09, z: 0}
inSlope: {x: 0, y: 0, z: 0}
outSlope: {x: 0, y: 0, z: 0}
tangentMode: 0
@ -1349,7 +1349,7 @@ AnimationClip:
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 0.81666666
m_StopTime: 1
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
@ -1372,15 +1372,15 @@ AnimationClip:
- serializedVersion: 3
time: 0
value: 0.01
inSlope: 0
outSlope: 0
inSlope: 8.485714
outSlope: 8.485714
tangentMode: 34
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 0.11666667
value: 0.01
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
@ -1389,7 +1389,7 @@ AnimationClip:
outWeight: 0.33333334
- serializedVersion: 3
time: 0.41666666
value: -4.93
value: 1.83
inSlope: 0
outSlope: 0
tangentMode: 0
@ -1398,7 +1398,7 @@ AnimationClip:
outWeight: 0.33333334
- serializedVersion: 3
time: 0.6166667
value: -5.325947
value: 2
inSlope: 0
outSlope: 0
tangentMode: 0
@ -1407,7 +1407,7 @@ AnimationClip:
outWeight: 0.33333334
- serializedVersion: 3
time: 0.81666666
value: -5.65
value: 2
inSlope: 0
outSlope: 0
tangentMode: 0
@ -1446,7 +1446,7 @@ AnimationClip:
outWeight: 0.33333334
- serializedVersion: 3
time: 0.41666666
value: 1.83
value: 2
inSlope: 0
outSlope: 0
tangentMode: 0
@ -4929,7 +4929,7 @@ AnimationClip:
m_Curve:
- serializedVersion: 3
time: 0
value: 0
value: 180
inSlope: 0
outSlope: 0
tangentMode: 34
@ -4938,7 +4938,7 @@ AnimationClip:
outWeight: 0.33333334
- serializedVersion: 3
time: 0.11666667
value: 0
value: 180
inSlope: 0
outSlope: 0
tangentMode: 34
@ -4947,7 +4947,7 @@ AnimationClip:
outWeight: 0.33333334
- serializedVersion: 3
time: 0.41666666
value: 0
value: 180
inSlope: 0
outSlope: 0
tangentMode: 0
@ -4956,7 +4956,7 @@ AnimationClip:
outWeight: 0.33333334
- serializedVersion: 3
time: 0.81666666
value: 0
value: 180
inSlope: 0
outSlope: 0
tangentMode: 0
@ -5064,7 +5064,7 @@ AnimationClip:
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_LocalEulerAngles.z
path: Rogue_pelvis_01
path: Rogue_pelvis_01/Rogue_torso_01/Rogue_shoulder_R_01/Rogue_elbow_R_01/Rogue_wrist_R_01
classID: 4
script: {fileID: 0}
flags: 16
@ -5076,7 +5076,7 @@ AnimationClip:
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_LocalEulerAngles.y
path: Rogue_pelvis_01
path: Rogue_pelvis_01/Rogue_torso_01/Rogue_shoulder_R_01/Rogue_elbow_R_01/Rogue_wrist_R_01
classID: 4
script: {fileID: 0}
flags: 16
@ -5088,7 +5088,7 @@ AnimationClip:
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_LocalEulerAngles.x
path: Rogue_pelvis_01
path: Rogue_pelvis_01/Rogue_torso_01/Rogue_shoulder_R_01/Rogue_elbow_R_01/Rogue_wrist_R_01
classID: 4
script: {fileID: 0}
flags: 16
@ -5460,10 +5460,10 @@ AnimationClip:
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_LocalEulerAngles.x
path: Rogue_pelvis_01/Rogue_torso_01/Rogue_shoulder_R_01/Rogue_elbow_R_01/Rogue_wrist_R_01
path: Rogue_pelvis_01
classID: 4
script: {fileID: 0}
flags: 16
flags: 0
- serializedVersion: 2
curve:
serializedVersion: 2
@ -5472,10 +5472,10 @@ AnimationClip:
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_LocalEulerAngles.y
path: Rogue_pelvis_01/Rogue_torso_01/Rogue_shoulder_R_01/Rogue_elbow_R_01/Rogue_wrist_R_01
path: Rogue_pelvis_01
classID: 4
script: {fileID: 0}
flags: 16
flags: 0
- serializedVersion: 2
curve:
serializedVersion: 2
@ -5484,10 +5484,24 @@ AnimationClip:
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_LocalEulerAngles.z
path: Rogue_pelvis_01/Rogue_torso_01/Rogue_shoulder_R_01/Rogue_elbow_R_01/Rogue_wrist_R_01
path: Rogue_pelvis_01
classID: 4
script: {fileID: 0}
flags: 16
flags: 0
m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0
m_Events: []
m_Events:
- time: 0
functionName: OnDeathBegin
data:
objectReferenceParameter: {fileID: 11500000, guid: c381ae66536829947bba4f54a4f83f04, type: 3}
floatParameter: 0
intParameter: 0
messageOptions: 0
- time: 1
functionName: OnDeathEnd
data:
objectReferenceParameter: {fileID: 11500000, guid: c381ae66536829947bba4f54a4f83f04, type: 3}
floatParameter: 0
intParameter: 0
messageOptions: 0

View File

@ -558,8 +558,8 @@ AnimatorStateTransition:
m_TransitionDuration: 0.25
m_TransitionOffset: 0
m_ExitTime: 0
m_HasExitTime: 1
m_HasFixedDuration: 1
m_HasExitTime: 0
m_HasFixedDuration: 0
m_InterruptionSource: 0
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 610695940cd6b124c8bf363d0289988e
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8e90d6bcd63b23f4387ce59988fc34d1
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -878,6 +878,7 @@ GameObject:
- component: {fileID: 7633178279901007628}
- component: {fileID: 4265284444154551416}
- component: {fileID: -4306594679098426553}
- component: {fileID: -3949889748814893039}
m_Layer: 0
m_Name: Enemy_1
m_TagString: Enemy
@ -1009,6 +1010,18 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
config: {fileID: 11400000, guid: d8fdc5ccf56a1ca4389e7927d0b86526, type: 2}
--- !u!114 &-3949889748814893039
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1000011821036864}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c381ae66536829947bba4f54a4f83f04, type: 3}
m_Name:
m_EditorClassIdentifier: '::'
--- !u!1 &1000012079282026
GameObject:
m_ObjectHideFlags: 0

View File

@ -1547,6 +1547,7 @@ GameObject:
- component: {fileID: 7939443397726716536}
- component: {fileID: -924318520420662969}
- component: {fileID: 2340304884233875183}
- component: {fileID: -7639911518411260797}
m_Layer: 0
m_Name: Enemy_2
m_TagString: Enemy
@ -1678,6 +1679,18 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
config: {fileID: 11400000, guid: d8fdc5ccf56a1ca4389e7927d0b86526, type: 2}
--- !u!114 &-7639911518411260797
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1000013301305156}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c381ae66536829947bba4f54a4f83f04, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::EnemyAnimationEvents
--- !u!1 &1000013442129446
GameObject:
m_ObjectHideFlags: 0

View File

@ -259,6 +259,7 @@ GameObject:
- component: {fileID: -5343150158617139208}
- component: {fileID: 2334527529858776447}
- component: {fileID: -7462686942147283313}
- component: {fileID: 6533472671113616431}
m_Layer: 0
m_Name: Enemy_Crab
m_TagString: Enemy
@ -390,6 +391,18 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
config: {fileID: 11400000, guid: d8fdc5ccf56a1ca4389e7927d0b86526, type: 2}
--- !u!114 &6533472671113616431
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2292326756536553419}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c381ae66536829947bba4f54a4f83f04, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::EnemyAnimationEvents
--- !u!1 &2349200483123940370
GameObject:
m_ObjectHideFlags: 0

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,63 @@
%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: d7fd9488000d3734a9e00ee676215985, type: 3}
m_Name: Global Volume Profile
m_EditorClassIdentifier: Unity.RenderPipelines.Core.Runtime::UnityEngine.Rendering.VolumeProfile
components:
- {fileID: 5350586350289149108}
--- !u!114 &5350586350289149108
MonoBehaviour:
m_ObjectHideFlags: 3
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: 0b2db86121404754db890f4c8dfe81b2, type: 3}
m_Name: Bloom
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.Bloom
active: 1
skipIterations:
m_OverrideState: 0
m_Value: 1
threshold:
m_OverrideState: 0
m_Value: 0.9
intensity:
m_OverrideState: 1
m_Value: 0
scatter:
m_OverrideState: 0
m_Value: 0.7
clamp:
m_OverrideState: 0
m_Value: 65472
tint:
m_OverrideState: 0
m_Value: {r: 1, g: 1, b: 1, a: 1}
highQualityFiltering:
m_OverrideState: 0
m_Value: 0
downscale:
m_OverrideState: 0
m_Value: 0
maxIterations:
m_OverrideState: 0
m_Value: 6
dirtTexture:
m_OverrideState: 0
m_Value: {fileID: 0}
dimension: 1
dirtIntensity:
m_OverrideState: 0
m_Value: 0

View File

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

View File

@ -0,0 +1,56 @@
using System;
using UnityEngine;
namespace RR.Game2D.Entities
{
[RequireComponent(typeof(Collider2D))]
public class Checkpoint : MonoBehaviour
{
[Tooltip("Уникальное имя в пределах сцены (например CP_01). Если пусто — возьмём имя объекта.")]
public string checkpointId;
[Tooltip("Опционально: куда и как смотреть после респавна.")]
public Vector2 spawnForward = Vector2.right;
[SerializeField, Tooltip("Тег объекта игрока, который активирует чекпоинт")] private string playerTag = "Player";
[Header("FX (необязательно)")] public GameObject activateVfx;
public AudioClip activateSfx;
bool _activated;
void Reset()
{
var col = GetComponent<Collider2D>();
col.isTrigger = true;
}
void Awake()
{
if (String.IsNullOrWhiteSpace(checkpointId))
checkpointId = gameObject.name;
}
void OnTriggerEnter2D(Collider2D other)
{
if (_activated) return;
// Определяем объект-источник (учтём Rigidbody, если он есть)
var source = other.attachedRigidbody ? other.attachedRigidbody.gameObject : other.gameObject;
if (!source.CompareTag(playerTag)) return;
_activated = true;
if (CheckpointSystem.Instance)
CheckpointSystem.Instance.SetActive(this);
if (activateVfx) Instantiate(activateVfx, transform.position, Quaternion.identity);
if (activateSfx) AudioSource.PlayClipAtPoint(activateSfx, transform.position);
}
public Vector3 GetSpawnPosition() => transform.position;
public Vector2 GetForward() => spawnForward.sqrMagnitude > 0.0001f ? spawnForward.normalized : Vector2.right;
// Для визуалки можно сделать метод Highlight(bool on) и менять спрайт/свет
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8ed83b33a6e095845a73838099cd40fa

View File

@ -0,0 +1,113 @@
using UnityEngine;
using UnityEngine.SceneManagement;
namespace RR.Game2D.Entities
{
// Явный делегат для события смены чекпоинта
public delegate void CheckpointChangedHandler(Checkpoint previous, Checkpoint current);
public class CheckpointSystem : MonoBehaviour
{
public static CheckpointSystem Instance { get; private set; }
[Tooltip("Сохранять последний чекпоинт в PlayerPrefs (по имени сцены).")]
public bool persistBetweenSessions = false;
private Checkpoint _active;
private Checkpoint[] _all;
// Событие для внешних подписчиков: (старый, новый)
public event CheckpointChangedHandler ActiveChanged;
// Текущий активный чекпоинт (read-only)
public Checkpoint Active => _active;
string PrefKey => $"CP_{SceneManager.GetActiveScene().name}";
void Awake()
{
if (Instance && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
_all = FindObjectsByType<Checkpoint>(FindObjectsSortMode.None);
// восстановление из PlayerPrefs
if (persistBetweenSessions && PlayerPrefs.HasKey(PrefKey))
{
var savedId = PlayerPrefs.GetString(PrefKey, "");
foreach (var cp in _all)
if (cp.checkpointId == savedId)
{
_active = cp;
break;
}
}
}
public void SetActive(Checkpoint cp)
{
if (_active == cp) return; // уже активен
var previous = _active;
_active = cp;
if (persistBetweenSessions)
{
if (cp != null)
PlayerPrefs.SetString(PrefKey, cp.checkpointId);
else
PlayerPrefs.DeleteKey(PrefKey);
PlayerPrefs.Save(); // гарантируем запись на диск
}
// Оповестим подписчиков о смене
if (ActiveChanged != null)
ActiveChanged(previous, _active);
// здесь можно задизейблить «подсветку» у старого и включить у нового
}
// Новый вспомогательный метод: активировать чекпоинт по его идентификатору
public void SetActiveById(string id)
{
if (string.IsNullOrWhiteSpace(id)) return;
// Обновим кэш, если он по какой-то причине пуст
if (_all == null || _all.Length == 0)
_all = FindObjectsByType<Checkpoint>(FindObjectsSortMode.None);
for (int i = 0; i < _all.Length; i++)
{
var cp = _all[i];
if (cp != null && cp.checkpointId == id)
{
SetActive(cp);
return;
}
}
// Если не нашли — ничего не делаем (можно добавить Debug.LogWarning при необходимости)
}
public Vector3 GetSpawnPosition(Vector3 defaultPos)
=> _active ? _active.GetSpawnPosition() : defaultPos;
public Vector2 GetSpawnForward(Vector2 defaultForward)
=> _active ? _active.GetForward() : defaultForward;
// Если нужно сбросить прогресс
public void ClearSaved()
{
if (persistBetweenSessions)
{
PlayerPrefs.DeleteKey(PrefKey);
PlayerPrefs.Save();
}
_active = null;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: acf0ce7850af4234385514e613639755

View File

@ -0,0 +1,23 @@
using UnityEngine;
using RR.Game2D.Behaviour;
public class EnemyAnimationEvents : MonoBehaviour
{
public void OnDeathEnd()
{
Destroy(gameObject);
}
public void OnDeathBegin()
{
Rigidbody2D rb = GetComponent<Rigidbody2D>();
Collider2D col = GetComponent<Collider2D>();
EnemyController controller = GetComponent<EnemyController>();
if (controller) controller.enabled = false;
if (col) col.enabled = false;
if (!rb) return;
rb.linearVelocity = Vector2.zero;
rb.bodyType = RigidbodyType2D.Kinematic;
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c381ae66536829947bba4f54a4f83f04

View File

@ -0,0 +1,32 @@
using System;
using RR.Game2D.Core;
using UnityEngine;
[RequireComponent(typeof(Renderer))]
public class NotVisibleHider : MonoBehaviour
{
// private Camera mainCamera;
private Transform playerTransform;
private Renderer _renderer;
private void Start()
{
// mainCamera = Camera.main;
playerTransform = GameManager.Instance.PlayerObj.transform;
_renderer = GetComponent<Renderer>();
}
private void OnBecameInvisible()
{
// gameObject.SetActive(false);
_renderer.enabled = false;
transform.position = playerTransform.position;
}
private void OnBecameVisible()
{
// gameObject.SetActive(true);
_renderer.enabled = true;
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b16d5c28e59cc014581e943b509f83a8

View File

@ -0,0 +1,16 @@
using UnityEngine;
public class PayerAnimationEvents : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5f4612beb3ca33c4b9e2a6a2068977ab

View File

@ -1,4 +1,5 @@
using UnityEngine;
using RR.Common.Interfaces;
using RR.Game2D.Core;
using RR.Game2D.Behaviour.ScriptableObjects;
@ -141,7 +142,8 @@ namespace RR.Game2D.Behaviour
}
public void Die()
{
Destroy(gameObject);
animator.Play("Death");
// Destroy(gameObject);
}
#if UNITY_EDITOR

View File

@ -3,6 +3,9 @@ using System.IO;
using UnityEngine;
using UnityEngine.SceneManagement;
using RR.Game2D.Behaviour;
using RR.Game2D.Entities;
namespace RR.Game2D.Core
{
[DefaultExecutionOrder(-1000)]
@ -218,6 +221,81 @@ namespace RR.Game2D.Core
PlayerSpawned?.Invoke(PlayerObj);
}
// Новый метод: респавн игрока без перезагрузки сцены
public void RespawnPlayer()
{
// отнимем жизнь (оставляем текущее поведение); монеты не сбрасываем
Lives--;
LivesChanged?.Invoke(Lives);
if (Lives <= 0)
{
GameOver();
return;
}
// Определяем дефолтные позицию и направление из PlayerSpawn в сцене
PlayerSpawn spawn = FindFirstObjectByType<PlayerSpawn>();
Vector3 defaultPos = spawn ? spawn.transform.position : new Vector3(0, 1.3f, 0);
Vector2 defaultForward = spawn ? spawn.defaultForward : Vector2.right;
// Если есть активный чекпоинт — берём из него; иначе дефолт
Vector3 respawnPos = defaultPos;
Vector2 respawnForward = defaultForward;
if (CheckpointSystem.Instance != null)
{
respawnPos = CheckpointSystem.Instance.GetSpawnPosition(defaultPos);
respawnForward = CheckpointSystem.Instance.GetSpawnForward(defaultForward);
if (CheckpointSystem.Instance.Active != null)
{
respawnPos = CheckpointSystem.Instance.Active.GetSpawnPosition();
respawnForward = CheckpointSystem.Instance.Active.GetForward();
}
}
// Если потеряли ссылку — попробуем найти игрока в сцене
if (PlayerObj == null)
PlayerObj = GameObject.FindGameObjectWithTag("Player");
if (PlayerObj == null)
{
// Создадим нового игрока, если объект был уничтожен
var prefab = ResolvePlayerPrefab();
if (prefab == null) return;
PlayerObj = Instantiate(prefab, respawnPos, Quaternion.identity);
SceneManager.MoveGameObjectToScene(PlayerObj, SceneManager.GetActiveScene());
PlayerSpawned?.Invoke(PlayerObj);
}
else
{
// Остановим движение и телепортируем
var rb = PlayerObj.GetComponent<Rigidbody2D>();
if (rb != null)
{
rb.linearVelocity = Vector2.zero;
rb.angularVelocity = 0f;
}
PlayerObj.transform.position = respawnPos;
}
// Повернём в нужную сторону (по X)
if (PlayerObj != null)
{
if (respawnForward.x != 0)
{
PlayerObj.transform.localEulerAngles = respawnForward.x >= 0
? Vector3.zero
: new Vector3(0, 180f, 0);
}
// Восстановим здоровье
var hp = PlayerObj.GetComponent<Health>();
if (hp != null)
hp.ResetHealth();
}
}
/// <summary>
/// Метод переход на следующий уровень.

View File

@ -1,5 +1,6 @@
using UnityEngine;
using UnityEngine.InputSystem;
using RR.Common.Interfaces;
using RR.Game2D.Core;
@ -178,7 +179,7 @@ namespace RR.Game2D.Behaviour
public void Die()
{
GameManager.Instance.ResetLevel();
GameManager.Instance.RespawnPlayer();
}
/// <summary>

View File

@ -1,19 +1,33 @@
using UnityEngine;
namespace RR.Game2D.Core
namespace RR.Game2D.Entities
{
[DisallowMultipleComponent]
public class PlayerSpawn : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
[Tooltip("Позиция игрока если нет активного чекпоинта")]
public Vector3 defaultSpawnPosition = Vector3.zero;
[Tooltip("Направление/вектор взгляда по умолчанию")]
public Vector2 defaultForward = Vector2.right;
void Start()
{
// Пытаемся получить позицию из CheckpointSystem, если он есть.
Vector3 spawnPos = defaultSpawnPosition;
Vector2 spawnForward = defaultForward;
}
// Update is called once per frame
void Update()
{
if (CheckpointSystem.Instance != null)
{
spawnPos = CheckpointSystem.Instance.GetSpawnPosition(defaultSpawnPosition);
spawnForward = CheckpointSystem.Instance.GetSpawnForward(defaultForward);
}
// Перемещаем объект (например, сам игрок или родителя)
transform.position = spawnPos;
transform.rotation = spawnForward == Vector2.right
? Quaternion.identity
: Quaternion.Inverse(transform.rotation);
}
}
}

View File

@ -300,7 +300,7 @@ PlayerSettings:
m_BuildTargetBatching:
- m_BuildTarget: Standalone
m_StaticBatching: 1
m_DynamicBatching: 0
m_DynamicBatching: 1
m_BuildTargetShaderSettings: []
m_BuildTargetGraphicsJobs: []
m_BuildTargetGraphicsJobMode: []
@ -598,6 +598,7 @@ PlayerSettings:
platformArchitecture: {}
scriptingBackend:
Android: 1
Standalone: 1
il2cppCompilerConfiguration: {}
il2cppCodeGeneration: {}
il2cppStacktraceInformation: {}