feat(core): implement playable CTF prototype with 6 core scripts
Implements the minimal playable core for the teaser prototype: - Game.cs: Bootstrap, scene setup, scoring, round reset, win condition - Unit.cs: Movement, route following, tagging, respawn - RouteDrawer.cs: Click-drag route input with LineRenderer preview - Flag.cs: Pickup, drop, return mechanics - Visibility.cs: Fog of war via SpriteRenderer visibility - SimpleAI.cs: Enemy AI that chases player flag All game objects created programmatically (no Editor setup required). Uses RuntimeInitializeOnLoadMethod for automatic bootstrap. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
147
Backyard CTF/Assets/Scripts/RouteDrawer.cs
Normal file
147
Backyard CTF/Assets/Scripts/RouteDrawer.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class RouteDrawer : MonoBehaviour
|
||||
{
|
||||
Unit selectedUnit;
|
||||
List<Vector2> currentRoute = new();
|
||||
LineRenderer lineRenderer;
|
||||
bool isDrawing;
|
||||
|
||||
const float MinPointDistance = 0.5f;
|
||||
|
||||
void Start()
|
||||
{
|
||||
CreateLineRenderer();
|
||||
}
|
||||
|
||||
void CreateLineRenderer()
|
||||
{
|
||||
var lineGO = new GameObject("RouteLine");
|
||||
lineRenderer = lineGO.AddComponent<LineRenderer>();
|
||||
lineRenderer.startWidth = 0.15f;
|
||||
lineRenderer.endWidth = 0.15f;
|
||||
lineRenderer.material = new Material(Shader.Find("Sprites/Default"));
|
||||
lineRenderer.startColor = new Color(1f, 1f, 1f, 0.5f);
|
||||
lineRenderer.endColor = new Color(1f, 1f, 1f, 0.5f);
|
||||
lineRenderer.sortingOrder = 20;
|
||||
lineRenderer.positionCount = 0;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
var mouse = Mouse.current;
|
||||
var touch = Touchscreen.current;
|
||||
|
||||
// Handle mouse input
|
||||
if (mouse != null)
|
||||
{
|
||||
HandlePointerInput(
|
||||
mouse.leftButton.wasPressedThisFrame,
|
||||
mouse.leftButton.wasReleasedThisFrame,
|
||||
mouse.leftButton.isPressed,
|
||||
mouse.position.ReadValue()
|
||||
);
|
||||
}
|
||||
// Handle touch input
|
||||
else if (touch != null && touch.primaryTouch.press.isPressed)
|
||||
{
|
||||
var primaryTouch = touch.primaryTouch;
|
||||
HandlePointerInput(
|
||||
primaryTouch.press.wasPressedThisFrame,
|
||||
primaryTouch.press.wasReleasedThisFrame,
|
||||
primaryTouch.press.isPressed,
|
||||
primaryTouch.position.ReadValue()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void HandlePointerInput(bool pressed, bool released, bool held, Vector2 screenPos)
|
||||
{
|
||||
Vector2 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
OnPointerDown(worldPos);
|
||||
}
|
||||
else if (released)
|
||||
{
|
||||
OnPointerUp();
|
||||
}
|
||||
else if (held && isDrawing)
|
||||
{
|
||||
OnPointerDrag(worldPos);
|
||||
}
|
||||
}
|
||||
|
||||
void OnPointerDown(Vector2 worldPos)
|
||||
{
|
||||
// Check if we clicked on a player unit
|
||||
var hit = Physics2D.OverlapPoint(worldPos);
|
||||
if (hit != null)
|
||||
{
|
||||
var unit = hit.GetComponent<Unit>();
|
||||
if (unit != null && unit.team == Unit.Team.Player && !unit.isTaggedOut)
|
||||
{
|
||||
selectedUnit = unit;
|
||||
isDrawing = true;
|
||||
currentRoute.Clear();
|
||||
currentRoute.Add(worldPos);
|
||||
UpdateLineRenderer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnPointerDrag(Vector2 worldPos)
|
||||
{
|
||||
if (!isDrawing || selectedUnit == null) return;
|
||||
|
||||
// Only add point if far enough from last point
|
||||
if (currentRoute.Count > 0)
|
||||
{
|
||||
float dist = Vector2.Distance(currentRoute[currentRoute.Count - 1], worldPos);
|
||||
if (dist >= MinPointDistance)
|
||||
{
|
||||
currentRoute.Add(worldPos);
|
||||
UpdateLineRenderer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnPointerUp()
|
||||
{
|
||||
if (isDrawing && selectedUnit != null && currentRoute.Count > 0)
|
||||
{
|
||||
// Remove the first point (unit's current position) and apply route
|
||||
if (currentRoute.Count > 1)
|
||||
{
|
||||
currentRoute.RemoveAt(0);
|
||||
}
|
||||
selectedUnit.SetRoute(currentRoute);
|
||||
}
|
||||
|
||||
// Clear drawing state
|
||||
isDrawing = false;
|
||||
selectedUnit = null;
|
||||
currentRoute.Clear();
|
||||
ClearLineRenderer();
|
||||
}
|
||||
|
||||
void UpdateLineRenderer()
|
||||
{
|
||||
if (lineRenderer == null) return;
|
||||
|
||||
lineRenderer.positionCount = currentRoute.Count;
|
||||
for (int i = 0; i < currentRoute.Count; i++)
|
||||
{
|
||||
lineRenderer.SetPosition(i, new Vector3(currentRoute[i].x, currentRoute[i].y, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void ClearLineRenderer()
|
||||
{
|
||||
if (lineRenderer == null) return;
|
||||
lineRenderer.positionCount = 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user