2015-08-27 3 views
0

Я строю простую сверхуную румяную игру, используя единство. У меня есть опыт разработки, но я новичок как в рамках единства, так и в C#. Есть ли чистый и изящный способ взаимодействия с объектами игроков с другими различными типами объектов в сцене?Единство, взаимодействующее с объектами

Например, сцена была бы полна стен, врагов и других объектов, которые блокируют путь, и игрок может взаимодействовать, пытаясь двигаться в их направлении. Стоя рядом с сундуком и двигаясь в его направлении, он не перемещал игрока, а открывал сундук. Если вы двигаетесь в стену, это повредит его и т. Д.

В настоящее время я использую raycast2d, чтобы получить объект, блокирующий путь, но не могу найти решение, как с ним взаимодействовать, не имея чтобы проверить, какой тип объекта он (стена, есть сундук и т. д.). Я создал интерфейс, который реализует все взаимодействующие объекты с помощью метода взаимодействия(), но разные типы объектов требуют различной информации. Стена потребует суммы урона, который он должен принять (зависит от статистики игрока, которая находится в классе игрока), сундук не принимает ничего. Поэтому всем им сложно реализовать один и тот же интерфейс. Если стена спросит у игрока, что у него есть, это также плохая практика программирования.

Я нашел аналогичный вопрос об этом, опубликованном некоторое время назад on stackowerflow. Это предполагает использование шаблона наблюдателя, но я не могу представить, чтобы каждый объект на сцену был подписан на событие движения игрока, и после каждого хода проверки погоды он попал или нет.

Есть ли стандартное решение для такого взаимодействия? Тот, который будет слабо связан, чист и будет следовать хорошей практике программирования?

+0

Ищите слои и коллайдеры. – Aybe

+0

как бы они помогли? Я мог бы не понимать слои и коллайдеры полностью. Я знаю, что они используются, чтобы указать, что объекты на одном слое могут столкнуться. Но как сундук, так и стена будут на том же блоке, что и игрок, я хочу, чтобы они реагировали на взаимодействие по-разному, не проверяя, есть ли это стена или что-то еще. –

ответ

1

Если бы я был в вашей ситуации, я бы добавил пустой объект GameObject с объектом Collider2D к объекту (стена, сундук и т. Д.) И переключил поле для isTrigger. (Обратите внимание, что это потребует, чтобы объект является производным от Monobehaviour и что не всегда может быть желательно.)

Оттуда я хотел бы использовать некоторую комбинацию специализированных функций OnTriggerStay, OnTriggerEnter и OnTriggerExit:

//in Chest.cs 
void OnTriggerEnter() //http://docs.unity3d.com/ScriptReference/Collider.OnTriggerEnter.html 
{ 
    OpenChest(); 
} 

//in Wall.cs 
void OnTriggerStay() //http://docs.unity3d.com/ScriptReference/Collider.OnTriggerStay.html 
{ 
    DamageWall(); 
} 

Отсюда у вас есть два варианта, чтобы убедиться, что определенные объекты gameObject не запускают неправильный коллайдер. Один из способов использует код:

//in Chest.cs 
void OnTriggerEnter(Collider other) 
{ 
    //notice this won't be very efficient 
    if(other.gameObject.GetComponent<PlayerScript>() != null) OpenChest(); 
    //if(other.name == "The Player") OpenChest(); //probably less efficient at runtime 
} 

Другое решение использует слои и является более эффективным. Чтобы добавить слои к Unity, пройдите edit ->project settings ->tags and layers (вкладки в левом верхнем углу) и добавьте несколько имен слоев (например, Wall, Chest, Player, Enemy). Затем найдите триггеры (и, желательно, родители триггеров), и пометьте объект как часть этого слоя в Inspector, переключившись с слоя Default на нужную метку (например, Wall).

Отсюда, вы можете использовать другой прием, селективные столкновений между слоями, пройдя через edit ->project settings ->physics и глядя на Layer Collision Matrix. Если два объекта должны столкнуться, оставьте флажок заполненным; если они никогда не сталкиваются, снимите флажок; если они должны столкнуться ситуативно, либо разделите слой на два, либо более или добавьте код, который определяет, следует ли сталкиваться или нет.

Еще один совет: если игрок должен только рубить дерево, удерживая бензопилу, вы можете сделать так, чтобы удерживание на бензопиле создало специальный триггер для уничтожения деревьев.

редактировать: дополнительные подводные камни:

1) two triggers cannot collide (one must be a trigger and the other must be a collider) 
2) triggers can move (they do not need to be stationary) 
3) if one collider-trigger pair seems illogical, switching which object is the trigger and which is the collider might make the code simpler. 

edit2: удаление муфты:

OnTriggerStay(Collider other) будет вызываться для каждого экземпляра и будет работать хорошо, если все монстры и игроки нанесли такой же урон, но это явно не случай. Если каждый экземпляр имеет дело различного количества урона, который вы можете сделать следующее:

void OnCollisionEnter(Collision other) 
{ 
    addSelfDPS(other.gameObject.GetComponent<WallDamager>().getDPS()); 
} 
void OnCollisionExit(Collision other) 
{ 
    addSelfDPS(-1*other.gameObject.GetComponent<WallDamager>().getDPS()); 
} 

, если вы используете этот метод, однако, не будут проблемы, когда объекты порождаются и уничтожены внутри триггера, так что вам, возможно, потребуется адрес, который у всех конструкторов (Awake/Start) или деструкторов (OnDestroy).

+0

спасибо за ответ, это было очень полезно и дало мне несколько идей. Однако это не полностью решает проблему. Например, игрок бьет по стене. Триггер погаснет, и DamageWall() может быть вызван, но это означает, что DamageWall() должен будет сохранить ссылку на объект игрока и проверить, какой урон ему потребуется. Это вызывает сцепление. Кроме того, если это монстр, а не игрок, ударяющий о стену, DamageWall() должен будет проверить тип монстра и получить его урон ... 20 разных монстров? Больше проверки типа и сцепления. –

+0

@ EimantasŠapoka np, рад, что смогу помочь. –

+0

@mattdnwny Я редактировал комментарий выше. Как мне избежать этой проблемы? –

Смежные вопросы