using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Collections;
using System.Collections.Generic;
// Zaroori: Script ka naam aur file ka naam same hona chahiye: "RacingGameSuperScript"
public class RacingGameSuperScript : MonoBehaviour
{
// ==========================================
// 1. GAME SETTINGS & REFERENCES
// ==========================================
[Header("--- Game References ---")]
public Transform playerCar; // Player ki car body
public Transform[] aiCars; // AI Cars ki list
public Transform cameraTarget; // Camera follow target (Player ke andar)
public Transform waypointContainer; // Empty object jiske bache waypoints hain
[Header("--- UI References ---")]
public GameObject mainMenuPanel;
public GameObject gameplayPanel;
public GameObject gameOverPanel;
public Text speedText;
public Text coinsText;
public Text positionText;
[Header("--- Mobile Controls (Assign UI Buttons) ---")]
// In buttons par EventTrigger laga kar ye bools control honge
public bool pressGas = false;
public bool pressBrake = false;
public bool pressLeft = false;
public bool pressRight = false;
// Internal States
private bool isGameActive = false;
private int coins = 0;
private float raceTimer = 0f;
// Singleton Instance
public static RacingGameSuperScript Instance;
void Awake()
{
Instance = this;
SetupUI();
}
void Update()
{
if (!isGameActive) return;
// UI Updates
if (playerCar != null)
{
float speed = playerCar.GetComponent().velocity.magnitude * 3.6f;
speedText.text = Mathf.FloorToInt(speed) + " KM/H";
}
raceTimer += Time.deltaTime;
// Quick Restart (Back Key for Android)
if (Input.GetKeyDown(KeyCode.Escape)) TogglePause();
}
// ==========================================
// 2. GAME LOGIC (MANAGER)
// ==========================================
public void StartGame()
{
isGameActive = true;
mainMenuPanel.SetActive(false);
gameplayPanel.SetActive(true);
gameOverPanel.SetActive(false);
// Initialize Player Car
SetupCarPhysics(playerCar, false);
// Initialize AI Cars
foreach (Transform ai in aiCars)
{
SetupCarPhysics(ai, true);
}
}
public void EndGame(bool win)
{
isGameActive = false;
gameplayPanel.SetActive(false);
gameOverPanel.SetActive(true);
// Show Ads Logic here
Debug.Log(win ? "You Won! +50 Coins" : "You Lost! Try Again");
if(win) coins += 50;
SaveData();
}
public void RestartGame()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
void SetupUI()
{
mainMenuPanel.SetActive(true);
gameplayPanel.SetActive(false);
gameOverPanel.SetActive(false);
coins = PlayerPrefs.GetInt("Coins", 0);
coinsText.text = "Coins: " + coins;
}
void SaveData()
{
PlayerPrefs.SetInt("Coins", coins);
PlayerPrefs.Save();
}
void TogglePause()
{
// Simple pause toggle
Time.timeScale = Time.timeScale == 0 ? 1 : 0;
}
// ==========================================
// 3. COMPONENT SETUP HELPER
// ==========================================
void SetupCarPhysics(Transform carObj, bool isAI)
{
// Agar pehle se components hain to hata do ya skip karo
if (carObj.GetComponent() == null)
{
SimpleCarController controller = carObj.gameObject.AddComponent();
controller.isAI = isAI;
// Basic physics setup
Rigidbody rb = carObj.GetComponent();
if(rb == null) rb = carObj.gameObject.AddComponent();
rb.mass = 1500;
rb.drag = 0.05f;
rb.angularDrag = 0.05f;
}
}
}
// ==========================================
// 4. THE CAR CONTROLLER LOGIC (Physics)
// ==========================================
public class SimpleCarController : MonoBehaviour
{
public bool isAI = false;
[Header("Settings")]
public float motorForce = 1500f;
public float steerAngle = 30f;
public float brakeForce = 3000f;
public float antiRoll = 5000f;
// Wheel Colliders (Code will find them automatically if named correctly)
public WheelCollider FL, FR, RL, RR;
private Rigidbody rb;
private RacingGameSuperScript gameManager;
// AI Variables
private List waypoints;
private int currentWaypoint = 0;
void Start()
{
rb = GetComponent();
gameManager = RacingGameSuperScript.Instance;
// Auto-Find Wheel Colliders (Ensure you name them FL, FR, RL, RR in Editor)
WheelCollider[] wheels = GetComponentsInChildren();
if(wheels.Length >= 4) { FL = wheels[0]; FR = wheels[1]; RL = wheels[2]; RR = wheels[3]; }
// Stabilize Car (Lower Center of Mass)
rb.centerOfMass = new Vector3(0, -0.5f, 0);
// AI Setup
if (isAI && gameManager.waypointContainer != null)
{
waypoints = new List();
foreach(Transform t in gameManager.waypointContainer) waypoints.Add(t);
}
}
void FixedUpdate()
{
float inputGas = 0f;
float inputSteer = 0f;
bool inputBrake = false;
if (isAI)
{
// --- AI LOGIC ---
if (waypoints != null && waypoints.Count > 0)
{
Vector3 target = waypoints[currentWaypoint].position;
Vector3 relativeVector = transform.InverseTransformPoint(target);
inputSteer = (relativeVector.x / relativeVector.magnitude);
inputGas = 1f; // Always accelerator
// Waypoint Distance Check
if (Vector3.Distance(transform.position, target) < 10f)
{
currentWaypoint = (currentWaypoint + 1) % waypoints.Count;
}
}
}
else
{
// --- PLAYER MOBILE INPUT ---
if (gameManager.pressGas) inputGas = 1f;
if (gameManager.pressLeft) inputSteer = -1f;
if (gameManager.pressRight) inputSteer = 1f;
if (gameManager.pressBrake) inputBrake = true;
// Keyboard Override for Editor
if (Application.isEditor && inputGas == 0 && inputSteer == 0)
{
inputGas = Input.GetAxis("Vertical");
inputSteer = Input.GetAxis("Horizontal");
inputBrake = Input.GetKey(KeyCode.Space);
}
}
MoveCar(inputGas, inputSteer, inputBrake);
}
void MoveCar(float gas, float steer, bool brake)
{
if (RL == null || RR == null) return; // Safety check
// Apply Motor
RL.motorTorque = gas * motorForce;
RR.motorTorque = gas * motorForce;
// Apply Steer
FL.steerAngle = steer * steerAngle;
FR.steerAngle = steer * steerAngle;
// Apply Brake
float currentBrake = brake ? brakeForce : 0f;
FL.brakeTorque = currentBrake;
FR.brakeTorque = currentBrake;
RL.brakeTorque = currentBrake;
RR.brakeTorque = currentBrake;
// Anti-Roll Bar Logic (Keeps car stable)
ApplyAntiRoll(FL, FR);
ApplyAntiRoll(RL, RR);
}
void ApplyAntiRoll(WheelCollider WL, WheelCollider WR)
{
WheelHit hit;
float travelL = 1.0f;
float travelR = 1.0f;
bool groundedL = WL.GetGroundHit(out hit);
if (groundedL) travelL = (-WL.transform.InverseTransformPoint(hit.point).y - WL.radius) / WL.suspensionDistance;
bool groundedR = WR.GetGroundHit(out hit);
if (groundedR) travelR = (-WR.transform.InverseTransformPoint(hit.point).y - WR.radius) / WR.suspensionDistance;
float antiRollForce = (travelL - travelR) * antiRoll;
if (groundedL) rb.AddForceAtPosition(WL.transform.up * -antiRollForce, WL.transform.position);
if (groundedR) rb.AddForceAtPosition(WR.transform.up * antiRollForce, WR.transform.position);
}
}
// ==========================================
// 5. CAMERA FOLLOW SCRIPT
// ==========================================
public class SimpleCameraFollow : MonoBehaviour
{
public Transform target;
public float distance = 6.0f;
public float height = 2.5f;
public float damping = 5.0f;
void Start()
{
// Auto find player if target is null
if(target == null && RacingGameSuperScript.Instance != null)
{
target = RacingGameSuperScript.Instance.playerCar;
}
}
void LateUpdate()
{
if (!target) return;
float wantedRotationAngle = target.eulerAngles.y;
float wantedHeight = target.position.y + height;
float currentRotationAngle = transform.eulerAngles.y;
float currentHeight = transform.position.y;
currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, damping * Time.deltaTime);
currentHeight = Mathf.Lerp(currentHeight, wantedHeight, damping * Time.deltaTime);
Quaternion currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);
Vector3 pos = target.position;
pos -= currentRotation * Vector3.forward * distance;
pos.y = currentHeight;
transform.position = pos;
transform.LookAt(target);
}
}