Added reclaim to pickable projectile

This commit is contained in:
Данил Ярош 2025-09-08 17:07:02 +03:00
parent 3aa7e50a64
commit 7d16edf73f
27 changed files with 371 additions and 610 deletions

View File

@ -32,7 +32,7 @@ Transform:
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 1
m_Children:
- {fileID: 8859797121973546175}
- {fileID: 7421163371325257947}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!50 &-640855425046532091
@ -137,7 +137,7 @@ MonoBehaviour:
stickDelayAfterImpact: 0.03
drawGizmos: 1
gizmoColor: {r: 0.2, g: 0.8, b: 1, a: 0.35}
--- !u!1 &6093063039154122651
--- !u!1 &7253843866260996112
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@ -145,37 +145,37 @@ GameObject:
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8859797121973546175}
- component: {fileID: 3362982869789392483}
- component: {fileID: 7421163371325257947}
- component: {fileID: 6144931758823249624}
m_Layer: 0
m_Name: Circle
m_Name: texture_round_0
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8859797121973546175
--- !u!4 &7421163371325257947
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6093063039154122651}
m_GameObject: {fileID: 7253843866260996112}
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_LocalScale: {x: 0.096, y: 0.096, z: 0.096}
m_ConstrainProportionsScale: 1
m_Children: []
m_Father: {fileID: 1452460312376183192}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!212 &3362982869789392483
--- !u!212 &6144931758823249624
SpriteRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6093063039154122651}
m_GameObject: {fileID: 7253843866260996112}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
@ -212,13 +212,13 @@ SpriteRenderer:
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 1
m_Sprite: {fileID: -2413806693520163455, guid: 7f76a84576351334b8517b4cd5666786, type: 3}
m_SortingOrder: 0
m_Sprite: {fileID: -2920598655614517764, guid: 698ae6f0523d818459c87d916f78d1e4, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 1, y: 1}
m_Size: {x: 10.24, y: 10.24}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1

View File

@ -60189,6 +60189,63 @@ SpriteRenderer:
m_WasSpriteAssigned: 1
m_MaskInteraction: 0
m_SpriteSortPoint: 0
--- !u!1001 &1409395841
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1452460312376183192, guid: 7fd3a37dc702ece42b51e5867473f0ff, type: 3}
propertyPath: m_LocalPosition.x
value: -3.1233063
objectReference: {fileID: 0}
- target: {fileID: 1452460312376183192, guid: 7fd3a37dc702ece42b51e5867473f0ff, type: 3}
propertyPath: m_LocalPosition.y
value: -19.482407
objectReference: {fileID: 0}
- target: {fileID: 1452460312376183192, guid: 7fd3a37dc702ece42b51e5867473f0ff, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1452460312376183192, guid: 7fd3a37dc702ece42b51e5867473f0ff, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1452460312376183192, guid: 7fd3a37dc702ece42b51e5867473f0ff, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1452460312376183192, guid: 7fd3a37dc702ece42b51e5867473f0ff, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1452460312376183192, guid: 7fd3a37dc702ece42b51e5867473f0ff, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1452460312376183192, guid: 7fd3a37dc702ece42b51e5867473f0ff, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1452460312376183192, guid: 7fd3a37dc702ece42b51e5867473f0ff, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1452460312376183192, guid: 7fd3a37dc702ece42b51e5867473f0ff, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5993946430821065449, guid: 7fd3a37dc702ece42b51e5867473f0ff, type: 3}
propertyPath: m_Name
value: PickableProjectile
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 7fd3a37dc702ece42b51e5867473f0ff, type: 3}
--- !u!1001 &1503664770
PrefabInstance:
m_ObjectHideFlags: 0
@ -60619,7 +60676,7 @@ Sprite:
format: 0
dimension: 0
m_DataSize: 80
_typelessdata: 000000bf0000003f000000000000003f0000003f00000000000000bf000000bf000000000000003f000000bf000000000000000000000000000000000000000000000000000000000000000000000000
_typelessdata: 000000bf0000003f000000000000003f0000003f00000000000000bf000000bf000000000000003f000000bf00000000000000000000803f0000803f0000803f00000000000000000000803f00000000
m_Bindpose: []
textureRect:
serializedVersion: 2
@ -61050,3 +61107,4 @@ SceneRoots:
- {fileID: 872032055}
- {fileID: 2041263421}
- {fileID: 2013056424}
- {fileID: 1409395841}

View File

@ -1,16 +1,16 @@
using UnityEngine;
using UnityEngine;
public class NewMonoBehaviourScript : MonoBehaviour
public class EnemyFireScript : 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: f005ea36a25360f448c5209ca82941b5

View File

