Моя проблема сегодня проста (две проблемы, если учесть тот факт, что Engli sh не является моим родным языком), но я не могу справиться с этим. Я пытаюсь сделать игру «вверх-вниз» в c#, и я пытаюсь улучшить сценарии движения, прежде чем работать над чем-то еще (поскольку я не хочу устранять серьезные ошибки позже).
проблема в том, что как только игрок входит в контакт с NP C, он должен перестать двигаться в своем общем направлении (он может двигаться в 8 направлениях, используя комбинации клавиш WASD). Движение NP C не доставляет никаких проблем, оно прекращает движение, как только воспринимает игрока. Вместо этого, когда игрок сталкивается с NP C, он продолжает двигаться в этом направлении, подталкивая его на полсекунды до остановки (как и должно быть). Итак, подводя итог, он не сразу останавливается, что нервирует, так как я много чего пытался остановить (включая замораживание позиции NP C, но это только ухудшило ситуацию).
Теперь коды:
Код движения NP C:
public class NPCFreeMovement : MonoBehaviour
{
public float speed = 2f; //how fast does the npc move
public float maxIdleTime = 3f; //max time the npc spends idling
public float maxChooseTime = 20f; //max time he spends moving
public float chooseDirTime = 0; //if 0, he chooses a direction
//possible directions
readonly Vector3[] directions = {Vector3.down, new Vector3(-0.5f, -0.5f, 0), Vector3.left, new Vector3(-0.5f, 0.5f, 0), Vector3.up,
new Vector3(0.5f, 0.5f, 0), Vector3.right, new Vector3(0.5f, -0.5f, 0)};
public int dir; //current direction
public bool canMove = true; //pretty self explainatory
public bool idle = true; //is the npc idle
public bool chase = false; //is the npc chasing after the player
public Vector3 goTo; //where to go if it's chasing after something
void Start()
{
StartCoroutine(Idle(maxIdleTime));
}
void Update()
{
chase = GetComponent<NPCLookForPlayerScript>().found;
if(canMove && !idle)
{
//move in the chosen direction
transform.position = Vector3.MoveTowards(transform.position, transform.position + directions[dir], Time.deltaTime * speed);
if (chooseDirTime > 0) //decrease movement time
{
chooseDirTime -= Time.deltaTime;
}
else
{
if(chase) StartCoroutine(Idle(0));
else StartCoroutine(Idle(Random.Range(0, maxIdleTime)));
}
}
}
//npc goes idle, then chooses a direction
public IEnumerator Idle(float f)
{
idle = true;
yield return new WaitForSeconds(f);
idle = false;
//here he chooses the direction depending of wether he's roaming or chasing
if (chase)
{
ChooseDirection();
chooseDirTime = maxChooseTime/4;
}
else
{
dir = Random.Range(0, directions.Length);
chooseDirTime = maxChooseTime;
}
}
//chooses a direction to take
void ChooseDirection()
{
Vector3 v = goTo - transform.position; //to check where to go
if (Mathf.Abs(v.x) <= 0.5)
{
if (v.y < 0) dir = 0; //go down
else dir = 4; //go up
}
if (Mathf.Abs(v.y) <= 0.5)
{
if (v.x < 0) dir = 2; //go left
else dir = 6; //go right
}
if (v.x < 0.5 && v.y < 0.5) dir = 1; //go down/left
if (v.x < 0.5 && v.y > 0.5) dir = 3; //go up/left
if (v.x > 0.5 && v.y > 0.5) dir = 5; //go up/right
if (v.x > 0.5 && v.y < 0.5) dir = 7; //go down/right
}
void OnCollisionEnter2D(Collision2D c)
{
if(c.gameObject.tag == "Obstacle") //stop and choose a new direction
{
StartCoroutine(Idle(Random.Range(0, maxIdleTime)));
}
if (c.gameObject.tag == "Player") //stop
{
canMove = false;
}
}
private void OnCollisionExit2D(Collision2D c)
{
if (c.gameObject.tag == "Player") //resume chasing the player
{
canMove = true;
}
}
}
Скрипт движения игрока:
public class PlayerFreeMovement : MonoBehaviour
{
public float speed = 2.0f; //movement speed
//where he's facing
public bool up;
public bool down;
public bool left;
public bool right;
public bool idle; //false if a movement button is pressed
public bool canMove = true;
//movement direction
public float dx;
public float dy;
public Vector3 v;
CollisionScript cs; //collision script
void Start()
{
down = true;
cs = GetComponent<CollisionScript>();
}
void Update() //move stickman in the direction of the keys and maintain the direction he's facing with animations
{
dx = 0;
dy = 0;
if (!(Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S))) //check if idle
{
idle = true;
v = new Vector3();
}
else //the player's moving
{
idle = false;
AllFalse();
//set dx and dy
if (canMove && Input.GetKey(KeyCode.D))
{
if(!cs.hitRight) dx = 1;
right = true;
}
if (canMove && Input.GetKey(KeyCode.A))
{
if (!cs.hitLeft) dx = -1;
left = true;
}
if (canMove && Input.GetKey(KeyCode.W))
{
if (!cs.hitUp) dy = 1;
up = true;
}
if (canMove && Input.GetKey(KeyCode.S))
{
if (!cs.hitDown) dy = -1;
down = true;
}
//create the motion vector
v = new Vector3(dx, dy, 0);
if(dx !=0 && dy != 0)
{
v = v / 2;
}
}
//move
transform.position = Vector3.MoveTowards(transform.position, transform.position + v, Time.deltaTime * speed);
}
//avoid bug by deactivating all direction booleans before changing one
void AllFalse()
{
up = false;
down = false;
left = false;
right = false;
}
}
И, наконец, скрипт столкновения, используемый для обнаруживать столкновения на своем пути
public class CollisionScript: MonoBehaviour
{
//where is the wall
public bool hitDown= false;
public bool hitLeft = false;
public bool hitRight = false;
public bool hitUp = false;
//gizmos
public float collisionRadius = 0.5f;
public Vector2 downOffset = new Vector2(0, -0.5f);
public Vector2 rightOffset = new Vector2(0, 0.5f);
public Vector2 leftOffset = new Vector2(-0.5f, 0);
public Vector2 upOffset = new Vector2(0, 0.5f);
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
hitDown = Physics2D.OverlapCircle((Vector2)transform.position + downOffset, collisionRadius).gameObject!=gameObject;
hitRight = Physics2D.OverlapCircle((Vector2)transform.position + rightOffset, collisionRadius).gameObject != gameObject;
hitLeft = Physics2D.OverlapCircle((Vector2)transform.position + leftOffset, collisionRadius).gameObject != gameObject;
hitUp = Physics2D.OverlapCircle((Vector2)transform.position + upOffset, collisionRadius).gameObject != gameObject;
}
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere((Vector2)transform.position + downOffset, collisionRadius);
Gizmos.DrawWireSphere((Vector2)transform.position + rightOffset, collisionRadius);
Gizmos.DrawWireSphere((Vector2)transform.position + leftOffset, collisionRadius);
Gizmos.DrawWireSphere((Vector2)transform.position + upOffset, collisionRadius);
}
}