// GDnD wiki example // Demonstrates: horizontal input, a fire-rate cooldown timer, pooled shooting, and taking a hit // Related pages: [[overview-arcade-classics-as-learning-projects]], [[unity-input]], [[object-pool-pattern]] using UnityEngine; // The player ship. Movement reuses the clamp pattern from earlier steps; the new // idea is a cooldown timer that limits fire rate independently of frame rate. public class PlayerShip : MonoBehaviour, IHittable { [SerializeField] private float speed = 9f; [SerializeField] private string horizontalAxis = "Horizontal"; [Header("Firing")] [SerializeField] private ProjectilePool bulletPool; [SerializeField] private float bulletSpeed = 12f; [SerializeField] private float fireCooldown = 0.4f; [Tooltip("Layer the player's bullets damage (the invaders).")] [SerializeField] private LayerMask invaderMask; private SpaceInvadersGame game; private float cooldownTimer; private float halfWidth; private float halfSize; private Camera cachedCamera; private void Awake() { cachedCamera = Camera.main; halfSize = GetComponent().bounds.extents.x; } public void Bind(SpaceInvadersGame owner) { game = owner; } private void Update() { Move(); TickFire(); } private void Move() { float input = Input.GetAxisRaw(horizontalAxis); Vector3 position = transform.position; position.x += input * speed * Time.deltaTime; halfWidth = cachedCamera.orthographicSize * cachedCamera.aspect - halfSize; position.x = Mathf.Clamp(position.x, -halfWidth, halfWidth); transform.position = position; } private void TickFire() { cooldownTimer -= Time.deltaTime; if (cooldownTimer > 0f || !Input.GetKey(KeyCode.Space) || bulletPool == null) { return; } cooldownTimer = fireCooldown; bulletPool.Get().Launch(transform.position + Vector3.up * 0.5f, +1f, bulletSpeed, invaderMask); } public void Hit() { game?.OnPlayerHit(); } }