Reputation: 33
I make a Turn-Based RPG Game using unity ML-Agents. My Unity ML-Agents here as the enemy and I want my Unity ML-Agents do their turn based on reward they received, but i still can't grasp the logic.
Here is my code in my EnemyAgentAI.cs
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Sensors.Reflection;
using UnityEngine;
public class EnemyAIAgent : Agent
{
public float attackPower = 10f;
public float weaknessMultiplier = 2f;
public float resistanceMultiplier = 0.5f;
public float blockMultiplier = 0.2f;
private int NUM_ELEMENT;
private float reward = 0f;
public override void OnEpisodeBegin()
{
}
public override void CollectObservations(VectorSensor sensor)
{
// Observe the attack element
AttackScript attackScript = GetComponent<AttackScript>();
NUM_ELEMENT = (int)AttackScript.magicElement.LastElement;
if (attackScript != null)
{
sensor.AddObservation(NUM_ELEMENT);
}
}
public void AgentAttack(ActionSegment<int> act)
{
AttackScript attackScript = GetComponent<AttackScript>();
FighterStats fighterStats = GetComponent<FighterStats>();
FighterAction fighterAction = GetComponent<FighterAction>();
var dirToGo = Vector3.zero;
var rotateDir = Vector3.zero;
var physicalAttack = act[0];
var fireAttack = act[1];
if(physicalAttack == 1)
{
attackScript = GameObject.Find("EMeleePrefab").GetComponent<AttackScript>();
fighterAction.SelectAttack("melee");
Debug.Log("Melee attack");
} else if (fireAttack == 1)
{
attackScript = GameObject.Find("ERangePrefab").GetComponent<AttackScript>();
fighterAction.SelectAttack("range");
Debug.Log("Range attack");
}
// If the agent is trying to attack
if (physicalAttack == 1 || fireAttack == 1)
{
if (attackScript.IsBlockingAttack)
{
// reward = -attackPower * blockMultiplier;
reward = -1f;
} else if (attackScript.IsResistingAttack)
{
// reward = -attackPower * resistanceMultiplier;
reward = -0.5f;
} else if (attackScript.IsWeakToAttack)
{
// reward = attackPower * weaknessMultiplier;
reward = 1f;
} else
{
// reward = attackPower;
reward = 0.5f;
}
}
}
public override void OnActionReceived(ActionBuffers actions)
{
AgentAttack(actions.DiscreteActions);
// Apply the reward
AddReward(reward);
Debug.Log("Reward: " + reward);
EndEpisode();
}
}
Now, i have three problems:
GameController.cs
but it will make my agent do static things (not choosing or trying other attacks, just do physical attack).using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Transactions;
using UnityEngine.SocialPlatforms;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;
public class GameController : MonoBehaviour
{
private List<FighterStats> fighterStats;
private GameObject battleMenu;
public Text battleText;
private void Awake()
{
battleMenu = GameObject.Find("ActionMenu");
}
void Start()
{
fighterStats = new List<FighterStats>();
GameObject hero = GameObject.FindGameObjectWithTag("Hero");
FighterStats currentFighterStats = hero.GetComponent<FighterStats>();
currentFighterStats.CalculateNextTurn(0);
fighterStats.Add(currentFighterStats);
GameObject enemy = GameObject.FindGameObjectWithTag("Enemy");
FighterStats currentEnemyStats = enemy.GetComponent<FighterStats>();
currentEnemyStats.CalculateNextTurn(0);
fighterStats.Add(currentEnemyStats);
fighterStats.Sort();
NextTurn();
}
public void NextTurn()
{
battleText.gameObject.SetActive(false);
FighterStats currentFighterStats = fighterStats[0];
fighterStats.Remove(currentFighterStats);
if (!currentFighterStats.GetDead())
{
GameObject currentUnit = currentFighterStats.gameObject;
currentFighterStats.CalculateNextTurn(currentFighterStats.nextActTurn);
fighterStats.Add(currentFighterStats);
fighterStats.Sort();
if (currentUnit.CompareTag("Hero"))
{
battleMenu.SetActive(true);
Debug.Log("Hero's turn");
}
else
{
battleMenu.SetActive(false);
Debug.Log("Enemy's turn");
// Scripted AI
// string attackType = Random.Range(0, 2) == 1 ? "melee" : "range";
// currentUnit.GetComponent<FighterAction>().SelectAttack(attackType);
// ML-Agents AI
float[] actions = new float[] { 0, 1, 0, 0, 0, 0, 0 };
ActionBuffers actionBuffers = ActionBuffers.FromDiscreteActions(actions);
currentUnit.GetComponent<EnemyAIAgent>().OnActionReceived(actionBuffers);
}
} else
{
NextTurn();
}
}
}
When I'm using OnActionReceived on my GameController.cs
, a warning appears: Fewer observations (0) made than vector observation size (1). The observations will be padded.
Then I try using RequestDecision, but the agent do nothing in their turn.
...
// ML-Agents AI
currentUnit.GetComponent<EnemyAIAgent>().RequestDecision();
...
Upvotes: 0
Views: 84