diff --git a/Assets/Materials/GhostProjectile.mat b/Assets/Materials/GhostProjectile.mat new file mode 100644 index 0000000..9a4e303 --- /dev/null +++ b/Assets/Materials/GhostProjectile.mat @@ -0,0 +1,137 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: GhostProjectile + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: + - _ALPHAPREMULTIPLY_ON + - _SURFACE_TYPE_TRANSPARENT + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: + - DepthOnly + - SHADOWCASTER + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _DstBlendAlpha: 10 + - _EnvironmentReflections: 1 + - _GlossMapScale: 0 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.005 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 1 + - _WorkflowMode: 1 + - _ZWrite: 0 + m_Colors: + - _BaseColor: {r: 0.38039213, g: 0.38431373, b: 0.39215687, a: 0.78431374} + - _Color: {r: 0.3803921, g: 0.3843137, b: 0.39215684, a: 0.78431374} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] +--- !u!114 &8625757837965251938 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 7 diff --git a/Assets/Materials/GhostProjectile.mat.meta b/Assets/Materials/GhostProjectile.mat.meta new file mode 100644 index 0000000..35f33a1 --- /dev/null +++ b/Assets/Materials/GhostProjectile.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 66b56adfef1823449b3992c35d0f489c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Models/GreenBoy.fbx b/Assets/Models/GreenBoy.fbx new file mode 100644 index 0000000..679e174 Binary files /dev/null and b/Assets/Models/GreenBoy.fbx differ diff --git a/Assets/Models/GreenBoy.fbx.meta b/Assets/Models/GreenBoy.fbx.meta new file mode 100644 index 0000000..e08f8f5 --- /dev/null +++ b/Assets/Models/GreenBoy.fbx.meta @@ -0,0 +1,109 @@ +fileFormatVersion: 2 +guid: 18a302e9a279644c19653ac58e191809 +ModelImporter: + serializedVersion: 22200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 0.1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 0.001 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Projectiles/ProjectileGhost.prefab b/Assets/Prefabs/Projectiles/ProjectileGhost.prefab new file mode 100644 index 0000000..06ed954 --- /dev/null +++ b/Assets/Prefabs/Projectiles/ProjectileGhost.prefab @@ -0,0 +1,85 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2962360034595352958 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 888336455889056387} + - component: {fileID: 345585203663460175} + - component: {fileID: 5408793041970514069} + m_Layer: 6 + m_Name: ProjectileGhost + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &888336455889056387 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2962360034595352958} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 7.372555, y: -18.054228, z: 22.62589} + m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &345585203663460175 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2962360034595352958} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &5408793041970514069 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2962360034595352958} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 66b56adfef1823449b3992c35d0f489c, 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: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} diff --git a/Assets/Prefabs/Projectiles/ProjectileGhost.prefab.meta b/Assets/Prefabs/Projectiles/ProjectileGhost.prefab.meta new file mode 100644 index 0000000..21e9423 --- /dev/null +++ b/Assets/Prefabs/Projectiles/ProjectileGhost.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f657bc53e175aad72a117bf3ef556359 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Towers/Turret.prefab b/Assets/Prefabs/Towers/Turret.prefab index 293205d..7c83451 100644 --- a/Assets/Prefabs/Towers/Turret.prefab +++ b/Assets/Prefabs/Towers/Turret.prefab @@ -1072,8 +1072,13 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3c6fb039e74d12a7bbfde22591bc7eee, type: 3} m_Name: m_EditorClassIdentifier: + barrel: {fileID: 2740722787380423134} horizontalArc: {fileID: 8981486734084153558} verticalArc: {fileID: 5247639431516572416} + spaceBetweenGhosts: 0.5 + trajectoryBounces: 4 + ghostPrefab: {fileID: 2962360034595352958, guid: f657bc53e175aad72a117bf3ef556359, + type: 3} attackSecondsDelay: 1 projectileSequence: - Arc: 0 @@ -1083,9 +1088,6 @@ MonoBehaviour: type: 3} Burst: 0 BurstDelay: 0 - barrel: {fileID: 2740722787380423134} - trajectory: {fileID: 3987931586699850031} - trajectoryBounces: 4 --- !u!4 &9116936080776508834 stripped Transform: m_CorrespondingSourceObject: {fileID: 527409087646353271, guid: f54a14318952c90c5b47a300aedb0d15, diff --git a/Assets/Scenes/TowerTest.unity b/Assets/Scenes/TowerTest.unity index 2e466c7..af54993 100644 --- a/Assets/Scenes/TowerTest.unity +++ b/Assets/Scenes/TowerTest.unity @@ -241,6 +241,74 @@ MonoBehaviour: m_LightCookieSize: {x: 1, y: 1} m_LightCookieOffset: {x: 0, y: 0} m_SoftShadowQuality: 1 +--- !u!1001 &504816165 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: 18a302e9a279644c19653ac58e191809, + type: 3} + propertyPath: m_LocalPosition.x + value: 0.8027312 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 18a302e9a279644c19653ac58e191809, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.20438403 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 18a302e9a279644c19653ac58e191809, + type: 3} + propertyPath: m_LocalPosition.z + value: -3.614678 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 18a302e9a279644c19653ac58e191809, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 18a302e9a279644c19653ac58e191809, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 18a302e9a279644c19653ac58e191809, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 18a302e9a279644c19653ac58e191809, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 18a302e9a279644c19653ac58e191809, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 18a302e9a279644c19653ac58e191809, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 18a302e9a279644c19653ac58e191809, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: 18a302e9a279644c19653ac58e191809, + type: 3} + propertyPath: m_Name + value: GreenBoy + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 18a302e9a279644c19653ac58e191809, type: 3} --- !u!1 &643774939 GameObject: m_ObjectHideFlags: 0 @@ -576,6 +644,16 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: 7437064479105606814, guid: 9415cb10a1bd579269301ca4f61a1554, + type: 3} + propertyPath: trajectoryBounces + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 7437064479105606814, guid: 9415cb10a1bd579269301ca4f61a1554, + type: 3} + propertyPath: trajectoryObjectPoolSize + value: 100 + objectReference: {fileID: 0} - target: {fileID: 7437064479105606814, guid: 9415cb10a1bd579269301ca4f61a1554, type: 3} propertyPath: projectileSequence.Array.data[0].Speed @@ -1165,7 +1243,7 @@ PrefabInstance: - target: {fileID: 7348612162646443967, guid: fd9f9b61c0ebb324ebc9f929e26706bc, type: 3} propertyPath: m_LocalRotation.w - value: -0.13805284 + value: -0.1380528 objectReference: {fileID: 0} - target: {fileID: 7348612162646443967, guid: fd9f9b61c0ebb324ebc9f929e26706bc, type: 3} @@ -1180,7 +1258,7 @@ PrefabInstance: - target: {fileID: 7348612162646443967, guid: fd9f9b61c0ebb324ebc9f929e26706bc, type: 3} propertyPath: m_LocalRotation.z - value: -0.13815573 + value: -0.13815574 objectReference: {fileID: 0} - target: {fileID: 8882344377078016156, guid: fd9f9b61c0ebb324ebc9f929e26706bc, type: 3} @@ -1496,3 +1574,4 @@ SceneRoots: - {fileID: 1932692269} - {fileID: 1671091699} - {fileID: 770231297} + - {fileID: 504816165} diff --git a/Assets/Scripts/Tower/AimTower.cs b/Assets/Scripts/Tower/AimTower.cs new file mode 100644 index 0000000..a9cac3c --- /dev/null +++ b/Assets/Scripts/Tower/AimTower.cs @@ -0,0 +1,116 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class AimTower : Tower +{ + [SerializeField] protected Barrel barrel; + [SerializeField] protected EditableArc horizontalArc; + [SerializeField] protected EditableArc verticalArc; + + [Header("Trajectory")] + [SerializeField] private float spaceBetweenGhosts = 0.5f; + [SerializeField] private int trajectoryBounces = 3; + private const float k_trajectory_maxdist = 100f; + private List ghosts = new(); + [SerializeField] private GameObject ghostPrefab; + [SerializeField] private int trajectoryObjectPoolSize = 25; + private int poolIdx = 0; + + public Vector3 AimDirection => barrel.transform.forward; + public Vector2 HorizontalRotationMinMax => horizontalArc.RotationMinMax; + public Vector2 VerticalRotationMinMax => verticalArc.RotationMinMax; + public float HorizontalRotation => horizontalArc.Value; + public float VerticalRotation => verticalArc.Value; + + + protected override void Awake() + { + horizontalArc.Value.AddListener(UpdateBarrelRotation); + verticalArc.Value.AddListener(UpdateBarrelRotation); + + horizontalArc.Value.AddListener(UpdateTrajectory); + verticalArc.Value.AddListener(UpdateTrajectory); + + horizontalArc.Value.AddListener(SnapVerticalToHorizontal); + + UpdateBarrelRotation(); + UpdateTrajectory(); + } + + protected override void OnDestroy() + { + horizontalArc.Value.RemoveListener(UpdateBarrelRotation); + verticalArc.Value.RemoveListener(UpdateBarrelRotation); + horizontalArc.Value.RemoveListener(SnapVerticalToHorizontal); + } + + private void UpdateBarrelRotation(float unused) => UpdateBarrelRotation(); + + // Rotate barrel to match rotation + private void UpdateBarrelRotation() + { + barrel.transform.localRotation = Quaternion.Euler(-verticalArc.Value, horizontalArc.Value, 0f); + } + + private void SnapVerticalToHorizontal(float horizontalAngle) + { + verticalArc.transform.rotation = Quaternion.Euler(verticalArc.transform.rotation.eulerAngles.x, horizontalAngle, verticalArc.transform.rotation.eulerAngles.z); + } + + private void UpdateTrajectory(float unused) => UpdateTrajectory(); + + private void UpdateTrajectory() + { + foreach (var ghost in ghosts) + { + ghost.SetActive(false); + } + + Vector3 origin = barrel.Tip.position; + Vector3 dir = barrel.transform.forward; + List pointsInTrajectory = new(); + pointsInTrajectory.Add(origin); + for (int i = 0; i < trajectoryBounces; i++) + { + Debug.DrawRay(origin, dir.normalized * k_trajectory_maxdist, Color.red, 5f); + RaycastHit hit; + if (!Physics.Raycast(origin, dir, out hit, k_trajectory_maxdist)) + break; + + pointsInTrajectory.Add(hit.point); + dir = Vector3.Reflect(dir, hit.normal); + origin = hit.point; + } + + // Build trajectory + for (int i = 0; i < pointsInTrajectory.Count - 1; i++) + { + Vector3 point1 = pointsInTrajectory[i]; + Vector3 point2 = pointsInTrajectory[i + 1]; + + Vector3 trajDir = (point2 - point1).normalized; + float dist = Vector3.Distance(point1, point2); + for (float j = 0; j < dist; j += spaceBetweenGhosts) + { + Vector3 ghostPos = point1 + trajDir * j; + + // Use object pool or spawn new + if (ghosts.Count >= trajectoryObjectPoolSize) + { + ghosts[poolIdx].transform.position = ghostPos; + ghosts[poolIdx].SetActive(true); + poolIdx = (poolIdx + 1) % trajectoryObjectPoolSize; + Debug.Log($"pool idx: {poolIdx}"); + } + else + { + var ghost = Instantiate(ghostPrefab); + ghost.transform.position = ghostPos; + ghost.transform.parent = transform; + ghosts.Add(ghost); + } + } + } + } +} diff --git a/Assets/Scripts/Tower/AimTower.cs.meta b/Assets/Scripts/Tower/AimTower.cs.meta new file mode 100644 index 0000000..3c682c5 --- /dev/null +++ b/Assets/Scripts/Tower/AimTower.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 07497cc2771c1090bb0a07e731976e15 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Tower/ProjectileTower.cs b/Assets/Scripts/Tower/ProjectileTower.cs index 3a1d227..bc6a932 100644 --- a/Assets/Scripts/Tower/ProjectileTower.cs +++ b/Assets/Scripts/Tower/ProjectileTower.cs @@ -4,26 +4,13 @@ using System.Collections.Generic; using UnityEngine; using UnityEngine.Assertions; -public class ProjectileTower : Tower +public class ProjectileTower : AimTower { - [SerializeField] protected EditableArc horizontalArc; - [SerializeField] protected EditableArc verticalArc; - [SerializeField, Range(0.01f, 20f)] private float attackSecondsDelay = 1f; [SerializeField] private ProjectilePattern[] projectileSequence; - [SerializeField] private Barrel barrel; - [SerializeField] private LineRenderer trajectory; - [SerializeField] private int trajectoryBounces = 2; - private const float k_trajectory_maxdist = 100f; private ProjectileSpawner projectileSpawner; - public Vector3 AimDirection => barrel.transform.forward; - public Vector2 HorizontalRotationMinMax => horizontalArc.RotationMinMax; - public Vector2 VerticalRotationMinMax => verticalArc.RotationMinMax; - public float HorizontalRotation => horizontalArc.Value; - public float VerticalRotation => verticalArc.Value; - protected override void Awake() { base.Awake(); @@ -31,74 +18,18 @@ public class ProjectileTower : Tower projectileSpawner = GetComponent(); Assert.IsNotNull(projectileSpawner); - horizontalArc.Value.AddListener(UpdateBarrelRotation); - verticalArc.Value.AddListener(UpdateBarrelRotation); - - horizontalArc.Value.AddListener(UpdateTrajectory); - verticalArc.Value.AddListener(UpdateTrajectory); - - horizontalArc.Value.AddListener(SnapVerticalToHorizontal); - - UpdateBarrelRotation(); - UpdateTrajectory(); StartCoroutine(AttackLoop()); } - private void SnapVerticalToHorizontal(float horizontalAngle) - { - verticalArc.transform.rotation = Quaternion.Euler(verticalArc.transform.rotation.eulerAngles.x, horizontalAngle, verticalArc.transform.rotation.eulerAngles.z); - } - - private void UpdateTrajectory(float unused) => UpdateTrajectory(); - - private void UpdateTrajectory() - { - if (trajectory == null) return; - - Vector3 origin = barrel.Tip.position; - Vector3 dir = barrel.transform.forward; - List pointsInTrajectory = new(); - pointsInTrajectory.Add(origin); - for (int i = 0; i < trajectoryBounces; i++) - { - Debug.DrawRay(origin, dir.normalized * k_trajectory_maxdist, Color.red, 5f); - RaycastHit hit; - if (!Physics.Raycast(origin, dir, out hit, k_trajectory_maxdist)) - break; - - pointsInTrajectory.Add(hit.point); - dir = Vector3.Reflect(dir, hit.normal); - origin = hit.point; - } - - trajectory.positionCount = pointsInTrajectory.Count; - trajectory.SetPositions(pointsInTrajectory.ToArray()); - } - - protected override void OnDestroy() - { - horizontalArc.Value.RemoveListener(UpdateBarrelRotation); - verticalArc.Value.RemoveListener(UpdateBarrelRotation); - horizontalArc.Value.RemoveListener(SnapVerticalToHorizontal); - } private IEnumerator AttackLoop() { do { yield return new WaitForSeconds(attackSecondsDelay); - UpdateBarrelRotation(); Debug.DrawRay(transform.position, horizontalArc.ToKnobVector, Color.red, attackSecondsDelay); Debug.DrawRay(transform.position, verticalArc.ToKnobVector, Color.green, attackSecondsDelay); Debug.DrawRay(transform.position, AimDirection, Color.yellow, attackSecondsDelay); projectileSpawner.RunBulletSequence(barrel.transform.position, transform.up, AimDirection, projectileSequence); } while (true); } - - private void UpdateBarrelRotation(float unused) => UpdateBarrelRotation(); - - // Rotate barrel to match rotation - private void UpdateBarrelRotation() - { - barrel.transform.localRotation = Quaternion.Euler(-verticalArc.Value, horizontalArc.Value, 0f); - } }