Я создаю небольшой игровой проект (впервые изучаю С#, поэтому кодирование довольно ужасное).
У меня есть желтый куб, который меняет цвет на зеленый после того, как логическими значениями были выбраны желтый и синий куб. Я заставил этот код работать и скопировал его в фиолетовый скрипт на синем кубе, чтобы изменить его на фиолетовый. Во время игры выполняется сценарий зеленого цвета, даже если щелкнуть красный куб, а ручная проверка логических значений в инспекторе игнорирует фиолетовую часть сценария, связанную с действием.
Код работает, выбирая куб и выбирая другой куб, при этом первый куб выполняет сценарий, который вызывает изменение цвета и убивает второй куб. Выбранные синий куб и желтый куб превращают синий куб в зеленый куб и убивают желтый куб. Когда я хотел выбрать синий куб и красный куб с помощью моего модифицированного кода зеленого куба, код не выполняется.
Синий скрипт на кубе (работает)
public bool bluetopurple = false;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
Renderer render = GetComponent<Renderer>();
render.material.color = Color.blue;
if (Input.GetMouseButtonDown (0)) {
bluetopurple = true;
}
Зеленый сценарий (работает)
public class greenscript : MonoBehaviour {
public GameObject yellow;
public yellowscript yellow1;
public GameObject blue;
public bluescript blue1;
public bool green;
// Use this for initialization
void Start () {
blue1 = GameObject.Find("blue").GetComponent<bluescript> ();
blue1.bluetopurple = false;
yellow1 = GameObject.Find("yellow").GetComponent<yellowscript> ();
yellow1.yellowchange = false;
green = false;
}
// Update is called once per frame
void Update () {
if (yellow1.yellowchange == true) {
if (blue1.bluetopurple == true) {
if (Input.GetMouseButtonDown (0)) {
green = true;
}
if (green == true) {
Renderer render = GetComponent<Renderer> ();
render.material.color = Color.green;
Destroy ((blue), 0.0f);
}
Фиолетовый скрипт (не работает, переменные изменены правильно, в отладчике не отображаются коды ошибок):
public class purplescript : MonoBehaviour {
public GameObject red;
public redscript red1;
public GameObject blue;
public bluescript blue1;
public bool purple;
// Use this for initialization
void Start () {
blue1 = GameObject.Find("blue").GetComponent<bluescript> ();
blue1.bluetopurple = false;
red1 = GameObject.Find("red").GetComponent<redscript> ();
red1.redtopurple = false;
purple = false;
}
// Update is called once per frame
void Update () {
if (red1.redtopurple == true) {
if (blue1.bluetopurple == true) {
if (Input.GetMouseButtonDown (0)) {
purple = true;
}
if (purple == true) {
Renderer render = GetComponent<Renderer> ();
render.material.color = Color.magenta;
Destroy ((red), 0.0f);
}
Я ожидал, что сценарий зеленого куба будет легко изменить, изменив переменные на другие кубы, которые я хотел выбрать, но, по-видимому, нет, и я не знаю, как это исправить.
у вас не должно быть 3 класса для каждого куба... У вас должен быть класс, прикрепленный ко всем кубам, и переменная, которая устанавливает инспектору, какой цвет у куба, и логическая активация. Затем создайте основной класс, содержащий массив со всеми кубами. И вам нужен абстрактный класс, у которого есть абстрактный метод Activate, каждый куб расширяет абстрактный класс. В основном классе при клике на куб берем из него абстрактный класс и вызываем метод Activate.
Спасибо за вклад, Джордж, я попытаюсь сжать их в два сценария, когда узнаю больше.
Прежде всего вместо
GameObject.Find("blue").GetComponent<bluescript>();
скорее использовать
FindObjectOfType<bluescript>();
это куда эффективнее. Или, если возможно, даже не используйте его вообще, а ссылайтесь на соответствующие компоненты в ваших скриптах уже в Инспекторе.
Я не совсем понял, чего вы пытаетесь достичь, но обратите внимание, что Input.GetMouseButtonDown(0)
есть true
на каждый GameObject.. не только тот, на который вы сейчас наводите указатель мыши!
Если вы хотите реализовать что-то, что должно происходить, когда вы нажимаете на определенный GameObject (с Collider
или GUIElement
), то лучше используйте OnMouseDown
. Кроме того, вы делаете много ненужных вещей в Update
, которые называются каждым кадром, поэтому могут быть некоторые проблемы.
Тогда в вашем коде много мелких проблем
для вашего синего сценария
Renderer render = GetComponent<Renderer>();
render.material.color = Color.blue;
Наличие этого в вашем методе Update
не имеет смысла, потому что
GetComponent
снова и снова, особенно в каждом кадретак что, вероятно, это должно выглядеть так
public class bluescript : MonoBehaviour
{
public bool bluetopurple = false;
// Use this for initialization
private void Start ()
{
Renderer render = GetComponent<Renderer>();
render.material.color = Color.blue;
}
// Catch the mousedown
private void OnMouseDown()
{
bluetopurple = true;
}
}
аналогичные проблемы также встречаются в greenscript. Вы вызываете один и тот же код снова и снова для каждого кадра в Update
, blue
может быть не установлен, поэтому он может не уничтожиться, а выдать ошибку. Также
Destroy(blue, 0.0f);
Здесь вы уничтожаете Компонент, а не GameObject! Я думаю, вы хотели сделать Destroy(blue.gameObject);
.. также прохождение 0.0f
можно пропустить, потому что оно 0
в любом случае по умолчанию.
public class greenscript : MonoBehaviour
{
// If possible set these already in the Inspector and don't use
// Find and GetComponent at all
public yellowscript yellow;
public bluescript blue;
public Renderer render;
public bool green;
// Use this for initialization
private void Start ()
{
Renderer render = GetComponent<Renderer>();
blue = FindObjectOfType<bluescript>();
blue.bluetopurple = false;
yellow = FindObjectOfType<yellowscript> ();
yellow.yellowchange = false;
green = false;
}
private void OnMouseDown()
{
if (!yellow.yellowchange) return;
// if you destroyed the blue GameObject already
// checking this again would throw an error so catch that case
if (!blue) return;
if (!blue.bluetopurple) return;
green = true;
render.material.color = Color.green;
Destroy(blue.gameObject);
}
}
И, наконец, фиолетовый скрипт
public class purplescript : MonoBehaviour
{
public redscript red;
public bluescript blue;
public Renderer render;
public bool purple;
// Use this for initialization
void Start()
{
Renderer render = GetComponent<Renderer>();
blue = FindObjectOfType<bluescript>();
blue.bluetopurple = false;
red = FindObjectOfType<redscript>();
red.redtopurple = false;
purple = false;
}
private void OnMouseDown()
{
// here again check if the object still exists first
if (!red) return;
if (!red.redtopurple) return;
if (!blue.bluetopurple) return;
purple = true;
render.material.color = Color.magenta;
Destroy(red.gameObject);
}
}
Вы не показали код для redscript
и yellowscript
. В greenscript
вы Destroy(blue)
, но в purplescript
вы полагаетесь на blue.bluetopurple
.. это не кажется правильным.
Из сценариев, которые я вижу здесь, вы можете значительно упростить это, используя только сценарии 2 сингла a:
Все остальные, такие как Какие значения проверять, к какому цвету я обращаюсь, какой объект я уничтожаю, вы можете установить с помощью параметров в Инспекторе. Таким образом, вы бы только
public class ScriptA : MonoBehaviour
{
[Header("Base-Components")]
public Renderer renderer;
[Header("Base-Settings")]
// start with this color
public Color InitialColor = Color.white;
// turn to this after being clicked
public Color TargetColor = Color.white;
[Header("Values")]
public bool WasClicked;
private void Awake()
{
SetUp();
}
private void SetUp()
{
if (!renderer) renderer = GetComponent<Renderer>();
renderer.material.color = InitialColor;
WasClicked = false;
}
private void OnMouseDown()
{
HandleClick();
}
// make this virtual so we can extend/overwrite it in child classes
protected virtual void HandleClick()
{
WasClicked = true;
renderer.material.color = TargetColor;
}
}
Так как второй скрипт очень похож, но только расширяет поведение, унаследованное от ScriptA. Это означает, что он будет иметь все уже реализованные свойства и методы, но теперь вы можете расширить те, которые реализованы как virtual
:
public class ScriptB : MonoBehaviour
{
// What does this script have, ScriptA didn't?
[Header("Additional Components")]
// The two components you want to check the bool for
public ScriptA FirstToCheck;
public ScriptA SecondToCheck;
[Space]
// The component you want to destroy
public ScriptA ToDestroy;
// Overwrite/Extend the behaviour of HandleClick
protected virtual void HandleClick()
{
// One of the references doesn't exist
// so object was probably already destroyed
if (!ToDestroy || !FirstToCheck || !SecondToCheck) return;
// One of the objects wasn't clicked yet
if (!FirstToCheck.WasClicked || !SecondToCheck.WasClicked) return;
// Do what the parent implemented
// in this case set my bool and change my color
base.HandleClick();
Destroy(ToDestroy.gameObject);
}
}
Поместите ScriptA
на куб(ы), который не зависит от других, чтобы активироваться. И ScriptB
на кубиках, которые сначала проверяют два других кубика. Затем настройте все параметры в Инспекторе и уже установите ссылки между всеми теми объектами.
Спасибо за помощь DerHugo, я внесу все изменения, которые вы рекомендовали, а я даже не знал о виртуальном классе.
Таким образом, вы можете избежать использования одного и того же скрипта на нескольких объектах, просто выполните тот, который вы щелкнули.