Compare commits

...

2 Commits

Author SHA1 Message Date
Michal Pikulski
e9320c6d03 Poop obstacle pipeline working 2025-11-21 11:33:49 +01:00
Michal Pikulski
b4b17c18ed Some b ase obstacle and poop spawning 2025-11-21 09:22:06 +01:00
27 changed files with 2626 additions and 381 deletions

View File

@@ -123,12 +123,6 @@ MonoBehaviour:
m_SerializedLabels: m_SerializedLabels:
- BlokkemonCard - BlokkemonCard
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: c73a9b19b3208d940b9fae7360287a48
m_Address: Assets/Data/Cards/Card_New Card.asset
m_ReadOnly: 0
m_SerializedLabels:
- BlokkemonCard
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: cd07dfe9285ad414a9b3bd71829b1c41 - m_GUID: cd07dfe9285ad414a9b3bd71829b1c41
m_Address: Assets/Data/Cards/Card_New Card.asset m_Address: Assets/Data/Cards/Card_New Card.asset
m_ReadOnly: 0 m_ReadOnly: 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,195 @@
fileFormatVersion: 2
guid: 9ef635f111f888a4386a7f0290117264
TextureImporter:
internalIDToNameTable:
- first:
213: 6130942287420046110
second: bird_poop_0
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 2
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: WindowsStoreApps
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites:
- serializedVersion: 2
name: bird_poop_0
rect:
serializedVersion: 2
x: 0
y: 0
width: 386
height: 371
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: e1bb71cf68b751550800000000000000
internalID: 6130942287420046110
vertices: []
indices:
edges: []
weights: []
outline: []
customData:
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable:
bird_poop_0: 6130942287420046110
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,180 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &5552423787977869117
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1501260903740545620}
- component: {fileID: 4535520683689111684}
- component: {fileID: 3364890105999893377}
- component: {fileID: 134329718604943685}
- component: {fileID: 4086097097060867018}
m_Layer: 0
m_Name: Poop
m_TagString: Projectile
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1501260903740545620
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5552423787977869117}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -11.18, y: -1.97, z: 0}
m_LocalScale: {x: 0.43, y: 0.43, z: 0.43}
m_ConstrainProportionsScale: 1
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!212 &4535520683689111684
SpriteRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5552423787977869117}
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: 6130942287420046110, guid: 9ef635f111f888a4386a7f0290117264, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 3.86, y: 3.71}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_MaskInteraction: 0
m_SpriteSortPoint: 0
--- !u!50 &3364890105999893377
Rigidbody2D:
serializedVersion: 5
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5552423787977869117}
m_BodyType: 1
m_Simulated: 1
m_UseFullKinematicContacts: 0
m_UseAutoMass: 0
m_Mass: 1
m_LinearDamping: 0
m_AngularDamping: 0.05
m_GravityScale: 1
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_Interpolate: 0
m_SleepingMode: 1
m_CollisionDetection: 0
m_Constraints: 0
--- !u!61 &134329718604943685
BoxCollider2D:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5552423787977869117}
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.5, y: 0.5}
oldSize: {x: 3.86, y: 3.71}
newSize: {x: 3.86, y: 3.71}
adaptiveTilingThreshold: 0.5
drawMode: 0
adaptiveTiling: 0
m_AutoTiling: 0
m_Size: {x: 3.86, y: 3.71}
m_EdgeRadius: 0
--- !u!114 &4086097097060867018
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5552423787977869117}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f2c53b7e2a0042efa4c6679b992b6b6c, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::Minigames.BirdPooper.PoopProjectile

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 066f9990a9b1f5547b387633d5d204c0
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View 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: []

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 020f7494c613b06479ccad2c4cedde0f
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@@ -306,7 +306,9 @@ 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}
--- !u!4 &128829408 --- !u!4 &128829408
Transform: Transform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -681,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:
@@ -712,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:
@@ -744,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:
@@ -774,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
@@ -796,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
@@ -822,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
@@ -939,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
@@ -1094,14 +1117,160 @@ RectTransform:
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, 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: 1122850720}
m_Father: {fileID: 1536057440} m_Father: {fileID: 1536057440}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0.5, y: 0.5} m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 100, y: 100} m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &1122850719
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1122850720}
- component: {fileID: 1122850723}
- component: {fileID: 1122850722}
- component: {fileID: 1122850721}
- component: {fileID: 1122850724}
m_Layer: 5
m_Name: Button
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1122850720
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1122850719}
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: 1088771378}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 1, y: 0}
m_AnchorMax: {x: 1, y: 0}
m_AnchoredPosition: {x: -91, y: 63}
m_SizeDelta: {x: 300, y: 300}
m_Pivot: {x: 1, y: 0}
--- !u!114 &1122850721
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1122850719}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Button
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 1122850722}
m_OnClick:
m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 128829407}
m_TargetAssemblyTypeName: Minigames.BirdPooper.BirdPooperGameManager, AppleHillsScripts
m_MethodName: SpawnPoop
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 1
--- !u!114 &1122850722
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1122850719}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 6130942287420046110, guid: 9ef635f111f888a4386a7f0290117264, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &1122850723
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1122850719}
m_CullTransparentMesh: 1
--- !u!114 &1122850724
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1122850719}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 494d0aedce9744308499355006071138, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::UI.DummyInput
--- !u!1 &1143700528 --- !u!1 &1143700528
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -1155,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
@@ -1428,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
@@ -1528,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}

