OnTriggerEnter2D не вызывается последовательно
GIF, который показывает несоответствия столкновений: http://imgur.com/QB4XOv0.gif
В моей игре Unity2D у меня есть рогатка (игрок), стреляющая шариками по стене (подумайте о головоломках- головоломках типа "Головоломка"). Каждый шарик является клоном префаба, и каждый префаб имеет твердое тело с проверкой IsKinematic вместе с CircleCollider с проверкой OnTrigger.
Когда мрамор сталкивается с двумя боковыми стенками, я использую OnTriggerEnter2D() и поворачиваю угол, чтобы он отскакивал от стен под углом. Когда мрамор сталкивается с верхней стенкой, он в основном замирает, после чего я удаляю компонент твердого тела и устанавливаю тэг "topObjects".
Несоответствия возникают, когда мрамор сталкивается с другим мрамором. Иногда вызывается триггерная функция, а иногда нет. Триггеры кажутся случайными и непредсказуемыми.
Вот мой код C# для обнаружения столкновений и поведения, которое сопровождает его (прикреплено к мрамору):
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class RockMove : MonoBehaviour
{
public float speed = 0.5f;
private Vector2 direction = new Vector2(0, 1);
// current angle
private float currentAngleZ;
// indendiary angle
private float angleB;
// rotation speed
private float rot;
// curving speed
private float rotMod;
// stops marble when collides with wall
private bool IsMoving = true;
void Start() {
}
void Update ()
{
if (IsMoving) {
rot = RockSpawn.rot;
currentAngleZ = transform.eulerAngles.z;
rotMod = transform.position.x * -0.5f;
// moves it forward + adds speed
transform.Translate(direction * Time.deltaTime * speed, Space.Self);
// curving
transform.Rotate (0, 0, rotMod, Space.Self);
if (transform.position.x >= 0) {
// faster speed when near walls "gravity/magnetism"
speed += transform.position.x * 8 * Time.deltaTime;
}
if (transform.position.x < 0) {
// faster speed when near walls "gravity/magnetism"
speed += transform.position.x * -8 * Time.deltaTime;
}
}
else {
// when object is stationary
speed = 0;
}
}
void OnTriggerEnter2D(Collider2D collider){
// if collides with another marble
if (collider.gameObject.tag == "topObjects" ) {
// get rid of rigidbody
// can't have 2 rigidbodies when 2 objects collide
Destroy(rigidbody2D);
// freeze movement
IsMoving = false;
Debug.Log ("you collided with a marble");
// freeze rotation
this.transform.Rotate (0, 0, 0, Space.Self);
// assign the new tag
this.tag = "topObjects";
}
else if(collider.name == "TopWall")
{
Destroy(rigidbody2D);
IsMoving = false;
Debug.Log ("you broke the fourth wall!");
transform.Rotate (0, 0, 0);
this.tag = "topObjects";
}
else {
// bounce off walls
currentAngleZ = transform.eulerAngles.z;
angleB = 360 - (2 * currentAngleZ);
transform.Rotate (0, 0, angleB);
}
}
}
Обновление: простое изменение функции Update() на FixedUpdate(), по-видимому, делает триггер более согласованным, однако в их обнаружении все еще есть несоответствия.
Я тестировал hardbody2d.velocity, transform.position и различные другие функции преобразования, но Transform.Translate дал лучшие результаты, отразив его от стен, хотя теоретически он просто телепортирует объект в новое место.
Уменьшение скорости также никак не влияет на согласованность и не меняет размер коллайдеров.
3 ответа
OnTriggerEnter2D должен работать последовательно независимо от того, используете вы физику или нет.
Однако, если gameObject поддерживает связь с другим gameObject, вы помечаете OnTriggerEnter только один раз, в самый первый момент, когда они сталкиваются. После этого вы можете получать информацию о том, сталкиваются ли два игровых объекта, вызывая OnTriggerStay.
Затем, после того как они прекратят сталкиваться, OnTriggerEnter будет сброшен и снова сработает при контакте с другим gameObject, даже если он тот же, что сталкивался ранее. Вы проверяли это?
Надеюсь, это поможет, у меня будет сообщение в качестве комментария, но у меня недостаточно репутационных баллов, поэтому я вынужден публиковать сообщения в качестве ответа извините, если не должен.
Здесь две очевидные вещи:
1.) у вашего игрового объекта есть Rigidbody2D, поэтому вы не должны перемещать его через преобразование, а вместо этого через жесткое тело с такими функциями:
rigidbody2D.MovePosition()
а также
rigidbody2D.MoveRotation()
Просто посмотрите их в документации Unity.
2.) Поместите все это в
void FixedUpdate()
{
...
}
Это то, где все, что касается физического движка, входит. Также есть много ресурсов онлайн, чтобы прочитать об этом:)
Насколько я понимаю, кинематические твердотельные тела не могут сталкиваться в 2D. Я все еще довольно новичок, но я нашел это в нескольких ответах с моими собственными проблемами. Вы должны посмотреть на это больше.