我正在使用C#脚本在Unity中开发等距2D游戏。角色将可以在8个不同的方向上奔跑。
我试图根据鼠标位置触发正在运行的动画。 我的脚本工作正常,但我认为不是解决此问题的最佳方法。
首先,我有一个可能的方向枚举:
public enum Orientations {N,NE,E,SE,S,SW,W,NW,NONE}
我写了一个方法,该方法返回基于运动的Orientations值。这是因为我想根据动作触发动画,因此角色将始终注视动作的方向:
public static Orientations GetOrientation(Vector2 movement)
{
if (movement.x == 0 && movement.y == 1)
{
return Orientations.N;
}
else if (movement.x == 1 && movement.y == 0)
{
return Orientations.E;
}
else if (movement.x == 0 && movement.y == -1)
{
return Orientations.S;
}
else if (movement.x == -1 && movement.y == 0)
{
return Orientations.W;
}
else if (movement.x == -1 && movement.y == 1)
{
return Orientations.NW;
}
else if (movement.x == 1 && movement.y == 1)
{
return Orientations.NE;
}
else if (movement.x == -1 && movement.y == -1)
{
return Orientations.SW;
}
else if (movement.x == 1 && movement.y == -1)
{
return Orientations.SE;
}
return Orientations.NONE;
}
接下来,我得到了角色和屏幕之间的鼠标角度。
public static float GetMousePosition(Transform transform)
{
float cameraDistance = Camera.main.transform.position.y - transform.position.y;
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, cameraDistance));
float angleRadius = Mathf.Atan2(mousePosition.y - transform.position.y, mousePosition.x - transform.position.x);
float angle = (180 / Mathf.PI) * angleRadius;
angle = (angle < 0) ? angle + 360 : angle;
return angle;
}
然后,我在Vector2中变换角度,因此我可以通过角色移动和鼠标位置在触发动画之间进行切换:
public static Vector2 AngleToVectorDirection(Transform transform)
{
Vector2 direction = new Vector2(0,0);
float angle = GetMousePosition(transform);
if(angle >= 67.5 && angle < 112.5)
{
direction = new Vector2(0,1);
}
else if (angle >= 112.5 && angle < 157.5)
{
direction = new Vector2(-1,1);
}
else if (angle >= 157.5 && angle < 202.5)
{
direction = new Vector2(-1, 0);
}
else if (angle >= 202.5 && angle < 247.5)
{
direction = new Vector2(-1, -1);
}
else if (angle >= 247.5 && angle < 292.5)
{
direction = new Vector2(0, -1);
}
else if (angle >= 292.5 && angle < 337.5)
{
direction = new Vector2(1, -1);
}
else if (angle >= 337.5 || angle < 22.5)
{
direction = new Vector2(1, 0);
}
else if (angle >= 22.5 && angle < 67.5)
{
direction = new Vector2(1, 1);
}
return direction;
}
最后,我返回我提到的方向:
public static Orientations GetOrientationByMovement(Transform transform, Vector2 movement)
{
Vector2 orientation;
if (!Input.GetButton("Fire1"))
{
orientation = movement;
}
else
{
orientation = AngleToVectorDirection(transform);
}
return GetOrientation(orientation);
}
此方向由触发动画的AnimationController脚本接收。
我不能简单地旋转角色,翻转精灵或类似的东西,因为它是基于动画的。
答案 0 :(得分:0)
您在这里做了两次工作。因此,从优化的角度来看,这不是理想的,但从设计的角度来看,可以很好地分离作品。问题是运动参数在GetOrientationByMovement方法中来自哪里?您可以改用方向枚举吗?如果是,那将大大简化您的代码! 您最终得到了:
public static Orientations AngleToVectorDirection(Transform transform)
{
float angle = GetMousePosition(transform);
if(angle >= 67.5 && angle < 112.5)
{
return Orientations.N;
}
else if (angle >= 112.5 && angle < 157.5)
{
return Orientations.NW;
}
else if (angle >= 157.5 && angle < 202.5)
{
return Orientations.W;
}
else if (angle >= 202.5 && angle < 247.5)
{
return Orientations.SW;
}
else if (angle >= 247.5 && angle < 292.5)
{
return Orientations.S;
}
else if (angle >= 292.5 && angle < 337.5)
{
return Orientations.SE;
}
else if (angle >= 337.5 || angle < 22.5)
{
return Orientations.E;
}
else if (angle >= 22.5 && angle < 67.5)
{
return Orientations.NE;
}
}
还要尝试保持代码的一致性。如果在if语句中使用返回值对两个函数都执行此操作,则在外部使用返回值时请在所有位置执行返回值。 请注意,在实现AngleToVectorDirection时,无需在一开始就创建新矢量,因为您已经覆盖了所有可能的角度。
答案 1 :(得分:0)
回答我自己的问题:
使用刚刚发布的unity 3.8f1补丁,我在他们的演示项目中发现了一种以非常简单的方式触发动画的方法。
我只是使用您可以在官方网站上找到的代码: https://blogs.unity3d.com/2019/03/18/isometric-2d-environments-with-tilemap/?_ga=2.120446600.1010886114.1552829987-288556513.1552829987
他们使用IsometricCharacterRenderer脚本,其中使用Animator.Play()作为参数,根据播放器的运动将string []的值作为参数传递。
public static readonly string[] staticDirections = { "Static N", "Static NW", "Static W", "Static SW", "Static S", "Static SE", "Static E", "Static NE" };
public static readonly string[] runDirections = { "Run N", "Run NW", "Run W", "Run SW", "Run S", "Run SE", "Run E", "Run NE" };
public void SetDirection(Vector2 direction)
{
//use the Run states by default
string[] directionArray = null;
//measure the magnitude of the input.
if (direction.magnitude < .01f)
{
//if we are basically standing still, we'll use the Static states
//we won't be able to calculate a direction if the user isn't pressing one, anyway!
directionArray = staticDirections;
}
else
{
//we can calculate which direction we are going in
//use DirectionToIndex to get the index of the slice from the direction vector
//save the answer to lastDirection
directionArray = runDirections;
lastDirection = DirectionToIndex(direction, 8);
}
//tell the animator to play the requested state
animator.Play(directionArray[lastDirection]);
}
并且为了获得方向索引,他们将角度转换为角度,就像我所做的那样,但是以一种聪明的方式。
public static int DirectionToIndex(Vector2 dir, int sliceCount)
{
//get the normalized direction
Vector2 normDir = dir.normalized;
//calculate how many degrees one slice is
float step = 360f / sliceCount;
//calculate how many degress half a slice is.
//we need this to offset the pie, so that the North (UP) slice is aligned in the center
float halfstep = step / 2;
//get the angle from -180 to 180 of the direction vector relative to the Up vector.
//this will return the angle between dir and North.
float angle = Vector2.SignedAngle(Vector2.up, normDir);
//add the halfslice offset
angle += halfstep;
//if angle is negative, then let's make it positive by adding 360 to wrap it around.
if (angle < 0)
{
angle += 360;
}
//calculate the amount of steps required to reach this angle
float stepCount = angle / step;
//round it, and we have the answer!
return Mathf.FloorToInt(stepCount);
}