@ -83,7 +83,6 @@ public class EnemyController : MonoBehaviour
}
else
{
//GameManager.Instance.ResetLevel();
playerController.Die();
}
}
@ -98,7 +97,6 @@ public class EnemyController : MonoBehaviour
Vector2 directionToPlayer = (playerObj.transform.position - transform.position);
float distanceToPlayer = directionToPlayer.magnitude;
// --- 1. Нарисуем конус обзора ---
Vector2 rightDir = Quaternion.Euler(0, 0, +viewAngle / 2f) * transform.right;
Vector2 leftDir = Quaternion.Euler(0, 0, -viewAngle / 2f) * transform.right;
@ -106,16 +104,13 @@ public class EnemyController : MonoBehaviour
Gizmos.DrawLine(origin, origin + (rightDir * viewDistance));
Gizmos.DrawLine(origin, origin + (leftDir * viewDistance));
// Полукруг радиуса viewDistance
Gizmos.DrawWireSphere(origin, viewDistance);
// --- 2. Нарисуем луч до игрока ---
if (distanceToPlayer <= viewDistance)
{
Gizmos.color = Color.red;
Gizmos.DrawLine(origin, playerObj.transform.position);
// Если хотим показать «RaycastHit»:
RaycastHit2D hit = Physics2D.Raycast(origin, directionToPlayer.normalized, distanceToPlayer);
if (hit.collider != null)
{

View File

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 6d0e8610ef68ca7489bf35f441b1e7de

View File

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

View File

@ -1,4 +1,5 @@
using UnityEngine;
using UnityEngine.SceneManagement;
[DisallowMultipleComponent]
[RequireComponent(typeof(Rigidbody2D))]
@ -7,7 +8,7 @@ public class PickableProjectile : BasicProjectile
{
public static PickableProjectile Instance { get; private set; }
public enum State { Held, Airborne, Grounded }
public enum State { Held, Airborne, Grounded, Returning }
public State CurrentState { get; private set; } = State.Grounded;
[Header("Pickup/Attach")]
@ -22,25 +23,32 @@ public class PickableProjectile : BasicProjectile
[Header("Bouncing")]
[Tooltip("Максимум отскоков прежде чем лечь на землю.")]
public int maxBounces = 3;
[Tooltip("Минимальная скорость для отскока.")]
public float minBounceSpeed = 0.8f;
[Tooltip("Коэффициент упругости (0..1).")]
[Range(0f, 1f)]
public float restitution = 0.6f;
[Range(0f, 1f)] public float restitution = 0.6f;
[Tooltip("Демпфирование вдоль поверхности (0..1), меньше — сильнее гасит скольжение.")]
[Range(0f, 1f)]
public float tangentDamping = 0.85f;
[Tooltip("Насколько «вверх» должна смотреть средняя нормаль, чтобы считать поверхность землёй (чем больше, тем мягче фильтр).")]
[Range(0f, 1f)]
public float groundUpTolerance = 0.25f;
[Range(0f, 1f)] public float tangentDamping = 0.85f;
[Tooltip("Насколько «вверх» должна смотреть средняя нормаль, чтобы считать поверхность землёй.")]
[Range(0f, 1f)] public float groundUpTolerance = 0.25f;
[Tooltip("Маленькая пауза, чтобы не прилипнуть в кадр столкновения.")]
public float stickDelayAfterImpact = 0.03f;
[Header("Persistence / Recall")]
[Tooltip("Сохранять снаряд между сценами.")]
public bool persistAcrossScenes = true;
[Tooltip("Если перед загрузкой новой сцены снаряд был в руке — автоматически прицепиться к игроку на новой сцене.")]
public bool reattachIfWasHeldOnLoad = true;
[Tooltip("Старт возврата, если дальше этой дистанции от точки руки.")]
public float recallStartDistance = 8f;
[Tooltip("На этой дистанции от руки считаем, что прилетел и подбираем.")]
public float recallArriveDistance = 1.4f;
[Tooltip("Максимальная скорость «магнита».")]
public float recallMaxSpeed = 16f;
[Tooltip("Ускорение «магнита».")]
public float recallAcceleration = 60f;
[Header("Gizmos")]
public bool drawGizmos;
public Color gizmoColor = new Color(0.2f, 0.8f, 1f, 0.35f);
@ -51,6 +59,11 @@ public class PickableProjectile : BasicProjectile
private int bounceCounter = 0;
private float lastImpactTime = -999f;
// «Когда-либо был в руке» — разрешает бумеранг
private bool hadBeenHeld = false;
// Запоминаем последнего игрока для возврата
private GameObject lastKnownHolder;
protected override void Awake()
{
base.Awake();
@ -62,6 +75,11 @@ public class PickableProjectile : BasicProjectile
}
Instance = this;
if (persistAcrossScenes)
DontDestroyOnLoad(gameObject);
SceneManager.sceneLoaded += OnSceneLoaded;
rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
col.isTrigger = false;
@ -71,6 +89,33 @@ public class PickableProjectile : BasicProjectile
private void OnDestroy()
{
if (Instance == this) Instance = null;
SceneManager.sceneLoaded -= OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
Debug.Log("OnSceneLoaded");
Debug.Log($"Owner: {owner}");
Debug.Log($"LastKnownHolder: {lastKnownHolder}");
if (!reattachIfWasHeldOnLoad) return;
// Если до загрузки мы были в руке — прицепляемся к игроку на новой сцене
if (CurrentState == State.Held || (hadBeenHeld && owner != null))
{
var playerGo =
(GameManager.Instance && GameManager.Instance.playerObj) ?
GameManager.Instance.playerObj :
GameObject.FindWithTag("Player");
Debug.Log($"PlayerObj: {playerGo}");
if (!playerGo) return;
var attach = FindAttachPointOn(playerGo) ?? playerGo.transform;
transform.SetParent(null, true);
TryPickup(playerGo, attach);
}
}
public bool TryPickup(GameObject newHolder, Transform optionalAttachPoint = null)
@ -78,6 +123,8 @@ public class PickableProjectile : BasicProjectile
if (CurrentState == State.Held) return true;
holder = newHolder;
lastKnownHolder = newHolder;
holderAttachPoint = optionalAttachPoint ?? FindAttachPointOn(holder);
if (holderAttachPoint == null) holderAttachPoint = holder.transform;
@ -89,24 +136,26 @@ public class PickableProjectile : BasicProjectile
transform.SetParent(holderAttachPoint, worldPositionStays: false);
transform.localPosition = heldLocalOffset;
transform.localRotation = Quaternion.identity;
transform.localScale = Vector3.one * 2;
transform.localScale = Vector3.one * 2; // оставляю как у тебя
// Игнор коллизии владельца нужен при броске, не при «магните»
StartCoroutine(IgnoreOwnerTemporarily(holder, ignoreOwnerTimeOnThrow));
CurrentState = State.Held;
launched = false;
owner = holder;
hadBeenHeld = true; // разрешаем бумеранг в будущем
return true;
}
public void Launch(Vector2 direction, float speed, GameObject throwOwner = null)
{
if (CurrentState == State.Held)
{
transform.SetParent(null, true);
}
holder = throwOwner;
lastKnownHolder = throwOwner;
holderAttachPoint = null;
rb.bodyType = RigidbodyType2D.Dynamic;
@ -144,13 +193,6 @@ public class PickableProjectile : BasicProjectile
BecomeGrounded(collision);
}
//else if (CurrentState == State.Grounded)
//{
// if (collision.collider.CompareTag("Player"))
// {
// TryPickup(collision.gameObject);
// }
//}
}
protected override void OnImpactFinal(Collision2D collision)
@ -239,6 +281,59 @@ public class PickableProjectile : BasicProjectile
if (rb.linearVelocity.sqrMagnitude < (sleepVelocity * sleepVelocity))
BecomeGrounded(null);
}
// Бумеранг только если снаряд когда-то уже был в руке
if (hadBeenHeld && CurrentState != State.Held)
HandleRecallToPlayer();
}
private void HandleRecallToPlayer()
{
// Целимся в актуального игрока, предпочтительно последнего владельца
GameObject playerGo = null;
if (lastKnownHolder != null)
playerGo = lastKnownHolder;
if (playerGo == null || !playerGo.activeInHierarchy)
playerGo = (GameManager.Instance && GameManager.Instance.playerObj)
? GameManager.Instance.playerObj
: GameObject.FindWithTag("Player");
if (!playerGo) return;
var hand = FindAttachPointOn(playerGo) ?? playerGo.transform;
Vector2 toHand = (Vector2)hand.position - rb.position;
float dist = toHand.magnitude;
if (dist > recallStartDistance)
{
// Начинаем «магнит»
if (CurrentState != State.Returning)
{
CurrentState = State.Returning;
rb.bodyType = RigidbodyType2D.Dynamic;
col.enabled = true;
// ВАЖНО: не игнорируем коллизию с игроком здесь, чтобы не проскальзывать через него
}
Vector2 desired = toHand.normalized * recallMaxSpeed;
rb.linearVelocity = Vector2.MoveTowards(
rb.linearVelocity, desired, recallAcceleration * Time.fixedDeltaTime);
if (rb.linearVelocity.sqrMagnitude > 0.01f)
transform.right = rb.linearVelocity.normalized;
if (dist <= recallArriveDistance)
TryPickup(playerGo, hand);
}
else
{
// Вышли из «дальней» зоны — возвращаем обычное состояние
if (CurrentState == State.Returning)
CurrentState = rb.bodyType == RigidbodyType2D.Dynamic ? State.Airborne : State.Grounded;
}
}
#if UNITY_EDITOR

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

@ -0,0 +1,156 @@
fileFormatVersion: 2
guid: 698ae6f0523d818459c87d916f78d1e4
TextureImporter:
internalIDToNameTable:
- first:
213: -2920598655614517764
second: texture_round_0
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: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
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: 4
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: 4
buildTarget: WebGL
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: texture_round_0
rect:
serializedVersion: 2
x: 0
y: 0
width: 1024
height: 1024
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: cfdfc982ff2f777d0800000000000000
internalID: -2920598655614517764
vertices: []
indices:
edges: []
weights: []
outline: []
customData:
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable:
texture_round_0: -2920598655614517764
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long