Я делаю "Танки!" Учебное пособие по Unity и руководство сказали мне удалить объект танка, так как это был Prefab и вместо него будут использоваться точки появления. Я проследил за видео, но он говорит, что m_Targets CameraControl не были назначены, так как он скрыт в инспекторе и не предназначен для изменения в соответствии с видео. Я пересмотрел их все, и это мое последнее средство. Я пытался изменить все остальные скрипты, но они не работают, независимо от того, что я делаю. Я попытался использовать законченные версии танка и все, что было завершено, но это не сработало, даже сам скрипт управления камерой. Как я могу получить его, чтобы установить цели на 2 и использовать префабы танков для цели камеры?
CameraControl.cs:
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;
/*[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 ();
}
}
}
Игра Менеджер:
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();
}
}
}
}
Менеджер танка:
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);
}
}
}
Configurations:
GameManager:
Camera Control = CameraRig (CameraControl)
Message Text = Text (Text)
Tank Prefab = Tank
--Tanks--
Size = 2
Все точки появления установлены на позиции из видеогидов.