2017-02-04 12 views
1

У меня есть этот код здесь:C# Unity - определить, какой метод влияет на GameObject

public void Move(Transform from, Transform to, float overTime) 
{ 
    StartCoroutine(_Move(from, to, overTime)); 
} 
IEnumerator _Move(Transform from, Transform to, float overTime) 
{ 
    Vector2 original = from.position; 
    float timer = 0.0f; 
    while (timer < overTime) 
    { 
     float step = Vector2.Distance(original, to.position) * (Time.deltaTime/overTime); 
     from.position = Vector2.MoveTowards(from.position, to.position, step); 
     timer += Time.deltaTime; 
     yield return null; 
    } 
} 

, которая довольно проста. Все, что он делает, это то, что с течением времени он перемещает GameObject. Я планирую использовать его для анимации пользовательского интерфейса. Тем не менее, все становится интересным, когда я хочу изменить использование этого. Например, я наводил указатель мыши на кнопку, которая начинает двигаться. В то время как он все еще перемещается, я могу снова нависнуть над ним, в этом случае я хочу, чтобы он перезапустился, поэтому он останавливает функцию , влияющую на ту же самую кнопку, и перезапускает другую. Я просто не знаю, как определить, какой вызов той же функции влияет на мой данный компонент. Или я должен добавить этот скрипт к каждому объекту, чтобы он мог влиять только на этот?

+0

Вы можете взглянуть на http://gamedev.stackexchange.com/ –

+0

не может быть плохой идеей. На данный момент, мой вопрос ясен? Или изменить? – hei

+2

Ваш вопрос ясен и уместен на этом сайте. – Programmer

ответ

1

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

Одно из решений состоит в закреплении сценарий, содержащий функцию сопрограммы каждого геймобжекты. Если вы не хотите этого делать, есть еще один способ сделать это.

Прежде всего, просто хранить IEnumerator недостаточно, чтобы на самом деле это сделать. Вам нужен способ идентифицировать GameObject, запущенный в последней сопрограмме.

. Получите значение, которое можно использовать для идентификации объекта. В этом случае идентификатор экземпляра с GetInstanceID() должен быть точным.

. Создайте простой файл struct, который будет содержать информацию старого сопроцессора.

.Finally, Сделать словарь, который будет содержать как идентификатор экземпляра (ключ) и эту структуру из # 2 в качестве значения.

С этими тремя вещами вы можете запустить сопрограмму, добавить ее в Dictionary. Когда сопрограмма завершена, снимите instance ID с Dictionary.

В приведенном ниже коде один объект управления сопрограммой будет содержать много объектов, не помещая функцию сопрограммы в свой собственный скрипт. Большая разница в том, что при вызове новой cororutine на одну и ту же функцию она останавливает старую на этом объекте только, затем создает новую и запускает ее.

Это то, что я использую. Это очень хорошо прокомментировано, чтобы вы знали, что происходит.

Dictionary<int, MoveInfo> movingObject = new Dictionary<int, MoveInfo>(); 

public void Move(Transform from, Transform to, float overTime) 
{ 
    MoveInfo moveInfo; 

    //Check if the Object exist in the Dictionay 
    if (movingObject.TryGetValue(from.GetInstanceID(), out moveInfo)) 
    { 
     //This Object exist and therefore, the coroutine function is already running. Stop it 

     //Remove it from the Dictionary 
     movingObject.Remove(from.GetInstanceID()); 

     //Stop the old coroutine 
     StopCoroutine(moveInfo.currentCoroutine); 
    } 

    //Create a new coroutine 
    moveInfo = createMoveInfoInstance(from); 

    //Add it to the dictionary 
    movingObject.Add(from.GetInstanceID(), moveInfo); 

    //Get instance of the new coroutine we are about to start 
    moveInfo.currentCoroutine = _Move(moveInfo, from, to, overTime); 

    //Modify the dictionary because the Add function does not update the currentCoroutine reference 
    movingObject[from.GetInstanceID()] = moveInfo; 

    //Start the coroutine 
    StartCoroutine(moveInfo.currentCoroutine); 
} 

