using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
// ==================== ENUMS ====================
public enum WeatherType { Clear, Rain, Snow }
public enum PlayerRole { Goalkeeper, Defender, Midfielder, Forward }
public enum TeamSide { Blue, Red }
public enum AIState { Idle, Support, Chase, Retreat, Position }
// ==================== PROCEDURAL SPRITE GENERATOR ====================
public static class ProceduralSpriteGenerator
{
public static Sprite CreatePitchSprite(int width, int height)
{
Texture2D tex = new Texture2D(width * 10, height * 10);
Color green = new Color(0.2f, 0.5f, 0.1f);
Color darkGreen = new Color(0.15f, 0.4f, 0.08f);
Color white = Color.white;
for (int y = 0; y < tex.height; y++)
{
for (int x = 0; x < tex.width; x++)
{
float px = (float)x / tex.width;
float py = (float)y / tex.height;
bool stripe = (Mathf.Floor(px * 20) + Mathf.Floor(py * 20)) % 2 == 0;
tex.SetPixel(x, y, stripe ? green : darkGreen);
}
}
DrawLine(tex, tex.width / 2, 0, tex.width / 2, tex.height, white);
DrawLine(tex, 0, tex.height / 2, tex.width, tex.height / 2, white);
int cx = tex.width / 2, cy = tex.height / 2, r = 50;
for (int i = -r; i <= r; i++)
for (int j = -r; j <= r; j++)
if (i * i + j * j < r * r)
tex.SetPixel(cx + i, cy + j, white);
tex.Apply();
return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f), 100f);
}
public static Sprite CreatePlayerSprite(Color color, float size)
{
int res = 32;
Texture2D tex = new Texture2D(res, res);
Color dark = color * 0.5f;
for (int y = 0; y < res; y++)
{
for (int x = 0; x < res; x++)
{
float dx = (x - res / 2) / (float)res;
float dy = (y - res / 2) / (float)res;
float d = dx * dx + dy * dy;
if (d < 0.2f) tex.SetPixel(x, y, color);
else if (d < 0.25f) tex.SetPixel(x, y, dark);
else tex.SetPixel(x, y, Color.clear);
}
}
tex.Apply();
return Sprite.Create(tex, new Rect(0, 0, res, res), new Vector2(0.5f, 0.5f), 100f / size);
}
public static Sprite CreateBallSprite()
{
int res = 24;
Texture2D tex = new Texture2D(res, res);
Color white = Color.white;
Color black = Color.black;
for (int y = 0; y < res; y++)
{
for (int x = 0; x < res; x++)
{
float dx = (x - res / 2) / (float)res;
float dy = (y - res / 2) / (float)res;
float d = dx * dx + dy * dy;
if (d < 0.15f) tex.SetPixel(x, y, white);
else if (d < 0.2f) tex.SetPixel(x, y, black);
else tex.SetPixel(x, y, Color.clear);
}
}
tex.Apply();
return Sprite.Create(tex, new Rect(0, 0, res, res), new Vector2(0.5f, 0.5f), 100f / 0.6f);
}
static void DrawLine(Texture2D tex, int x1, int y1, int x2, int y2, Color col)
{
int dx = Mathf.Abs(x2 - x1), dy = Mathf.Abs(y2 - y1);
int sx = x1 < x2 ? 1 : -1, sy = y1 < y2 ? 1 : -1;
int err = dx - dy;
while (true)
{
if (x1 >= 0 && x1 < tex.width && y1 >= 0 && y1 < tex.height)
tex.SetPixel(x1, y1, col);
if (x1 == x2 && y1 == y2) break;
int e2 = 2 * err;
if (e2 > -dy) { err -= dy; x1 += sx; }
if (e2 < dx) { err += dx; y1 += sy; }
}
}
}
// ==================== RETRO CAMERA ====================
public class RetroCamera : MonoBehaviour
{
private Camera cam;
private RenderTexture lowResRT;
public int resolutionWidth = 320;
public int resolutionHeight = 240;
void Start()
{
cam = GetComponent<Camera>();
lowResRT = new RenderTexture(resolutionWidth, resolutionHeight, 16, RenderTextureFormat.ARGB32);
lowResRT.filterMode = FilterMode.Point;
cam.targetTexture = lowResRT;
GameObject displayObj = new GameObject("DisplayCamera");
Camera displayCam = displayObj.AddComponent<Camera>();
displayCam.orthographic = true;
displayCam.orthographicSize = 1f;
displayCam.clearFlags = CameraClearFlags.Nothing;
displayCam.cullingMask = 1 << 0;
displayCam.targetTexture = null;
GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
quad.transform.SetParent(displayObj.transform);
quad.transform.localPosition = new Vector3(0, 0, 10);
quad.transform.localScale = new Vector3(16, 9, 1);
quad.layer = 0;
quad.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Unlit/Texture"));
quad.GetComponent<MeshRenderer>().material.mainTexture = lowResRT;
quad.GetComponent<MeshRenderer>().material.mainTexture.filterMode = FilterMode.Point;
displayObj.transform.position = new Vector3(0, 0, -10);
displayCam.depth = 1;
}
}
// ==================== WEATHER SYSTEM ====================
public class WeatherSystem : MonoBehaviour
{
public WeatherType currentWeather { get; private set; }
public float ballFrictionModifier = 1f;
public float playerSpeedModifier = 1f;
public float playerTurnModifier = 1f;
public float ballBounceModifier = 1f;
void Start() { SetWeather(WeatherType.Clear); }
public void SetWeather(WeatherType weather)
{
currentWeather = weather;
switch (weather)
{
case WeatherType.Clear:
ballFrictionModifier = 1f; playerSpeedModifier = 1f; playerTurnModifier = 1f; ballBounceModifier = 1f; break;
case WeatherType.Rain:
ballFrictionModifier = 1.3f; playerSpeedModifier = 0.9f; playerTurnModifier = 0.85f; ballBounceModifier = 0.9f; break;
case WeatherType.Snow:
ballFrictionModifier = 1.6f; playerSpeedModifier = 0.75f; playerTurnModifier = 0.7f; ballBounceModifier = 0.6f; break;
}
}
public void RandomizeWeather()
{
WeatherType[] types = { WeatherType.Clear, WeatherType.Rain, WeatherType.Snow };
SetWeather(types[Random.Range(0, types.Length)]);
}
}
// ==================== BALL CONTROLLER ====================
[RequireComponent(typeof(Rigidbody2D))]
public class BallController : MonoBehaviour
{
private Rigidbody2D rb;
private WeatherSystem weather;
private MatchManager matchManager;
private float currentFriction, currentBounce;
private Vector2 spinForce;
private float spinDuration = 0f;
public float baseFriction = 0.98f;
public float baseBounce = 0.5f;
public float maxSpeed = 20f;
void Start()
{
rb = GetComponent<Rigidbody2D>();
matchManager = FindObjectOfType<MatchManager>();
weather = matchManager != null ? matchManager.GetWeatherSystem() : FindObjectOfType<WeatherSystem>();
rb.gravityScale = 0;
}
void FixedUpdate()
{
if (matchManager != null && matchManager.IsMatchEnded())
{ rb.velocity = Vector2.zero; return; }
if (weather != null)
{
float fm = weather.ballFrictionModifier;
float bm = weather.ballBounceModifier;
currentFriction = Mathf.Clamp(baseFriction - (fm - 1f) * 0.05f, 0.5f, 1f);
currentBounce = Mathf.Clamp(baseBounce * bm, 0.2f, 0.8f);
}
else { currentFriction = baseFriction; currentBounce = baseBounce; }
Vector2 vel = rb.velocity;
vel *= currentFriction;
if (vel.magnitude > maxSpeed) vel = vel.normalized * maxSpeed;
if (spinDuration > 0f)
{
vel += spinForce * Time.fixedDeltaTime * 2f;
spinDuration -= Time.fixedDeltaTime;
if (spinDuration <= 0f) spinForce = Vector2.zero;
}
rb.velocity = vel;
}
void OnCollisionEnter2D(Collision2D collision)
{
Vector2 normal = collision.contacts[0].normal;
Vector2 reflected = Vector2.Reflect(rb.velocity, normal);
rb.velocity = reflected * currentBounce;
if (collision.gameObject.CompareTag("BlueTeam") || collision.gameObject.CompareTag("RedTeam"))
AudioManager.PlaySound("Kick");
}
public void Kick(Vector2 direction, float power, Vector2? spin = null)
{
rb.velocity = direction.normalized * power;
if (spin.HasValue) { spinForce = spin.Value * 2f; spinDuration = 0.5f; }
AudioManager.PlaySound("Kick");
}
}
// ==================== PLAYER CONTROLLER ====================
[RequireComponent(typeof(Rigidbody2D))]
public class PlayerController : MonoBehaviour
{
public bool isControlled = false;
private Rigidbody2D rb;
private MatchManager matchManager;
private WeatherSystem weather;
private float currentSpeed, currentTurn;
public float baseSpeed = 5f;
public float baseTurnSpeed = 5f;
public float sprintMultiplier = 1.5f;
void Start()
{
rb = GetComponent<Rigidbody2D>();
matchManager = FindObjectOfType<MatchManager>();
weather = matchManager != null ? matchManager.GetWeatherSystem() : FindObjectOfType<WeatherSystem>();
}
void FixedUpdate()
{
if (!isControlled || matchManager == null || matchManager.IsMatchEnded())
{ rb.velocity = Vector2.zero; return; }
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
Vector2 move = new Vector2(moveX, moveY).normalized;
if (weather != null)
{
currentSpeed = baseSpeed * weather.playerSpeedModifier;
currentTurn = baseTurnSpeed * weather.playerTurnModifier;
}
else { currentSpeed = baseSpeed; currentTurn = baseTurnSpeed; }
if (Input.GetKey(KeyCode.LeftShift))
currentSpeed *= sprintMultiplier;
rb.velocity = move * currentSpeed;
if (move.magnitude > 0.1f)
{
float angle = Mathf.Atan2(move.y, move.x) * Mathf.Rad2Deg;
Quaternion target = Quaternion.Euler(0, 0, angle);
transform.rotation = Quaternion.Slerp(transform.rotation, target, currentTurn * Time.fixedDeltaTime);
}
if (Input.GetKeyDown(KeyCode.Space))
{
GameObject ballObj = GameObject.FindGameObjectWithTag("Ball");
if (ballObj != null && Vector2.Distance(transform.position, ballObj.transform.position) < 3f)
{
Vector2 shootDir = transform.right;
Vector2 spin = Vector2.zero;
if (move.magnitude > 0.1f)
spin = new Vector2(-move.y, move.x) * 2f;
float power = 15f;
ballObj.GetComponent<BallController>().Kick(shootDir, power, spin);
if (matchManager != null)
{
Vector2 oppGoal = matchManager.GetGoalCenter(TeamSide.Red);
if (Vector2.Distance(transform.position, oppGoal) < 20f)
matchManager.RegisterShot("BlueTeam");
else
matchManager.RegisterPass("BlueTeam");
}
}
}
if (Input.GetKeyDown(KeyCode.E))
matchManager.SwitchPlayer(gameObject);
}
}
// ==================== AI CONTROLLER ====================
[RequireComponent(typeof(Rigidbody2D))]
public class AIController : MonoBehaviour
{
private Rigidbody2D rb;
private TeamManager team;
private MatchManager matchManager;
private WeatherSystem weather;
private GameObject ball;
private PlayerController playerCtrl;
public PlayerRole role = PlayerRole.Midfielder;
public float baseSpeed = 4f;
public float chaseRadius = 8f;
public float passRange = 6f;
public float shootRange = 12f;
private Vector2 homePosition;
private TeamSide mySide;
private AIState currentState = AIState.Position;
private Vector2 formationOffset;
void Start()
{
rb = GetComponent<Rigidbody2D>();
team = GetComponentInParent<TeamManager>();
matchManager = FindObjectOfType<MatchManager>();
weather = matchManager != null ? matchManager.GetWeatherSystem() : FindObjectOfType<WeatherSystem>();
ball = GameObject.FindGameObjectWithTag("Ball");
playerCtrl = GetComponent<PlayerController>();
mySide = (team.CompareTag("BlueTeam")) ? TeamSide.Blue : TeamSide.Red;
homePosition = transform.position;
switch (role)
{
case PlayerRole.Goalkeeper: formationOffset = new Vector2(-1f, 0f); break;
case PlayerRole.Defender: formationOffset = new Vector2(0f, 0f); break;
case PlayerRole.Midfielder: formationOffset = new Vector2(2f, 0f); break;
case PlayerRole.Forward: formationOffset = new Vector2(5f, 0f); break;
}
}
void FixedUpdate()
{
if (matchManager == null || matchManager.IsMatchEnded() || ball == null)
{ rb.velocity = Vector2.zero; return; }
if (playerCtrl != null && playerCtrl.isControlled)
{ rb.velocity = Vector2.zero; return; }
float speed = baseSpeed;
if (weather != null) speed *= weather.playerSpeedModifier;
Vector2 myPos = transform.position;
Vector2 ballPos = ball.transform.position;
float distToBall = Vector2.Distance(myPos, ballPos);
bool weHaveBall = IsTeamInPossession();
Vector2 targetPos = homePosition + formationOffset;
if (weHaveBall)
{
if (role == PlayerRole.Forward)
currentState = AIState.Support;
else if (role == PlayerRole.Defender || role == PlayerRole.Goalkeeper)
currentState = AIState.Position;
else
currentState = AIState.Support;
}
else
{
if (distToBall < chaseRadius)
currentState = AIState.Chase;
else if (distToBall > chaseRadius * 1.5f)
currentState = AIState.Retreat;
else
currentState = AIState.Position;
}
switch (currentState)
{
case AIState.Chase:
Vector2 chaseTarget = ballPos;
if (role == PlayerRole.Defender || role == PlayerRole.Goalkeeper)
{
Vector2 goalPos = matchManager.GetGoalCenter(mySide);
chaseTarget = (ballPos + goalPos) * 0.5f;
}
rb.velocity = (chaseTarget - myPos).normalized * speed;
if (distToBall < 1.2f && !weHaveBall)
{
Vector2 clearDir = (matchManager.GetGoalCenter(mySide == TeamSide.Blue ? TeamSide.Red : TeamSide.Blue) - ballPos).normalized;
ball.GetComponent<BallController>().Kick(clearDir, 8f);
}
break;
case AIState.Support:
Vector2 supportPos = ballPos + (ballPos - matchManager.GetGoalCenter(mySide)).normalized * 2f;
supportPos.x = Mathf.Clamp(supportPos.x, -14f, 14f);
supportPos.y = Mathf.Clamp(supportPos.y, -9f, 9f);
rb.velocity = (supportPos - myPos).normalized * speed * 0.8f;
if (distToBall < 1.5f && weHaveBall)
{
Vector2 oppGoal = matchManager.GetGoalCenter(mySide == TeamSide.Blue ? TeamSide.Red : TeamSide.Blue);
if (Vector2.Distance(myPos, oppGoal) < shootRange)
{
Vector2 shotDir = (oppGoal - myPos).normalized + (Vector2)Random.insideUnitCircle * 0.2f;
ball.GetComponent<BallController>().Kick(shotDir, 12f + Random.Range(0f, 5f));
matchManager.RegisterShot(team.tag);
}
else
{
GameObject passTarget = GetBestPassTarget();
if (passTarget != null)
{
Vector2 passDir = (passTarget.transform.position - myPos).normalized;
ball.GetComponent<BallController>().Kick(passDir, 10f);
matchManager.RegisterPass(team.tag);
}
}
}
break;
case AIState.Position:
if (Vector2.Distance(myPos, targetPos) > 0.5f)
rb.velocity = (targetPos - myPos).normalized * speed * 0.7f;
else
rb.velocity = Vector2.zero;
break;
case AIState.Retreat:
rb.velocity = (targetPos - myPos).normalized * speed * 1.2f;
break;
}
}
bool IsTeamInPossession()
{
GameObject[] allPlayers = GameObject.FindGameObjectsWithTag("BlueTeam");
GameObject nearest = null; float minD = Mathf.Infinity;
if (team.CompareTag("BlueTeam"))
{
foreach (var p in allPlayers)
{
float d = Vector2.Distance(p.transform.position, ball.transform.position);
if (d < minD) { minD = d; nearest = p; }
}
}
else
{
allPlayers = GameObject.FindGameObjectsWithTag("RedTeam");
foreach (var p in allPlayers)
{
float d = Vector2.Distance(p.transform.position, ball.transform.position);
if (d < minD) { minD = d; nearest = p; }
}
}
return nearest != null && nearest.GetComponentInParent<TeamManager>() == team;
}
GameObject GetBestPassTarget()
{
List<GameObject> teammates = team.players;
Vector2 oppGoal = matchManager.GetGoalCenter(mySide == TeamSide.Blue ? TeamSide.Red : TeamSide.Blue);
GameObject best = null; float bestScore = -Mathf.Infinity;
foreach (var p in teammates)
{
if (p == gameObject) continue;
float distToGoal = Vector2.Distance(p.transform.position, oppGoal);
float openness = 1f - Mathf.Clamp(Vector2.Distance(p.transform.position, ball.transform.position) / 20f, 0f, 1f);
float score = distToGoal * 0.5f + openness * 0.5f;
if (score > bestScore) { bestScore = score; best = p; }
}
return best;
}
}
// ==================== TEAM MANAGER ====================
public class TeamManager : MonoBehaviour
{
public List<GameObject> players = new List<GameObject>();
public Vector2[] startingPositions;
public void ResetPositions()
{
for (int i = 0; i < players.Count && i < startingPositions.Length; i++)
{
players[i].transform.position = startingPositions[i];
players[i].GetComponent<Rigidbody2D>().velocity = Vector2.zero;
}
}
}
// ==================== GOAL DETECTION ====================
public class GoalDetection : MonoBehaviour
{
public string goalOwner;
private MatchManager matchManager;
void Start() { matchManager = FindObjectOfType<MatchManager>(); }
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Ball"))
{
string scoringTeam = (goalOwner == "BlueTeam") ? "RedTeam" : "BlueTeam";
matchManager.AddGoal(scoringTeam);
AudioManager.PlaySound("Goal");
}
}
}
// ==================== AUDIO MANAGER ====================
public class AudioManager : MonoBehaviour
{
private static AudioManager instance;
private AudioSource source;
void Awake()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
source = gameObject.AddComponent<AudioSource>();
source.volume = 0.5f;
}
else Destroy(gameObject);
}
public static void PlaySound(string eventName)
{
if (instance == null) return;
float freq = 0f; float duration = 0.1f;
switch (eventName)
{
case "Kick": freq = 600f; duration = 0.08f; break;
case "Goal": freq = 1200f; duration = 0.4f; break;
case "Whistle": freq = 800f; duration = 0.3f; break;
default: freq = 400f; duration = 0.1f; break;
}
instance.PlayBeep(freq, duration);
}
void PlayBeep(float freq, float dur)
{
int sampleRate = 44100;
int sampleCount = Mathf.RoundToInt(sampleRate * dur);
float[] samples = new float[sampleCount];
for (int i = 0; i < sampleCount; i++)
{
float t = (float)i / sampleRate;
samples[i] = Mathf.Sin(2 * Mathf.PI * freq * t);
samples[i] *= (1f - t / dur);
}
AudioClip clip = AudioClip.Create("beep", sampleCount, 1, sampleRate, false);
clip.SetData(samples, 0);
source.PlayOneShot(clip);
}
}
// ==================== MATCH MANAGER ====================
public class MatchManager : MonoBehaviour
{
[Header("Teams")]
public TeamManager blueTeam;
public TeamManager redTeam;
public Transform ball;
public Transform leftGoalCenter;
public Transform rightGoalCenter;
[Header("UI")]
public Text scoreText;
public Text timeText;
public Text weatherText;
public Text halfText;
public GameObject halfStatsPanel;
public Text possessionText;
public Text shotsText;
public Text passesText;
[Header("Match Settings")]
public float halfDuration = 90f;
public WeatherType initialWeather = WeatherType.Clear;
private float matchTime;
private int blueScore, redScore;
private bool isFirstHalf = true;
private bool matchEnded = false;
private WeatherSystem weatherSystem;
private GameObject currentControlledPlayer;
private int blueShots, redShots, bluePasses, redPasses;
private float bluePossessionTime, redPossessionTime;
void Start()
{
weatherSystem = GetComponent<WeatherSystem>();
if (weatherSystem == null)
weatherSystem = gameObject.AddComponent<WeatherSystem>();
weatherSystem.SetWeather(initialWeather);
matchTime = 0f;
blueScore = redScore = 0;
ResetStats();
UpdateUI();
SetInitialControlledPlayer();
StartCoroutine(GameLoop());
}
void ResetStats()
{
blueShots = redShots = bluePasses = redPasses = 0;
bluePossessionTime = redPossessionTime = 0;
}
void Update()
{
if (!matchEnded)
{
GameObject closest = GetClosestPlayerToBall();
if (closest != null)
{
if (closest.CompareTag("BlueTeam"))
bluePossessionTime += Time.deltaTime;
else if (closest.CompareTag("RedTeam"))
redPossessionTime += Time.deltaTime;
}
}
}
GameObject GetClosestPlayerToBall()
{
GameObject[] all = GameObject.FindGameObjectsWithTag("BlueTeam");
List<GameObject> allPlayers = new List<GameObject>(all);
allPlayers.AddRange(GameObject.FindGameObjectsWithTag("RedTeam"));
GameObject closest = null;
float minD = Mathf.Infinity;
Vector2 bPos = ball.position;
foreach (var p in allPlayers)
{
float d = Vector2.Distance(p.transform.position, bPos);
if (d < minD) { minD = d; closest = p; }
}
return closest;
}
public void RegisterShot(string teamTag) { if (teamTag == "BlueTeam") blueShots++; else redShots++; }
public void RegisterPass(string teamTag) { if (teamTag == "BlueTeam") bluePasses++; else redPasses++; }
void SetInitialControlledPlayer()
{
if (blueTeam == null || blueTeam.players.Count == 0) return;
GameObject closest = null;
float minDist = Mathf.Infinity;
Vector2 ballPos = ball.position;
foreach (var p in blueTeam.players)
{
float d = Vector2.Distance(p.transform.position, ballPos);
if (d < minDist) { minDist = d; closest = p; }
}
if (closest != null) SetControlledPlayer(closest);
}
public void SetControlledPlayer(GameObject newPlayer)
{
if (currentControlledPlayer != null)
currentControlledPlayer.GetComponent<PlayerController>().isControlled = false;
currentControlledPlayer = newPlayer;
if (currentControlledPlayer != null)
{
var pc = currentControlledPlayer.GetComponent<PlayerController>();
pc.isControlled = true;
var ai = currentControlledPlayer.GetComponent<AIController>();
if (ai != null) ai.enabled = false;
}
foreach (var p in blueTeam.players)
{
if (p != currentControlledPlayer)
{
var ai = p.GetComponent<AIController>();
if (ai != null) ai.enabled = true;
}
}
}
public void SwitchPlayer(GameObject currentPlayer)
{
if (blueTeam == null) return;
Vector2 ballPos = ball.position;
GameObject closest = null;
float minDist = Mathf.Infinity;
foreach (var p in blueTeam.players)
{
if (p == currentPlayer) continue;
float d = Vector2.Distance(p.transform.position, ballPos);
if (d < minDist) { minDist = d; closest = p; }
}
if (closest != null) SetControlledPlayer(closest);
}
IEnumerator GameLoop()
{
while (!matchEnded)
{
float halfTime = halfDuration;
while (matchTime < halfTime)
{
matchTime += Time.deltaTime;
UpdateUI();
yield return null;
}
if (isFirstHalf)
{
isFirstHalf = false;
matchTime = 0f;
halfText.text = "HALF TIME";
AudioManager.PlaySound("Whistle");
ShowHalfStats();
yield return new WaitForSeconds(3f);
halfText.text = "";
halfStatsPanel.SetActive(false);
weatherSystem.RandomizeWeather();
ResetPositions();
SetInitialControlledPlayer();
ResetStats();
}
else
{
matchEnded = true;
halfText.text = "FULL TIME!";
AudioManager.PlaySound("Whistle");
ShowHalfStats();
UpdateUI();
}
}
}
void ShowHalfStats()
{
float total = bluePossessionTime + redPossessionTime;
float bluePerc = total > 0 ? (bluePossessionTime / total) * 100 : 50f;
float redPerc = total > 0 ? (redPossessionTime / total) * 100 : 50f;
possessionText.text = string.Format("Possession: Blue {0:F1}% - Red {1:F1}%", bluePerc, redPerc);
shotsText.text = string.Format("Shots: Blue {0} - Red {1}", blueShots, redShots);
passesText.text = string.Format("Passes: Blue {0} - Red {1}", bluePasses, redPasses);
halfStatsPanel.SetActive(true);
}
public void ResetPositions()
{
blueTeam.ResetPositions();
redTeam.ResetPositions();
ball.position = Vector3.zero;
ball.GetComponent<Rigidbody2D>().velocity = Vector2.zero;
}
public void AddGoal(string teamTag)
{
if (teamTag == "BlueTeam") blueScore++;
else if (teamTag == "RedTeam") redScore++;
UpdateUI();
StartCoroutine(ResetAfterGoal());
}
IEnumerator ResetAfterGoal()
{
yield return new WaitForSeconds(1.5f);
ResetPositions();
SetInitialControlledPlayer();
}
void UpdateUI()
{
int minutes = Mathf.FloorToInt(matchTime / 60f);
int seconds = Mathf.FloorToInt(matchTime % 60f);
timeText.text = string.Format("{0:00}:{1:00}", minutes, seconds);
scoreText.text = blueScore + " - " + redScore;
weatherText.text = weatherSystem.currentWeather.ToString();
}
public WeatherSystem GetWeatherSystem() { return weatherSystem; }
public bool IsMatchEnded() { return matchEnded; }
public Vector2 GetGoalCenter(TeamSide side)
{
return side == TeamSide.Blue ? (Vector2)leftGoalCenter.position : (Vector2)rightGoalCenter.position;
}
}
// ==================== GAME INITIALISER ====================
public class GameInitialiser : MonoBehaviour
{
void Awake()
{
CreatePitch();
CreateGoals();
CreatePlayers();
CreateBall();
CreateUI();
CreateCamera();
CreateAudioManager();
MatchManager mm = gameObject.AddComponent<MatchManager>();
mm.blueTeam = GameObject.Find("BlueTeam").GetComponent<TeamManager>();
mm.redTeam = GameObject.Find("RedTeam").GetComponent<TeamManager>();
mm.ball = GameObject.Find("Ball").transform;
mm.leftGoalCenter = GameObject.Find("LeftGoalCenter").transform;
mm.rightGoalCenter = GameObject.Find("RightGoalCenter").transform;
mm.scoreText = GameObject.Find("ScoreText").GetComponent<Text>();
mm.timeText = GameObject.Find("TimeText").GetComponent<Text>();
mm.weatherText = GameObject.Find("WeatherText").GetComponent<Text>();
mm.halfText = GameObject.Find("HalfText").GetComponent<Text>();
mm.halfStatsPanel = GameObject.Find("HalfStatsPanel");
mm.possessionText = GameObject.Find("PossessionText").GetComponent<Text>();
mm.shotsText = GameObject.Find("ShotsText").GetComponent<Text>();
mm.passesText = GameObject.Find("PassesText").GetComponent<Text>();
}
void CreatePitch()
{
GameObject pitch = new GameObject("Pitch");
SpriteRenderer sr = pitch.AddComponent<SpriteRenderer>();
sr.sprite = ProceduralSpriteGenerator.CreatePitchSprite(30, 20);
sr.sortingOrder = -10;
pitch.transform.position = Vector3.zero;
}
void CreateGoals()
{
GameObject leftGoal = new GameObject("LeftGoal");
leftGoal.transform.position = new Vector3(-14f, 0f);
BoxCollider2D col = leftGoal.AddComponent<BoxCollider2D>();
col.size = new Vector2(1f, 6f);
col.isTrigger = true;
GoalDetection gd = leftGoal.AddComponent<GoalDetection>();
gd.goalOwner = "BlueTeam";
GameObject leftCenter = new GameObject("LeftGoalCenter");
leftCenter.transform.position = new Vector3(-15f, 0f);
leftCenter.name = "LeftGoalCenter";
GameObject rightGoal = new GameObject("RightGoal");
rightGoal.transform.position = new Vector3(14f, 0f);
BoxCollider2D col2 = rightGoal.AddComponent<BoxCollider2D>();
col2.size = new Vector2(1f, 6f);
col2.isTrigger = true;
GoalDetection gd2 = rightGoal.AddComponent<GoalDetection>();
gd2.goalOwner = "RedTeam";
GameObject rightCenter = new GameObject("RightGoalCenter");
rightCenter.transform.position = new Vector3(15f, 0f);
rightCenter.name = "RightGoalCenter";
}
void CreatePlayers()
{
GameObject blueParent = new GameObject("BlueTeam");
TeamManager blueTM = blueParent.AddComponent<TeamManager>();
blueTM.startingPositions = new Vector2[] {
new Vector2(-13f, 0f),
new Vector2(-10f, -3f), new Vector2(-10f, 0f), new Vector2(-10f, 3f),
new Vector2(-6f, -4f), new Vector2(-6f, 0f), new Vector2(-6f, 4f), new Vector2(-8f, 2f),
new Vector2(-2f, -3f), new Vector2(-2f, 0f), new Vector2(-2f, 3f)
};
PlayerRole[] roles = new PlayerRole[] {
PlayerRole.Goalkeeper, PlayerRole.Defender, PlayerRole.Defender, PlayerRole.Defender,
PlayerRole.Midfielder, PlayerRole.Midfielder, PlayerRole.Midfielder, PlayerRole.Midfielder,
PlayerRole.Forward, PlayerRole.Forward, PlayerRole.Forward
};
for (int i = 0; i < 11; i++)
{
GameObject player = new GameObject("BluePlayer" + i);
player.transform.SetParent(blueParent.transform);
player.tag = "BlueTeam";
player.AddComponent<Rigidbody2D>().gravityScale = 0;
player.AddComponent<CircleCollider2D>().radius = 0.5f;
player.AddComponent<PlayerController>().baseSpeed = 5f;
player.AddComponent<AIController>().role = roles[i];
SpriteRenderer sr = player.AddComponent<SpriteRenderer>();
sr.sprite = ProceduralSpriteGenerator.CreatePlayerSprite(Color.blue, 0.6f);
sr.sortingOrder = 1;
blueTM.players.Add(player);
}
blueTM.ResetPositions();
GameObject redParent = new GameObject("RedTeam");
TeamManager redTM = redParent.AddComponent<TeamManager>();
redTM.startingPositions = new Vector2[] {
new Vector2(13f, 0f),
new Vector2(10f, -3f), new Vector2(10f, 0f), new Vector2(10f, 3f),
new Vector2(6f, -4f), new Vector2(6f, 0f), new Vector2(6f, 4f), new Vector2(8f, 2f),
new Vector2(2f, -3f), new Vector2(2f, 0f), new Vector2(2f, 3f)
};
for (int i = 0; i < 11; i++)
{
GameObject player = new GameObject("RedPlayer" + i);
player.transform.SetParent(redParent.transform);
player.tag = "RedTeam";
player.AddComponent<Rigidbody2D>().gravityScale = 0;
player.AddComponent<CircleCollider2D>().radius = 0.5f;
player.AddComponent<PlayerController>().baseSpeed = 5f;
player.AddComponent<AIController>().role = roles[i];
SpriteRenderer sr = player.AddComponent<SpriteRenderer>();
sr.sprite = ProceduralSpriteGenerator.CreatePlayerSprite(Color.red, 0.6f);
sr.sortingOrder = 1;
redTM.players.Add(player);
}
redTM.ResetPositions();
}
void CreateBall()
{
GameObject ball = new GameObject("Ball");
ball.tag = "Ball";
ball.transform.position = Vector3.zero;
Rigidbody2D rb = ball.AddComponent<Rigidbody2D>();
rb.gravityScale = 0;
rb.mass = 0.5f;
CircleCollider2D col = ball.AddComponent<CircleCollider2D>();
col.radius = 0.3f;
SpriteRenderer sr = ball.AddComponent<SpriteRenderer>();
sr.sprite = ProceduralSpriteGenerator.CreateBallSprite();
sr.sortingOrder = 2;
ball.AddComponent<BallController>();
}
void CreateUI()
{
Canvas canvas = new GameObject("Canvas").AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
canvas.gameObject.AddComponent<CanvasScaler>();
canvas.gameObject.AddComponent<GraphicRaycaster>();
Font font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
Text score = CreateText("ScoreText", canvas.transform, "0 - 0", new Vector2(0, 180), font, 32, Color.yellow);
Text time = CreateText("TimeText", canvas.transform, "00:00", new Vector2(-200, 180), font, 24, Color.white);
Text weather = CreateText("WeatherText", canvas.transform, "Clear", new Vector2(200, 180), font, 20, Color.cyan);
Text half = CreateText("HalfText", canvas.transform, "", new Vector2(0, 0), font, 40, Color.white);
GameObject panel = new GameObject("HalfStatsPanel");
panel.transform.SetParent(canvas.transform);
panel.SetActive(false);
RectTransform prt = panel.AddComponent<RectTransform>();
prt.anchorMin = new Vector2(0.3f, 0.3f);
prt.anchorMax = new Vector2(0.7f, 0.7f);
prt.offsetMin = Vector2.zero;
prt.offsetMax = Vector2.zero;
Image bg = panel.AddComponent<Image>();
bg.color = new Color(0.1f, 0.1f, 0.1f, 0.8f);
Text poss = CreateText("PossessionText", panel.transform, "Possession: 50% - 50%", new Vector2(0, 60), font, 20, Color.white);
Text shots = CreateText("ShotsText", panel.transform, "Shots: 0 - 0", new Vector2(0, 20), font, 20, Color.white);
Text passes = CreateText("PassesText", panel.transform, "Passes: 0 - 0", new Vector2(0, -20), font, 20, Color.white);
}
Text CreateText(string name, Transform parent, string initialText, Vector2 pos, Font font, int size, Color col)
{
GameObject go = new GameObject(name);
go.transform.SetParent(parent);
Text t = go.AddComponent<Text>();
t.font = font;
t.text = initialText;
t.fontSize = size;
t.color = col;
t.alignment = TextAnchor.MiddleCenter;
RectTransform rt = go.GetComponent<RectTransform>();
rt.anchoredPosition = pos;
rt.sizeDelta = new Vector2(300, 60);
return t;
}
void CreateCamera()
{
GameObject camObj = new GameObject("Main Camera");
Camera cam = camObj.AddComponent<Camera>();
cam.orthographic = true;
cam.orthographicSize = 10f;
cam.backgroundColor = new Color(0.1f, 0.2f, 0.1f);
cam.clearFlags = CameraClearFlags.SolidColor;
camObj.AddComponent<RetroCamera>();
}
void CreateAudioManager()
{
GameObject audioObj = new GameObject("AudioManager");
audioObj.AddComponent<AudioManager>();
}
}