我正在使用下面链接中提到的教程创建一个Ofscreen Enemy指标。但是我可以让指示器旋转指向敌人,但指示器不会从屏幕的一端移动到另一端。
这是理想的结果:
直到现在我已经设法弄清楚下面请帮忙。
var screenCenter:Vector3 = new Vector3(0.5, 0.5, 0f);
//Note coordinates are translated
//Make 00 the centre of the screen instead of bottom left
screenpos -= screenCenter;
//find angle from center of screen instead of bototom left
var angle:float = Mathf.Atan2(screenpos.y, screenpos.x);
angle -= 90 * Mathf.Deg2Rad;
var cos:float = Mathf.Cos(angle);
var sin:float = -Mathf.Cos(angle);
screenpos = screenCenter + new Vector3(sin*150, cos*150, 0);
//y=mx + b format
var m:float = cos/sin;
var ScreenBounds:Vector3 = screenCenter;// * 0.9f;
//Check up and down first
if(cos > 0){
screenpos = new Vector3(ScreenBounds.y/m, ScreenBounds.y, 0);
}else{//down
screenpos = new Vector3(-ScreenBounds.y/m, -ScreenBounds.y, 0);
}
//If out of bound then get point on appropriate side
if(screenpos.x > ScreenBounds.x){//Out of bound must be on right
screenpos = new Vector3(ScreenBounds.x, ScreenBounds.y*m, 0);
}else if(screenpos.x < ScreenBounds.x){//Out of bound must be on left
screenpos = new Vector3(-ScreenBounds.x, -ScreenBounds.y*m, 0);
}
//Remove the co ordinate translation
screenpos += screenCenter;
var DistanceIndicatorRectT = DistanceIndicator.GetComponent(RectTransform);
DistanceIndicatorRectT.localPosition = new Vector3(screenpos.x * scrWidth/2, screenpos.y * scrHeight/2, DistanceIndicatorRectT.localPosition.z * screenpos.z);
DistanceIndicator.transform.rotation = Quaternion.Euler(0, 0, angle*Mathf.Rad2Deg);
答案 0 :(得分:3)
我做了一些与你不同的方法,卡洛斯建议但没有使用物理学。
如果&#34; t&#34;是你的目标,这样你可以在屏幕上以像素为单位获得它的位置(如果它在屏幕外它只是去负值或高于那个宽度的值)
Vector3 targetPosOnScreen = Camera.main.WorldToScreenPoint (t.position);
这个函数返回一个bool,无论Vector3(以像素为单位)是否在屏幕上
bool onScreen(Vector2 input){
return !(input.x > Screen.width || input.x < 0 || input.y > Screen.height || input.y < 0);
}
我们应该做的第一件事就是检查目标是否在屏幕上,如果它没有继续代码。
if (onScreen (targetPosOnScreen)) {
//Some code to destroy indicator or make it invisible
return;
}
然后简单计算屏幕中心与目标之间的角度。
Vector3 center = new Vector3 (Screen.width / 2f, Screen.height / 2f, 0);
float angle = Mathf.Atan2(targetPosOnScreen.y-center.y, targetPosOnScreen.x-center.x) * Mathf.Rad2Deg;
下一部分代码根据我们刚刚计算的角度确定对象与相机的比较位置。
float coef;
if (Screen.width > Screen.height)
coef = Screen.width / Screen.height;
else
coef = Screen.height / Screen.width;
float degreeRange = 360f / (coef + 1);
if(angle < 0) angle = angle + 360;
int edgeLine;
if(angle < degreeRange / 4f) edgeLine = 0;
else if (angle < 180 - degreeRange / 4f) edgeLine = 1;
else if (angle < 180 + degreeRange / 4f) edgeLine = 2;
else if (angle < 360 - degreeRange / 4f) edgeLine = 3;
else edgeLine = 0;
http://s23.postimg.org/ytpm82ad7/Untitled_1.png
图像代表什么价值&#34; edgeLine&#34;将基于目标位置(红色代表相机的视图)和黑色线条划分空间。
然后我们将这个代码设置为Transform&#34; t2&#34; (指示器)纠正位置和角度。
t2.position = Camera.main.ScreenToWorldPoint(intersect(edgeLine, center, targetPosOnScreen)+new Vector3(0,0,10));
t2.eulerAngles = new Vector3 (0, 0, angle);
下面我们有功能&#34;相交&#34;哪个代码是:
Vector3 intersect(int edgeLine, Vector3 line2point1, Vector3 line2point2){
float[] A1 = {-Screen.height, 0, Screen.height, 0};
float[] B1 = {0, -Screen.width, 0, Screen.width};
float[] C1 = {-Screen.width * Screen.height,-Screen.width * Screen.height,0, 0};
float A2 = line2point2.y - line2point1.y;
float B2 = line2point1.x - line2point2.x;
float C2 = A2 * line2point1.x + B2 * line2point1.y;
float det = A1[edgeLine] * B2 - A2 * B1[edgeLine];
return new Vector3 ((B2 * C1[edgeLine] - B1[edgeLine] * C2) / det, (A1[edgeLine] * C2 - A2 * C1[edgeLine]) / det, 0);
}
我们向这个函数发送我们需要检查交叉点的相机视线(矩形)的索引,并在屏幕中心和目标位置之间构建一条线。
有关此功能的更好说明,请查看此处:https://www.topcoder.com/community/data-science/data-science-tutorials/geometry-concepts-line-intersection-and-its-applications/
我刚刚修改了A1,B1和C1的值,每个值现在都是4的数组,每个值代表一行相机视图(矩形)所需的值。
如果要实现边距,只需更改指示器的轴心(将实际的精灵渲染器设置为子节点,然后根据需要将其移动到局部空间中)。
接下来的事情就是让这个目标阵列工作,并将所有这些目标放在给定的数组中。希望这会对我有所帮助,对我来说不会太难,这是我第一次在这里发帖:)
答案 1 :(得分:2)
创建一个矩形框对撞机,用于界定屏幕的边框,并在敌人的方向上使用Physics2D.Raycast。
碰撞点会告诉您需要绘制绿色箭头的位置。
答案 2 :(得分:0)
在上面的示例中,直角矩形的可见角度定义存在错误。
private void SetIndicatorPosition(Indicator obj)
{
var target = obj.Target;
var indicator = obj.PointToTarget;
if (target == null)
{
indicator.SetActive(false);
return;
}
Vector3 targetPosOnScreen = cam.WorldToScreenPoint(target.transform.position);
if (onScreen(targetPosOnScreen))
{
indicator.SetActive(false);
return;
}
indicator.SetActive(true);
Vector3 center = new Vector3(Screen.width / 2f, Screen.height / 2f, 0);
float angle = Mathf.Atan2(targetPosOnScreen.y - center.y, targetPosOnScreen.x - center.x) * Mathf.Rad2Deg;
float scale;
if (Screen.width > Screen.height)
scale = Screen.width / Screen.height;
else
scale = Screen.height / Screen.width;
float degreeRange = 360f / (scale + 1);
float angle2 = Mathf.Atan2(Screen.height - center.y, Screen.width - center.x) * Mathf.Rad2Deg;
if (angle < 0) angle = angle + 360;
int edgeLine;
if (angle < angle2) edgeLine = 0;
else if (angle < 180 - angle2) edgeLine = 1;
else if (angle < 180 + angle2) edgeLine = 2;
else if (angle < 360 - angle2) edgeLine = 3;
else edgeLine = 0;
indicator.transform.position = Camera.main.ScreenToWorldPoint(Intersect(edgeLine, center, targetPosOnScreen));
indicator.transform.eulerAngles = new Vector3(0, 0, angle);
}
Vector3 Intersect(int edgeLine, Vector3 line2point1, Vector3 line2point2)
{
float[] A1 = { -Screen.height, 0, Screen.height, 0 };
float[] B1 = { 0, -Screen.width, 0, Screen.width };
float[] C1 = { -Screen.width * Screen.height, -Screen.width * Screen.height, 0, 0 };
float A2 = line2point2.y - line2point1.y;
float B2 = line2point1.x - line2point2.x;
float C2 = A2 * line2point1.x + B2 * line2point1.y;
float det = A1[edgeLine] * B2 - A2 * B1[edgeLine];
var x = (B2 * C1[edgeLine] - B1[edgeLine] * C2) / det;
var y = (A1[edgeLine] * C2 - A2 * C1[edgeLine]) / det;
return new Vector3(x, y, 0);
}
bool onScreen(Vector2 input)
{
return !(input.x > Screen.width || input.x < 0 || input.y > Screen.height || input.y < 0);
}
public class Indicator
{
public GameObject Target { get; private set; }
public GameObject PointToTarget { get; private set; }
public Indicator(GameObject target, GameObject pointToTarget, ObjectTypeEnum type)
{
Target = target;
PointToTarget = pointToTarget;
var texture = pointToTarget.GetComponentInChildren<UITexture>();
if (texture != null)
{
texture.color = Helper.GetHintColor(type);
}
}
}
您可以在更新中调用
foreach (var obj in listIndicator)
{
SetIndicatorPosition(obj);
}