I tried to write a script, that gives the movement direction of my GO, when it moves more than 0.2 float, into an int.
The problem is the yield function. oldPos and newPos are the same value, despite the WaitForSeconds
Hope you can help me^^
public int direction;
public Vector3 oldPos;
public Vector3 newPos;
void Start () {
}
void Update () {
StartCoroutine(CheckMoving ());
Direction ();
}
private IEnumerator CheckMoving()
{
oldPos = transform.position;
yield return new WaitForSeconds(0.5f);
newPos = transform.position;
}
void Direction()
{
//Up
if (oldPos.y < newPos.y && (newPos.y - oldPos.y) > 0.2) {
direction = 1;
}
//Down
if (oldPos.y > newPos.y && (newPos.y + oldPos.y) > 0.2) {
direction = 2;
}
//Left
if (oldPos.x < newPos.x && (newPos.x - oldPos.x) > 0.2) {
direction = 3;
}
//Right
if (oldPos.x > newPos.x && (newPos.x + oldPos.x) > 0.2) {
direction = 4;
}
}
The problem is that you’re starting another instance of the coroutine on every frame. This means that you’ve got a bunch of updates of the newPos and oldPos variables all the time, which will cause a bunch of problems. You’ll want to cut the coroutine entirely, and do this instead:
In that way, when you run the Direction method, oldPos will be the value of your position on the last frame, and newPos will be the position on this frame. To make that work, you’ll want to make your code framerate independent - which means that you need to replace 0.2 with (0.2 * Time.deltaTime):
if (oldPos.y < newPos.y && (newPos.y - oldPos.y) > 0.2 * Time.deltaTime) {
direction = 1;
}
Also, if you care, there is a completely unrelated bugs in your code; for Down and Right, you’re doing this:
//Down
if (oldPos.y > newPos.y && (newPos.y + oldPos.y) > 0.2) {
direction = 2;
}
If oldPos.y = 50.0000001 and newPos.y = 50, that if will evaluate to true, as newPos.y + oldPos.y = 100.0000001. You want (oldPos.y - newPos.y) instead.
Another issue, if your game has diagonal movement, all diagonal movement will be registered as either right or left. Since you check those after up and down, those will overwrite the direction value. If that’s a problem, you’re going to have to rethink things.
Finally, I’d recommend replacing integers representing the direction with a proper Enum; see the Unity tutorial or the official microsoft C# docs
As @Baste mentioned, there are significant problems with your current approach. But even if you get them fixed, there is a conceptual problem. Assuming you are checking each frame but are updating every 0.5 seconds, the data becomes stale, and your direction will only update at the rate you sample regardless of the number of times you test. I’m assuming you have a 0.5 wait because you want to average the direction over time.
An alternate approach is to use a circular buffer of positions. With 25 buffer positions being updated in FixedUpdate (running at the default speed), there will be about 1/2 second between the current position and the ‘previous’ position no matter when the testing is done. You can increase or decrease the time for testing by increasing or decreasing the number of buffer positions (‘frameCount’). Fifty positions means 1.0 seconds for example.
In addition, I’ve use Vector3.Dot() to figure out the predominant direction of movement:
using UnityEngine;
using System.Collections;
public class Example : MonoBehaviour {
Vector3[] dirs = {Vector3.up, Vector3.down, Vector3.right, Vector3.left};
string[] stDirs = {"up", "down", "right", "left"};
int frameCount = 25;
Vector3[] positions;
int currPos;
int comparePos;
void Start () {
positions = new Vector3[frameCount];
for (int i = 0; i < positions.Length; i++) {
positions *= transform.position;*
}*
currPos = frameCount -1;*
comparePos = 0;*
}*
void FixedUpdate() {*
currPos = (currPos + 1) % frameCount;*
comparePos = (comparePos + 1) % frameCount;*
positions[currPos] = transform.position;*
}*
void Update () {*
int i = Direction();*
if (i == -1) {*
Debug.Log ("Not moving");*
}*
else {*
_ Debug.Log ("Primary direction is "+stDirs*);_
_ }_
_ }*_
* int Direction() {* * Vector3 dir = positions[currPos] - positions[comparePos];* * if (dir == Vector3.zero)* * return -1;* * int iPos = 0;* * float dot = Vector3.Dot(dirs[0], dir);* * for (int i = 1; i < dirs.Length; i++) {* _ float f = Vector3.Dot(dirs*, dir); if (f > dot) { dot = f; iPos = i; } } return iPos; } }*_