Refactor teleport actions and add mouse world position overlay for improved scene interaction
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled

This commit is contained in:
Данил Ярош 2025-12-26 12:51:53 +03:00
parent bd44b3ab9b
commit 3bb2591a1d
13 changed files with 1656 additions and 4107 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1870,6 +1870,7 @@ MonoBehaviour:
launchPoint: {fileID: 4334291816879735074}
attachPoint: {fileID: 2104289427863468492}
throwSounds: {fileID: 11400000, guid: 4b774d97282b77f45b08068d61682269, type: 2}
enableFire: 1
--- !u!114 &7565635284530052038
MonoBehaviour:
m_ObjectHideFlags: 0
@ -1884,6 +1885,8 @@ MonoBehaviour:
m_EditorClassIdentifier: Assembly-CSharp::RR.Game2D.Animations.PlayerAnimationEvents
deathVFX: {fileID: 8926484042661614526, guid: 6c4fdce0f9a1b184d9c3660014bdfdb5, type: 3}
deathVFXOffset: {x: 0.2, y: -0.25, z: 0}
runVFX: {fileID: 8926484042661614526, guid: 4916628c3425a704989f02cb136b655b, type: 3}
runVFXOffset: {x: 0, y: 0, z: 0}
--- !u!1 &3858368938151547924
GameObject:
m_ObjectHideFlags: 0

View File

@ -500,7 +500,7 @@ Transform:
m_GameObject: {fileID: 136585477}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: -9.116049}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
@ -4305,7 +4305,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
m_IsActive: 1
--- !u!4 &767070203
Transform:
m_ObjectHideFlags: 0
@ -4315,7 +4315,7 @@ Transform:
m_GameObject: {fileID: 767070202}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 7, y: -1, z: 0}
m_LocalPosition: {x: 20, y: 31, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
@ -5593,7 +5593,7 @@ MonoBehaviour:
- rid: 1880696480842645505
type: {class: WaitAction, ns: RR.Common.Behaviour, asm: Assembly-CSharp}
data:
duration: 1
duration: 0.2
- rid: 1880696480842645506
type: {class: TeleportPlayerAction, ns: RR.Common.Behaviour, asm: Assembly-CSharp}
data:
@ -5605,7 +5605,7 @@ MonoBehaviour:
- rid: 1880696480842645618
type: {class: WaitAction, ns: RR.Common.Behaviour, asm: Assembly-CSharp}
data:
duration: 0.5
duration: 0.1
--- !u!61 &953429935
BoxCollider2D:
m_ObjectHideFlags: 0
@ -10116,7 +10116,7 @@ MonoBehaviour:
- rid: 1880696480842645505
type: {class: WaitAction, ns: RR.Common.Behaviour, asm: Assembly-CSharp}
data:
duration: 1
duration: 0.2
- rid: 1880696480842645506
type: {class: TeleportPlayerAction, ns: RR.Common.Behaviour, asm: Assembly-CSharp}
data:
@ -10128,7 +10128,7 @@ MonoBehaviour:
- rid: 1880696480842645618
type: {class: WaitAction, ns: RR.Common.Behaviour, asm: Assembly-CSharp}
data:
duration: 0.5
duration: 0.1
--- !u!61 &1805554001
BoxCollider2D:
m_ObjectHideFlags: 0
@ -10915,7 +10915,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
m_IsActive: 1
--- !u!73398921 &2072045120
VFXRenderer:
serializedVersion: 1
@ -10924,7 +10924,7 @@ VFXRenderer:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2072045119}
m_Enabled: 0
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
@ -10971,7 +10971,7 @@ VisualEffect:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2072045119}
m_Enabled: 1
m_Asset: {fileID: 8926484042661614526, guid: 6c4fdce0f9a1b184d9c3660014bdfdb5, type: 3}
m_Asset: {fileID: 8926484042661614526, guid: 4916628c3425a704989f02cb136b655b, type: 3}
m_InitialEventName: OnPlay
m_InitialEventNameOverriden: 0
m_StartSeed: 0

View File