View File

@@ -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);
} }
} }
} }

View File

@@ -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; }
} }
} }

View File

@@ -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();
} }

View File

@@ -16,7 +16,13 @@ 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;
[Header("Game State")]
private int targetsHit;
private bool isGameOver;
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
@@ -42,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!");
@@ -51,12 +62,21 @@ namespace Minigames.BirdPooper
// Hide game over screen on start // Hide game over screen on start
gameOverScreen.gameObject.SetActive(false); gameOverScreen.gameObject.SetActive(false);
} }
if (poopPrefab == null)
{
Debug.LogWarning("[BirdPooperGameManager] Poop prefab not assigned!");
}
} }
internal override void OnManagedStart() internal override void OnManagedStart()
{ {
base.OnManagedStart(); base.OnManagedStart();
// Initialize game state
isGameOver = false;
targetsHit = 0;
// Subscribe to player events // Subscribe to player events
if (player != null) if (player != null)
{ {
@@ -70,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()
@@ -95,7 +122,10 @@ namespace Minigames.BirdPooper
/// </summary> /// </summary>
private void HandlePlayerDamaged() private void HandlePlayerDamaged()
{ {
Debug.Log("[BirdPooperGameManager] Player damaged - showing game over screen"); if (isGameOver) return;
isGameOver = true;
Debug.Log($"[BirdPooperGameManager] Player damaged - Game Over! Targets Hit: {targetsHit}");
// Stop spawning obstacles // Stop spawning obstacles
if (obstacleSpawner != null) if (obstacleSpawner != null)
@@ -103,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)
{ {
@@ -113,6 +149,39 @@ namespace Minigames.BirdPooper
Debug.LogError("[BirdPooperGameManager] GameOverScreen reference missing!"); Debug.LogError("[BirdPooperGameManager] GameOverScreen reference missing!");
} }
} }
/// <summary>
/// Spawns a poop projectile at the player's current position.
/// Called by UI button OnClick event.
/// </summary>
public void SpawnPoop()
{
if (isGameOver || player == null || poopPrefab == null)
return;
Vector3 spawnPosition = player.transform.position;
Instantiate(poopPrefab, spawnPosition, Quaternion.identity);
Debug.Log($"[BirdPooperGameManager] Spawned poop at {spawnPosition}");
}
/// <summary>
/// Called when a target is successfully hit by poop (Phase 5).
/// </summary>
public void OnTargetHit()
{
if (isGameOver) return;
targetsHit++;
Debug.Log($"[BirdPooperGameManager] Target Hit! Total: {targetsHit}");
}
#region Public Accessors
public bool IsGameOver => isGameOver;
public int TargetsHit => targetsHit;
#endregion
} }
} }

View File

@@ -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
} }
} }