MoveInfo createMoveInfoInstance(Transform from) 
{ 
    MoveInfo moveInfo = new MoveInfo(); 
    moveInfo.instanceID = from.GetInstanceID(); 
    return moveInfo; 
} 

IEnumerator _Move(MoveInfo moveInfo, Transform from, Transform to, float overTime) 
{ 
    Vector2 original = from.position; 
    float timer = 0.0f; 

    Debug.Log("New Coroutine Started"); 
    while (timer < overTime) 
    { 
     float step = Vector2.Distance(original, to.position) * (Time.deltaTime/overTime); 
     from.position = Vector2.MoveTowards(from.position, to.position, step); 
     timer += Time.deltaTime; 
     yield return null; 
    } 

    //Remove it from the Dictionary if it exist 
    if (movingObject.ContainsKey(from.GetInstanceID())) 
    { 
     movingObject.Remove(from.GetInstanceID()); 
    } 
} 

public struct MoveInfo 
{ 
    public IEnumerator currentCoroutine; 
    public int instanceID; 

    public MoveInfo(IEnumerator currentCoroutine, int instanceID) 
    { 
     this.currentCoroutine = currentCoroutine; 
     this.instanceID = instanceID; 
    } 
} 
+0

Продвинутый материал, возможно, слишком продвинутый для меня, но это то, как я узнаю :) Я пытаюсь его реализовать, но в случае неудачи я все еще могу скомпилировать свои функции в .dll файл и использовать их в скрипте, который помещается в каждый из моих элементов пользовательского интерфейса, где элемент пользовательского интерфейса и сценарий имеют соотношение 1: 1 (только для этого, только для эффектов). – hei

+0

Это не продвижение вперед. Если вы скопируете это и замените его кодом в своем вопросе, он должен скомпилироваться и работать нормально. * Цель этого решения заключается в том, что он делает так, что вам не нужно прикреплять код Move к очень UI *. Вы просто передаете преобразование и новое зелье, и это позаботится об этом. – Programmer

2

Здесь я бы поступил иначе. Во-первых, если ваш объект Ui уже затронут сопрограммой, вы не хотите, чтобы на нее также воздействовала другая сопрограмма, только новая сопрограмма. Чтобы избежать этого объявить сопрограмму переменную:

IEnumerator myCoRoutine 

При первой мыши над начать сопрограмму так:

myCoRoutine = _Move(from, to, overTime); 
Start Coroutine(_Move()); 

Но, вы хотите проверить, если сопрограмма еще не запущен, и остановить если это так, тогда запустите новый, верно? Итак, сделайте следующее:

if(myCoRoutine !=null) StopCoroutine(mtCoRoutine); 
myCoRoutine = _Move(from, to, overTime); 
Start Coroutine(_Move()); 

Вы, вероятно, хотите, чтобы начать свой сопрограмм используя OnPointerEnter

+0

Спасибо за помощь, полезная. Теперь я могу сказать изображение с двумя из них, поскольку у меня есть масштаб, вращение, lerpAlpha и т. Д., Написанные, например, кнопка немного растет и исчезает. Но в целом, да, я хочу только масштаб _one_, только один ход и т. д., чтобы это исправить. Я google об этом 'OnPointerEnter'. – hei

+0

Примечание: внизу мы должны 'StartCoroutine (myCoRoutine)' вместо 'Start Coroutine (_Move())'? Или я что-то понимаю неправильно? – hei

+0

Если вы хотите, чтобы с объектом было несколько вещей, лучше всего объединить их в одну сопрограмму, поэтому, возможно, ваша функция _Move будет делать масштаб, поворот и положение, или у вас будет несколько способов сделать это. В любом случае все это делается в одной сопрограмме. Что касается StartCouroutine да, вы начинаете сопроводительную копию, которую вы объявили как переменную, см. Здесь https://docs.unity3d.com/ScriptReference/MonoBehaviour.StartCoroutine.html – Absinthe