Poop obstacle pipeline working
This commit is contained in:
@@ -15,7 +15,7 @@ GameObject:
|
|||||||
- component: {fileID: 4086097097060867018}
|
- component: {fileID: 4086097097060867018}
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: Poop
|
m_Name: Poop
|
||||||
m_TagString: Untagged
|
m_TagString: Projectile
|
||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
m_StaticEditorFlags: 0
|
m_StaticEditorFlags: 0
|
||||||
@@ -150,7 +150,7 @@ BoxCollider2D:
|
|||||||
m_CallbackLayers:
|
m_CallbackLayers:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_Bits: 4294967295
|
m_Bits: 4294967295
|
||||||
m_IsTrigger: 0
|
m_IsTrigger: 1
|
||||||
m_UsedByEffector: 0
|
m_UsedByEffector: 0
|
||||||
m_CompositeOperation: 0
|
m_CompositeOperation: 0
|
||||||
m_CompositeOrder: 0
|
m_CompositeOrder: 0
|
||||||
|
|||||||
8
Assets/Prefabs/Minigames/BirdPoop/Targets.meta
Normal file
8
Assets/Prefabs/Minigames/BirdPoop/Targets.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: dbcdce294136cfa4aa1091cf3ff03bcf
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
217
Assets/Prefabs/Minigames/BirdPoop/Targets/Target.prefab
Normal file
217
Assets/Prefabs/Minigames/BirdPoop/Targets/Target.prefab
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &3536052400313117972
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 2159841359414636212}
|
||||||
|
- component: {fileID: 4795053012425497095}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Visual
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &2159841359414636212
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3536052400313117972}
|
||||||
|
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: 6842023794578555096}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!212 &4795053012425497095
|
||||||
|
SpriteRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3536052400313117972}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 0
|
||||||
|
m_ReceiveShadows: 0
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_StaticShadowCaster: 0
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 1
|
||||||
|
m_ReflectionProbeUsage: 1
|
||||||
|
m_RayTracingMode: 0
|
||||||
|
m_RayTraceProcedural: 0
|
||||||
|
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||||
|
m_RayTracingAccelStructBuildFlags: 1
|
||||||
|
m_SmallMeshCulling: 1
|
||||||
|
m_ForceMeshLod: -1
|
||||||
|
m_MeshLodSelectionBias: 0
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 2100000, guid: 9dfc825aed78fcd4ba02077103263b40, type: 2}
|
||||||
|
m_StaticBatchInfo:
|
||||||
|
firstSubMesh: 0
|
||||||
|
subMeshCount: 0
|
||||||
|
m_StaticBatchRoot: {fileID: 0}
|
||||||
|
m_ProbeAnchor: {fileID: 0}
|
||||||
|
m_LightProbeVolumeOverride: {fileID: 0}
|
||||||
|
m_ScaleInLightmap: 1
|
||||||
|
m_ReceiveGI: 1
|
||||||
|
m_PreserveUVs: 0
|
||||||
|
m_IgnoreNormalsForChartDetection: 0
|
||||||
|
m_ImportantGI: 0
|
||||||
|
m_StitchLightmapSeams: 1
|
||||||
|
m_SelectedEditorRenderState: 0
|
||||||
|
m_MinimumChartSize: 4
|
||||||
|
m_AutoUVMaxDistance: 0.5
|
||||||
|
m_AutoUVMaxAngle: 89
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_GlobalIlluminationMeshLod: 0
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingLayer: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_Sprite: {fileID: 2133529702, guid: 99d4c3083e9c24142bc20deaeaf95720, type: 3}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_FlipX: 0
|
||||||
|
m_FlipY: 0
|
||||||
|
m_DrawMode: 0
|
||||||
|
m_Size: {x: 2.56, y: 4.94}
|
||||||
|
m_AdaptiveModeThreshold: 0.5
|
||||||
|
m_SpriteTileMode: 0
|
||||||
|
m_WasSpriteAssigned: 1
|
||||||
|
m_MaskInteraction: 0
|
||||||
|
m_SpriteSortPoint: 0
|
||||||
|
--- !u!1 &8373178063207716143
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 6842023794578555096}
|
||||||
|
- component: {fileID: 1509565078017969516}
|
||||||
|
- component: {fileID: 11467650667563993}
|
||||||
|
- component: {fileID: 8135420306913345847}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Target
|
||||||
|
m_TagString: Target
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &6842023794578555096
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 8373178063207716143}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 7.27167, y: -14.259, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 2159841359414636212}
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!61 &1509565078017969516
|
||||||
|
BoxCollider2D:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 8373178063207716143}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Density: 1
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_ForceSendLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_ForceReceiveLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_ContactCaptureLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_CallbackLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_IsTrigger: 0
|
||||||
|
m_UsedByEffector: 0
|
||||||
|
m_CompositeOperation: 0
|
||||||
|
m_CompositeOrder: 0
|
||||||
|
m_Offset: {x: 0.10432935, y: 1.5258197}
|
||||||
|
m_SpriteTilingProperty:
|
||||||
|
border: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
pivot: {x: 0, y: 0}
|
||||||
|
oldSize: {x: 0, y: 0}
|
||||||
|
newSize: {x: 0, y: 0}
|
||||||
|
adaptiveTilingThreshold: 0
|
||||||
|
drawMode: 0
|
||||||
|
adaptiveTiling: 0
|
||||||
|
m_AutoTiling: 0
|
||||||
|
m_Size: {x: 2.773602, y: 4.729781}
|
||||||
|
m_EdgeRadius: 0
|
||||||
|
--- !u!114 &11467650667563993
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 8373178063207716143}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: ed380d10e1e04ae7990e5c726c929063, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: AppleHillsScripts::AppleHillsCamera.EdgeAnchor
|
||||||
|
referenceMarker: {fileID: 0}
|
||||||
|
cameraAdapter: {fileID: 0}
|
||||||
|
anchorEdge: 2
|
||||||
|
useReferenceMargin: 0
|
||||||
|
customMargin: 0
|
||||||
|
adjustOnStart: 1
|
||||||
|
adjustOnScreenResize: 1
|
||||||
|
preserveOtherAxes: 1
|
||||||
|
accountForObjectSize: 1
|
||||||
|
customAnchorPoint: {fileID: 0}
|
||||||
|
showVisualization: 1
|
||||||
|
visualizationColor: {r: 1, g: 0, b: 0, a: 0.8}
|
||||||
|
showObjectBounds: 1
|
||||||
|
debugMode: 0
|
||||||
|
--- !u!114 &8135420306913345847
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 8373178063207716143}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 5331a770bc634a738b82f9450441de12, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: AppleHillsScripts::Minigames.BirdPooper.Target
|
||||||
|
verticalAnchor: 2
|
||||||
|
spriteRenderer: {fileID: 4795053012425497095}
|
||||||
|
hitColor: {r: 1, g: 0, b: 0, a: 1}
|
||||||
|
onTargetHit:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 020f7494c613b06479ccad2c4cedde0f
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -306,6 +306,7 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier: AppleHillsScripts::Minigames.BirdPooper.BirdPooperGameManager
|
m_EditorClassIdentifier: AppleHillsScripts::Minigames.BirdPooper.BirdPooperGameManager
|
||||||
player: {fileID: 941621859}
|
player: {fileID: 941621859}
|
||||||
obstacleSpawner: {fileID: 938885957}
|
obstacleSpawner: {fileID: 938885957}
|
||||||
|
targetSpawner: {fileID: 1838778561}
|
||||||
gameOverScreen: {fileID: 81231374}
|
gameOverScreen: {fileID: 81231374}
|
||||||
poopPrefab: {fileID: 5552423787977869117, guid: 066f9990a9b1f5547b387633d5d204c0, type: 3}
|
poopPrefab: {fileID: 5552423787977869117, guid: 066f9990a9b1f5547b387633d5d204c0, type: 3}
|
||||||
--- !u!4 &128829408
|
--- !u!4 &128829408
|
||||||
@@ -682,12 +683,12 @@ Transform:
|
|||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 690060017}
|
m_GameObject: {fileID: 690060017}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
m_LocalPosition: {x: 30.01, y: 0, z: 0}
|
m_LocalPosition: {x: 33.56759, y: 1.13668, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 938885956}
|
m_Father: {fileID: 1498486831}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &938473625
|
--- !u!1 &938473625
|
||||||
GameObject:
|
GameObject:
|
||||||
@@ -713,12 +714,12 @@ Transform:
|
|||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 938473625}
|
m_GameObject: {fileID: 938473625}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
m_LocalPosition: {x: -30.12, y: 0, z: 0}
|
m_LocalPosition: {x: -26.56241, y: 1.13668, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 938885956}
|
m_Father: {fileID: 1498486831}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &938885955
|
--- !u!1 &938885955
|
||||||
GameObject:
|
GameObject:
|
||||||
@@ -745,14 +746,12 @@ Transform:
|
|||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 938885955}
|
m_GameObject: {fileID: 938885955}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 3.55759, y: 1.13668, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children: []
|
||||||
- {fileID: 690060018}
|
m_Father: {fileID: 1498486831}
|
||||||
- {fileID: 938473626}
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!114 &938885957
|
--- !u!114 &938885957
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
@@ -775,18 +774,10 @@ MonoBehaviour:
|
|||||||
- {fileID: 5356906417396349863, guid: cc2a11f7e5edd7640921d1db442a7224, type: 3}
|
- {fileID: 5356906417396349863, guid: cc2a11f7e5edd7640921d1db442a7224, type: 3}
|
||||||
- {fileID: 1771686652490758453, guid: c2dcfdcc678ff3248b40d189f46a4d3b, type: 3}
|
- {fileID: 1771686652490758453, guid: c2dcfdcc678ff3248b40d189f46a4d3b, type: 3}
|
||||||
- {fileID: 2166804132462075410, guid: c60915cb9b989c04caf075ed31cb2a53, type: 3}
|
- {fileID: 2166804132462075410, guid: c60915cb9b989c04caf075ed31cb2a53, type: 3}
|
||||||
- {fileID: 8872570883018587233, guid: ef4923a2e60ffa540b99d955668c9491, type: 3}
|
|
||||||
- {fileID: 6378685721593782219, guid: 6b5e79bd10362854e96e56400a25794d, type: 3}
|
|
||||||
- {fileID: 5221014930798827916, guid: c0d26b0d29c2d5a41a60dc01f80bd500, type: 3}
|
|
||||||
- {fileID: 9077746715280142631, guid: 830960246de8eec4d9535097ce3653db, type: 3}
|
- {fileID: 9077746715280142631, guid: 830960246de8eec4d9535097ce3653db, type: 3}
|
||||||
- {fileID: 7335086015568222999, guid: 06674917a922d6c48a2d0ac0f6056e01, type: 3}
|
- {fileID: 7335086015568222999, guid: 06674917a922d6c48a2d0ac0f6056e01, type: 3}
|
||||||
- {fileID: 8558432647259683993, guid: 8c71dd9ad06dafc41a3308f566726ac5, type: 3}
|
- {fileID: 8558432647259683993, guid: 8c71dd9ad06dafc41a3308f566726ac5, type: 3}
|
||||||
- {fileID: 461075067585331030, guid: 6a77320ba6ef47f448aa934a22bf396f, type: 3}
|
- {fileID: 461075067585331030, guid: 6a77320ba6ef47f448aa934a22bf396f, type: 3}
|
||||||
- {fileID: 552236068384934285, guid: a9a0c00b5622246429ebd7eaa351d175, type: 3}
|
|
||||||
- {fileID: 2022439803908362932, guid: 75f3874bd8cb48f4c8c7ff4452ec1c5f, type: 3}
|
|
||||||
- {fileID: 1526963434598685192, guid: 1a8e2dd4ee8bcab44850e0e63f14777d, type: 3}
|
|
||||||
- {fileID: 539450891493405750, guid: 700d5f9584069e940baa7107695d2788, type: 3}
|
|
||||||
- {fileID: 8553623782462946796, guid: de509c8e31091fc469f238050ff49c20, type: 3}
|
|
||||||
--- !u!1 &941621855
|
--- !u!1 &941621855
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -797,12 +788,12 @@ GameObject:
|
|||||||
m_Component:
|
m_Component:
|
||||||
- component: {fileID: 941621856}
|
- component: {fileID: 941621856}
|
||||||
- component: {fileID: 941621858}
|
- component: {fileID: 941621858}
|
||||||
- component: {fileID: 941621857}
|
|
||||||
- component: {fileID: 941621859}
|
- component: {fileID: 941621859}
|
||||||
- component: {fileID: 941621860}
|
- component: {fileID: 941621860}
|
||||||
|
- component: {fileID: 941621861}
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: Bird
|
m_Name: Bird
|
||||||
m_TagString: Untagged
|
m_TagString: Player
|
||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
m_StaticEditorFlags: 0
|
m_StaticEditorFlags: 0
|
||||||
@@ -823,52 +814,6 @@ Transform:
|
|||||||
- {fileID: 989743355}
|
- {fileID: 989743355}
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!61 &941621857
|
|
||||||
BoxCollider2D:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 941621855}
|
|
||||||
m_Enabled: 1
|
|
||||||
serializedVersion: 3
|
|
||||||
m_Density: 1
|
|
||||||
m_Material: {fileID: 0}
|
|
||||||
m_IncludeLayers:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Bits: 0
|
|
||||||
m_ExcludeLayers:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Bits: 0
|
|
||||||
m_LayerOverridePriority: 0
|
|
||||||
m_ForceSendLayers:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Bits: 4294967295
|
|
||||||
m_ForceReceiveLayers:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Bits: 4294967295
|
|
||||||
m_ContactCaptureLayers:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Bits: 4294967295
|
|
||||||
m_CallbackLayers:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Bits: 4294967295
|
|
||||||
m_IsTrigger: 1
|
|
||||||
m_UsedByEffector: 0
|
|
||||||
m_CompositeOperation: 0
|
|
||||||
m_CompositeOrder: 0
|
|
||||||
m_Offset: {x: 0.10795927, y: 0.15422785}
|
|
||||||
m_SpriteTilingProperty:
|
|
||||||
border: {x: 0, y: 0, z: 0, w: 0}
|
|
||||||
pivot: {x: 0, y: 0}
|
|
||||||
oldSize: {x: 0, y: 0}
|
|
||||||
newSize: {x: 0, y: 0}
|
|
||||||
adaptiveTilingThreshold: 0
|
|
||||||
drawMode: 0
|
|
||||||
adaptiveTiling: 0
|
|
||||||
m_AutoTiling: 0
|
|
||||||
m_Size: {x: 3.1489096, y: 3.1797535}
|
|
||||||
m_EdgeRadius: 0
|
|
||||||
--- !u!50 &941621858
|
--- !u!50 &941621858
|
||||||
Rigidbody2D:
|
Rigidbody2D:
|
||||||
serializedVersion: 5
|
serializedVersion: 5
|
||||||
@@ -940,6 +885,83 @@ MonoBehaviour:
|
|||||||
visualizationColor: {r: 1, g: 0, b: 0, a: 0.8}
|
visualizationColor: {r: 1, g: 0, b: 0, a: 0.8}
|
||||||
showObjectBounds: 1
|
showObjectBounds: 1
|
||||||
debugMode: 0
|
debugMode: 0
|
||||||
|
--- !u!60 &941621861
|
||||||
|
PolygonCollider2D:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 941621855}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Density: 1
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_ForceSendLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_ForceReceiveLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_ContactCaptureLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_CallbackLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_IsTrigger: 1
|
||||||
|
m_UsedByEffector: 0
|
||||||
|
m_CompositeOperation: 0
|
||||||
|
m_CompositeOrder: 0
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_SpriteTilingProperty:
|
||||||
|
border: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
pivot: {x: 0, y: 0}
|
||||||
|
oldSize: {x: 0, y: 0}
|
||||||
|
newSize: {x: 0, y: 0}
|
||||||
|
adaptiveTilingThreshold: 0
|
||||||
|
drawMode: 0
|
||||||
|
adaptiveTiling: 0
|
||||||
|
m_AutoTiling: 0
|
||||||
|
m_Points:
|
||||||
|
m_Paths:
|
||||||
|
- - {x: 1.1532116, y: 0.58190906}
|
||||||
|
- {x: 1.4644184, y: 0.5569483}
|
||||||
|
- {x: 1.4214172, y: 0.31169766}
|
||||||
|
- {x: 1.6079073, y: 0.28156418}
|
||||||
|
- {x: 1.8019552, y: 0.67698365}
|
||||||
|
- {x: 1.8297558, y: 1.323832}
|
||||||
|
- {x: 1.654233, y: 1.3764026}
|
||||||
|
- {x: 1.5695343, y: 1.1152095}
|
||||||
|
- {x: 0.92802143, y: 1.1187038}
|
||||||
|
- {x: 0.7329979, y: 1.503772}
|
||||||
|
- {x: 0.46102428, y: 1.5575173}
|
||||||
|
- {x: 0.085243225, y: 1.2721097}
|
||||||
|
- {x: -0.123518944, y: 1.4144537}
|
||||||
|
- {x: -0.55174446, y: 1.6402422}
|
||||||
|
- {x: -0.64256763, y: 1.5012914}
|
||||||
|
- {x: -0.6007347, y: 1.0087695}
|
||||||
|
- {x: -0.7314367, y: 0.7691624}
|
||||||
|
- {x: -0.92963314, y: 0.907363}
|
||||||
|
- {x: -1.0350323, y: 0.77632636}
|
||||||
|
- {x: -0.7913971, y: 0.43193945}
|
||||||
|
- {x: -1.1180935, y: 0.46667978}
|
||||||
|
- {x: -1.1118784, y: 0.20180213}
|
||||||
|
- {x: -0.65509033, y: 0.111432254}
|
||||||
|
- {x: -0.5556206, y: -0.24077833}
|
||||||
|
- {x: -0.1923418, y: -0.6376203}
|
||||||
|
- {x: 0.0838753, y: -0.5945872}
|
||||||
|
- {x: 0.32236862, y: -0.4514704}
|
||||||
|
- {x: 0.4662609, y: -0.059037298}
|
||||||
|
- {x: 0.802371, y: 0.12178908}
|
||||||
|
- {x: 0.9939432, y: 0.33046013}
|
||||||
|
m_UseDelaunayMesh: 0
|
||||||
--- !u!1 &989743352
|
--- !u!1 &989743352
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -1302,6 +1324,41 @@ Transform:
|
|||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &1498486830
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1498486831}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Spawners
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &1498486831
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1498486830}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: -3.55759, y: -1.13668, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 938885956}
|
||||||
|
- {fileID: 1838778560}
|
||||||
|
- {fileID: 690060018}
|
||||||
|
- {fileID: 938473626}
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &1536057436
|
--- !u!1 &1536057436
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -1575,6 +1632,56 @@ Transform:
|
|||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &1838778559
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1838778560}
|
||||||
|
- component: {fileID: 1838778561}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: TargetSpawner
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &1838778560
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1838778559}
|
||||||
|
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: 1498486831}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &1838778561
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1838778559}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 16beae843b5f431f9256a56aab02b53d, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: AppleHillsScripts::Minigames.BirdPooper.TargetSpawner
|
||||||
|
spawnPoint: {fileID: 690060018}
|
||||||
|
despawnPoint: {fileID: 938473626}
|
||||||
|
referenceMarker: {fileID: 1143700529}
|
||||||
|
cameraAdapter: {fileID: 2103114179}
|
||||||
|
targetPrefabs:
|
||||||
|
- {fileID: 8373178063207716143, guid: 020f7494c613b06479ccad2c4cedde0f, type: 3}
|
||||||
--- !u!1 &2103114174
|
--- !u!1 &2103114174
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -1675,6 +1782,6 @@ SceneRoots:
|
|||||||
- {fileID: 580848255}
|
- {fileID: 580848255}
|
||||||
- {fileID: 941621856}
|
- {fileID: 941621856}
|
||||||
- {fileID: 1143700530}
|
- {fileID: 1143700530}
|
||||||
- {fileID: 938885956}
|
- {fileID: 1498486831}
|
||||||
- {fileID: 1536057440}
|
- {fileID: 1536057440}
|
||||||
- {fileID: 128829408}
|
- {fileID: 128829408}
|
||||||
|
|||||||
@@ -55,6 +55,13 @@ namespace Core.Settings
|
|||||||
[Tooltip("Y position where poop is destroyed (off-screen bottom)")]
|
[Tooltip("Y position where poop is destroyed (off-screen bottom)")]
|
||||||
[SerializeField] private float poopDestroyYPosition = -10f;
|
[SerializeField] private float poopDestroyYPosition = -10f;
|
||||||
|
|
||||||
|
[Header("Targets")]
|
||||||
|
[Tooltip("Target scroll speed in units/s (can be different from obstacles)")]
|
||||||
|
[SerializeField] private float targetMoveSpeed = 4f;
|
||||||
|
|
||||||
|
[Tooltip("Time between target spawns in seconds")]
|
||||||
|
[SerializeField] private float targetSpawnInterval = 3f;
|
||||||
|
|
||||||
// Interface implementation
|
// Interface implementation
|
||||||
public float Gravity => gravity;
|
public float Gravity => gravity;
|
||||||
public float FlapForce => flapForce;
|
public float FlapForce => flapForce;
|
||||||
@@ -71,6 +78,8 @@ namespace Core.Settings
|
|||||||
public float ObstacleMaxSpawnY => obstacleMaxSpawnY;
|
public float ObstacleMaxSpawnY => obstacleMaxSpawnY;
|
||||||
public float PoopFallSpeed => poopFallSpeed;
|
public float PoopFallSpeed => poopFallSpeed;
|
||||||
public float PoopDestroyYPosition => poopDestroyYPosition;
|
public float PoopDestroyYPosition => poopDestroyYPosition;
|
||||||
|
public float TargetMoveSpeed => targetMoveSpeed;
|
||||||
|
public float TargetSpawnInterval => targetSpawnInterval;
|
||||||
|
|
||||||
public override void OnValidate()
|
public override void OnValidate()
|
||||||
{
|
{
|
||||||
@@ -83,6 +92,8 @@ namespace Core.Settings
|
|||||||
maxRotationAngle = Mathf.Clamp(maxRotationAngle, 0f, 90f);
|
maxRotationAngle = Mathf.Clamp(maxRotationAngle, 0f, 90f);
|
||||||
rotationSpeed = Mathf.Max(0.1f, rotationSpeed);
|
rotationSpeed = Mathf.Max(0.1f, rotationSpeed);
|
||||||
obstacleSpawnInterval = Mathf.Max(0.1f, obstacleSpawnInterval);
|
obstacleSpawnInterval = Mathf.Max(0.1f, obstacleSpawnInterval);
|
||||||
|
targetMoveSpeed = Mathf.Max(0.1f, targetMoveSpeed);
|
||||||
|
targetSpawnInterval = Mathf.Max(0.1f, targetSpawnInterval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,10 @@
|
|||||||
// Poop Projectile
|
// Poop Projectile
|
||||||
float PoopFallSpeed { get; }
|
float PoopFallSpeed { get; }
|
||||||
float PoopDestroyYPosition { get; }
|
float PoopDestroyYPosition { get; }
|
||||||
|
|
||||||
|
// Targets
|
||||||
|
float TargetMoveSpeed { get; }
|
||||||
|
float TargetSpawnInterval { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,12 +56,12 @@ namespace Minigames.BirdPooper
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register as override consumer to capture ALL input (except UI button)
|
// Register as default consumer (gets input if nothing else consumes it)
|
||||||
// Register as override consumer to capture ALL input (except UI button)
|
// This allows UI buttons to work while still flapping when tapping empty space
|
||||||
if (Input.InputManager.Instance != null)
|
if (Input.InputManager.Instance != null)
|
||||||
{
|
{
|
||||||
Input.InputManager.Instance.RegisterOverrideConsumer(this);
|
Input.InputManager.Instance.SetDefaultConsumer(this);
|
||||||
Debug.Log("[BirdPlayerController] Registered as override input consumer");
|
Debug.Log("[BirdPlayerController] Registered as default input consumer");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -161,12 +161,12 @@ namespace Minigames.BirdPooper
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when a trigger collider enters this object's trigger.
|
/// Called when a trigger collider enters this object's trigger.
|
||||||
/// Used for detecting obstacles without physics interactions.
|
/// Used for detecting obstacles and targets without physics interactions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnTriggerEnter2D(Collider2D other)
|
private void OnTriggerEnter2D(Collider2D other)
|
||||||
{
|
{
|
||||||
// Check if the colliding object is tagged as an obstacle
|
// Check if the colliding object is tagged as an obstacle or target
|
||||||
if (other.CompareTag("Obstacle"))
|
if (other.CompareTag("Obstacle") || other.CompareTag("Target"))
|
||||||
{
|
{
|
||||||
HandleDeath();
|
HandleDeath();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ namespace Minigames.BirdPooper
|
|||||||
[Header("References")]
|
[Header("References")]
|
||||||
[SerializeField] private BirdPlayerController player;
|
[SerializeField] private BirdPlayerController player;
|
||||||
[SerializeField] private ObstacleSpawner obstacleSpawner;
|
[SerializeField] private ObstacleSpawner obstacleSpawner;
|
||||||
|
[SerializeField] private TargetSpawner targetSpawner;
|
||||||
[SerializeField] private GameOverScreen gameOverScreen;
|
[SerializeField] private GameOverScreen gameOverScreen;
|
||||||
[SerializeField] private GameObject poopPrefab;
|
[SerializeField] private GameObject poopPrefab;
|
||||||
|
|
||||||
@@ -47,6 +48,11 @@ namespace Minigames.BirdPooper
|
|||||||
Debug.LogError("[BirdPooperGameManager] ObstacleSpawner reference not assigned!");
|
Debug.LogError("[BirdPooperGameManager] ObstacleSpawner reference not assigned!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (targetSpawner == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[BirdPooperGameManager] TargetSpawner reference not assigned! Targets will not spawn.");
|
||||||
|
}
|
||||||
|
|
||||||
if (gameOverScreen == null)
|
if (gameOverScreen == null)
|
||||||
{
|
{
|
||||||
Debug.LogError("[BirdPooperGameManager] GameOverScreen reference not assigned!");
|
Debug.LogError("[BirdPooperGameManager] GameOverScreen reference not assigned!");
|
||||||
@@ -84,6 +90,13 @@ namespace Minigames.BirdPooper
|
|||||||
obstacleSpawner.StartSpawning();
|
obstacleSpawner.StartSpawning();
|
||||||
Debug.Log("[BirdPooperGameManager] Started obstacle spawning");
|
Debug.Log("[BirdPooperGameManager] Started obstacle spawning");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start target spawning
|
||||||
|
if (targetSpawner != null)
|
||||||
|
{
|
||||||
|
targetSpawner.StartSpawning();
|
||||||
|
Debug.Log("[BirdPooperGameManager] Started target spawning");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void OnManagedDestroy()
|
internal override void OnManagedDestroy()
|
||||||
@@ -120,6 +133,12 @@ namespace Minigames.BirdPooper
|
|||||||
obstacleSpawner.StopSpawning();
|
obstacleSpawner.StopSpawning();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop spawning targets
|
||||||
|
if (targetSpawner != null)
|
||||||
|
{
|
||||||
|
targetSpawner.StopSpawning();
|
||||||
|
}
|
||||||
|
|
||||||
// Show game over screen
|
// Show game over screen
|
||||||
if (gameOverScreen != null)
|
if (gameOverScreen != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,300 +1,28 @@
|
|||||||
using UnityEngine;
|
|
||||||
using Core;
|
|
||||||
using Core.Settings;
|
|
||||||
using AppleHillsCamera;
|
|
||||||
|
|
||||||
namespace Minigames.BirdPooper
|
namespace Minigames.BirdPooper
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Individual obstacle behavior for Bird Pooper minigame.
|
/// Obstacle entity for Bird Pooper minigame.
|
||||||
/// Scrolls left at constant speed and self-destructs when reaching despawn position.
|
/// Inherits scrolling, anchoring, and despawn behavior from ScrollingEntity.
|
||||||
/// Uses trigger colliders for collision detection (no Rigidbody2D needed).
|
/// Player dies on collision with obstacles.
|
||||||
/// Uses EdgeAnchor for vertical positioning (Top/Middle/Bottom).
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RequireComponent(typeof(Collider2D))]
|
public class Obstacle : ScrollingEntity
|
||||||
[RequireComponent(typeof(EdgeAnchor))]
|
|
||||||
public class Obstacle : MonoBehaviour
|
|
||||||
{
|
{
|
||||||
[Header("Positioning")]
|
|
||||||
[Tooltip("Which vertical edge to anchor to (Top/Middle/Bottom)")]
|
|
||||||
[SerializeField] private EdgeAnchor.AnchorEdge verticalAnchor = EdgeAnchor.AnchorEdge.Middle;
|
|
||||||
|
|
||||||
private IBirdPooperSettings settings;
|
|
||||||
private float despawnXPosition;
|
|
||||||
private bool isInitialized;
|
|
||||||
private EdgeAnchor edgeAnchor;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize the obstacle with despawn position and EdgeAnchor references.
|
/// Returns obstacle move speed from settings.
|
||||||
/// Called by ObstacleSpawner immediately after instantiation.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="despawnX">X position where obstacle should be destroyed</param>
|
protected override float GetMoveSpeed()
|
||||||
/// <param name="referenceMarker">ScreenReferenceMarker for EdgeAnchor</param>
|
|
||||||
/// <param name="cameraAdapter">CameraScreenAdapter for EdgeAnchor</param>
|
|
||||||
public void Initialize(float despawnX, ScreenReferenceMarker referenceMarker, CameraScreenAdapter cameraAdapter)
|
|
||||||
{
|
{
|
||||||
despawnXPosition = despawnX;
|
return settings != null ? settings.ObstacleMoveSpeed : 5f;
|
||||||
isInitialized = true;
|
|
||||||
|
|
||||||
// Load settings
|
|
||||||
settings = GameManager.GetSettingsObject<IBirdPooperSettings>();
|
|
||||||
if (settings == null)
|
|
||||||
{
|
|
||||||
Debug.LogError("[Obstacle] BirdPooperSettings not found!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tag all child GameObjects with colliders as "Obstacle" for trigger detection
|
|
||||||
TagChildCollidersRecursive(transform);
|
|
||||||
|
|
||||||
// Configure and update EdgeAnchor
|
|
||||||
edgeAnchor = GetComponent<EdgeAnchor>();
|
|
||||||
if (edgeAnchor != null)
|
|
||||||
{
|
|
||||||
// Assign references from spawner
|
|
||||||
edgeAnchor.referenceMarker = referenceMarker;
|
|
||||||
edgeAnchor.cameraAdapter = cameraAdapter;
|
|
||||||
|
|
||||||
// Only allow Top, Middle, or Bottom anchoring
|
|
||||||
if (verticalAnchor == EdgeAnchor.AnchorEdge.Left || verticalAnchor == EdgeAnchor.AnchorEdge.Right)
|
|
||||||
{
|
|
||||||
Debug.LogWarning("[Obstacle] Invalid anchor edge (Left/Right not supported). Defaulting to Middle.");
|
|
||||||
verticalAnchor = EdgeAnchor.AnchorEdge.Middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
edgeAnchor.anchorEdge = verticalAnchor;
|
|
||||||
edgeAnchor.useReferenceMargin = false; // No custom offset
|
|
||||||
edgeAnchor.customMargin = 0f;
|
|
||||||
edgeAnchor.preserveOtherAxes = true; // Keep X position (for scrolling)
|
|
||||||
edgeAnchor.accountForObjectSize = true;
|
|
||||||
|
|
||||||
// Trigger position update
|
|
||||||
edgeAnchor.UpdatePosition();
|
|
||||||
|
|
||||||
Debug.Log($"[Obstacle] EdgeAnchor configured to {verticalAnchor} at position {transform.position}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogError("[Obstacle] EdgeAnchor component not found! Make sure the prefab has an EdgeAnchor component.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug.Log($"[Obstacle] Initialized at position {transform.position} with despawn X: {despawnX}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Recursively tag all GameObjects with Collider2D as "Obstacle" for player collision detection.
|
/// Returns "Obstacle" tag for collision detection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void TagChildCollidersRecursive(Transform current)
|
protected override string GetColliderTag()
|
||||||
{
|
{
|
||||||
// Tag this GameObject if it has a collider
|
return "Obstacle";
|
||||||
Collider2D col = current.GetComponent<Collider2D>();
|
|
||||||
if (col != null && !current.CompareTag("Obstacle"))
|
|
||||||
{
|
|
||||||
current.tag = "Obstacle";
|
|
||||||
Debug.Log($"[Obstacle] Tagged '{current.name}' as Obstacle");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurse to children
|
|
||||||
foreach (Transform child in current)
|
|
||||||
{
|
|
||||||
TagChildCollidersRecursive(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
/// <summary>
|
|
||||||
/// Called when values are changed in the Inspector (Editor only).
|
|
||||||
/// Updates EdgeAnchor configuration to match Obstacle settings.
|
|
||||||
/// Also finds and assigns ScreenReferenceMarker and CameraScreenAdapter for visual updates.
|
|
||||||
/// </summary>
|
|
||||||
private void OnValidate()
|
|
||||||
{
|
|
||||||
// Only run in editor, not during play mode
|
|
||||||
if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)
|
|
||||||
return;
|
|
||||||
|
|
||||||
EdgeAnchor anchor = GetComponent<EdgeAnchor>();
|
|
||||||
if (anchor != null)
|
|
||||||
{
|
|
||||||
// Auto-find and assign references if not set (for editor-time visual updates)
|
|
||||||
if (anchor.referenceMarker == null)
|
|
||||||
{
|
|
||||||
anchor.referenceMarker = FindAnyObjectByType<ScreenReferenceMarker>();
|
|
||||||
if (anchor.referenceMarker == null)
|
|
||||||
{
|
|
||||||
Debug.LogWarning("[Obstacle] No ScreenReferenceMarker found in scene. EdgeAnchor positioning won't work in editor.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (anchor.cameraAdapter == null)
|
|
||||||
{
|
|
||||||
anchor.cameraAdapter = FindAnyObjectByType<CameraScreenAdapter>();
|
|
||||||
// CameraScreenAdapter is optional - EdgeAnchor can auto-find camera
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate and set anchor edge
|
|
||||||
if (verticalAnchor == EdgeAnchor.AnchorEdge.Left || verticalAnchor == EdgeAnchor.AnchorEdge.Right)
|
|
||||||
{
|
|
||||||
Debug.LogWarning("[Obstacle] Invalid anchor edge (Left/Right not supported). Defaulting to Middle.");
|
|
||||||
verticalAnchor = EdgeAnchor.AnchorEdge.Middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure EdgeAnchor to match Obstacle settings
|
|
||||||
anchor.anchorEdge = verticalAnchor;
|
|
||||||
anchor.useReferenceMargin = false;
|
|
||||||
anchor.customMargin = 0f;
|
|
||||||
anchor.preserveOtherAxes = true;
|
|
||||||
anchor.accountForObjectSize = true;
|
|
||||||
|
|
||||||
// Mark as dirty so Unity saves the changes
|
|
||||||
UnityEditor.EditorUtility.SetDirty(anchor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tag all child GameObjects with colliders as "Obstacle" for collision detection
|
|
||||||
TagChildCollidersRecursiveEditor(transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Editor version of recursive tagging for child colliders.
|
|
||||||
/// </summary>
|
|
||||||
private void TagChildCollidersRecursiveEditor(Transform current)
|
|
||||||
{
|
|
||||||
// Tag this GameObject if it has a collider
|
|
||||||
Collider2D col = current.GetComponent<Collider2D>();
|
|
||||||
if (col != null && !current.CompareTag("Obstacle"))
|
|
||||||
{
|
|
||||||
current.tag = "Obstacle";
|
|
||||||
UnityEditor.EditorUtility.SetDirty(current.gameObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recurse to children
|
|
||||||
foreach (Transform child in current)
|
|
||||||
{
|
|
||||||
TagChildCollidersRecursiveEditor(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
if (!isInitialized || settings == null) return;
|
|
||||||
|
|
||||||
MoveLeft();
|
|
||||||
CheckBounds();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Move obstacle left at constant speed (manual movement, no physics).
|
|
||||||
/// </summary>
|
|
||||||
private void MoveLeft()
|
|
||||||
{
|
|
||||||
transform.position += Vector3.left * (settings.ObstacleMoveSpeed * Time.deltaTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check if obstacle has passed despawn position and destroy if so.
|
|
||||||
/// </summary>
|
|
||||||
private void CheckBounds()
|
|
||||||
{
|
|
||||||
if (transform.position.x < despawnXPosition)
|
|
||||||
{
|
|
||||||
Debug.Log($"[Obstacle] Reached despawn position, destroying at X: {transform.position.x}");
|
|
||||||
Destroy(gameObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
/// <summary>
|
|
||||||
/// Draw debug visualization of the obstacle's anchor point.
|
|
||||||
/// Red horizontal line through custom anchor point OR bounds edge (top/bottom).
|
|
||||||
/// </summary>
|
|
||||||
private void OnDrawGizmos()
|
|
||||||
{
|
|
||||||
EdgeAnchor anchor = GetComponent<EdgeAnchor>();
|
|
||||||
if (anchor == null) return;
|
|
||||||
|
|
||||||
// Determine what Y position to visualize
|
|
||||||
float visualY;
|
|
||||||
|
|
||||||
// If using custom anchor point, draw line through it
|
|
||||||
if (anchor.customAnchorPoint != null)
|
|
||||||
{
|
|
||||||
visualY = anchor.customAnchorPoint.position.y;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Get bounds and determine which edge to visualize
|
|
||||||
Bounds bounds = GetVisualBounds();
|
|
||||||
|
|
||||||
// Check which vertical anchor is configured
|
|
||||||
EdgeAnchor.AnchorEdge edge = anchor.anchorEdge;
|
|
||||||
|
|
||||||
if (edge == EdgeAnchor.AnchorEdge.Top)
|
|
||||||
{
|
|
||||||
// Show top edge of bounds
|
|
||||||
visualY = bounds.max.y;
|
|
||||||
}
|
|
||||||
else if (edge == EdgeAnchor.AnchorEdge.Bottom)
|
|
||||||
{
|
|
||||||
// Show bottom edge of bounds
|
|
||||||
visualY = bounds.min.y;
|
|
||||||
}
|
|
||||||
else // Middle
|
|
||||||
{
|
|
||||||
// Show center of bounds
|
|
||||||
visualY = bounds.center.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw thick red horizontal line through the anchor point
|
|
||||||
Color oldColor = Gizmos.color;
|
|
||||||
Gizmos.color = Color.red;
|
|
||||||
|
|
||||||
// Draw multiple lines to make it thicker
|
|
||||||
float lineLength = 2f; // Extend 2 units on each side
|
|
||||||
Vector3 leftPoint = new Vector3(transform.position.x - lineLength, visualY, transform.position.z);
|
|
||||||
Vector3 rightPoint = new Vector3(transform.position.x + lineLength, visualY, transform.position.z);
|
|
||||||
|
|
||||||
// Draw 5 lines stacked vertically to create thickness
|
|
||||||
for (int i = -2; i <= 2; i++)
|
|
||||||
{
|
|
||||||
float offset = i * 0.02f; // Small vertical offset for thickness
|
|
||||||
Vector3 offsetLeft = leftPoint + Vector3.up * offset;
|
|
||||||
Vector3 offsetRight = rightPoint + Vector3.up * offset;
|
|
||||||
Gizmos.DrawLine(offsetLeft, offsetRight);
|
|
||||||
}
|
|
||||||
|
|
||||||
Gizmos.color = oldColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get bounds for visualization purposes (works in editor without initialized settings).
|
|
||||||
/// </summary>
|
|
||||||
private Bounds GetVisualBounds()
|
|
||||||
{
|
|
||||||
// Get all renderers in this object and its children
|
|
||||||
Renderer[] renderers = GetComponentsInChildren<Renderer>();
|
|
||||||
|
|
||||||
if (renderers.Length > 0)
|
|
||||||
{
|
|
||||||
Bounds bounds = renderers[0].bounds;
|
|
||||||
for (int i = 1; i < renderers.Length; i++)
|
|
||||||
{
|
|
||||||
bounds.Encapsulate(renderers[i].bounds);
|
|
||||||
}
|
|
||||||
return bounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to collider bounds
|
|
||||||
Collider2D col = GetComponent<Collider2D>();
|
|
||||||
if (col != null)
|
|
||||||
{
|
|
||||||
return col.bounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default small bounds
|
|
||||||
return new Bounds(transform.position, new Vector3(0.5f, 0.5f, 0.1f));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
300
Assets/Scripts/Minigames/BirdPooper/Obstacle.cs.backup
Normal file
300
Assets/Scripts/Minigames/BirdPooper/Obstacle.cs.backup
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using Core;
|
||||||
|
using Core.Settings;
|
||||||
|
using AppleHillsCamera;
|
||||||
|
|
||||||
|
namespace Minigames.BirdPooper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Individual obstacle behavior for Bird Pooper minigame.
|
||||||
|
/// Scrolls left at constant speed and self-destructs when reaching despawn position.
|
||||||
|
/// Uses trigger colliders for collision detection (no Rigidbody2D needed).
|
||||||
|
/// Uses EdgeAnchor for vertical positioning (Top/Middle/Bottom).
|
||||||
|
/// </summary>
|
||||||
|
[RequireComponent(typeof(Collider2D))]
|
||||||
|
[RequireComponent(typeof(EdgeAnchor))]
|
||||||
|
public class Obstacle : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Header("Positioning")]
|
||||||
|
[Tooltip("Which vertical edge to anchor to (Top/Middle/Bottom)")]
|
||||||
|
[SerializeField] private EdgeAnchor.AnchorEdge verticalAnchor = EdgeAnchor.AnchorEdge.Middle;
|
||||||
|
|
||||||
|
private IBirdPooperSettings settings;
|
||||||
|
private float despawnXPosition;
|
||||||
|
private bool isInitialized;
|
||||||
|
private EdgeAnchor edgeAnchor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize the obstacle with despawn position and EdgeAnchor references.
|
||||||
|
/// Called by ObstacleSpawner immediately after instantiation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="despawnX">X position where obstacle should be destroyed</param>
|
||||||
|
/// <param name="referenceMarker">ScreenReferenceMarker for EdgeAnchor</param>
|
||||||
|
/// <param name="cameraAdapter">CameraScreenAdapter for EdgeAnchor</param>
|
||||||
|
public void Initialize(float despawnX, ScreenReferenceMarker referenceMarker, CameraScreenAdapter cameraAdapter)
|
||||||
|
{
|
||||||
|
despawnXPosition = despawnX;
|
||||||
|
isInitialized = true;
|
||||||
|
|
||||||
|
// Load settings
|
||||||
|
settings = GameManager.GetSettingsObject<IBirdPooperSettings>();
|
||||||
|
if (settings == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("[Obstacle] BirdPooperSettings not found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag all child GameObjects with colliders as "Obstacle" for trigger detection
|
||||||
|
TagChildCollidersRecursive(transform);
|
||||||
|
|
||||||
|
// Configure and update EdgeAnchor
|
||||||
|
edgeAnchor = GetComponent<EdgeAnchor>();
|
||||||
|
if (edgeAnchor != null)
|
||||||
|
{
|
||||||
|
// Assign references from spawner
|
||||||
|
edgeAnchor.referenceMarker = referenceMarker;
|
||||||
|
edgeAnchor.cameraAdapter = cameraAdapter;
|
||||||
|
|
||||||
|
// Only allow Top, Middle, or Bottom anchoring
|
||||||
|
if (verticalAnchor == EdgeAnchor.AnchorEdge.Left || verticalAnchor == EdgeAnchor.AnchorEdge.Right)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[Obstacle] Invalid anchor edge (Left/Right not supported). Defaulting to Middle.");
|
||||||
|
verticalAnchor = EdgeAnchor.AnchorEdge.Middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
edgeAnchor.anchorEdge = verticalAnchor;
|
||||||
|
edgeAnchor.useReferenceMargin = false; // No custom offset
|
||||||
|
edgeAnchor.customMargin = 0f;
|
||||||
|
edgeAnchor.preserveOtherAxes = true; // Keep X position (for scrolling)
|
||||||
|
edgeAnchor.accountForObjectSize = true;
|
||||||
|
|
||||||
|
// Trigger position update
|
||||||
|
edgeAnchor.UpdatePosition();
|
||||||
|
|
||||||
|
Debug.Log($"[Obstacle] EdgeAnchor configured to {verticalAnchor} at position {transform.position}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError("[Obstacle] EdgeAnchor component not found! Make sure the prefab has an EdgeAnchor component.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"[Obstacle] Initialized at position {transform.position} with despawn X: {despawnX}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Recursively tag all GameObjects with Collider2D as "Obstacle" for player collision detection.
|
||||||
|
/// </summary>
|
||||||
|
private void TagChildCollidersRecursive(Transform current)
|
||||||
|
{
|
||||||
|
// Tag this GameObject if it has a collider
|
||||||
|
Collider2D col = current.GetComponent<Collider2D>();
|
||||||
|
if (col != null && !current.CompareTag("Obstacle"))
|
||||||
|
{
|
||||||
|
current.tag = "Obstacle";
|
||||||
|
Debug.Log($"[Obstacle] Tagged '{current.name}' as Obstacle");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recurse to children
|
||||||
|
foreach (Transform child in current)
|
||||||
|
{
|
||||||
|
TagChildCollidersRecursive(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
/// <summary>
|
||||||
|
/// Called when values are changed in the Inspector (Editor only).
|
||||||
|
/// Updates EdgeAnchor configuration to match Obstacle settings.
|
||||||
|
/// Also finds and assigns ScreenReferenceMarker and CameraScreenAdapter for visual updates.
|
||||||
|
/// </summary>
|
||||||
|
private void OnValidate()
|
||||||
|
{
|
||||||
|
// Only run in editor, not during play mode
|
||||||
|
if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EdgeAnchor anchor = GetComponent<EdgeAnchor>();
|
||||||
|
if (anchor != null)
|
||||||
|
{
|
||||||
|
// Auto-find and assign references if not set (for editor-time visual updates)
|
||||||
|
if (anchor.referenceMarker == null)
|
||||||
|
{
|
||||||
|
anchor.referenceMarker = FindAnyObjectByType<ScreenReferenceMarker>();
|
||||||
|
if (anchor.referenceMarker == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[Obstacle] No ScreenReferenceMarker found in scene. EdgeAnchor positioning won't work in editor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anchor.cameraAdapter == null)
|
||||||
|
{
|
||||||
|
anchor.cameraAdapter = FindAnyObjectByType<CameraScreenAdapter>();
|
||||||
|
// CameraScreenAdapter is optional - EdgeAnchor can auto-find camera
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate and set anchor edge
|
||||||
|
if (verticalAnchor == EdgeAnchor.AnchorEdge.Left || verticalAnchor == EdgeAnchor.AnchorEdge.Right)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[Obstacle] Invalid anchor edge (Left/Right not supported). Defaulting to Middle.");
|
||||||
|
verticalAnchor = EdgeAnchor.AnchorEdge.Middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure EdgeAnchor to match Obstacle settings
|
||||||
|
anchor.anchorEdge = verticalAnchor;
|
||||||
|
anchor.useReferenceMargin = false;
|
||||||
|
anchor.customMargin = 0f;
|
||||||
|
anchor.preserveOtherAxes = true;
|
||||||
|
anchor.accountForObjectSize = true;
|
||||||
|
|
||||||
|
// Mark as dirty so Unity saves the changes
|
||||||
|
UnityEditor.EditorUtility.SetDirty(anchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag all child GameObjects with colliders as "Obstacle" for collision detection
|
||||||
|
TagChildCollidersRecursiveEditor(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Editor version of recursive tagging for child colliders.
|
||||||
|
/// </summary>
|
||||||
|
private void TagChildCollidersRecursiveEditor(Transform current)
|
||||||
|
{
|
||||||
|
// Tag this GameObject if it has a collider
|
||||||
|
Collider2D col = current.GetComponent<Collider2D>();
|
||||||
|
if (col != null && !current.CompareTag("Obstacle"))
|
||||||
|
{
|
||||||
|
current.tag = "Obstacle";
|
||||||
|
UnityEditor.EditorUtility.SetDirty(current.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recurse to children
|
||||||
|
foreach (Transform child in current)
|
||||||
|
{
|
||||||
|
TagChildCollidersRecursiveEditor(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
if (!isInitialized || settings == null) return;
|
||||||
|
|
||||||
|
MoveLeft();
|
||||||
|
CheckBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Move obstacle left at constant speed (manual movement, no physics).
|
||||||
|
/// </summary>
|
||||||
|
private void MoveLeft()
|
||||||
|
{
|
||||||
|
transform.position += Vector3.left * (settings.ObstacleMoveSpeed * Time.deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if obstacle has passed despawn position and destroy if so.
|
||||||
|
/// </summary>
|
||||||
|
private void CheckBounds()
|
||||||
|
{
|
||||||
|
if (transform.position.x < despawnXPosition)
|
||||||
|
{
|
||||||
|
Debug.Log($"[Obstacle] Reached despawn position, destroying at X: {transform.position.x}");
|
||||||
|
Destroy(gameObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
/// <summary>
|
||||||
|
/// Draw debug visualization of the obstacle's anchor point.
|
||||||
|
/// Red horizontal line through custom anchor point OR bounds edge (top/bottom).
|
||||||
|
/// </summary>
|
||||||
|
private void OnDrawGizmos()
|
||||||
|
{
|
||||||
|
EdgeAnchor anchor = GetComponent<EdgeAnchor>();
|
||||||
|
if (anchor == null) return;
|
||||||
|
|
||||||
|
// Determine what Y position to visualize
|
||||||
|
float visualY;
|
||||||
|
|
||||||
|
// If using custom anchor point, draw line through it
|
||||||
|
if (anchor.customAnchorPoint != null)
|
||||||
|
{
|
||||||
|
visualY = anchor.customAnchorPoint.position.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Get bounds and determine which edge to visualize
|
||||||
|
Bounds bounds = GetVisualBounds();
|
||||||
|
|
||||||
|
// Check which vertical anchor is configured
|
||||||
|
EdgeAnchor.AnchorEdge edge = anchor.anchorEdge;
|
||||||
|
|
||||||
|
if (edge == EdgeAnchor.AnchorEdge.Top)
|
||||||
|
{
|
||||||
|
// Show top edge of bounds
|
||||||
|
visualY = bounds.max.y;
|
||||||
|
}
|
||||||
|
else if (edge == EdgeAnchor.AnchorEdge.Bottom)
|
||||||
|
{
|
||||||
|
// Show bottom edge of bounds
|
||||||
|
visualY = bounds.min.y;
|
||||||
|
}
|
||||||
|
else // Middle
|
||||||
|
{
|
||||||
|
// Show center of bounds
|
||||||
|
visualY = bounds.center.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw thick red horizontal line through the anchor point
|
||||||
|
Color oldColor = Gizmos.color;
|
||||||
|
Gizmos.color = Color.red;
|
||||||
|
|
||||||
|
// Draw multiple lines to make it thicker
|
||||||
|
float lineLength = 2f; // Extend 2 units on each side
|
||||||
|
Vector3 leftPoint = new Vector3(transform.position.x - lineLength, visualY, transform.position.z);
|
||||||
|
Vector3 rightPoint = new Vector3(transform.position.x + lineLength, visualY, transform.position.z);
|
||||||
|
|
||||||
|
// Draw 5 lines stacked vertically to create thickness
|
||||||
|
for (int i = -2; i <= 2; i++)
|
||||||
|
{
|
||||||
|
float offset = i * 0.02f; // Small vertical offset for thickness
|
||||||
|
Vector3 offsetLeft = leftPoint + Vector3.up * offset;
|
||||||
|
Vector3 offsetRight = rightPoint + Vector3.up * offset;
|
||||||
|
Gizmos.DrawLine(offsetLeft, offsetRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gizmos.color = oldColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get bounds for visualization purposes (works in editor without initialized settings).
|
||||||
|
/// </summary>
|
||||||
|
private Bounds GetVisualBounds()
|
||||||
|
{
|
||||||
|
// Get all renderers in this object and its children
|
||||||
|
Renderer[] renderers = GetComponentsInChildren<Renderer>();
|
||||||
|
|
||||||
|
if (renderers.Length > 0)
|
||||||
|
{
|
||||||
|
Bounds bounds = renderers[0].bounds;
|
||||||
|
for (int i = 1; i < renderers.Length; i++)
|
||||||
|
{
|
||||||
|
bounds.Encapsulate(renderers[i].bounds);
|
||||||
|
}
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to collider bounds
|
||||||
|
Collider2D col = GetComponent<Collider2D>();
|
||||||
|
if (col != null)
|
||||||
|
{
|
||||||
|
return col.bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default small bounds
|
||||||
|
return new Bounds(transform.position, new Vector3(0.5f, 0.5f, 0.1f));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bc9c7bac4482311439b4c2e7879f3d73
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -21,6 +21,12 @@ namespace Minigames.BirdPooper
|
|||||||
{
|
{
|
||||||
base.OnManagedAwake();
|
base.OnManagedAwake();
|
||||||
|
|
||||||
|
// Tag as Projectile for target detection
|
||||||
|
if (!gameObject.CompareTag("Projectile"))
|
||||||
|
{
|
||||||
|
gameObject.tag = "Projectile";
|
||||||
|
}
|
||||||
|
|
||||||
// Load settings
|
// Load settings
|
||||||
settings = GameManager.GetSettingsObject<IBirdPooperSettings>();
|
settings = GameManager.GetSettingsObject<IBirdPooperSettings>();
|
||||||
if (settings == null)
|
if (settings == null)
|
||||||
@@ -37,16 +43,19 @@ namespace Minigames.BirdPooper
|
|||||||
Rigidbody2D rb = GetComponent<Rigidbody2D>();
|
Rigidbody2D rb = GetComponent<Rigidbody2D>();
|
||||||
if (rb != null)
|
if (rb != null)
|
||||||
{
|
{
|
||||||
rb.bodyType = RigidbodyType2D.Dynamic;
|
rb.bodyType = RigidbodyType2D.Kinematic; // Kinematic = manual control, no physics
|
||||||
rb.gravityScale = 0f; // Manual gravity
|
|
||||||
rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
|
rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify collider is trigger (for target detection in Phase 5)
|
// Find and set all colliders to trigger (we use OnTriggerEnter2D)
|
||||||
Collider2D col = GetComponent<Collider2D>();
|
Collider2D[] colliders = GetComponentsInChildren<Collider2D>(true);
|
||||||
if (col != null && !col.isTrigger)
|
foreach (Collider2D col in colliders)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[PoopProjectile] Collider should be set as Trigger for target detection!");
|
if (!col.isTrigger)
|
||||||
|
{
|
||||||
|
col.isTrigger = true;
|
||||||
|
Debug.Log($"[PoopProjectile] Set collider '{col.name}' to trigger");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,12 +100,10 @@ namespace Minigames.BirdPooper
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Trigger collision detection for targets (Phase 5).
|
/// Trigger collision detection for targets (Phase 5).
|
||||||
/// TODO: Uncomment when Target.cs is implemented in Phase 5
|
/// Uses OnTriggerEnter2D with trigger collider.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnTriggerEnter2D(Collider2D other)
|
private void OnTriggerEnter2D(Collider2D other)
|
||||||
{
|
{
|
||||||
// Phase 5 integration - currently commented out
|
|
||||||
/*
|
|
||||||
if (other.CompareTag("Target"))
|
if (other.CompareTag("Target"))
|
||||||
{
|
{
|
||||||
// Notify target it was hit
|
// Notify target it was hit
|
||||||
@@ -108,7 +115,6 @@ namespace Minigames.BirdPooper
|
|||||||
|
|
||||||
Destroy(gameObject);
|
Destroy(gameObject);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
230
Assets/Scripts/Minigames/BirdPooper/ScrollingEntity.cs
Normal file
230
Assets/Scripts/Minigames/BirdPooper/ScrollingEntity.cs
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using Core;
|
||||||
|
using Core.Settings;
|
||||||
|
using AppleHillsCamera;
|
||||||
|
|
||||||
|
namespace Minigames.BirdPooper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract base class for all scrolling entities in Bird Pooper minigame.
|
||||||
|
/// Provides common functionality: manual left-scrolling, EdgeAnchor integration, despawn detection.
|
||||||
|
/// Subclasses: Obstacle, Target
|
||||||
|
/// </summary>
|
||||||
|
[RequireComponent(typeof(Collider2D))]
|
||||||
|
[RequireComponent(typeof(EdgeAnchor))]
|
||||||
|
public abstract class ScrollingEntity : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Header("Positioning")]
|
||||||
|
[Tooltip("Which vertical edge to anchor to (Top/Middle/Bottom)")]
|
||||||
|
[SerializeField] protected EdgeAnchor.AnchorEdge verticalAnchor = EdgeAnchor.AnchorEdge.Middle;
|
||||||
|
|
||||||
|
protected IBirdPooperSettings settings;
|
||||||
|
protected float despawnXPosition;
|
||||||
|
protected bool isInitialized;
|
||||||
|
protected EdgeAnchor edgeAnchor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize the entity with despawn position and EdgeAnchor references.
|
||||||
|
/// Called by spawner immediately after instantiation.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Initialize(float despawnX, ScreenReferenceMarker referenceMarker, CameraScreenAdapter cameraAdapter)
|
||||||
|
{
|
||||||
|
despawnXPosition = despawnX;
|
||||||
|
isInitialized = true;
|
||||||
|
|
||||||
|
// Load settings
|
||||||
|
settings = GameManager.GetSettingsObject<IBirdPooperSettings>();
|
||||||
|
if (settings == null)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[{GetType().Name}] BirdPooperSettings not found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag all child GameObjects with colliders
|
||||||
|
TagChildCollidersRecursive(transform);
|
||||||
|
|
||||||
|
// Find and set all colliders to trigger (we use OnTriggerEnter2D)
|
||||||
|
Collider2D[] colliders = GetComponentsInChildren<Collider2D>(true);
|
||||||
|
foreach (Collider2D col in colliders)
|
||||||
|
{
|
||||||
|
if (!col.isTrigger)
|
||||||
|
{
|
||||||
|
col.isTrigger = true;
|
||||||
|
Debug.Log($"[{GetType().Name}] Set collider '{col.name}' to trigger");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure and update EdgeAnchor
|
||||||
|
edgeAnchor = GetComponent<EdgeAnchor>();
|
||||||
|
if (edgeAnchor != null)
|
||||||
|
{
|
||||||
|
// Assign references from spawner
|
||||||
|
edgeAnchor.referenceMarker = referenceMarker;
|
||||||
|
edgeAnchor.cameraAdapter = cameraAdapter;
|
||||||
|
|
||||||
|
// Only allow Top, Middle, or Bottom anchoring
|
||||||
|
if (verticalAnchor == EdgeAnchor.AnchorEdge.Left || verticalAnchor == EdgeAnchor.AnchorEdge.Right)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[{GetType().Name}] Invalid anchor edge (Left/Right not supported). Defaulting to Middle.");
|
||||||
|
verticalAnchor = EdgeAnchor.AnchorEdge.Middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
edgeAnchor.anchorEdge = verticalAnchor;
|
||||||
|
edgeAnchor.useReferenceMargin = false; // No custom offset
|
||||||
|
edgeAnchor.customMargin = 0f;
|
||||||
|
edgeAnchor.preserveOtherAxes = true; // Keep X position (for scrolling)
|
||||||
|
edgeAnchor.accountForObjectSize = true;
|
||||||
|
|
||||||
|
// Trigger position update
|
||||||
|
edgeAnchor.UpdatePosition();
|
||||||
|
|
||||||
|
Debug.Log($"[{GetType().Name}] EdgeAnchor configured to {verticalAnchor} at position {transform.position}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError($"[{GetType().Name}] EdgeAnchor component not found! Make sure the prefab has an EdgeAnchor component.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"[{GetType().Name}] Initialized at position {transform.position} with despawn X: {despawnX}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Recursively tag all GameObjects with Collider2D for collision detection.
|
||||||
|
/// Subclasses override GetColliderTag() to specify their tag.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void TagChildCollidersRecursive(Transform current)
|
||||||
|
{
|
||||||
|
string tagToApply = GetColliderTag();
|
||||||
|
|
||||||
|
// Tag this GameObject if it has a collider
|
||||||
|
Collider2D col = current.GetComponent<Collider2D>();
|
||||||
|
if (col != null && !current.CompareTag(tagToApply))
|
||||||
|
{
|
||||||
|
current.tag = tagToApply;
|
||||||
|
Debug.Log($"[{GetType().Name}] Tagged '{current.name}' as {tagToApply}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recurse to children
|
||||||
|
foreach (Transform child in current)
|
||||||
|
{
|
||||||
|
TagChildCollidersRecursive(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
/// <summary>
|
||||||
|
/// Called when values are changed in the Inspector (Editor only).
|
||||||
|
/// Updates EdgeAnchor configuration to match entity settings.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnValidate()
|
||||||
|
{
|
||||||
|
// Only run in editor, not during play mode
|
||||||
|
if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EdgeAnchor anchor = GetComponent<EdgeAnchor>();
|
||||||
|
if (anchor != null)
|
||||||
|
{
|
||||||
|
// Auto-find and assign references if not set (for editor-time visual updates)
|
||||||
|
if (anchor.referenceMarker == null)
|
||||||
|
{
|
||||||
|
anchor.referenceMarker = FindAnyObjectByType<ScreenReferenceMarker>();
|
||||||
|
if (anchor.referenceMarker == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[{GetType().Name}] No ScreenReferenceMarker found in scene. EdgeAnchor positioning won't work in editor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anchor.cameraAdapter == null)
|
||||||
|
{
|
||||||
|
anchor.cameraAdapter = FindAnyObjectByType<CameraScreenAdapter>();
|
||||||
|
// CameraScreenAdapter is optional - EdgeAnchor can auto-find camera
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate and set anchor edge
|
||||||
|
if (verticalAnchor == EdgeAnchor.AnchorEdge.Left || verticalAnchor == EdgeAnchor.AnchorEdge.Right)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[{GetType().Name}] Invalid anchor edge (Left/Right not supported). Defaulting to Middle.");
|
||||||
|
verticalAnchor = EdgeAnchor.AnchorEdge.Middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure EdgeAnchor to match entity settings
|
||||||
|
anchor.anchorEdge = verticalAnchor;
|
||||||
|
anchor.useReferenceMargin = false;
|
||||||
|
anchor.customMargin = 0f;
|
||||||
|
anchor.preserveOtherAxes = true;
|
||||||
|
anchor.accountForObjectSize = true;
|
||||||
|
|
||||||
|
// Mark as dirty so Unity saves the changes
|
||||||
|
UnityEditor.EditorUtility.SetDirty(anchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag all child GameObjects with colliders
|
||||||
|
TagChildCollidersRecursiveEditor(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Editor version of recursive tagging for child colliders.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void TagChildCollidersRecursiveEditor(Transform current)
|
||||||
|
{
|
||||||
|
string tagToApply = GetColliderTag();
|
||||||
|
|
||||||
|
// Tag this GameObject if it has a collider
|
||||||
|
Collider2D col = current.GetComponent<Collider2D>();
|
||||||
|
if (col != null && !current.CompareTag(tagToApply))
|
||||||
|
{
|
||||||
|
current.tag = tagToApply;
|
||||||
|
UnityEditor.EditorUtility.SetDirty(current.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recurse to children
|
||||||
|
foreach (Transform child in current)
|
||||||
|
{
|
||||||
|
TagChildCollidersRecursiveEditor(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected virtual void Update()
|
||||||
|
{
|
||||||
|
if (!isInitialized || settings == null) return;
|
||||||
|
|
||||||
|
MoveLeft();
|
||||||
|
CheckBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Move entity left at constant speed (manual movement, no physics).
|
||||||
|
/// Override GetMoveSpeed() to customize speed per entity type.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void MoveLeft()
|
||||||
|
{
|
||||||
|
transform.position += Vector3.left * (GetMoveSpeed() * Time.deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if entity has passed despawn position and destroy if so.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void CheckBounds()
|
||||||
|
{
|
||||||
|
if (transform.position.x < despawnXPosition)
|
||||||
|
{
|
||||||
|
Debug.Log($"[{GetType().Name}] Reached despawn position, destroying at X: {transform.position.x}");
|
||||||
|
Destroy(gameObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the move speed for this entity type.
|
||||||
|
/// Subclasses override to return appropriate speed from settings.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract float GetMoveSpeed();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the tag to apply to colliders for this entity type.
|
||||||
|
/// Subclasses override to return "Obstacle", "Target", etc.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract string GetColliderTag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 69a3d32fc5cf4789a5e6e8dbc5f64996
|
||||||
|
timeCreated: 1763713709
|
||||||
117
Assets/Scripts/Minigames/BirdPooper/Target.cs
Normal file
117
Assets/Scripts/Minigames/BirdPooper/Target.cs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using AppleHillsCamera;
|
||||||
|
|
||||||
|
namespace Minigames.BirdPooper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Target entity for Bird Pooper minigame.
|
||||||
|
/// Inherits scrolling, anchoring, and despawn behavior from ScrollingEntity.
|
||||||
|
/// Can be hit by poop projectiles for scoring. Player still dies on collision.
|
||||||
|
/// </summary>
|
||||||
|
public class Target : ScrollingEntity
|
||||||
|
{
|
||||||
|
[Header("Visual Feedback")]
|
||||||
|
[SerializeField] private SpriteRenderer spriteRenderer;
|
||||||
|
[SerializeField] private Color hitColor = Color.green;
|
||||||
|
|
||||||
|
[Header("Events")]
|
||||||
|
public UnityEvent onTargetHit;
|
||||||
|
|
||||||
|
private bool isHit;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize target and set up event.
|
||||||
|
/// </summary>
|
||||||
|
public override void Initialize(float despawnX, ScreenReferenceMarker referenceMarker, CameraScreenAdapter cameraAdapter)
|
||||||
|
{
|
||||||
|
base.Initialize(despawnX, referenceMarker, cameraAdapter);
|
||||||
|
|
||||||
|
isHit = false;
|
||||||
|
|
||||||
|
// Initialize event
|
||||||
|
if (onTargetHit == null)
|
||||||
|
{
|
||||||
|
onTargetHit = new UnityEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find and set all colliders to trigger (we use OnTriggerEnter2D)
|
||||||
|
Collider2D[] colliders = GetComponentsInChildren<Collider2D>(true);
|
||||||
|
foreach (Collider2D col in colliders)
|
||||||
|
{
|
||||||
|
if (!col.isTrigger)
|
||||||
|
{
|
||||||
|
col.isTrigger = true;
|
||||||
|
Debug.Log($"[Target] Set collider '{col.name}' to trigger");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Override Update to stop movement when hit.
|
||||||
|
/// </summary>
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
if (isHit) return; // Don't move or check bounds if hit
|
||||||
|
|
||||||
|
base.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns target move speed from settings.
|
||||||
|
/// </summary>
|
||||||
|
protected override float GetMoveSpeed()
|
||||||
|
{
|
||||||
|
return settings != null ? settings.TargetMoveSpeed : 4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns "Target" tag for collision detection.
|
||||||
|
/// </summary>
|
||||||
|
protected override string GetColliderTag()
|
||||||
|
{
|
||||||
|
return "Target";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Trigger collision detection for both player and projectiles.
|
||||||
|
/// Single trigger collider handles both cases.
|
||||||
|
/// </summary>
|
||||||
|
private void OnTriggerEnter2D(Collider2D other)
|
||||||
|
{
|
||||||
|
// Check for projectile collision
|
||||||
|
if (other.CompareTag("Projectile") && !isHit)
|
||||||
|
{
|
||||||
|
OnHitByProjectile();
|
||||||
|
}
|
||||||
|
// Player collision is handled by BirdPlayerController's OnTriggerEnter2D
|
||||||
|
// (both have trigger colliders, so trigger occurs naturally)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when target is hit by a poop projectile.
|
||||||
|
/// Shows visual feedback and notifies manager.
|
||||||
|
/// </summary>
|
||||||
|
public void OnHitByProjectile()
|
||||||
|
{
|
||||||
|
if (isHit) return;
|
||||||
|
|
||||||
|
isHit = true;
|
||||||
|
|
||||||
|
// Visual feedback
|
||||||
|
if (spriteRenderer != null)
|
||||||
|
{
|
||||||
|
spriteRenderer.color = hitColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify manager
|
||||||
|
onTargetHit?.Invoke();
|
||||||
|
|
||||||
|
Debug.Log($"[Target] Hit by projectile at position {transform.position}");
|
||||||
|
|
||||||
|
// Destroy after brief delay for visual feedback
|
||||||
|
Destroy(gameObject, 0.2f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
3
Assets/Scripts/Minigames/BirdPooper/Target.cs.meta
Normal file
3
Assets/Scripts/Minigames/BirdPooper/Target.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5331a770bc634a738b82f9450441de12
|
||||||
|
timeCreated: 1763713776
|
||||||
198
Assets/Scripts/Minigames/BirdPooper/TargetSpawner.cs
Normal file
198
Assets/Scripts/Minigames/BirdPooper/TargetSpawner.cs
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using Core;
|
||||||
|
using Core.Settings;
|
||||||
|
using Core.Lifecycle;
|
||||||
|
using AppleHillsCamera;
|
||||||
|
|
||||||
|
namespace Minigames.BirdPooper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Spawns targets at regular intervals for Bird Pooper minigame.
|
||||||
|
/// Uses Transform references for spawn and despawn positions.
|
||||||
|
/// All targets are spawned at Y = 0 (EdgeAnchor positions them vertically).
|
||||||
|
/// </summary>
|
||||||
|
public class TargetSpawner : ManagedBehaviour
|
||||||
|
{
|
||||||
|
[Header("Spawn Configuration")]
|
||||||
|
[Tooltip("Transform marking where targets spawn (off-screen right)")]
|
||||||
|
[SerializeField] private Transform spawnPoint;
|
||||||
|
|
||||||
|
[Tooltip("Transform marking where targets despawn (off-screen left)")]
|
||||||
|
[SerializeField] private Transform despawnPoint;
|
||||||
|
|
||||||
|
[Header("EdgeAnchor References")]
|
||||||
|
[Tooltip("ScreenReferenceMarker to pass to spawned targets")]
|
||||||
|
[SerializeField] private ScreenReferenceMarker referenceMarker;
|
||||||
|
|
||||||
|
[Tooltip("CameraScreenAdapter to pass to spawned targets")]
|
||||||
|
[SerializeField] private CameraScreenAdapter cameraAdapter;
|
||||||
|
|
||||||
|
[Header("Target Prefabs")]
|
||||||
|
[Tooltip("Array of target prefabs to spawn randomly")]
|
||||||
|
[SerializeField] private GameObject[] targetPrefabs;
|
||||||
|
|
||||||
|
private IBirdPooperSettings settings;
|
||||||
|
private float spawnTimer;
|
||||||
|
private bool isSpawning;
|
||||||
|
|
||||||
|
internal override void OnManagedAwake()
|
||||||
|
{
|
||||||
|
base.OnManagedAwake();
|
||||||
|
|
||||||
|
// Load settings
|
||||||
|
settings = GameManager.GetSettingsObject<IBirdPooperSettings>();
|
||||||
|
if (settings == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("[TargetSpawner] BirdPooperSettings not found!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate references
|
||||||
|
if (spawnPoint == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("[TargetSpawner] Spawn Point not assigned! Please assign a Transform in the Inspector.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (despawnPoint == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("[TargetSpawner] Despawn Point not assigned! Please assign a Transform in the Inspector.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetPrefabs == null || targetPrefabs.Length == 0)
|
||||||
|
{
|
||||||
|
Debug.LogError("[TargetSpawner] No target prefabs assigned! Please assign at least one prefab in the Inspector.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (referenceMarker == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("[TargetSpawner] ScreenReferenceMarker not assigned! Targets need this for EdgeAnchor positioning.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cameraAdapter == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[TargetSpawner] CameraScreenAdapter not assigned. EdgeAnchor will attempt to auto-find camera.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log("[TargetSpawner] Initialized successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
if (!isSpawning || settings == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spawnTimer += Time.deltaTime;
|
||||||
|
|
||||||
|
if (spawnTimer >= settings.TargetSpawnInterval)
|
||||||
|
{
|
||||||
|
SpawnTarget();
|
||||||
|
spawnTimer = 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Spawns a random target prefab at the spawn point.
|
||||||
|
/// Target is spawned at Y = 0, EdgeAnchor will position it vertically.
|
||||||
|
/// </summary>
|
||||||
|
private void SpawnTarget()
|
||||||
|
{
|
||||||
|
if (targetPrefabs == null || targetPrefabs.Length == 0 || spawnPoint == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("[TargetSpawner] Cannot spawn target - missing prefabs or spawn point!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Randomly select target prefab
|
||||||
|
GameObject prefab = targetPrefabs[Random.Range(0, targetPrefabs.Length)];
|
||||||
|
|
||||||
|
// Spawn at spawn point X, but Y = 0 (EdgeAnchor will position vertically)
|
||||||
|
Vector3 spawnPosition = new Vector3(spawnPoint.position.x, 0f, 0f);
|
||||||
|
GameObject targetObj = Instantiate(prefab, spawnPosition, Quaternion.identity);
|
||||||
|
|
||||||
|
// Initialize target
|
||||||
|
Target target = targetObj.GetComponent<Target>();
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
float despawnX = despawnPoint != null ? despawnPoint.position.x : -12f;
|
||||||
|
target.Initialize(despawnX, referenceMarker, cameraAdapter);
|
||||||
|
|
||||||
|
// Subscribe to target hit event to notify manager
|
||||||
|
target.onTargetHit.AddListener(OnTargetHit);
|
||||||
|
|
||||||
|
Debug.Log($"[TargetSpawner] Spawned target at {spawnPosition}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError($"[TargetSpawner] Spawned prefab '{prefab.name}' does not have Target component!");
|
||||||
|
Destroy(targetObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a target is hit by a projectile.
|
||||||
|
/// Notifies the game manager for score tracking.
|
||||||
|
/// </summary>
|
||||||
|
private void OnTargetHit()
|
||||||
|
{
|
||||||
|
// Find and notify manager
|
||||||
|
BirdPooperGameManager manager = BirdPooperGameManager.Instance;
|
||||||
|
if (manager != null)
|
||||||
|
{
|
||||||
|
manager.OnTargetHit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[TargetSpawner] BirdPooperGameManager not found!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start spawning targets at regular intervals.
|
||||||
|
/// </summary>
|
||||||
|
public void StartSpawning()
|
||||||
|
{
|
||||||
|
isSpawning = true;
|
||||||
|
spawnTimer = 0f;
|
||||||
|
Debug.Log("[TargetSpawner] Started spawning targets");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stop spawning new targets (existing targets continue).
|
||||||
|
/// </summary>
|
||||||
|
public void StopSpawning()
|
||||||
|
{
|
||||||
|
isSpawning = false;
|
||||||
|
Debug.Log("[TargetSpawner] Stopped spawning targets");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if spawner is currently spawning.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSpawning => isSpawning;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draw gizmos to visualize spawn and despawn points in the editor.
|
||||||
|
/// </summary>
|
||||||
|
private void OnDrawGizmos()
|
||||||
|
{
|
||||||
|
if (spawnPoint != null)
|
||||||
|
{
|
||||||
|
Gizmos.color = Color.cyan;
|
||||||
|
Gizmos.DrawLine(
|
||||||
|
new Vector3(spawnPoint.position.x, -10f, 0f),
|
||||||
|
new Vector3(spawnPoint.position.x, 10f, 0f)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (despawnPoint != null)
|
||||||
|
{
|
||||||
|
Gizmos.color = Color.magenta;
|
||||||
|
Gizmos.DrawLine(
|
||||||
|
new Vector3(despawnPoint.position.x, -10f, 0f),
|
||||||
|
new Vector3(despawnPoint.position.x, 10f, 0f)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 16beae843b5f431f9256a56aab02b53d
|
||||||
|
timeCreated: 1763713803
|
||||||
@@ -8,6 +8,8 @@ TagManager:
|
|||||||
- Pulver
|
- Pulver
|
||||||
- Rock
|
- Rock
|
||||||
- Obstacle
|
- Obstacle
|
||||||
|
- Projectile
|
||||||
|
- Target
|
||||||
layers:
|
layers:
|
||||||
- Default
|
- Default
|
||||||
- TransparentFX
|
- TransparentFX
|
||||||
|
|||||||
Reference in New Issue
Block a user