I am making a game in Unity (C#), where you need to shoot a target.
Once you make a shot - the accuracy of your shot is to be shown.
The idea of my game is to be as precise as possible, so I cannot just make zones on the target for 100% accuracy, 90%, 80%, etc.
My idea for the calculations is the following:
PercentageErrorForXCoordinate = ((YourShotX – CenterOfTargetX)/ CenterOfTargetX) x 100;
PercentageErrorForYCoordinate = ((YourShotY – CenterOfTargetY)/ CenterOfTargetY) x 100;
TotalPercentageError = (PercentageErrorForXCoordinate PercentageErrorForYCoordinate)/2;
=> eventually I have 2 big problems:
Do you have any ideas on how to calculate correctly in this case? The code is below:
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public GameObject spawnManager;
//public GameObject shot;
public List<GameObject> Prefabs;
//public Vector3 miwen;
public bool GameIsActive;
private float minValueX = -2.5f; // x value of the center of the left-most square
private float minValueY = -9f; // y value of the center of the bottom-most square
private float targetPosX;
private float targetPosY;
private float pointerPosX;
private float pointerPosY;
private float pointerCorPosX;
private float pointerCorPosY;
private float pointerDisplayPosX;
private float pointerDisplayPosY;
private float AccuracyX;
private float AccuracyY;
private float TotalAccuracy;
public TextMeshProUGUI centerCalculator;
// Start is called before the first frame update
void Start()
{
SpawnerActivator();
GameIsActive = true;
centerCalculator.gameObject.SetActive(false);
}
// Update is called once per frame
void Update()
{
}
void SpawnerActivator()
{
int index = Random.Range(0, Prefabs.Count);
Instantiate(Prefabs[index], RandomSpawnPosition(), Prefabs[index].transform.rotation);
SpawnerPrecisionCalculator();
}
// Generate a random spawn position based on a random index from 0 to 3
Vector3 RandomSpawnPosition()
{
float spawnPosX = minValueX RandomPosX();
float spawnPosY = minValueY RandomPosY();
Vector3 spawnPosition = new Vector3(spawnPosX, spawnPosY, 0);
return spawnPosition;
}
// Generates random square index from 0 to 3, which determines which square the target will appear in
float RandomPosX()
{
return Random.Range(-1, 7);
}
// Generates random square index from 0 to 3, which determines which square the target will appear in
float RandomPosY()
{
return Random.Range(0, 19);
}
void SpawnerPrecisionCalculator()
{
targetPosX = GameObject.FindGameObjectWithTag("Miwen").transform.position.x;
targetPosY = GameObject.FindGameObjectWithTag("Miwen").transform.position.y;
//Debug.Log(targetPosX " " targetPosY);
}
public void CalculatePosition()
{
pointerPosX = GameObject.FindGameObjectWithTag("Pointer").transform.position.x;
pointerPosY = GameObject.FindGameObjectWithTag("Pointer").transform.position.y;
//Debug.Log("Pointer:" " " pointerPosX " " pointerPosY " " "target" " " targetPosX " " targetPosY);
}
public void CorPosCalculator()
{
//pointerCorPosX = Mathf.Round(targetPosX - pointerPosX);
//pointerCorPosY = Mathf.Round(targetPosY - pointerPosY);
pointerCorPosX = targetPosX - pointerPosX;
pointerCorPosY = targetPosY - pointerPosY;
pointerDisplayPosX = (Mathf.Round((targetPosX - pointerPosX) * 1000)) / 1000;
pointerDisplayPosY = (Mathf.Round((targetPosY - pointerPosY) * 1000)) / 1000;
AccuracyX = ((Mathf.Abs(pointerPosX) - Mathf.Abs(targetPosX)) / Mathf.Abs(targetPosX)) * 100;
AccuracyY = ((Mathf.Abs(pointerPosY) - Mathf.Abs(targetPosY)) / Mathf.Abs(targetPosY)) * 100;
TotalAccuracy = (AccuracyX AccuracyY) / 2;
Debug.Log($"Pointer: {pointerPosX} {pointerPosY}\nTargett: {targetPosX} {targetPosY}\nTotalAccuracy: {TotalAccuracy}");
centerCalculator.text = "Diff X:" pointerDisplayPosX " " "Diff Y:" pointerDisplayPosY;
centerCalculator.gameObject.SetActive(true);
}
}
CodePudding user response:
Typically you would use an exponential function to calculate a fixed range score with a potentially infinite numeric input.
In your case the following function could be used:
y = 100*10^(-x*strictness)
For any positive x value (zero included) you will receive a value for y that is between 0 and 100. Exactly zero for x will net you 100 and infinity will give you 0. You can adjust how generous the awarded points are by modifying the strictness constant.
public Vector2 YourShot;
public Vector2 CenterOfTarget;
public float strictness;//You will likely need a value above 1
float distance = Vecor2.Distance(YourShot,CenterOfTarget);
float score = 100*Mathf.Pow(10,-distance*strictness);
CodePudding user response:
You must not take the coordinates of the target as reference but its radius. Something like this
float radiusOfTarget = ...;
float radiusSquared = radiusOfTarget * radiusOfTarget;
float dx = CenterOfTargetX - YourShotX;
float dy = CenterOfTargetY - YourShotY;
float deviationSquared = dx * dx dy * dy;
if (deviationSquared >= radiusSquared) { // Pythagoras!
error = 100;
} else {
error = 100 * MathF.Sqrt(deviationSquared) / radiusOfTarget;
}
Or, if you are happy with a quadratic mapping
error = 100 * deviationSquared / radiusSquared;
This will be more forgiving when close to the target center.