using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; public class DifficultyManager { private Dictionary<String, double> means = new Dictionary<string, double>(); private Dictionary<String, double> stdDevs = new Dictionary<string, double>(); public double gamerScore; private List<String> keys = new List<string>{"accuracy", "killsPerSecond", "headshotPercentage", "timeToDamage", "averageHealthLoss", "timeToKill"}; public void LogGame(GameResults results) { // add game to log of previous 10 games GameLog gameLog = JsonUtility.FromJson<GameLog>(PlayerPrefs.GetString("gameLog")); if (gameLog.gameResultsList.Count >= 10) gameLog.gameResultsList.RemoveAt(0); if (gameLog.accuracies.Count >= 10) gameLog.accuracies.RemoveAt(0); if (gameLog.headshotPercentage.Count >= 10) gameLog.headshotPercentage.RemoveAt(0); if (gameLog.averageHealthLoss.Count >= 10) gameLog.averageHealthLoss.RemoveAt(0); if (gameLog.killsPerSecond.Count >= 10) gameLog.killsPerSecond.RemoveAt(0); if (gameLog.timeToDamage.Count >= 10) gameLog.timeToDamage.RemoveAt(0); if (gameLog.timeToKill.Count >= 10) gameLog.timeToKill.RemoveAt(0); gameLog.gameResultsList.Add(results); gameLog.accuracies.Add(results.accuracy); gameLog.headshotPercentage.Add(results.headshotPercentage); gameLog.averageHealthLoss.Add(results.averageHealthLoss > 0 ? results.averageHealthLoss : 100f); gameLog.killsPerSecond.Add(results.killsPerSecond); gameLog.timeToDamage.Add(results.timeToDamage > 0 ? results.timeToDamage : 100f); gameLog.timeToKill.Add(results.timeToKill > 0 ? results.timeToKill : 100f); String newLog = JsonUtility.ToJson(gameLog); PlayerPrefs.SetString("gameLog", newLog); } public int DecideLevel(GameResults results) { // return an int representing how much to shift the level (0 means stay, -1/-2 lower, +1/+2 higher) // creates a score based on a normal distribution of all statistics GameLog gameLog = JsonUtility.FromJson<GameLog>(PlayerPrefs.GetString("gameLog")); if (gameLog.gameResultsList.Count < 5) { return 0; } GetStats(gameLog); var accuracyScore = GetScore("accuracy", results.accuracy); var headshotScore = GetScore("headshotPercentage", results.headshotPercentage); var killsScore = GetScore("killsPerSecond", results.killsPerSecond); var ttdScore = 1 - GetScore("timeToDamage", results.timeToDamage); var healthScore = 1 - GetScore("averageHealthLoss", results.averageHealthLoss); var ttkScore = 1 - GetScore("timeToKill", results.timeToKill); double winScore; if (results.won) { winScore = 1f; } else { winScore = 0f; } gamerScore = winScore * 40 + accuracyScore * 10 + killsScore * 10 + headshotScore * 10 + ttdScore * 10 + healthScore * 10 + ttkScore * 10; //gamerScore *= 1.25f; // sets it to be a num between 0 - 100 // weighted winning more as if you were able to win but played poorly it wouldnt change the difficulty at all - if you are consistently winning it should make it harder until you start losing sometimes Debug.Log(gamerScore); if (gamerScore >= 80) { return 2; } else if (gamerScore >= 60) { return 1; } else if (gamerScore >= 40) { return 0; } else if (gamerScore >= 20) { return -1; } else { return -2; } } private void GetStats(GameLog log) { means.Add("accuracy", log.accuracies.Average()); means.Add("killsPerSecond", log.killsPerSecond.Average()); means.Add("headshotPercentage", log.headshotPercentage.Average()); means.Add("timeToDamage", log.timeToDamage.Average()); means.Add("averageHealthLoss", log.averageHealthLoss.Average()); means.Add("timeToKill", log.timeToKill.Average()); GetStdDev("accuracy", log.accuracies); GetStdDev("killsPerSecond", log.killsPerSecond); GetStdDev("headshotPercentage", log.headshotPercentage); GetStdDev("timeToDamage", log.timeToDamage); GetStdDev("averageHealthLoss", log.averageHealthLoss); GetStdDev("timeToKill", log.timeToKill); } private void GetStdDev(String key, List<float> values) { var avg = means[key]; var sum = values.Sum(f => Math.Pow(f - avg, 2f)); stdDevs.Add(key, Math.Sqrt((sum) / values.Count)); } private double GetScore(String key, float value) { return Phi((value - means[key]) / stdDevs[key]); } private double Phi(double zScore) { float a1 = 0.254829592f; float a2 = -0.284496736f; float a3 = 1.421413741f; float a4 = -1.453152027f; float a5 = 1.061405429f; float p = 0.3275911f; int sign = 1; if (zScore < 0) sign = -1; zScore = Math.Abs(zScore) / (float) Math.Sqrt(2); double t = 1f / (1 + p * zScore); double y = 1f - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * (float) Math.Exp(-zScore * zScore); return 0.5f * (1 + sign * y); } }