더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PenguinArea : MonoBehaviour
{
public GameObject penguinAgent;
public GameObject penguinBaby;
public Fish fishPrefab;
public int FishRemaining
{
get { return fishList.Count; }
}
private List<GameObject> fishList;
void Start()
{
ResetArea();
}
public void ResetArea()
{
RemoveAllFish();
PlacePenguin();
PlaceBaby();
SpawnFish(4, .5f);
}
void RemoveAllFish()
{
if (fishList != null)
{
for (int i = 0; i < fishList.Count; i++)
{
if (fishList[i] != null)
{
Destroy(fishList[i]);
}
}
}
fishList = new List<GameObject>();
}
void PlacePenguin()
{
Rigidbody rigidbody = penguinAgent.GetComponent<Rigidbody>();
rigidbody.velocity = Vector3.zero;
rigidbody.angularVelocity = Vector3.zero;
penguinAgent.transform.position = ChooseRandomPosition(transform.position, 0f, 360f, 0f, 9f) + Vector3.up * .5f;
penguinAgent.transform.rotation = Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f);
}
public static Vector3 ChooseRandomPosition(Vector3 center, float minAngle, float maxAngle, float minRadius, float maxRadius)
{
float radius = minRadius;
float angle = minAngle;
if (maxRadius > minRadius)
{
// Pick a random radius
radius = UnityEngine.Random.Range(minRadius, maxRadius);
}
if (maxAngle > minAngle)
{
// Pick a random angle
angle = UnityEngine.Random.Range(minAngle, maxAngle);
}
// Center position + forward vector rotated around the Y axis by "angle" degrees, multiplies by "radius"
var quaternion = Quaternion.Euler(0f, angle, 0f);
return center + quaternion * Vector3.forward * radius;
//0, 0, 1
}
void PlaceBaby()
{
Rigidbody rigidbody = penguinBaby.GetComponent<Rigidbody>();
rigidbody.velocity = Vector3.zero;
rigidbody.angularVelocity = Vector3.zero;
penguinBaby.transform.position = ChooseRandomPosition(transform.position, -45f, 45f, 4f, 9f) + Vector3.up * .5f;
penguinBaby.transform.rotation = Quaternion.Euler(0f, 180f, 0f);
}
void SpawnFish(int count, float fishSpeed)
{
for (int i = 0; i < count; i++)
{
// Spawn and place the fish
GameObject fishObject = Instantiate<GameObject>(fishPrefab.gameObject);
fishObject.transform.position = ChooseRandomPosition(transform.position, 100f, 260f, 2f, 13f) + Vector3.up * .5f;
fishObject.transform.rotation = Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f);
// Set the fish's parent to this area's transform
fishObject.transform.SetParent(transform);
// Keep track of the fish
fishList.Add(fishObject);
// Set the fish speed
fishObject.GetComponent<Fish>().fishSpeed = fishSpeed;
}
}
public void RemoveSpecificFish(GameObject fishObject)
{
fishList.Remove(fishObject);
Destroy(fishObject);
}
}
더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fish : MonoBehaviour
{
public float fishSpeed;
private float randomizedSpeed = 0f;
private float nextActionTime = -1f;
private Vector3 targetPosition;
private void FixedUpdate()
{
if (fishSpeed > 0f)
{
Swim();
}
}
private void Swim()
{
// If it's time for the next action, pick a new speed and destination
// Else, swim toward the destination
if (Time.fixedTime >= nextActionTime)
{
// Randomize the speed
randomizedSpeed = fishSpeed * UnityEngine.Random.Range(.5f, 1.5f);
// Pick a random target
targetPosition = PenguinArea.ChooseRandomPosition(transform.parent.position, 100f, 260f, 2f, 13f);
// Rotate toward the target
transform.rotation = Quaternion.LookRotation(targetPosition - transform.position, Vector3.up);
// Calculate the time to get there
float timeToGetThere = Vector3.Distance(transform.position, targetPosition) / randomizedSpeed;
nextActionTime = Time.fixedTime + timeToGetThere;
}
else
{
// Make sure that the fish does not swim past the target
Vector3 moveVector = randomizedSpeed * transform.forward * Time.fixedDeltaTime;
if (moveVector.magnitude <= Vector3.Distance(transform.position, targetPosition))
{
transform.position += moveVector;
}
else
{
transform.position = targetPosition;
nextActionTime = Time.fixedTime;
}
}
}
}
더보기
using System.Collections;
using System.Collections.Generic;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;
using UnityEngine;
public class PenguinAgent : Agent
{
public float moveSpeed = 5f;
public float turnSpeed = 180f;
private PenguinArea penguinArea;
new private Rigidbody rigidbody;
//new : 객체생성 또는 기존에 있는 필드를 재정의할때 사용됨
private GameObject baby;
private bool isFull; // If true, penguin has a full stomach
public override void Initialize()
{
base.Initialize();
penguinArea = GetComponentInParent<PenguinArea>();
baby = penguinArea.penguinBaby;
rigidbody = GetComponent<Rigidbody>();
}
public override void OnEpisodeBegin()
{
isFull = false;
penguinArea.ResetArea();
}
public override void CollectObservations(VectorSensor sensor)
{
// Whether the penguin has eaten a fish (1 float = 1 value)
sensor.AddObservation(isFull);
// Distance to the baby (1 float = 1 value)
sensor.AddObservation(Vector3.Distance(baby.transform.position, transform.position));
// Direction to baby (1 Vector3 = 3 values)
sensor.AddObservation((baby.transform.position - transform.position).normalized);
// Direction penguin is facing (1 Vector3 = 3 values)
sensor.AddObservation(transform.forward);
// 1 + 1 + 3 + 3 = 8 total values
}
public override void OnActionReceived(ActionBuffers actions)
{
// Convert the first action to forward movement
float forwardAmount = actions.DiscreteActions[0];
// Convert the second action to turning left or right
float turnAmount = 0f;
if (actions.DiscreteActions[1] == 1f)
{
turnAmount = -1f;
}
else if (actions.DiscreteActions[1] == 2f)
{
turnAmount = 1f;
}
// Apply movement
rigidbody.MovePosition(transform.position + transform.forward * forwardAmount * moveSpeed * Time.fixedDeltaTime);
transform.Rotate(transform.up * turnAmount * turnSpeed * Time.fixedDeltaTime);
// Apply a tiny negative reward every step to encourage action
if (MaxStep > 0) AddReward(-1f / MaxStep);
}
public override void Heuristic(in ActionBuffers actionsOut)
{
int forwardAction = 0;
int turnAction = 0;
if (Input.GetKey(KeyCode.W))
{
// move forward
forwardAction = 1;
}
if (Input.GetKey(KeyCode.A))
{
// turn left
turnAction = 1;
}
else if (Input.GetKey(KeyCode.D))
{
// turn right
turnAction = 2;
}
// Put the actions into the array
actionsOut.DiscreteActions.Array[0] = forwardAction;
actionsOut.DiscreteActions.Array[1] = turnAction;
}
private void OnCollisionEnter(Collision collision)
{
if (collision.transform.CompareTag("fish"))
{
// Try to eat the fish
EatFish(collision.gameObject);
}
else if (collision.transform.CompareTag("baby"))
{
// Try to feed the baby
RegurgitateFish();
}
}
private void EatFish(GameObject fishObject)
{
if (isFull) return; // Can't eat another fish while full
isFull = true;
penguinArea.RemoveSpecificFish(fishObject);
AddReward(1f);
}
private void RegurgitateFish()
{
if (!isFull) return; // Nothing to regurgitate
isFull = false;
AddReward(1f);
if (penguinArea.FishRemaining <= 0)
{
EndEpisode();
}
}
}
더보기
behaviors:
Penguin:
trainer_type: ppo
hyperparameters:
batch_size: 128
buffer_size: 2048
learning_rate: 0.0003
beta: 0.01
epsilon: 0.2
lambd: 0.95
num_epoch: 3
learning_rate_schedule: linear
network_settings:
normalize: false
hidden_units: 256
num_layers: 2
vis_encode_type: simple
reward_signals:
extrinsic:
gamma: 0.99
strength: 1.0
keep_checkpoints: 5
max_steps: 1000000
time_horizon: 128
summary_freq: 5000
threaded: true
'유니티 > 수업 내용' 카테고리의 다른 글
게임인공지능 MLAgent RollerBall 복습 (0) | 2022.01.18 |
---|---|
게임인공지능 Ml-Agents - RollerBall 환경 바꾸기 (벽 세우기) (0) | 2022.01.18 |
게임인공지능 Ml-Agents - rollerball_config (0) | 2022.01.18 |
[UGUI] Scrollview (0) | 2022.01.18 |
[UGUI] Joystick (0) | 2022.01.18 |