Tanks(二)—— 攝像機與遊戲管理器指令碼
阿新 • • 發佈:2018-12-21
Camera - CameraControl
沒看明白啊,有空再看
using UnityEngine; namespace Complete { public class CameraControl : MonoBehaviour { public float m_DampTime = 0.2f; // Approximate time for the camera to refocus. public float m_ScreenEdgeBuffer = 4f; // Space between the top/bottom most target and the screen edge. public float m_MinSize = 6.5f; // The smallest orthographic size the camera can be. [HideInInspector] public Transform[] m_Targets; // All the targets the camera needs to encompass. private Camera m_Camera; // Used for referencing the camera. private float m_ZoomSpeed; // Reference speed for the smooth damping of the orthographic size. private Vector3 m_MoveVelocity; // Reference velocity for the smooth damping of the position. private Vector3 m_DesiredPosition; // The position the camera is moving towards. private void Awake () { m_Camera = GetComponentInChildren<Camera> (); } private void FixedUpdate () { // Move the camera towards a desired position. Move (); // Change the size of the camera based. Zoom (); } private void Move () { // Find the average position of the targets. FindAveragePosition (); // Smoothly transition to that position. transform.position = Vector3.SmoothDamp(transform.position, m_DesiredPosition, ref m_MoveVelocity, m_DampTime); } private void FindAveragePosition () { Vector3 averagePos = new Vector3 (); int numTargets = 0; // Go through all the targets and add their positions together. for (int i = 0; i < m_Targets.Length; i++) { // If the target isn't active, go on to the next one. if (!m_Targets[i].gameObject.activeSelf) continue; // Add to the average and increment the number of targets in the average. averagePos += m_Targets[i].position; numTargets++; } // If there are targets divide the sum of the positions by the number of them to find the average. if (numTargets > 0) averagePos /= numTargets; // Keep the same y value. averagePos.y = transform.position.y; // The desired position is the average position; m_DesiredPosition = averagePos; } private void Zoom () { // Find the required size based on the desired position and smoothly transition to that size. float requiredSize = FindRequiredSize(); m_Camera.orthographicSize = Mathf.SmoothDamp (m_Camera.orthographicSize, requiredSize, ref m_ZoomSpeed, m_DampTime); } private float FindRequiredSize () { // Find the position the camera rig is moving towards in its local space. Vector3 desiredLocalPos = transform.InverseTransformPoint(m_DesiredPosition); // Start the camera's size calculation at zero. float size = 0f; // Go through all the targets... for (int i = 0; i < m_Targets.Length; i++) { // ... and if they aren't active continue on to the next target. if (!m_Targets[i].gameObject.activeSelf) continue; // Otherwise, find the position of the target in the camera's local space. Vector3 targetLocalPos = transform.InverseTransformPoint(m_Targets[i].position); // Find the position of the target from the desired position of the camera's local space. Vector3 desiredPosToTarget = targetLocalPos - desiredLocalPos; // Choose the largest out of the current size and the distance of the tank 'up' or 'down' from the camera. size = Mathf.Max(size, Mathf.Abs(desiredPosToTarget.y)); // Choose the largest out of the current size and the calculated size based on the tank being to the left or right of the camera. size = Mathf.Max(size, Mathf.Abs(desiredPosToTarget.x) / m_Camera.aspect); } // Add the edge buffer to the size. size += m_ScreenEdgeBuffer; // Make sure the camera's size isn't below the minimum. size = Mathf.Max (size, m_MinSize); return size; } public void SetStartPositionAndSize () { // Find the desired position. FindAveragePosition (); // Set the camera's position to the desired position without damping. transform.position = m_DesiredPosition; // Find and set the required size of the camera. m_Camera.orthographicSize = FindRequiredSize (); } } }
Managers - TankManager
注意這裡沒有給m_PlayerColor設定初始值,預設為紅色,第一輛坦克手動調為了藍色。
using System; using UnityEngine; namespace Complete { [Serializable] public class TankManager { // This class is to manage various settings on a tank. // It works with the GameManager class to control how the tanks behave // and whether or not players have control of their tank in the // different phases of the game. public Color m_PlayerColor; // This is the color this tank will be tinted. public Transform m_SpawnPoint; // The position and direction the tank will have when it spawns. [HideInInspector] public int m_PlayerNumber; // This specifies which player this the manager for. [HideInInspector] public string m_ColoredPlayerText; // A string that represents the player with their number colored to match their tank. [HideInInspector] public GameObject m_Instance; // A reference to the instance of the tank when it is created. [HideInInspector] public int m_Wins; // The number of wins this player has so far. private TankMovement m_Movement; // Reference to tank's movement script, used to disable and enable control. private TankShooting m_Shooting; // Reference to tank's shooting script, used to disable and enable control. private GameObject m_CanvasGameObject; // Used to disable the world space UI during the Starting and Ending phases of each round. public void Setup () { // Get references to the components. m_Movement = m_Instance.GetComponent<TankMovement> (); m_Shooting = m_Instance.GetComponent<TankShooting> (); m_CanvasGameObject = m_Instance.GetComponentInChildren<Canvas> ().gameObject; // Set the player numbers to be consistent across the scripts. m_Movement.m_PlayerNumber = m_PlayerNumber; m_Shooting.m_PlayerNumber = m_PlayerNumber; // Create a string using the correct color that says 'PLAYER 1' etc based on the tank's color and the player's number. m_ColoredPlayerText = "<color=#" + ColorUtility.ToHtmlStringRGB(m_PlayerColor) + ">PLAYER " + m_PlayerNumber + "</color>"; // Get all of the renderers of the tank. MeshRenderer[] renderers = m_Instance.GetComponentsInChildren<MeshRenderer> (); // Go through all the renderers... for (int i = 0; i < renderers.Length; i++) { // ... set their material color to the color specific to this tank. renderers[i].material.color = m_PlayerColor; } } // Used during the phases of the game where the player shouldn't be able to control their tank. public void DisableControl () { m_Movement.enabled = false; m_Shooting.enabled = false; m_CanvasGameObject.SetActive (false); } // Used during the phases of the game where the player should be able to control their tank. public void EnableControl () { m_Movement.enabled = true; m_Shooting.enabled = true; m_CanvasGameObject.SetActive (true); } // Used at the start of each round to put the tank into it's default state. public void Reset () { m_Instance.transform.position = m_SpawnPoint.position; m_Instance.transform.rotation = m_SpawnPoint.rotation; m_Instance.SetActive (false); m_Instance.SetActive (true); } } }
Manager - GameManager
using System.Collections; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; namespace Complete { public class GameManager : MonoBehaviour { public int m_NumRoundsToWin = 5; // The number of rounds a single player has to win to win the game. public float m_StartDelay = 3f; // The delay between the start of RoundStarting and RoundPlaying phases. public float m_EndDelay = 3f; // The delay between the end of RoundPlaying and RoundEnding phases. public CameraControl m_CameraControl; // Reference to the CameraControl script for control during different phases. public Text m_MessageText; // Reference to the overlay Text to display winning text, etc. public GameObject m_TankPrefab; // Reference to the prefab the players will control. public TankManager[] m_Tanks; // A collection of managers for enabling and disabling different aspects of the tanks. private int m_RoundNumber; // Which round the game is currently on. private WaitForSeconds m_StartWait; // Used to have a delay whilst the round starts. private WaitForSeconds m_EndWait; // Used to have a delay whilst the round or game ends. private TankManager m_RoundWinner; // Reference to the winner of the current round. Used to make an announcement of who won. private TankManager m_GameWinner; // Reference to the winner of the game. Used to make an announcement of who won. private void Start() { // Create the delays so they only have to be made once. m_StartWait = new WaitForSeconds (m_StartDelay); m_EndWait = new WaitForSeconds (m_EndDelay); SpawnAllTanks(); SetCameraTargets(); // Once the tanks have been created and the camera is using them as targets, start the game. StartCoroutine (GameLoop ()); } private void SpawnAllTanks() { // For all the tanks... for (int i = 0; i < m_Tanks.Length; i++) { // ... create them, set their player number and references needed for control. m_Tanks[i].m_Instance = Instantiate(m_TankPrefab, m_Tanks[i].m_SpawnPoint.position, m_Tanks[i].m_SpawnPoint.rotation) as GameObject; m_Tanks[i].m_PlayerNumber = i + 1; m_Tanks[i].Setup(); } } private void SetCameraTargets() { // Create a collection of transforms the same size as the number of tanks. Transform[] targets = new Transform[m_Tanks.Length]; // For each of these transforms... for (int i = 0; i < targets.Length; i++) { // ... set it to the appropriate tank transform. targets[i] = m_Tanks[i].m_Instance.transform; } // These are the targets the camera should follow. m_CameraControl.m_Targets = targets; } // This is called from start and will run each phase of the game one after another. private IEnumerator GameLoop () { // Start off by running the 'RoundStarting' coroutine but don't return until it's finished. yield return StartCoroutine (RoundStarting ()); // Once the 'RoundStarting' coroutine is finished, run the 'RoundPlaying' coroutine but don't return until it's finished. yield return StartCoroutine (RoundPlaying()); // Once execution has returned here, run the 'RoundEnding' coroutine, again don't return until it's finished. yield return StartCoroutine (RoundEnding()); // This code is not run until 'RoundEnding' has finished. At which point, check if a game winner has been found. if (m_GameWinner != null) { // If there is a game winner, restart the level. SceneManager.LoadScene (0); } else { // If there isn't a winner yet, restart this coroutine so the loop continues. // Note that this coroutine doesn't yield. This means that the current version of the GameLoop will end. StartCoroutine (GameLoop ()); } } private IEnumerator RoundStarting () { // As soon as the round starts reset the tanks and make sure they can't move. ResetAllTanks (); DisableTankControl (); // Snap the camera's zoom and position to something appropriate for the reset tanks. m_CameraControl.SetStartPositionAndSize (); // Increment the round number and display text showing the players what round it is. m_RoundNumber++; m_MessageText.text = "ROUND " + m_RoundNumber; // Wait for the specified length of time until yielding control back to the game loop. yield return m_StartWait; } private IEnumerator RoundPlaying () { // As soon as the round begins playing let the players control the tanks. EnableTankControl (); // Clear the text from the screen. m_MessageText.text = string.Empty; // While there is not one tank left... while (!OneTankLeft()) { // ... return on the next frame. yield return null; } } private IEnumerator RoundEnding () { // Stop tanks from moving. DisableTankControl (); // Clear the winner from the previous round. m_RoundWinner = null; // See if there is a winner now the round is over. m_RoundWinner = GetRoundWinner (); // If there is a winner, increment their score. if (m_RoundWinner != null) m_RoundWinner.m_Wins++; // Now the winner's score has been incremented, see if someone has one the game. m_GameWinner = GetGameWinner (); // Get a message based on the scores and whether or not there is a game winner and display it. string message = EndMessage (); m_MessageText.text = message; // Wait for the specified length of time until yielding control back to the game loop. yield return m_EndWait; } // This is used to check if there is one or fewer tanks remaining and thus the round should end. private bool OneTankLeft() { // Start the count of tanks left at zero. int numTanksLeft = 0; // Go through all the tanks... for (int i = 0; i < m_Tanks.Length; i++) { // ... and if they are active, increment the counter. if (m_Tanks[i].m_Instance.activeSelf) numTanksLeft++; } // If there are one or fewer tanks remaining return true, otherwise return false. return numTanksLeft <= 1; } // This function is to find out if there is a winner of the round. // This function is called with the assumption that 1 or fewer tanks are currently active. private TankManager GetRoundWinner() { // Go through all the tanks... for (int i = 0; i < m_Tanks.Length; i++) { // ... and if one of them is active, it is the winner so return it. if (m_Tanks[i].m_Instance.activeSelf) return m_Tanks[i]; } // If none of the tanks are active it is a draw so return null. return null; } // This function is to find out if there is a winner of the game. private TankManager GetGameWinner() { // Go through all the tanks... for (int i = 0; i < m_Tanks.Length; i++) { // ... and if one of them has enough rounds to win the game, return it. if (m_Tanks[i].m_Wins == m_NumRoundsToWin) return m_Tanks[i]; } // If no tanks have enough rounds to win, return null. return null; } // Returns a string message to display at the end of each round. private string EndMessage() { // By default when a round ends there are no winners so the default end message is a draw. string message = "DRAW!"; // If there is a winner then change the message to reflect that. if (m_RoundWinner != null) message = m_RoundWinner.m_ColoredPlayerText + " WINS THE ROUND!"; // Add some line breaks after the initial message. message += "\n\n\n\n"; // Go through all the tanks and add each of their scores to the message. for (int i = 0; i < m_Tanks.Length; i++) { message += m_Tanks[i].m_ColoredPlayerText + ": " + m_Tanks[i].m_Wins + " WINS\n"; } // If there is a game winner, change the entire message to reflect that. if (m_GameWinner != null) message = m_GameWinner.m_ColoredPlayerText + " WINS THE GAME!"; return message; } // This function is used to turn all the tanks back on and reset their positions and properties. private void ResetAllTanks() { for (int i = 0; i < m_Tanks.Length; i++) { m_Tanks[i].Reset(); } } private void EnableTankControl() { for (int i = 0; i < m_Tanks.Length; i++) { m_Tanks[i].EnableControl(); } } private void DisableTankControl() { for (int i = 0; i < m_Tanks.Length; i++) { m_Tanks[i].DisableControl(); } } } }