我在使用此脚本时遇到问题。你能帮助一个新手吗? 我需要敌人追赶玩家并避开障碍物。上面的游戏
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemy : MonoBehaviour
{
public float speed = 5f;
public float maxSpeed = 10f;
public float avoidanceForceMultiplier = 5f;
public float raySpacing = 0.5f;
public LayerMask obstacleLayerMask;
private Rigidbody2D rb;
private Transform Player;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
Player = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();
}
private void Update()
{
// Determine direction of movement
Vector2 playerDirection = (Player.position - transform.position).normalized;
// Cast rays to detect obstacles
RaycastHit2D[] hits = new RaycastHit2D[3];
Vector2 rayStart = transform.position * playerDirection * rb.velocity.magnitude * Time.deltaTime;
for (int i = 0; i < 3; i++)
{
Vector2 rayDirection = Quaternion.AngleAxis((i - 1) * 30f, Vector3.forward) * playerDirection;
hits[i] = Physics2D.Raycast(rayStart, rayDirection, raySpacing, obstacleLayerMask);
Debug.DrawRay(rayStart, rayDirection * raySpacing, Color.red);
}
// Calculate avoidance force
Vector2 avoidanceForce = Vector2.zero;
foreach (RaycastHit2D hit in hits)
{
if (hit.collider != null)
{
float distanceToObstacle = Vector2.Distance(transform.position, hit.collider.transform.position);
float distanceToRay = Vector2.Distance(rayStart, hit.point);
avoidanceForce += Vector2.Lerp(playerDirection, hit.normal, distanceToRay / distanceToObstacle) * avoidanceForceMultiplier;
}
}
// Apply avoidance force to velocity
rb.AddForce(avoidanceForce);
// Normalize velocity to max speed
if (rb.velocity.magnitude > maxSpeed)
{
rb.velocity = rb.velocity.normalized * maxSpeed;
}
// Move towards player
rb.velocity += playerDirection * speed * Time.deltaTime;
}
}
我注意到,你抱怨敌人在舞台上绕圈,这可能只是因为你错误地将敌人命名为“玩家”。这意味着它认为它到达了目的地。我看不出你如何检测和避开障碍物有多少逻辑。 derHugo 关于速度变化的说法是正确的,你应该只改变它一次,例如有一些 if 和 else,并且根据某些条件,每个
Update
仅将其设置为不同的值一次。还有一些变量名称不正确:raySpacing
实际上不是间距,而是光线长度。在这种情况下,使用 Time.deltaTime
是没有意义的,您正在更新速度,而不是对象的确切位置。
我做了一些更改并添加了一个简单的寻路算法。制作阻挡路径的地形时,将所有连接的对象(敌人没有可以通过的孔)放在一个空的游戏对象下(该算法计算一组中对象的质心)您应该为地形创建新图层,并在编辑器中将其选择为
Obstacle Layer Mask
,我添加了一些可更改的值,例如光线投射的数量(我建议仅使用奇数)以进一步调整移动速度。敌人的速度永远是最大速度。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemy : MonoBehaviour
{
public float speed = 5f;
public float maxSpeed = 10f;
public float avoidanceForceMultiplier = 5f;
public float raySpacing = 2f;
public LayerMask obstacleLayerMask;
public float allowed_distance = 1f;
public int amount_of_raycasts = 7;
private Rigidbody2D rb;
private Transform Player;
private Vector2 shortest_vector_to_target;
private Vector2 closest_point_to_target;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
Player = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();
}
private void Update()
{
// Determine direction of movement
Vector2 playerDirection = (Player.position - transform.position).normalized;
bool ray_hit = false;
// Cast rays to detect obstacles
RaycastHit2D[] hits = new RaycastHit2D[amount_of_raycasts];
Vector2 rayStart = transform.position;
for (int i = 0; i < amount_of_raycasts; i++)
{
Vector2 rayDirection = Quaternion.AngleAxis((i - ((amount_of_raycasts - amount_of_raycasts % 2) / 2)) * 30f, Vector3.forward) * playerDirection;
hits[i] = Physics2D.Raycast(rayStart, rayDirection, raySpacing, obstacleLayerMask);
Debug.DrawRay(rayStart, rayDirection.normalized * raySpacing, Color.red);
}
// Calculate avoidance force
Vector2 avoidanceForce = Vector2.zero;
float lowest_distance = 0f;
foreach (RaycastHit2D hit in hits)
{
if(hit.collider != null)
{
closest_point_to_target = hit.collider.ClosestPoint(transform.position);
if (!ray_hit)
{
lowest_distance = Vector2.Distance(closest_point_to_target, new Vector2(transform.position.x, transform.position.y));
shortest_vector_to_target = closest_point_to_target - new Vector2(transform.position.x, transform.position.y);
}
else if(lowest_distance > Vector2.Distance(closest_point_to_target, new Vector2(transform.position.x, transform.position.y)))
{
lowest_distance = Vector2.Distance(closest_point_to_target, new Vector2(transform.position.x, transform.position.y));
shortest_vector_to_target = closest_point_to_target - new Vector2(transform.position.x, transform.position.y);
}
Vector2 direction_to_objects = GetCenterOfParentInWorldSpace(hit.collider.gameObject.transform.parent) - new Vector2(transform.position.x, transform.position.y);
Debug.DrawRay(rayStart, direction_to_objects, Color.green);
float right_or_left = direction_to_objects.x * playerDirection.y - direction_to_objects.y * playerDirection.x;
Debug.Log(right_or_left);
if (right_or_left > 0)
{
// left
avoidanceForce = new Vector2(-shortest_vector_to_target.y, shortest_vector_to_target.x) * avoidanceForceMultiplier;
}
else if (right_or_left < 0)
{
// right
avoidanceForce = new Vector2(shortest_vector_to_target.y, -shortest_vector_to_target.x) * avoidanceForceMultiplier;
}
else avoidanceForce = new Vector2(-shortest_vector_to_target.y, shortest_vector_to_target.x) * avoidanceForceMultiplier;
Debug.DrawRay(rayStart, shortest_vector_to_target, Color.yellow);
avoidanceForce = avoidanceForce.normalized * maxSpeed;
ray_hit = true;
}
}
float distance_from_object = Mathf.Sqrt(shortest_vector_to_target.x * shortest_vector_to_target.x + shortest_vector_to_target.y * shortest_vector_to_target.y);
if (ray_hit)
{
if (distance_from_object < allowed_distance)
{
rb.velocity = (avoidanceForce - shortest_vector_to_target).normalized * maxSpeed;
}
else if (distance_from_object > (raySpacing - raySpacing/5))
{
rb.velocity = (shortest_vector_to_target).normalized * maxSpeed;
}
else
{
rb.velocity = (avoidanceForce + playerDirection).normalized * maxSpeed;
}
}
else
{
rb.velocity = (playerDirection).normalized * maxSpeed;
}
}
Vector2 GetCenterOfParentInWorldSpace(Transform parent)
{
if (parent.childCount == 0)
{
return parent.position;
}
Vector3 totalPosition = Vector3.zero;
foreach (Transform child in parent)
{
totalPosition += parent.TransformPoint(child.localPosition);
}
return totalPosition / parent.childCount;
}
}
如果您对算法、功能或其他任何问题还有其他疑问,请随时提问。