c# - 我怎样才能让光线投射命中只与玩家一起命中?
问题描述
我正在使用线条渲染器创建一个圆圈,并且在更新中我希望如果玩家触摸圆圈的绘制部分以检测到它击中它。问题是无论玩家是否在圆圈上,它总是能检测到地形。
此脚本附加到空的 GameObject。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[ExecuteAlways]
[RequireComponent(typeof(UnityEngine.LineRenderer))]
public class DrawCircle : MonoBehaviour
{
public GameObject centerObject;
[Range(1, 50)] public int segments = 50;
[Range(1, 500)] public float xRadius = 5;
[Range(1, 500)] public float yRadius = 5;
[Range(0.1f, 5)] public float width = 0.1f;
[Range(0, 100)] public float height = 0;
public bool controlBothXradiusYradius = false;
public bool draw = true;
private Vector3 startPos;
private Vector3 endPos;
private bool detected = false;
[SerializeField] private LineRenderer line;
private void Start()
{
if (!line) line = GetComponent<LineRenderer>();
if (draw)
CreatePoints();
startPos = line.GetPosition(0);
endPos = line.GetPosition(line.positionCount - 1);
}
private void Update()
{
RaycastHit hit;
if (Physics.Raycast(startPos, endPos - startPos, out hit))
{
if(hit.transform.gameObject.name == "Player")
{
print("player detected");
detected = true;
}
else if(detected)
{
print("player NOT detected");
detected = false;
}
}
}
public void CreatePoints()
{
line.enabled = true;
line.widthMultiplier = width;
line.useWorldSpace = false;
line.widthMultiplier = width;
line.positionCount = segments + 1;
float x;
float y;
var angle = 20f;
var points = new Vector3[segments + 1];
for (int i = 0; i < segments + 1; i++)
{
x = Mathf.Sin(Mathf.Deg2Rad * angle) * xRadius;
y = Mathf.Cos(Mathf.Deg2Rad * angle) * yRadius;
points[i] = new Vector3(x, height, y);
angle += (380f / segments);
}
// it's way more efficient to do this in one go!
line.SetPositions(points);
}
#if UNITY_EDITOR
private float prevXRadius, prevYRadius;
private int prevSegments;
private float prevWidth;
private float prevHeight;
private void OnValidate()
{
// Can't set up our line if the user hasn't connected it yet.
if (!line) line = GetComponent<LineRenderer>();
if (!line) return;
if (!draw)
{
// instead simply disable the component
line.enabled = false;
}
else
{
// Otherwise re-enable the component
// This will simply re-use the previously created points
line.enabled = true;
if (xRadius != prevXRadius || yRadius != prevYRadius || segments != prevSegments || width != prevWidth || height != prevHeight)
{
CreatePoints();
// Cache our most recently used values.
prevXRadius = xRadius;
prevYRadius = yRadius;
prevSegments = segments;
prevWidth = width;
prevHeight = height;
}
if (controlBothXradiusYradius)
{
yRadius = xRadius;
}
}
}
#endif
}
播放器有一个刚体 3d 组件、胶囊碰撞器、第三人称用户控件和第三人称角色。我正在使用键 WSAD 来移动播放器。
我尝试使用 Physics.CheckSphere 但如果玩家在半径区域内,它也会显示“检测到玩家”,并且我希望它仅在圆的绘制线上检测玩家。
此屏幕截图显示玩家触摸圆圈线:这就是我的意思是触摸圆圈的绘制线:
这是当玩家在圆圈内移动并且它也写玩家检测到但它应该写未检测到这就是我想要的,只有当他触摸线检测玩家时。
这就是我在脚本中所做的更改:我添加了一个 targetLayers 变量,然后在 Update 中使用 Physics.CheckSphere。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[ExecuteAlways]
[RequireComponent(typeof(UnityEngine.LineRenderer))]
public class DrawCircle : MonoBehaviour
{
public GameObject centerObject;
[Range(1, 50)] public int segments = 50;
[Range(1, 500)] public float xRadius = 5;
[Range(1, 500)] public float yRadius = 5;
[Range(0.1f, 5)] public float width = 0.1f;
[Range(0, 100)] public float height = 0;
public bool controlBothXradiusYradius = false;
public bool draw = true;
[SerializeField] private LayerMask targetLayers;
private Vector3 startPos;
private Vector3 endPos;
[SerializeField] private LineRenderer line;
private void Start()
{
if (!line) line = GetComponent<LineRenderer>();
if (draw)
CreatePoints();
startPos = line.GetPosition(0);
endPos = line.GetPosition(line.positionCount - 1);
}
private void Update()
{
if (Physics.CheckSphere(transform.position, xRadius, targetLayers))
{
Debug.Log("player detected");
}
else
{
Debug.Log("player NOT detected");
}
}
public void CreatePoints()
{
line.enabled = true;
line.widthMultiplier = width;
line.useWorldSpace = false;
line.widthMultiplier = width;
line.positionCount = segments + 1;
float x;
float y;
var angle = 20f;
var points = new Vector3[segments + 1];
for (int i = 0; i < segments + 1; i++)
{
x = Mathf.Sin(Mathf.Deg2Rad * angle) * xRadius;
y = Mathf.Cos(Mathf.Deg2Rad * angle) * yRadius;
points[i] = new Vector3(x, height, y);
angle += (380f / segments);
}
// it's way more efficient to do this in one go!
line.SetPositions(points);
}
#if UNITY_EDITOR
private float prevXRadius, prevYRadius;
private int prevSegments;
private float prevWidth;
private float prevHeight;
private void OnValidate()
{
// Can't set up our line if the user hasn't connected it yet.
if (!line) line = GetComponent<LineRenderer>();
if (!line) return;
if (!draw)
{
// instead simply disable the component
line.enabled = false;
}
else
{
// Otherwise re-enable the component
// This will simply re-use the previously created points
line.enabled = true;
if (xRadius != prevXRadius || yRadius != prevYRadius || segments != prevSegments || width != prevWidth || height != prevHeight)
{
CreatePoints();
// Cache our most recently used values.
prevXRadius = xRadius;
prevYRadius = yRadius;
prevSegments = segments;
prevWidth = width;
prevHeight = height;
}
if (controlBothXradiusYradius)
{
yRadius = xRadius;
}
}
}
#endif
}
解决方案
您的光线投射只能命中确定的层。例如:
int layerMask1 = 1 << LayerMask.NameToLayer("EnemiesLayer");
int layerMask2 = 1 << LayerMask.NameToLayer("GroundLayer");
int layerMask3 = 1 << LayerMask.NameToLayer("PlayerPlayer");
int myLayerMask= layerMask1 | layerMask1 | layerMask3;
然后使用此光线投射重载,将图层作为参数,以便您可以检索包含任何相关图层的第一个命中。
public static bool Raycast(Vector3 origin, Vector3 direction, out RaycastHit hitInfo, float maxDistance, int layerMask);
您只需要使用这种方法为您的播放器设置一个图层并为光线投射定义相应的图层。
推荐阅读
- javascript - SyntaxError: 应为. 线 (17:9)
- python - 避免重复 if 语句
- flutter - 如何使 Flutter HTTP 部分(范围)请求?
- javascript - 如何设置输入按键的默认输入?
- object - 扩展接口时,我们应该使用object关键字吗?
- delphi - 如何确定服务器是否只能使用 IPv6 访问
- reactjs - 将 TextInput 中输入的文本打印到控制台
- python - 在自定义 html 模板中使用 django 表单
- r - 试图在 R 中创建一个表,在其中我按向量的变量对列进行分组
- php - 使用资源控制器的 Laravel 自定义操作名称和路由名称?