@ -10,14 +10,26 @@ namespace RR.Game2D.Animations
{
public class PlayerAnimationEvents : MonoBehaviour, CreatureAnimationEvents
{
// --- VFX Assets ---
[SerializeField] private VisualEffectAsset deathVFX;
[SerializeField] private Vector3 deathVFXOffset = Vector3.zero;
[SerializeField] private VisualEffectAsset runVFX;
[SerializeField] private Vector3 runVFXOffset = Vector3.zero;
// --- Private Fields ---
// SFX Assets
private SFXAsset _stepSounds;
private SFXAsset _hurtSounds;
private SFXAsset _jumpSounds;
// Components
private Rigidbody2D _rb;
private Vector3 _vfxSpawnPoint;
private Collider2D _col;
// VFX Spawn Points
private Vector3 _deathVFXSpawnPoint;
private Vector3 _runVFXSpawnPoint;
private void OnEnable() => LevelPlayerSFX.Instance.SFXChanged += UpdateSFX;
@ -30,10 +42,13 @@ namespace RR.Game2D.Animations
UpdateSFX();
_rb = GetComponent<Rigidbody2D>();
Collider2D col = GetComponent<Collider2D>();
_col = GetComponent<Collider2D>();
// Учитываем поворот объекта при вычислении смещения
Vector3 rotatedOffset = transform.rotation * deathVFXOffset;
_vfxSpawnPoint = (col ? col.bounds.center : transform.position) + rotatedOffset;
Vector3 deathRotatedOffset = transform.rotation * deathVFXOffset;
Vector3 runRotatedOffset = transform.rotation * runVFXOffset;
_deathVFXSpawnPoint = (_col ? _col.bounds.center : transform.position) + deathRotatedOffset;
_runVFXSpawnPoint = (_col ? _col.bounds.center : transform.position) + runRotatedOffset;
}
public void UpdateSFX()
@ -57,12 +72,12 @@ namespace RR.Game2D.Animations
public void OnDeathEnd()
{
Collider2D col = GetComponent<Collider2D>();
if (!_col) _col = GetComponent<Collider2D>();
Vector3 rotatedOffset = transform.rotation * deathVFXOffset;
_vfxSpawnPoint = col ? col.bounds.center : transform.position + rotatedOffset;
_deathVFXSpawnPoint = _col ? _col.bounds.center : transform.position + rotatedOffset;
if (deathVFX) VFXPool.Instance.Spawn(deathVFX, _vfxSpawnPoint, 1f);
if (deathVFX) VFXPool.Instance.Spawn(deathVFX, _deathVFXSpawnPoint, 1f);
gameObject.layer = LayerMask.NameToLayer("Default");
_rb.constraints = RigidbodyConstraints2D.FreezeRotation;
@ -76,6 +91,13 @@ namespace RR.Game2D.Animations
{
if (_stepSounds && _stepSounds.soundEffects.Length > 0)
GameManager.Instance.Audio.PlayRandomSfxAt(_stepSounds.soundEffects, transform.position);
if (!_col) _col = GetComponent<Collider2D>();
Vector3 rotatedOffset = transform.rotation * runVFXOffset;
_runVFXSpawnPoint = _col ? _col.bounds.center : transform.position + rotatedOffset;
if (deathVFX) VFXPool.Instance.Spawn(runVFX, _runVFXSpawnPoint, 1f);
}
public void OnJump()

View File

@ -1,17 +1,26 @@
using System;
using System.Collections;
using RR.Game2D.Core.Managers;
using UnityEngine;
namespace RR.Common.Behaviour
{
[Serializable]
public class FreezePlayerAction : SequenceAction
{
[SerializeField] private RigidbodyConstraints2D freezeMode = RigidbodyConstraints2D.FreezeAll;
public override IEnumerator Execute(Sequencer context, GameObject target)
{
if (!target || !target.CompareTag("Player")) yield break;
GameObject playerObject = target;
if (!playerObject || !playerObject.CompareTag("Player")) playerObject = GameManager.Instance.PlayerObj;
target.GetComponent<Rigidbody2D>().constraints = freezeMode;
if (!playerObject || !playerObject.CompareTag("Player")) yield break;
playerObject.GetComponent<Rigidbody2D>().constraints = freezeMode;
yield return null;
}
}
}

View File

@ -1,9 +1,11 @@
using System;
using System.Collections;
using RR.Game2D.Core.Managers;
using UnityEngine;
namespace RR.Common.Behaviour
{
[Serializable]
public class TeleportPlayerAction : SequenceAction
{
[SerializeField] private bool useRelativePosition = false;

View File

@ -1,5 +1,6 @@
using System;
using System.Collections;
using RR.Game2D.Core.Managers;
using UnityEngine;
namespace RR.Common.Behaviour
@ -9,9 +10,15 @@ namespace RR.Common.Behaviour
{
public override IEnumerator Execute(Sequencer context, GameObject target)
{
if (!target || !target.CompareTag("Player")) yield break;
GameObject playerObject = target;
if (!playerObject || !playerObject.CompareTag("Player")) playerObject = GameManager.Instance.PlayerObj;
target.GetComponent<Rigidbody2D>().constraints = RigidbodyConstraints2D.FreezeRotation;
if (!playerObject || !playerObject.CompareTag("Player")) yield break;
playerObject.GetComponent<Rigidbody2D>().constraints = RigidbodyConstraints2D.FreezeRotation;
yield return null;
}
}
}

View File

@ -0,0 +1,135 @@
#if UNITY_EDITOR && UNITY_2021_2_OR_NEWER
using UnityEditor;
using UnityEditor.Overlays;
using UnityEngine;
using UnityEngine.UIElements;
[Overlay(typeof(SceneView), id: "mouse-world-position", displayName: "Mouse World Position")]
[Icon("d_Grid.BoxTool")]
public class MouseWorldPositionOverlay : Overlay
{
private enum PlaneMode { XY, XZ, YZ, CameraFacing }
private static readonly float[] Multipliers = { 1f, 10f, 100f, 1000f, 10000f, 100000f, 1000000f };
private PlaneMode planeMode = PlaneMode.XY;
private float planeOffset;
private int decimals = 2;
private Vector3 displayWorld;
private bool hasPoint;
private Label positionLabel;
public override void OnCreated()
{
SceneView.duringSceneGui += OnSceneGUI;
}
public override void OnWillBeDestroyed()
{
SceneView.duringSceneGui -= OnSceneGUI;
}
public override VisualElement CreatePanelContent()
{
VisualElement root = new() { style = { minWidth = 220 } };
// Плоскость
EnumField planeModeField = new("Плоскость", planeMode);
planeModeField.RegisterValueChangedCallback(evt => planeMode = (PlaneMode)evt.newValue);
root.Add(planeModeField);
// Смещение
FloatField offsetField = new("Смещение") { value = planeOffset };
offsetField.RegisterValueChangedCallback(evt => planeOffset = evt.newValue);
root.Add(offsetField);
// Знаки после запятой
SliderInt decimalsSlider = new("Знаки", 0, 6) { value = decimals, showInputField = true };
decimalsSlider.RegisterValueChangedCallback(evt => decimals = evt.newValue);
root.Add(decimalsSlider);
// Позиция (только для чтения)
positionLabel = new Label("—") { style = { marginTop = 8, unityFontStyleAndWeight = FontStyle.Bold } };
root.Add(positionLabel);
// Кнопка копирования
Button copyButton = new(() =>
{
if (!hasPoint) return;
string f = "F" + decimals;
EditorGUIUtility.systemCopyBuffer = $"{displayWorld.x.ToString(f)}, {displayWorld.y.ToString(f)}, {displayWorld.z.ToString(f)}";
}) { text = "Копировать (x,y,z)" };
root.Add(copyButton);
return root;
}
private void OnSceneGUI(SceneView sv)
{
if (containerWindow != sv) return;
Event e = Event.current;
if (e == null) return;
if (e.type != EventType.MouseMove && e.type != EventType.MouseDrag && e.type != EventType.Repaint)
return;
Ray ray = HandleUtility.GUIPointToWorldRay(e.mousePosition);
hasPoint = TryGetPoint(ray, sv.camera, out Vector3 world);
if (hasPoint)
{
float mult = Multipliers[decimals];
displayWorld = new Vector3(
Mathf.Ceil(world.x * mult) / mult,
Mathf.Ceil(world.y * mult) / mult,
Mathf.Ceil(world.z * mult) / mult
);
string f = "F" + decimals;
positionLabel?.schedule.Execute(() =>
positionLabel.text = $"X:{displayWorld.x.ToString(f)} Y:{displayWorld.y.ToString(f)} Z:{displayWorld.z.ToString(f)}"
);
}
else
{
positionLabel?.schedule.Execute(() => positionLabel.text = "—");
}
}
private bool TryGetPoint(Ray ray, Camera cam, out Vector3 world)
{
Plane plane;
switch (planeMode)
{
case PlaneMode.XY:
plane = new Plane(Vector3.forward, new Vector3(0f, 0f, planeOffset));
break;
case PlaneMode.XZ:
plane = new Plane(Vector3.up, new Vector3(0f, planeOffset, 0f));
break;
case PlaneMode.YZ:
plane = new Plane(Vector3.right, new Vector3(planeOffset, 0f, 0f));
break;
case PlaneMode.CameraFacing:
default:
plane = new Plane(cam.transform.forward, cam.transform.position);
break;
}
if (plane.Raycast(ray, out float enter))
{
world = ray.GetPoint(enter);
return true;
}
world = default;
return false;
}
}
#endif

View File

@ -1,141 +0,0 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
public class MouseWorldPositionWindow : EditorWindow
{
private enum PlaneMode { XY, XZ, YZ, CameraFacing }
// Множители для быстрого доступа: multipliers[d] = 10^d
private static readonly float[] Multipliers = { 1f, 10f, 100f, 1000f, 10000f, 100000f, 1000000f };
private PlaneMode planeMode = PlaneMode.XZ;
private float planeOffset;
private bool lockToSceneView = true;
private int decimals = 3;
private Vector3 lastWorld;
private Vector3 displayWorld;
private bool hasPoint;
[MenuItem("Tools/Mouse World Position")]
public static void Open()
{
GetWindow<MouseWorldPositionWindow>("Mouse World Pos");
}
private void OnEnable()
{
SceneView.duringSceneGui += OnSceneGUI;
}
private void OnDisable()
{
SceneView.duringSceneGui -= OnSceneGUI;
}
private void OnGUI()
{
EditorGUILayout.LabelField("Source", EditorStyles.boldLabel);
lockToSceneView = EditorGUILayout.ToggleLeft("Use last active Scene View", lockToSceneView);
EditorGUILayout.Space(6);
EditorGUILayout.LabelField("Projection", EditorStyles.boldLabel);
planeMode = (PlaneMode)EditorGUILayout.EnumPopup("Плоскость", planeMode);
if (planeMode != PlaneMode.CameraFacing)
planeOffset = EditorGUILayout.FloatField("Смещение плоскости", planeOffset);
decimals = EditorGUILayout.IntSlider("Decimals", decimals, 0, 6);
EditorGUILayout.Space(10);
EditorGUILayout.LabelField("Result", EditorStyles.boldLabel);
using (new EditorGUI.DisabledScope(true))
{
EditorGUILayout.Toggle("Has Point", hasPoint);
EditorGUILayout.Vector3Field("World", displayWorld);
}
using (new EditorGUI.DisabledScope(!hasPoint))
{
if (GUILayout.Button("Copy (x,y,z)"))
{
string f = "F" + decimals;
EditorGUIUtility.systemCopyBuffer = $"{displayWorld.x.ToString(f)}, {displayWorld.y.ToString(f)}, {displayWorld.z.ToString(f)}";
}
}
}
private void OnSceneGUI(SceneView sv)
{
if (!lockToSceneView && sv != SceneView.lastActiveSceneView) return;
Event e = Event.current;
if (e == null) return;
// Берём позицию мыши только когда курсор над SceneView
if (e.type != EventType.MouseMove && e.type != EventType.MouseDrag && e.type != EventType.Repaint)
return;
Ray ray = HandleUtility.GUIPointToWorldRay(e.mousePosition);
hasPoint = TryGetPoint(ray, sv.camera, out lastWorld);
// Вычисляем displayWorld один раз при изменении позиции
if (hasPoint)
{
float mult = Multipliers[decimals];
displayWorld = new Vector3(
Mathf.Ceil(lastWorld.x * mult) / mult,
Mathf.Ceil(lastWorld.y * mult) / mult,
Mathf.Ceil(lastWorld.z * mult) / mult
);
}
else
{
displayWorld = default;
}
Repaint();
}
private bool TryGetPoint(Ray ray, Camera cam, out Vector3 world)
{
// Для CameraFacing: плоскость, перпендикулярная камере, проходящая через origin камеры + (forward * planeOffset)
Plane plane;
switch (planeMode)
{
case PlaneMode.XY:
plane = new Plane(Vector3.forward, new Vector3(0f, 0f, planeOffset)); // Z = offset
break;
case PlaneMode.XZ:
plane = new Plane(Vector3.up, new Vector3(0f, planeOffset, 0f)); // Y = offset
break;
case PlaneMode.YZ:
plane = new Plane(Vector3.right, new Vector3(planeOffset, 0f, 0f)); // X = offset
break;
case PlaneMode.CameraFacing:
default:
Vector3 normal = cam.transform.forward;
Vector3 point = cam.transform.position; // можно поменять на position + forward*dist если надо
plane = new Plane(normal, point);
break;
}
if (plane.Raycast(ray, out float enter))
{
world = ray.GetPoint(enter);
return true;
}
world = default;
return false;
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -2,13 +2,14 @@ fileFormatVersion: 2
guid: 4916628c3425a704989f02cb136b655b
VisualEffectImporter:
externalObjects: {}
serializedVersion: 1
serializedVersion: 2
template:
name:
category:
description:
icon: {instanceID: 0}
thumbnail: {instanceID: 0}
useAsTemplate: 0
userData:
assetBundleName:
assetBundleVariant: