diff --git a/Assets/Prefabs/Minigames/BirdPoop/Poop.prefab b/Assets/Prefabs/Minigames/BirdPoop/Poop.prefab index e948e930..924b39f0 100644 --- a/Assets/Prefabs/Minigames/BirdPoop/Poop.prefab +++ b/Assets/Prefabs/Minigames/BirdPoop/Poop.prefab @@ -15,7 +15,7 @@ GameObject: - component: {fileID: 4086097097060867018} m_Layer: 0 m_Name: Poop - m_TagString: Untagged + m_TagString: Projectile m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 @@ -150,7 +150,7 @@ BoxCollider2D: m_CallbackLayers: serializedVersion: 2 m_Bits: 4294967295 - m_IsTrigger: 0 + m_IsTrigger: 1 m_UsedByEffector: 0 m_CompositeOperation: 0 m_CompositeOrder: 0 diff --git a/Assets/Prefabs/Minigames/BirdPoop/Targets.meta b/Assets/Prefabs/Minigames/BirdPoop/Targets.meta new file mode 100644 index 00000000..54c708b6 --- /dev/null +++ b/Assets/Prefabs/Minigames/BirdPoop/Targets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dbcdce294136cfa4aa1091cf3ff03bcf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Minigames/BirdPoop/Targets/Target.prefab b/Assets/Prefabs/Minigames/BirdPoop/Targets/Target.prefab new file mode 100644 index 00000000..9fa56ef5 --- /dev/null +++ b/Assets/Prefabs/Minigames/BirdPoop/Targets/Target.prefab @@ -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: [] diff --git a/Assets/Prefabs/Minigames/BirdPoop/Targets/Target.prefab.meta b/Assets/Prefabs/Minigames/BirdPoop/Targets/Target.prefab.meta new file mode 100644 index 00000000..ca99e295 --- /dev/null +++ b/Assets/Prefabs/Minigames/BirdPoop/Targets/Target.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 020f7494c613b06479ccad2c4cedde0f +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/MiniGames/BirdPoop.unity b/Assets/Scenes/MiniGames/BirdPoop.unity index ec505bee..897c3daa 100644 --- a/Assets/Scenes/MiniGames/BirdPoop.unity +++ b/Assets/Scenes/MiniGames/BirdPoop.unity @@ -306,6 +306,7 @@ MonoBehaviour: m_EditorClassIdentifier: AppleHillsScripts::Minigames.BirdPooper.BirdPooperGameManager player: {fileID: 941621859} obstacleSpawner: {fileID: 938885957} + targetSpawner: {fileID: 1838778561} gameOverScreen: {fileID: 81231374} poopPrefab: {fileID: 5552423787977869117, guid: 066f9990a9b1f5547b387633d5d204c0, type: 3} --- !u!4 &128829408 @@ -682,12 +683,12 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 690060017} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 30.01, y: 0, z: 0} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 33.56759, y: 1.13668, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 938885956} + m_Father: {fileID: 1498486831} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &938473625 GameObject: @@ -713,12 +714,12 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 938473625} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -30.12, y: 0, z: 0} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -26.56241, y: 1.13668, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 938885956} + m_Father: {fileID: 1498486831} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &938885955 GameObject: @@ -745,14 +746,12 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 938885955} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} + 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: 690060018} - - {fileID: 938473626} - m_Father: {fileID: 0} + m_Children: [] + m_Father: {fileID: 1498486831} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &938885957 MonoBehaviour: @@ -775,18 +774,10 @@ MonoBehaviour: - {fileID: 5356906417396349863, guid: cc2a11f7e5edd7640921d1db442a7224, type: 3} - {fileID: 1771686652490758453, guid: c2dcfdcc678ff3248b40d189f46a4d3b, 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: 7335086015568222999, guid: 06674917a922d6c48a2d0ac0f6056e01, type: 3} - {fileID: 8558432647259683993, guid: 8c71dd9ad06dafc41a3308f566726ac5, 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 GameObject: m_ObjectHideFlags: 0 @@ -797,12 +788,12 @@ GameObject: m_Component: - component: {fileID: 941621856} - component: {fileID: 941621858} - - component: {fileID: 941621857} - component: {fileID: 941621859} - component: {fileID: 941621860} + - component: {fileID: 941621861} m_Layer: 0 m_Name: Bird - m_TagString: Untagged + m_TagString: Player m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 @@ -823,52 +814,6 @@ Transform: - {fileID: 989743355} m_Father: {fileID: 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 Rigidbody2D: serializedVersion: 5 @@ -940,6 +885,83 @@ MonoBehaviour: visualizationColor: {r: 1, g: 0, b: 0, a: 0.8} showObjectBounds: 1 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 GameObject: m_ObjectHideFlags: 0 @@ -1302,6 +1324,41 @@ Transform: m_Children: [] m_Father: {fileID: 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 GameObject: m_ObjectHideFlags: 0 @@ -1575,6 +1632,56 @@ Transform: m_Children: [] m_Father: {fileID: 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 GameObject: m_ObjectHideFlags: 0 @@ -1675,6 +1782,6 @@ SceneRoots: - {fileID: 580848255} - {fileID: 941621856} - {fileID: 1143700530} - - {fileID: 938885956} + - {fileID: 1498486831} - {fileID: 1536057440} - {fileID: 128829408} diff --git a/Assets/Scripts/Core/Settings/BirdPooperSettings.cs b/Assets/Scripts/Core/Settings/BirdPooperSettings.cs index ffea64e8..e0f6af68 100644 --- a/Assets/Scripts/Core/Settings/BirdPooperSettings.cs +++ b/Assets/Scripts/Core/Settings/BirdPooperSettings.cs @@ -55,6 +55,13 @@ namespace Core.Settings [Tooltip("Y position where poop is destroyed (off-screen bottom)")] [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 public float Gravity => gravity; public float FlapForce => flapForce; @@ -71,6 +78,8 @@ namespace Core.Settings public float ObstacleMaxSpawnY => obstacleMaxSpawnY; public float PoopFallSpeed => poopFallSpeed; public float PoopDestroyYPosition => poopDestroyYPosition; + public float TargetMoveSpeed => targetMoveSpeed; + public float TargetSpawnInterval => targetSpawnInterval; public override void OnValidate() { @@ -83,6 +92,8 @@ namespace Core.Settings maxRotationAngle = Mathf.Clamp(maxRotationAngle, 0f, 90f); rotationSpeed = Mathf.Max(0.1f, rotationSpeed); obstacleSpawnInterval = Mathf.Max(0.1f, obstacleSpawnInterval); + targetMoveSpeed = Mathf.Max(0.1f, targetMoveSpeed); + targetSpawnInterval = Mathf.Max(0.1f, targetSpawnInterval); } } } diff --git a/Assets/Scripts/Core/Settings/IBirdPooperSettings.cs b/Assets/Scripts/Core/Settings/IBirdPooperSettings.cs index fd08547f..43e3b388 100644 --- a/Assets/Scripts/Core/Settings/IBirdPooperSettings.cs +++ b/Assets/Scripts/Core/Settings/IBirdPooperSettings.cs @@ -28,6 +28,10 @@ // Poop Projectile float PoopFallSpeed { get; } float PoopDestroyYPosition { get; } + + // Targets + float TargetMoveSpeed { get; } + float TargetSpawnInterval { get; } } } diff --git a/Assets/Scripts/Minigames/BirdPooper/BirdPlayerController.cs b/Assets/Scripts/Minigames/BirdPooper/BirdPlayerController.cs index 9331c247..401d31a0 100644 --- a/Assets/Scripts/Minigames/BirdPooper/BirdPlayerController.cs +++ b/Assets/Scripts/Minigames/BirdPooper/BirdPlayerController.cs @@ -56,12 +56,12 @@ namespace Minigames.BirdPooper return; } - // Register as override consumer to capture ALL input (except UI button) - // Register as override consumer to capture ALL input (except UI button) + // Register as default consumer (gets input if nothing else consumes it) + // This allows UI buttons to work while still flapping when tapping empty space if (Input.InputManager.Instance != null) { - Input.InputManager.Instance.RegisterOverrideConsumer(this); - Debug.Log("[BirdPlayerController] Registered as override input consumer"); + Input.InputManager.Instance.SetDefaultConsumer(this); + Debug.Log("[BirdPlayerController] Registered as default input consumer"); } else { @@ -161,12 +161,12 @@ namespace Minigames.BirdPooper /// /// 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. /// private void OnTriggerEnter2D(Collider2D other) { - // Check if the colliding object is tagged as an obstacle - if (other.CompareTag("Obstacle")) + // Check if the colliding object is tagged as an obstacle or target + if (other.CompareTag("Obstacle") || other.CompareTag("Target")) { HandleDeath(); } diff --git a/Assets/Scripts/Minigames/BirdPooper/BirdPooperGameManager.cs b/Assets/Scripts/Minigames/BirdPooper/BirdPooperGameManager.cs index bc555f4a..937691c7 100644 --- a/Assets/Scripts/Minigames/BirdPooper/BirdPooperGameManager.cs +++ b/Assets/Scripts/Minigames/BirdPooper/BirdPooperGameManager.cs @@ -16,6 +16,7 @@ namespace Minigames.BirdPooper [Header("References")] [SerializeField] private BirdPlayerController player; [SerializeField] private ObstacleSpawner obstacleSpawner; + [SerializeField] private TargetSpawner targetSpawner; [SerializeField] private GameOverScreen gameOverScreen; [SerializeField] private GameObject poopPrefab; @@ -47,6 +48,11 @@ namespace Minigames.BirdPooper Debug.LogError("[BirdPooperGameManager] ObstacleSpawner reference not assigned!"); } + if (targetSpawner == null) + { + Debug.LogWarning("[BirdPooperGameManager] TargetSpawner reference not assigned! Targets will not spawn."); + } + if (gameOverScreen == null) { Debug.LogError("[BirdPooperGameManager] GameOverScreen reference not assigned!"); @@ -84,6 +90,13 @@ namespace Minigames.BirdPooper obstacleSpawner.StartSpawning(); Debug.Log("[BirdPooperGameManager] Started obstacle spawning"); } + + // Start target spawning + if (targetSpawner != null) + { + targetSpawner.StartSpawning(); + Debug.Log("[BirdPooperGameManager] Started target spawning"); + } } internal override void OnManagedDestroy() @@ -120,6 +133,12 @@ namespace Minigames.BirdPooper obstacleSpawner.StopSpawning(); } + // Stop spawning targets + if (targetSpawner != null) + { + targetSpawner.StopSpawning(); + } + // Show game over screen if (gameOverScreen != null) { diff --git a/Assets/Scripts/Minigames/BirdPooper/Obstacle.cs b/Assets/Scripts/Minigames/BirdPooper/Obstacle.cs index 0168acf2..b2793fdc 100644 --- a/Assets/Scripts/Minigames/BirdPooper/Obstacle.cs +++ b/Assets/Scripts/Minigames/BirdPooper/Obstacle.cs @@ -1,300 +1,28 @@ -using UnityEngine; -using Core; -using Core.Settings; -using AppleHillsCamera; - + namespace Minigames.BirdPooper { /// - /// 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). + /// Obstacle entity for Bird Pooper minigame. + /// Inherits scrolling, anchoring, and despawn behavior from ScrollingEntity. + /// Player dies on collision with obstacles. /// - [RequireComponent(typeof(Collider2D))] - [RequireComponent(typeof(EdgeAnchor))] - public class Obstacle : MonoBehaviour + public class Obstacle : ScrollingEntity { - [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; - /// - /// Initialize the obstacle with despawn position and EdgeAnchor references. - /// Called by ObstacleSpawner immediately after instantiation. + /// Returns obstacle move speed from settings. /// - /// X position where obstacle should be destroyed - /// ScreenReferenceMarker for EdgeAnchor - /// CameraScreenAdapter for EdgeAnchor - public void Initialize(float despawnX, ScreenReferenceMarker referenceMarker, CameraScreenAdapter cameraAdapter) + protected override float GetMoveSpeed() { - despawnXPosition = despawnX; - isInitialized = true; - - // Load settings - settings = GameManager.GetSettingsObject(); - 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(); - 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}"); + return settings != null ? settings.ObstacleMoveSpeed : 5f; } /// - /// Recursively tag all GameObjects with Collider2D as "Obstacle" for player collision detection. + /// Returns "Obstacle" tag for collision detection. /// - private void TagChildCollidersRecursive(Transform current) + protected override string GetColliderTag() { - // Tag this GameObject if it has a collider - Collider2D col = current.GetComponent(); - 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); - } + return "Obstacle"; } - -#if UNITY_EDITOR - /// - /// 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. - /// - private void OnValidate() - { - // Only run in editor, not during play mode - if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode) - return; - - EdgeAnchor anchor = GetComponent(); - if (anchor != null) - { - // Auto-find and assign references if not set (for editor-time visual updates) - if (anchor.referenceMarker == null) - { - anchor.referenceMarker = FindAnyObjectByType(); - 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 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); - } - - /// - /// Editor version of recursive tagging for child colliders. - /// - private void TagChildCollidersRecursiveEditor(Transform current) - { - // Tag this GameObject if it has a collider - Collider2D col = current.GetComponent(); - 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(); - } - - /// - /// Move obstacle left at constant speed (manual movement, no physics). - /// - private void MoveLeft() - { - transform.position += Vector3.left * (settings.ObstacleMoveSpeed * Time.deltaTime); - } - - /// - /// Check if obstacle has passed despawn position and destroy if so. - /// - 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 - /// - /// Draw debug visualization of the obstacle's anchor point. - /// Red horizontal line through custom anchor point OR bounds edge (top/bottom). - /// - private void OnDrawGizmos() - { - EdgeAnchor anchor = GetComponent(); - 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; - } - - /// - /// Get bounds for visualization purposes (works in editor without initialized settings). - /// - private Bounds GetVisualBounds() - { - // Get all renderers in this object and its children - Renderer[] renderers = GetComponentsInChildren(); - - 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(); - if (col != null) - { - return col.bounds; - } - - // Default small bounds - return new Bounds(transform.position, new Vector3(0.5f, 0.5f, 0.1f)); - } -#endif } } diff --git a/Assets/Scripts/Minigames/BirdPooper/Obstacle.cs.backup b/Assets/Scripts/Minigames/BirdPooper/Obstacle.cs.backup new file mode 100644 index 00000000..0168acf2 --- /dev/null +++ b/Assets/Scripts/Minigames/BirdPooper/Obstacle.cs.backup @@ -0,0 +1,300 @@ +using UnityEngine; +using Core; +using Core.Settings; +using AppleHillsCamera; + +namespace Minigames.BirdPooper +{ + /// + /// 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). + /// + [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; + + /// + /// Initialize the obstacle with despawn position and EdgeAnchor references. + /// Called by ObstacleSpawner immediately after instantiation. + /// + /// X position where obstacle should be destroyed + /// ScreenReferenceMarker for EdgeAnchor + /// CameraScreenAdapter for EdgeAnchor + public void Initialize(float despawnX, ScreenReferenceMarker referenceMarker, CameraScreenAdapter cameraAdapter) + { + despawnXPosition = despawnX; + isInitialized = true; + + // Load settings + settings = GameManager.GetSettingsObject(); + 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(); + 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}"); + } + + /// + /// Recursively tag all GameObjects with Collider2D as "Obstacle" for player collision detection. + /// + private void TagChildCollidersRecursive(Transform current) + { + // Tag this GameObject if it has a collider + Collider2D col = current.GetComponent(); + 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 + /// + /// 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. + /// + private void OnValidate() + { + // Only run in editor, not during play mode + if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode) + return; + + EdgeAnchor anchor = GetComponent(); + if (anchor != null) + { + // Auto-find and assign references if not set (for editor-time visual updates) + if (anchor.referenceMarker == null) + { + anchor.referenceMarker = FindAnyObjectByType(); + 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 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); + } + + /// + /// Editor version of recursive tagging for child colliders. + /// + private void TagChildCollidersRecursiveEditor(Transform current) + { + // Tag this GameObject if it has a collider + Collider2D col = current.GetComponent(); + 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(); + } + + /// + /// Move obstacle left at constant speed (manual movement, no physics). + /// + private void MoveLeft() + { + transform.position += Vector3.left * (settings.ObstacleMoveSpeed * Time.deltaTime); + } + + /// + /// Check if obstacle has passed despawn position and destroy if so. + /// + 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 + /// + /// Draw debug visualization of the obstacle's anchor point. + /// Red horizontal line through custom anchor point OR bounds edge (top/bottom). + /// + private void OnDrawGizmos() + { + EdgeAnchor anchor = GetComponent(); + 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; + } + + /// + /// Get bounds for visualization purposes (works in editor without initialized settings). + /// + private Bounds GetVisualBounds() + { + // Get all renderers in this object and its children + Renderer[] renderers = GetComponentsInChildren(); + + 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(); + if (col != null) + { + return col.bounds; + } + + // Default small bounds + return new Bounds(transform.position, new Vector3(0.5f, 0.5f, 0.1f)); + } +#endif + } +} + diff --git a/Assets/Scripts/Minigames/BirdPooper/Obstacle.cs.backup.meta b/Assets/Scripts/Minigames/BirdPooper/Obstacle.cs.backup.meta new file mode 100644 index 00000000..2b7f6239 --- /dev/null +++ b/Assets/Scripts/Minigames/BirdPooper/Obstacle.cs.backup.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bc9c7bac4482311439b4c2e7879f3d73 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Minigames/BirdPooper/PoopProjectile.cs b/Assets/Scripts/Minigames/BirdPooper/PoopProjectile.cs index 118a66fd..d39416b6 100644 --- a/Assets/Scripts/Minigames/BirdPooper/PoopProjectile.cs +++ b/Assets/Scripts/Minigames/BirdPooper/PoopProjectile.cs @@ -21,6 +21,12 @@ namespace Minigames.BirdPooper { base.OnManagedAwake(); + // Tag as Projectile for target detection + if (!gameObject.CompareTag("Projectile")) + { + gameObject.tag = "Projectile"; + } + // Load settings settings = GameManager.GetSettingsObject(); if (settings == null) @@ -37,16 +43,19 @@ namespace Minigames.BirdPooper Rigidbody2D rb = GetComponent(); if (rb != null) { - rb.bodyType = RigidbodyType2D.Dynamic; - rb.gravityScale = 0f; // Manual gravity + rb.bodyType = RigidbodyType2D.Kinematic; // Kinematic = manual control, no physics rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous; } - // Verify collider is trigger (for target detection in Phase 5) - Collider2D col = GetComponent(); - if (col != null && !col.isTrigger) + // Find and set all colliders to trigger (we use OnTriggerEnter2D) + Collider2D[] colliders = GetComponentsInChildren(true); + 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 /// /// Trigger collision detection for targets (Phase 5). - /// TODO: Uncomment when Target.cs is implemented in Phase 5 + /// Uses OnTriggerEnter2D with trigger collider. /// private void OnTriggerEnter2D(Collider2D other) { - // Phase 5 integration - currently commented out - /* if (other.CompareTag("Target")) { // Notify target it was hit @@ -108,7 +115,6 @@ namespace Minigames.BirdPooper Destroy(gameObject); } - */ } } } diff --git a/Assets/Scripts/Minigames/BirdPooper/ScrollingEntity.cs b/Assets/Scripts/Minigames/BirdPooper/ScrollingEntity.cs new file mode 100644 index 00000000..e9d043b8 --- /dev/null +++ b/Assets/Scripts/Minigames/BirdPooper/ScrollingEntity.cs @@ -0,0 +1,230 @@ +using UnityEngine; +using Core; +using Core.Settings; +using AppleHillsCamera; + +namespace Minigames.BirdPooper +{ + /// + /// Abstract base class for all scrolling entities in Bird Pooper minigame. + /// Provides common functionality: manual left-scrolling, EdgeAnchor integration, despawn detection. + /// Subclasses: Obstacle, Target + /// + [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; + + /// + /// Initialize the entity with despawn position and EdgeAnchor references. + /// Called by spawner immediately after instantiation. + /// + public virtual void Initialize(float despawnX, ScreenReferenceMarker referenceMarker, CameraScreenAdapter cameraAdapter) + { + despawnXPosition = despawnX; + isInitialized = true; + + // Load settings + settings = GameManager.GetSettingsObject(); + 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(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(); + 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}"); + } + + /// + /// Recursively tag all GameObjects with Collider2D for collision detection. + /// Subclasses override GetColliderTag() to specify their tag. + /// + protected virtual void TagChildCollidersRecursive(Transform current) + { + string tagToApply = GetColliderTag(); + + // Tag this GameObject if it has a collider + Collider2D col = current.GetComponent(); + 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 + /// + /// Called when values are changed in the Inspector (Editor only). + /// Updates EdgeAnchor configuration to match entity settings. + /// + protected virtual void OnValidate() + { + // Only run in editor, not during play mode + if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode) + return; + + EdgeAnchor anchor = GetComponent(); + if (anchor != null) + { + // Auto-find and assign references if not set (for editor-time visual updates) + if (anchor.referenceMarker == null) + { + anchor.referenceMarker = FindAnyObjectByType(); + 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 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); + } + + /// + /// Editor version of recursive tagging for child colliders. + /// + protected virtual void TagChildCollidersRecursiveEditor(Transform current) + { + string tagToApply = GetColliderTag(); + + // Tag this GameObject if it has a collider + Collider2D col = current.GetComponent(); + 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(); + } + + /// + /// Move entity left at constant speed (manual movement, no physics). + /// Override GetMoveSpeed() to customize speed per entity type. + /// + protected virtual void MoveLeft() + { + transform.position += Vector3.left * (GetMoveSpeed() * Time.deltaTime); + } + + /// + /// Check if entity has passed despawn position and destroy if so. + /// + protected virtual void CheckBounds() + { + if (transform.position.x < despawnXPosition) + { + Debug.Log($"[{GetType().Name}] Reached despawn position, destroying at X: {transform.position.x}"); + Destroy(gameObject); + } + } + + /// + /// Get the move speed for this entity type. + /// Subclasses override to return appropriate speed from settings. + /// + protected abstract float GetMoveSpeed(); + + /// + /// Get the tag to apply to colliders for this entity type. + /// Subclasses override to return "Obstacle", "Target", etc. + /// + protected abstract string GetColliderTag(); + } +} + diff --git a/Assets/Scripts/Minigames/BirdPooper/ScrollingEntity.cs.meta b/Assets/Scripts/Minigames/BirdPooper/ScrollingEntity.cs.meta new file mode 100644 index 00000000..00097016 --- /dev/null +++ b/Assets/Scripts/Minigames/BirdPooper/ScrollingEntity.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 69a3d32fc5cf4789a5e6e8dbc5f64996 +timeCreated: 1763713709 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/BirdPooper/Target.cs b/Assets/Scripts/Minigames/BirdPooper/Target.cs new file mode 100644 index 00000000..6151e095 --- /dev/null +++ b/Assets/Scripts/Minigames/BirdPooper/Target.cs @@ -0,0 +1,117 @@ +using UnityEngine; +using UnityEngine.Events; +using AppleHillsCamera; + +namespace Minigames.BirdPooper +{ + /// + /// 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. + /// + 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; + + /// + /// Initialize target and set up event. + /// + 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(true); + foreach (Collider2D col in colliders) + { + if (!col.isTrigger) + { + col.isTrigger = true; + Debug.Log($"[Target] Set collider '{col.name}' to trigger"); + } + } + } + + /// + /// Override Update to stop movement when hit. + /// + protected override void Update() + { + if (isHit) return; // Don't move or check bounds if hit + + base.Update(); + } + + /// + /// Returns target move speed from settings. + /// + protected override float GetMoveSpeed() + { + return settings != null ? settings.TargetMoveSpeed : 4f; + } + + /// + /// Returns "Target" tag for collision detection. + /// + protected override string GetColliderTag() + { + return "Target"; + } + + /// + /// Trigger collision detection for both player and projectiles. + /// Single trigger collider handles both cases. + /// + 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) + } + + /// + /// Called when target is hit by a poop projectile. + /// Shows visual feedback and notifies manager. + /// + 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); + } + } +} + diff --git a/Assets/Scripts/Minigames/BirdPooper/Target.cs.meta b/Assets/Scripts/Minigames/BirdPooper/Target.cs.meta new file mode 100644 index 00000000..14ddb9db --- /dev/null +++ b/Assets/Scripts/Minigames/BirdPooper/Target.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5331a770bc634a738b82f9450441de12 +timeCreated: 1763713776 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/BirdPooper/TargetSpawner.cs b/Assets/Scripts/Minigames/BirdPooper/TargetSpawner.cs new file mode 100644 index 00000000..1d78b6ea --- /dev/null +++ b/Assets/Scripts/Minigames/BirdPooper/TargetSpawner.cs @@ -0,0 +1,198 @@ +using UnityEngine; +using Core; +using Core.Settings; +using Core.Lifecycle; +using AppleHillsCamera; + +namespace Minigames.BirdPooper +{ + /// + /// 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). + /// + 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(); + 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; + } + } + + /// + /// Spawns a random target prefab at the spawn point. + /// Target is spawned at Y = 0, EdgeAnchor will position it vertically. + /// + 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(); + 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); + } + } + + /// + /// Called when a target is hit by a projectile. + /// Notifies the game manager for score tracking. + /// + private void OnTargetHit() + { + // Find and notify manager + BirdPooperGameManager manager = BirdPooperGameManager.Instance; + if (manager != null) + { + manager.OnTargetHit(); + } + else + { + Debug.LogWarning("[TargetSpawner] BirdPooperGameManager not found!"); + } + } + + /// + /// Start spawning targets at regular intervals. + /// + public void StartSpawning() + { + isSpawning = true; + spawnTimer = 0f; + Debug.Log("[TargetSpawner] Started spawning targets"); + } + + /// + /// Stop spawning new targets (existing targets continue). + /// + public void StopSpawning() + { + isSpawning = false; + Debug.Log("[TargetSpawner] Stopped spawning targets"); + } + + /// + /// Check if spawner is currently spawning. + /// + public bool IsSpawning => isSpawning; + + /// + /// Draw gizmos to visualize spawn and despawn points in the editor. + /// + 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) + ); + } + } + } +} + diff --git a/Assets/Scripts/Minigames/BirdPooper/TargetSpawner.cs.meta b/Assets/Scripts/Minigames/BirdPooper/TargetSpawner.cs.meta new file mode 100644 index 00000000..02c61148 --- /dev/null +++ b/Assets/Scripts/Minigames/BirdPooper/TargetSpawner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 16beae843b5f431f9256a56aab02b53d +timeCreated: 1763713803 \ No newline at end of file diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 513b242d..8d40c99f 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -8,6 +8,8 @@ TagManager: - Pulver - Rock - Obstacle + - Projectile + - Target layers: - Default - TransparentFX