Agent stuck in loop MLAgents in Unity - c#

Goal: The agent need to shoot red dots.
The agent shoots a ball that when it hits a red dot, it removes the dot and himself but when it hits an obstacle, only the ball disappear. (There's no bounce)
Example Level 1
The agent on the first level does really good, the problem is when i train on the other levels.
Example Level 2
Example Level 3 (Obstacles are moving left and right)
The agent does some success but after many episodes it gets stuck on loop, going left and right.
public class Capsule_ML : Agent
{
public GameObject sfera;
private int num, num_rossi; //tiri, numero rossi
public bool activate_shoot = false;
public Text num_sfere, punteggio, tempo_Rimanente;
//private float time_Left;
//private bool timer_Active;
public override void OnEpisodeBegin()
{
Episode_Debug.Episode += 1;
this.transform.rotation = Quaternion.Euler(Vector3.zero);
activate_shoot = false;
//timer_Active = true;
//time_Left = 60;
Active(this.transform.parent);
SearchRossiInParent(this.transform.parent);
punteggio.text = "#ROSSI: " + num_rossi;
num_sfere.text = "#SFERE: " + num;
}
//private void Update()
//{
// if (timer_Active)
// {
// time_Left -= Time.deltaTime;
// tempo_Rimanente.text = "Tempo Rimanente: " + time_Left + "s";
// if (time_Left <= 0)
// {
// timer_Active = false;
// TimeError();
// }
// }
//}
public void TimeError()
{
AddReward(-1.0f);
Episode_Debug.Fail += 1;
EndEpisode();
}
public override void CollectObservations(VectorSensor sensor)
{
}
public override void OnActionReceived(float[] action)
{
this.transform.Rotate(Vector3.back * action[0] * 60 * Time.deltaTime);
this.transform.Rotate(-Vector3.back * action[1] * 60 * Time.deltaTime);
if(UnityEditor.TransformUtils.GetInspectorRotation(this.transform).z < -90 || UnityEditor.TransformUtils.GetInspectorRotation(this.transform).z > 90)
{
AddReward(-1.0f);
Episode_Debug.Fail += 1;
EndEpisode();
}
RaycastHit2D hit = Physics2D.Raycast(this.transform.position, transform.TransformDirection(Vector3.down), Mathf.Infinity);
if (activate_shoot == false && hit.collider.tag == "red")
{
Debug.Log("Raycast colpisce " + hit.collider.name);
activate_shoot = true;
Debug.Log(activate_shoot);
Shoot();
//AddReward(1.0f);
}
//if (activate_shoot == false && action[2] == 1)
//{
// activate_shoot = true;
// Shoot();
//}
if ((num_rossi == 0 && num == 0) || (num_rossi == 0 && num > 0))
{
Episode_Debug.Success += 1;
AddReward(1.0f);
EndEpisode();
}
//if (num_rossi > 0 && num == 0)
//{
// Episode_Debug.Fail += 1;
// AddReward(-0.3f);
// EndEpisode();
//}
if (num < num_rossi)
{
Episode_Debug.Fail += 1;
AddReward(-1.0f);
EndEpisode();
}
Episode_Debug.ScreenText();
}
public void Shoot()
{
if (num > 0)
{
num -= 1;
num_sfere.text = "#SFERE: " + num;
GameObject clone = GameObject.Instantiate(sfera);
clone.transform.position = transform.position - transform.up * 1.0f;
clone.GetComponent<Rigidbody2D>().AddForce(-transform.up * 15.0f, ForceMode2D.Impulse);
}
}
public int GetCountRossi() //Numero Rossi Text
{
return num_rossi;
}
public void SetCountRossi(int x) //Numero Rossi Text
{
num_rossi = x;
}
//public void Shoot_Rosso() //check rosso colpito
//{
// AddReward(0.5f);
//}
public void Shoot_Error()
{
AddReward(-0.5f);
}
public void SearchRossiInParent(Transform parent) //Numero rossi iniziali nel livello e numero tiri
{
num_rossi = 0;
foreach(Transform red in parent)
{
if (red.gameObject.tag == "red")
num_rossi++;
}
num = num_rossi + 1;
}
public void Active(Transform parent)
{
foreach (Transform sphere in parent)
{
if (sphere.gameObject.tag == "red" || sphere.gameObject.tag == "blu")
sphere.gameObject.SetActive(true);
}
}
This is the code of the agent.
This is the .yaml config
behaviors:
Capsule_ML:
trainer_type: ppo
hyperparameters:
batch_size: 1024
buffer_size: 10240
learning_rate: 0.0004
beta: 0.005
epsilon: 0.2
lambd: 0.95
num_epoch: 5
learning_rate_schedule: linear
network_settings:
normalize: false
hidden_units: 128
num_layers: 2
vis_encode_type: simple
memory:
use_recurrent: true
sequence_length: 64
memory_size: 256
goal_conditioning_type: hyper
deterministic: false
reward_signals:
extrinsic:
gamma: 0.99
strength: 1.0
init_path: null
keep_checkpoints: 5
checkpoint_interval: 500000
max_steps: 500000
time_horizon: 64
summary_freq: 50000
threaded: false
self_play: null
behavioral_cloning: null
env_settings:
env_path: null
env_args: null
base_port: 5005
num_envs: 1
seed: -1
engine_settings:
width: 84
height: 84
quality_level: 5
time_scale: 20
target_frame_rate: -1
capture_frame_rate: 60
no_graphics: false
environment_parameters: null
checkpoint_settings:
run_id: TL1.1
initialize_from: null
load_model: false
resume: false
force: false
train_model: false
inference: false
debug: false
I'm using the RayPerception with these settings:
Settings
Tried to use a timer to end the episodes that gets stuck, but the agent is always in loop, even after many and many steps

Related

Trying to generate prefabs over and over in semi-random positions

So I made this code in an effort to start making a script that generates bush objects in my scene randomly, however when in runs it only spawns the first bush. Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BushSpawner : MonoBehaviour
{
public GameObject bush;
private float x = 0f;
private float y = -.47f;
private float z = 0f;
private int bushCount = 0;
private Vector3 origPos;
private bool xPlus = false;
private bool xMinus = false;
private bool zPlus = false;
private bool zMinus = false;
// Use this for initialization
void Start()
{
SpawnBushes();
}
// Update is called once per frame
void Update()
{
}
void SpawnBushes()
{
Vector3 startPos = new Vector3(x, y, z);
Instantiate(bush, startPos, Quaternion.identity);
bushCount += 1;
while (bushCount < 100)
{
Vector3 checkPos = new Vector3(x, y, z);
Collider[] intersecting = Physics.OverlapSphere(checkPos, 1f);
if (intersecting.Length == 0)
{
//code to run if nothing is intersecting as the length is 0
Instantiate(bush, checkPos, Quaternion.identity);
bushCount += 1;
}
else
{
//code to run if something is intersecting it
RollPos();
}
}
}
void RollPos()
{
if (xPlus == true
&& xMinus == true
&& zPlus == true
&& zMinus == true)
{
int newRoll = Random.Range(1, 4);
if (newRoll == 1)
{
x += 10f;
}
else if (newRoll == 2)
{
x -= 10f;
}
else if (newRoll == 3)
{
z += 10f;
}
else if (newRoll == 4)
{
z -= 10f;
}
xPlus = false;
xMinus = false;
zPlus = false;
zMinus = false;
}
else
{
int roll = Random.Range(1, 4);
if (roll == 1)
{
if (xPlus == false)
{
x += 2f;
xPlus = true;
}
else
{
RollPos();
}
}
if (roll == 2)
{
if (xMinus == false)
{
x -= 2f;
xMinus = true;
}
else
{
RollPos();
}
}
if (roll == 3)
{
if (zPlus == false)
{
z += 2f;
zPlus = true;
}
else
{
RollPos();
}
}
if (roll == 4)
{
if (zMinus == false)
{
z -= 2f;
zMinus = true;
}
else
{
RollPos();
}
}
}
}
}
I tried putting SpawnBushes in Update to run while a bool is true then make it false when SpawnBushes is done, but that creates the first bush, then 99 other bushes in one random position next to it.
If someone can point me in the right direction or tell me I'm completely off-base I would appreciate it immensely!
Ron Beyer pointed out that I didn't have a large enough range in my Random.Range in RollPos(). Thanks again Ron!

PONG Collision Need assistance

I have to make pong for a school assignment. Everything was going pretty well
until I came to the collision part. Can somebody maybe help me?
I am doing it in visual studios c#, and I am a beginner, so I don't understand a lot. I have tried a lot of different solutions, but none of them seems to have worked out.
public override void GameStart()
{
}
public override void GameEnd()
{
}
public override void Update()
{
float DeltaTime = GAME_ENGINE.GetDeltaTime();
//Frame Rate Unlock
if (GAME_ENGINE.GetKeyDown(Key.V))
{
bool isLocked = GAME_ENGINE.GetVSync();
GAME_ENGINE.SetVSync(!isLocked);
}
//Player 1 Movement
if (GAME_ENGINE.GetKey(Key.W) && m_PlayerY1 != 0)
{
m_PlayerY1 -= 250 * DeltaTime;
}
if (GAME_ENGINE.GetKey(Key.S) && m_PlayerY1 != 300)
{
m_PlayerY1 += 250 * DeltaTime;
}
if (m_PlayerY1 < 0)
{
m_PlayerY1 = 0;
}
if (m_PlayerY1 > 350)
{
m_PlayerY1 = 350;
}
//Player 2
if (GAME_ENGINE.GetKey(Key.Up) && m_PlayerY2 != 0)
{
m_PlayerY2 -= 250 * DeltaTime;
}
if (GAME_ENGINE.GetKey(Key.Down) && m_PlayerY2 != 300)
{
m_PlayerY2 += 250 * DeltaTime;
}
if (m_PlayerY2 < 0)
{
m_PlayerY2 = 0;
}
if (m_PlayerY2 > 350)
{
m_PlayerY2 = 350;
}
//Ball Stuff
Random RnD = new Random();
m_XBallSpeed = RnD.Next(2, 3);
m_YBallSpeed = RnD.Next(2, 3);
m_XBall += m_XBallSpeed;
if (m_XBall < 0)
{
m_XBallSpeed = -m_XBallSpeed;
}
else if (m_XBall + m_BallWidth > GAME_ENGINE.GetScreenWidth())
{
m_XBallSpeed = -m_XBallSpeed;
}
m_YBall += m_YBallSpeed;
if (m_YBall < 0)
{
m_YBallSpeed = -m_YBallSpeed;
}
else if (m_YBall + m_BallHeight > GAME_ENGINE.GetScreenHeight())
{
m_YBallSpeed = -m_YBallSpeed;
}
if (m_XBall >= m_PlayerHeight1 && m_YBall >= m_PlayerHeight2)
{
m_XBallSpeed += 1;
m_YBallSpeed += 1;
m_XBallSpeed = -m_YBallSpeed;
}
if (m_YBall >= m_PlayerWidth1 && m_YBall >= m_PlayerWidth2)
{
m_XBallSpeed += 1;
m_YBallSpeed += 1;
m_XBallSpeed = -m_YBallSpeed;
}
}
public override void Paint()
{
//Player 1 and 2 and Ball
GAME_ENGINE.SetColor(255, 255, 255);
GAME_ENGINE.FillRectangle(m_PlayerX1, m_PlayerY1, m_PlayerWidth1, m_PlayerHeight1);
GAME_ENGINE.FillRectangle(m_PlayerX2, m_PlayerY2, m_PlayerWidth2, m_PlayerHeight2);
GAME_ENGINE.FillRoundedRectangle(m_XBall, m_YBall, m_BallWidth, m_BallHeight, 50, 50);
}

Enemy appear behind player chance 1 on 5

I've written a script that makes the enemy appear behind the player, with a 1 in 5 chance every 3 minutes, I've changed the 1 in 5 chance to a 1 in 1 chance for testing purposes, but I'am unsure if it works.
I know how to place the enemy behind the player but not with a chance of 1 on 5.
I've tried this with a random number between 1 and 5. And that if the random number equals 1 he has to spawn the enemy and else not.
This is the code:
using UnityEngine;
using System.Collections;
public class MainEnemy : MonoBehaviour
{
public GameObject Main;
public GameObject Holder;
public Transform player;
public Transform FPSController;
bool wantPosition;
bool appear;
float timer;
Vector3 temp;
// Use this for initialization
void Start()
{
wantPosition = true;
appear = false;
temp = new Vector3(0, 0, 0);
timer = 20;// 180;
}
// Update is called once per frame
void Update()
{
Appear();
}
Vector3 GetPosition()
{
Debug.Log("Hij doet het getposition");
float px = player.transform.position.x;
float pz = player.transform.position.z;
//
float angle2 = Mathf.Cos(Camera.main.transform.eulerAngles.y) + 180;
//
float distance = 20;
float distancex = Mathf.Cos(angle2 + 180) * distance;
float distancez = Mathf.Sin(angle2 + 180) * distance;
// Tell distanceen bij coordinaten op
temp = new Vector3(distancex, -3, distancez);
return temp;
}
void SetFalse()
{
if (timer < 1)
{
timer = 10;// 180; // na 3 minuten weer kijken of hij hem laat zien
}
Main.SetActive(false);
}
void Position()
{
if (wantPosition)
{
temp = GetPosition();
Holder.transform.position = player.position + temp;
Main.SetActive(true);
if (timer < 0)
{
timer = 10; // kort zichtbaar
}
wantPosition = false;
}
}
bool Appeared()
{
bool appear = false;
int rand = Random.Range(1, 1);
if (rand == 1)
{
appear = true;
}
else
{
appear = false;
}
return appear;
}
void Appear()
{
bool appear = false;
if (timer <= 0)
{
appear = Appeared();
}
else
{
timer -= Time.deltaTime;
if (timer < 10)
{
Debug.Log(timer);
}
}
if (appear == true)
{
Position();
}
else
{
SetFalse();
}
}
}
Firstly be aware that Random.Range returns a number that is greater than or equal to min, but less than (but not equal to) max. If the special case where min == max, then that value will be returned.
Secondly your Appeared function is a bit verbose. Assuming we set it back to a 1 in 5 chance, you'd have this:
bool Appeared()
{
bool appear = false;
int rand = Random.Range(1, 6);
if (rand == 1)
{
appear = true;
}
else
{
appear = false;
}
return appear;
}
Firstly let me point out that saying:
if(x)
y = true
else
y = false
Where x is a Boolean condition, is exactly the same as saying
y = x
So perhaps you'd change it to:
bool Appeared()
{
bool appear = false;
int rand = Random.Range(1, 6);
appear = rand == 1;
return appear;
}
Now look, why bother setting appear to false at the start? That value never gets used. Perhaps this:
bool Appeared()
{
int rand = Random.Range(1, 6);
bool appear = rand == 1;
return appear;
}
Hmm, now we're just assigning a variable and then returning it on the next line. OK, maybe this:
bool Appeared()
{
int rand = Random.Range(1, 6);
return rand == 1;
}
Right, yeah. This looks familiar. Now, again, we're almost just assigning a variable and then returning it on the next line. Do we really need that rand variable now? Probably not. How about this then:
bool Appeared()
{
return Random.Range(1, 6) == 1;
}
Much better.
An easy and performant way to get a 1/5 chance in Unity3D is
if(Random.value < 1f/5f)
//do something
Random.value is returning a float 0 <= value <= 1
**EDIT Updated for UnityEngine
Change your bool Appeared method to:
bool Appeared()
{
bool appear = false;
int rand = Random.Range(1,6)
if (rand == 1)
{
appear = true;
} // else not needed
return appear;
}

How to create time intervals between states in an FSM

I would like to create a timer interval between the execution of a state in an FSM.
What I have at the moment is pretty basic as I'm still quite new to programming. It'd be great if you could keep any possible solutions to around a basic level.
public override void Execute()
{
//Logic for Idle state
if (dirRight)
oFSM.transform.Translate(Vector2.right * speed * Time.deltaTime);
else
oFSM.transform.Translate(-Vector2.right * speed * Time.deltaTime);
if (oFSM.transform.position.x >= 2.0f)
dirRight = false;
else if (oFSM.transform.position.x <= -2.0f)
dirRight = true;
//play animation
//Transition out of Idle state
//SUBJECT TO CHANGE
float timer = 0f;
timer += Time.time;
if (timer >= 3f)
{
int rng = Random.Range(0, 5);
if (rng >= 0 && rng <= 1)
{
timer = 0;
oFSM.ChangeStateTo(FSM.States.AtkPatt1);
}
else if (rng >= 2 && rng <= 3)
{
timer = 0;
oFSM.ChangeStateTo(FSM.States.AtkPatt2);
}
else if (rng >= 4 && rng <= 5)
{
timer = 0;
oFSM.ChangeStateTo(FSM.States.AtkPatt3);
}
}
}
You need to use Coroutines, and use the method WaitForSeconds.
Then you can do something like this:
private float timeToWait = 3f;
private bool keepExecuting = false;
private Coroutine executeCR;
public void CallerMethod()
{
// If the Coroutine is != null, we will stop it.
if(executeCR != null)
{
StopCoroutine(executeCR);
}
// Start Coroutine execution:
executeCR = StartCoroutine( ExecuteCR() );
}
public void StoperMethod()
{
keepExecuting = false;
}
private IEnumerator ExecuteCR()
{
keepExecuting = true;
while (keepExecuting)
{
// do something
yield return new WaitForSeconds(timeToWait);
int rng = UnityEngine.Random.Range(0, 5);
if (rng >= 0 && rng <= 1)
{
oFSM.ChangeStateTo(FSM.States.AtkPatt1);
}
else if (rng >= 2 && rng <= 3)
{
oFSM.ChangeStateTo(FSM.States.AtkPatt2);
}
else if (rng >= 4 && rng <= 5)
{
oFSM.ChangeStateTo(FSM.States.AtkPatt3);
}
}
// All Coroutines should "return" (they use "yield") something
yield return null;
}

Removing the barrier after the collision? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm making a game (Breakout) and I have a question,
The question is how can I remove the barriers after they get hit by the ball?
Of course, the ball must be able to go through the track after that (like Breakout game in general)
the next question is that can I make the barriers in run time mode?
Thanks
private void timer1_Tick(object sender, EventArgs e)
{
ball.Top += step;
ball.Left += stepleft;
//board simulate collision
bool collisonX = ball.Location.X + ball.Width > board.Location.X && ball.Location.X < board.Location.X + board.Width;
bool collisonY = ball.Top + ball.Height == board.Location.Y || ball.Top + ball.Height - 1 == board.Location.Y;
//board2(button1) simulate collision
bool collisonX2 = ball.Location.X + ball.Width > board2.Location.X && ball.Location.X < board2.Location.X + board2.Width;
bool collisonY2 = ball.Top + ball.Height == board2.Location.Y || ball.Top + ball.Height - 1 == board2.Location.Y;
//Collision the ball with under buttons
bool collsionButtonY = ball.Top - ball.Height == board2.Location.Y || ball.Top - ball.Height == board2.Location.Y - 1;
//collision leftwall
bool leftWall = ball.Left == 0 || ball.Left == -1 || ball.Left == 1;
//collision rightwall
bool topWall = ball.Top == 0 || ball.Top == -1 || ball.Top == 1;
bool bottomWall = collisonX && collisonY;
bool toppWall = collisonX2 && collisonY2;
//collision
bool barrier = collisonX2 && collsionButtonY;
bool collisionLeft = ((ball.Location.Y + ball.Height >= board2.Location.Y) && (ball.Location.Y <= board2.Location.Y + board2.Height) && (ball.Location.X + ball.Width >= board2.Location.X) && (ball.Location.X <= board2.Location.X + board2.Height));
//rightwall
bool rightWall = ball.Left + ball.Width == this.ClientSize.Width || ball.Left + ball.Width == this.ClientSize.Width - 1;
// sidewall = collision rightwall or leftwall
bool sideWall = leftWall || rightWall;
//Check the ball hit the ground
bool check = ball.Top + ball.Height < this.ClientSize.Height;
//if topWall true,This means that the ball is hit to the topwall
if (topWall)
{
flagBottom = false;
flagTop = true;
if (stepleft > 0)
{
step = 2;
}
else if (stepleft < 0)
{
step = 2;
}
}
//if bottomWall true,This means that the ball is hit to the board
else if (bottomWall)
{
flagBottom = true;
flagTop = false;
if (stepleft > 0)
{
step = step * -1;
}
else if (stepleft < 0)
{
step = step * -1;
}
}
//if barrier true and flagbottom true,This means that the ball is hit to the board2(button1)
else if (barrier && flagBottom)
{
collisionLeft = false;
if (stepleft > 0)
{
step = step * -1;
}
else if (stepleft < 0)
{
step = step * -1;
}
}
//if toppWall true and flagTop true,This means that the ball is hit to The top button is hit
else if (toppWall && flagTop)
{
collisionLeft = false;
if (stepleft > 0)
{
step = step * -1;
}
else if (stepleft < 0)
{
step = step * -1;
}
}
else if (flagTop && collisionLeft)
{
barrier = false;
if (stepleft > 0)
{
stepleft = -2;
step = 2;
}
else if (stepleft < 0)
{
stepleft = 2;
step = 2;
}
}
else if (flagBottom && collisionLeft)
{
barrier = false;
if (stepleft > 0)
{
stepleft = -2;
step = -2;
}
else if (stepleft < 0)
{
stepleft = 2;
step = -2;
}
}
else if (sideWall)
{
//if leftwall true,This means that the ball is hit to the left side wall
if (leftWall)
{
if (flagTop)
{
stepleft = 2;
}
else if (flagBottom)
{
stepleft = 2;
}
}
//if rightWall true,This means that the ball is hit to the left side wall
else if (rightWall)
{
if (flagTop)
{
stepleft = -2;
}
else if (flagBottom)
{
stepleft = -2;
}
}
}
//check if ckeck==ture,this mean the ball is hit the ground
else if (!check)
{
timer1.Enabled = false;
}
}
private void board_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
MouseDownLocation = e.Location;
}
}
private void board_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
board.Left = e.X + board.Left - MouseDownLocation.X;
}
You need to learn use lists and proper use of classes.
For example :
public class GameObject{
public GameObject(int x, int y, int width, int height){
this.X = x;
this.Y = y;
this.Width = width;
this.Height = height;
}
int X;
int Y;
int Width;
int Height;
public bool DetectCollision(bool Ball){
//code to detect collision
}
}
Then in your main class, you can do thing like that.
List<GameObject> gameObjects = new List<GameObject>();
gameObjects.add(new GameObject(10,10,50,50));
gameObjects.add(new GameObject(20,10,20,50));
gameObjects.add(new GameObject(30,10,50,70));
gameObjects.add(new GameObject(40,10,90,50));
And to detect the collisions :
foreach (GameObject gameObject in gameObjects){
if (gameObject.DetectCollision(ball)){
//do something
}
}

Categories