我正在使用镜像开发 RTS 游戏,但遇到了问题。 我正在研究单位的自动攻击功能。 一切都适用于主机,但不适用于客户端。 任何帮助将不胜感激,我已经在这几天了.. 帮助! 或者至少在这里指出我正确的方向。 稍后我会更好地优化它,我只需要了解为什么它在客户端上不起作用。我还注意到客户端会将自己添加到敌人列表中,它似乎忽略了“hasAuthority”检查
写的有点多,所以我会尽量让它更容易理解。
Unit 被实例化,这是附加到它的脚本:
import 'firebase/analytics'
接下来是ArrayDetect函数 使用 Physics.OverlapSphere 检测单元,确保它具有权限并将其添加到敌人对撞机列表中,我还添加了 layerMask 以确保它仅检查单元。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mirror;
using System.Linq;
public class UnitFiring : NetworkBehaviour
{
[SerializeField] private Targeter targeter = null;
[SerializeField] private GameObject projectilePrefab = null;
[SerializeField] private Transform projectileSpawnPoint = null;
[SerializeField] private float fireRange = 10f;
[SerializeField] private float fireRate = 1f;
[SerializeField] private float rotationSpeed = 20f;
private float lastFireTime;
//auto attack
[SerializeField] private Transform ownAimAtPoint = null;
[SerializeField] private LayerMask layerMask;
[SerializeField] private int updateFunctionFrequency = 60; //in frames
[ServerCallback]
private void Update()
{
if (Time.frameCount % this.updateFunctionFrequency != 0) return;
//runs update every 60 frames
enemyColliders.RemoveAll(Collider => Collider == null);
//if enemyCollider List has GameObject that was destroyed or null, it removes it from the list.
Targetable target = targeter.GetTarget();
if(target == null)
{
ArrayDetect();
AttackUnit();
return;
}
if (!CanFireAtTarget()) { return; }
//look at target
Quaternion targetRotation =
Quaternion.LookRotation(target.transform.position - transform.position);
//Rotate
transform.rotation = Quaternion.RotateTowards
(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
if(Time.time > (1 / fireRate) +lastFireTime)
{
Quaternion projectileRotation = Quaternion.LookRotation(
target.GetAimAtPoint().position - projectileSpawnPoint.position);
GameObject projectileInstance = Instantiate(
projectilePrefab, projectileSpawnPoint.position, projectileRotation);
NetworkServer.Spawn(projectileInstance, connectionToClient);
lastFireTime = Time.time;
}
}
[Client]
private bool CanFireAtTarget()
{
return (targeter.GetTarget().transform.position - transform.position).sqrMagnitude
<= fireRange * fireRange;
}
[SerializeField] private Collider[] colliderArray;
[SerializeField] private List<GameObject> enemyColliders;
现在AttackUnit函数,它会考虑敌人的碰撞器列表并将它们设置为攻击目标
[Server]
private void ArrayDetect()
{
colliderArray = Physics.OverlapSphere(ownAimAtPoint.position, fireRange, layerMask);
foreach (Collider collider in colliderArray)
{
Debug.Log("we hit a", collider);
if (!collider.TryGetComponent<Targetable>(out Targetable potentialTarget))
{
return;
}
if (potentialTarget.hasAuthority)
{
return; //if the hit target is the players, do nothing
}
else
{
enemyColliders = enemyColliders.Distinct().ToList();
enemyColliders.Add(collider.gameObject);
Debug.Log("Found an enemy", potentialTarget);
}
}
}
这是 Targetable Script,它只是返回 AimAtPoint:
[ServerCallback]
private void AttackUnit()
{
foreach (GameObject enemy in enemyColliders)
{
Debug.Log("We got confirmed enemy", enemy);
//GetComponent<Targeter>().CmdSetTarget(enemy);
targeter.CmdSetTarget(enemy);
//attack the enemy
}
}
这是 Targeter 脚本中的 CmdSetTarget 命令:
public class Targetable : NetworkBehaviour
{
[SerializeField] private Transform aimAtPoint = null;
public Transform GetAimAtPoint()
{
return aimAtPoint;
}
}
这是我在控制台中得到的错误,但只有在客户端单元上,主机才能正常运行:
[Command]
public void CmdSetTarget(GameObject targetGameObject)
{
if(!targetGameObject.TryGetComponent<Targetable>(out Targetable newTarget)) { return; }
//if game object does not have a target, return
target = newTarget;
}
感谢您花时间阅读本文