Home > Enterprise >  How to calculate the accuracy of shot in percentage
How to calculate the accuracy of shot in percentage

Time:10-17

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:

  • when spawned coordinates are (0,0) - as I won't be able to divide later;
  • if the shot is far away from the target the result is too big.

    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.

    • Related