Как мне улучшить систему помощи при прицеливании в игре?C#

Место общения программистов C#
Ответить
Гость
 Как мне улучшить систему помощи при прицеливании в игре?

Сообщение Гость »

Я делаю 2D-игру с видом сверху в Unity, в которой вы выбираете направление стрельбы с помощью аналогового джойстика.
Я решил добавить систему помощи при прицеливании, которая проверяет, есть ли цели достаточно близко к куда игрок целится. Если это так, прицел корректируется соответствующим образом, чтобы гарантировать попадание в цель.
Чтобы добиться этого, я решил выстрелить тремя лучами. Один находится в том же направлении, в котором стреляют, а два других образуют конус. Затем функция корректирует направление стрельбы в соответствии с кратчайшим лучом, обнаружившим вражескую цель. Эта проверка очень полезна, поскольку после изменения цели текущая цель не изменится, поскольку «прямой» луч всегда будет более коротким (если что-то еще не пройдет перед текущей целью).
Меня это уже немного расстраивает. Я знаю, что рейкасты не очень хороши с точки зрения производительности, и я постоянно снимаю три из них одновременно. Возможно, есть лучший способ добиться того, что мне нужно... но это еще не конец! Видите ли, в игре также используются надувные стены. Они отражают снаряды, и мне нужно принять это во внимание и для помощи прицеливанию.
В этом случае мне нужно, чтобы помощь прицеливания регулировала угол так, чтобы стрельба отскакивала и попадала во врага. В этом случае, когда луч ударяется о упругую стену, он «отражается» и продолжает двигаться, пока не найдет врага или не найдет ничего. Конечно, «отражение» осуществляется путем съемки еще одного рейкаста, а это означает, что количество увеличивается еще больше! Если я создам уровень с множеством упругих стен, игра гарантированно будет иметь большие скачки задержки, а то и вовсе вылетит. Простое решение — просто остановить «отражение», если оно происходит X раз в одном и том же исходном raycast, что я и реализовал до сих пор, но меня это решение не устраивает.
В этом сценарии я по-прежнему снимаю сумасшедшее количество лучей в каждом кадре, и выбор количества отражений «слишком много» может быть утомительным. Может быть, лучи можно было бы «отражать» без необходимости снимать новый для каждого отражения? Может быть, я смогу реализовать эту систему вообще без использования raycasts? Я не уверен. В любом случае, вот код:

Код: Выделить всё

private float AngledRaycastDistance(float angle, Vector2 origin, bool testRaycast, float currentDistance = 0)
{
float totalDistance = currentDistance;
Vector2 dir = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
Vector2 currentPoint = origin;
RaycastHit2D hit;
Collider2D lastHit = null;

// This is just for debugging and avoiding infinite loop to gather data
int numberOfReflections = 0;

while (totalDistance < Mathf.Infinity) // && numberOfReflections < 7)
{
numberOfReflections++;
hit = Physics2D.Raycast(currentPoint, dir.normalized, Mathf.Infinity, mask);
if (hit.collider != null)
{
if (hit.collider.tag == "Enemy")
{
totalDistance += hit.distance;
break;
}
else if (hit.collider.tag == "BouncyWall")
{

// For debugging
if(testRaycast)
{
Debug.DrawRay(currentPoint, dir, Color.green);
// EditorApplication.isPaused = true;
}

// This part is necessary otherwise the reflected raycast will keep hitting the
// surface it was just reflected on, instead of keep traveling.
// The first time it gets to this check, it will always go on the "else"
if (lastHit != null && hit.collider == lastHit)
{
currentPoint += dir;
} else
{
currentPoint = hit.point;
Vector2 reflectionDir = Vector2.Reflect(dir, hit.normal);
dir = reflectionDir.normalized;
totalDistance += hit.distance;
lastHit = hit.collider;

Debug.Log("Surface Normal: " + hit.normal);
Debug.Log("Incident Direction: " + dir);
Debug.Log("Reflected Direction: " + reflectionDir);
}

}
else
{
Debug.LogError("It should never come here");
return Mathf.Infinity;
}
}
else
{
return Mathf.Infinity;
}
}

return totalDistance;
}

public void SetStickInput(InputAction.CallbackContext context)
{
// I'm taking the shoot direction directly from the new input system
shootDirection = context.ReadValue();
float angle = Mathf.Atan2(shootDirection.y, shootDirection.x);

// Ignore this
if (_isUsingSnap && shootDirection != Vector2.zero)
{
float snapAngle = 4f * Mathf.Deg2Rad;
float snappedAngle = Mathf.Round(angle / snapAngle) * snapAngle;
Vector2 snappedDirection = new Vector2(Mathf.Cos(snappedAngle), Mathf.Sin(snappedAngle));
shootDirection = snappedDirection;
angle = Mathf.Atan2(shootDirection.y, shootDirection.x);
}

else if(_isUsingLockOn && shootDirection != Vector2.zero)
{
float coneBroadness = 3f;

// Shoot three raycasts. Each bounces from bouncyWalls and stops if it meets an enemy.  Returns the total distance traveled
float straightDistance = AngledRaycastDistance(angle, transform.position, true);
float angledUpDistance = AngledRaycastDistance(angle + (coneBroadness * Mathf.Deg2Rad), transform.position, false);
float angledDownDistance = AngledRaycastDistance(angle - (coneBroadness * Mathf.Deg2Rad), transform.position, false);

float smallestValue = Mathf.Min(straightDistance, angledUpDistance, angledDownDistance);

if (Mathf.Abs(angledUpDistance - smallestValue) < 0.0001f)
{
Vector2 lockedDirection = new Vector2(Mathf.Cos(angle + (coneBroadness * Mathf.Deg2Rad)), Mathf.Sin(angle + (coneBroadness * Mathf.Deg2Rad)));
shootDirection = lockedDirection;
}
else if (Mathf.Abs(angledDownDistance - smallestValue) < 0.0001f)
{
Vector2 lockedDirection = new Vector2(Mathf.Cos(angle - (coneBroadness * Mathf.Deg2Rad)), Mathf.Sin(angle - (coneBroadness * Mathf.Deg2Rad)));
shootDirection = lockedDirection;
}

// For debugging
//Debug.DrawRay(transform.position, new Vector2(Mathf.Cos(angle + (coneBroadness * Mathf.Deg2Rad)), Mathf.Sin(angle + (coneBroadness * Mathf.Deg2Rad))) * 10f, Color.yellow, 0.1f);
//Debug.DrawRay(transform.position, new Vector2(Mathf.Cos(angle - (coneBroadness * Mathf.Deg2Rad)), Mathf.Sin(angle - (coneBroadness * Mathf.Deg2Rad))) * 10f, Color.yellow, 0.1f);
//Debug.DrawRay(transform.position, new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * 10f, Color.red, 0.1f);
}

}
Ах, да, как вы можете заметить, я также добавил еще одно исправление, в котором я слегка «перемещаю» исходную точку рейкаста после каждого отражения, иначе он продолжал бы сталкиваться с той же самой прыгающей стеной. вообще не путешествуя. Это еще одна проблема, о которой мне нужно позаботиться (если я сохраню эту систему raycast).
Я знаю, что нужно многое решить, но буду признателен за любое предложение!
Заранее всем спасибо за уделенное время!

Подробнее здесь: https://stackoverflow.com/questions/781 ... in-my-game
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»