View 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
}
}

View File

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

View File

@@ -0,0 +1,121 @@
using Core;
using Core.Lifecycle;
using Core.Settings;
using UnityEngine;
namespace Minigames.BirdPooper
{
/// <summary>
/// Poop projectile that falls straight down with manual gravity.
/// Destroys when off-screen or hitting targets (Phase 5).
/// </summary>
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(Collider2D))]
public class PoopProjectile : ManagedBehaviour
{
private IBirdPooperSettings settings;
private float verticalVelocity; // Current downward velocity
private const float GravityAcceleration = 20f; // Gravity acceleration (units/s²)
internal override void OnManagedAwake()
{
base.OnManagedAwake();
// Tag as Projectile for target detection
if (!gameObject.CompareTag("Projectile"))
{
gameObject.tag = "Projectile";
}
// Load settings
settings = GameManager.GetSettingsObject<IBirdPooperSettings>();
if (settings == null)
{
Debug.LogError("[PoopProjectile] BirdPooperSettings not found!");
Destroy(gameObject);
return;
}
// Initialize velocity with settings speed as starting velocity
verticalVelocity = settings.PoopFallSpeed;
// Verify Rigidbody2D configuration
Rigidbody2D rb = GetComponent<Rigidbody2D>();
if (rb != null)
{
rb.bodyType = RigidbodyType2D.Kinematic; // Kinematic = manual control, no physics
rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
}
// 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($"[PoopProjectile] Set collider '{col.name}' to trigger");
}
}
}
private void Update()
{
if (settings != null)
{
ApplyGravity();
FallDown();
CheckBounds();
}
}
/// <summary>
/// Apply gravity acceleration to velocity.
/// </summary>
private void ApplyGravity()
{
// Increase downward velocity over time (gravity acceleration)
verticalVelocity += GravityAcceleration * Time.deltaTime;
}
/// <summary>
/// Manual downward movement using current velocity.
/// </summary>
private void FallDown()
{
// Move straight down at current velocity
transform.position += Vector3.down * verticalVelocity * Time.deltaTime;
}
/// <summary>
/// Check if projectile is off-screen and should be destroyed.
/// </summary>
private void CheckBounds()
{
if (transform.position.y < settings.PoopDestroyYPosition)
{
Destroy(gameObject);
}
}
/// <summary>
/// Trigger collision detection for targets (Phase 5).
/// Uses OnTriggerEnter2D with trigger collider.
/// </summary>
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Target"))
{
// Notify target it was hit
Target target = other.GetComponent<Target>();
if (target != null)
{
target.OnHitByProjectile();
}
Destroy(gameObject);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f2c53b7e2a0042efa4c6679b992b6b6c
timeCreated: 1763711288

View 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();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 69a3d32fc5cf4789a5e6e8dbc5f64996
timeCreated: 1763713709

View 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);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5331a770bc634a738b82f9450441de12
timeCreated: 1763713776

View 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)
);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 16beae843b5f431f9256a56aab02b53d
timeCreated: 1763713803

View File

@@ -17,6 +17,8 @@ MonoBehaviour:
maxFallSpeed: 150 maxFallSpeed: 150
minY: -15 minY: -15
maxY: 15 maxY: 15
maxRotationAngle: 30
rotationSpeed: 8
obstacleMoveSpeed: 5 obstacleMoveSpeed: 5
obstacleSpawnInterval: 2 obstacleSpawnInterval: 2
obstacleSpawnXPosition: 12 obstacleSpawnXPosition: 12
@@ -24,4 +26,4 @@ MonoBehaviour:
obstacleMinSpawnY: -3 obstacleMinSpawnY: -3
obstacleMaxSpawnY: 3 obstacleMaxSpawnY: 3
poopFallSpeed: 10 poopFallSpeed: 10
poopDestroyYPosition: -10 poopDestroyYPosition: -20

View File

@@ -8,6 +8,8 @@ TagManager:
- Pulver - Pulver
- Rock - Rock
- Obstacle - Obstacle
- Projectile
- Target
layers: layers:
- Default - Default
- TransparentFX - TransparentFX