Unity ML-Agents 2.0 (Flappy Bird 훈련)

Version : Unity 2021.3.5f1

Unity ML-Agents 2.0 을 이용한 Flappy Bird 훈련

ML-Agents 를 이용하여 Flappy Bird 를 교육시켰다.

Flappy Bird는 중력의 영향을 받아 아래 계속 떨어지고 점프를 통하여 위쪽으로 가속도를 줄 수 있다.

파이프는 배경과 같은 속도로 랜덤하게 나오도록 설계 ( 파이프[위/아래] 사이의 거리는 레벨에 따라 다르다. )

점수는 파이프와 파이프 사이에 오프젝트를 만들어 부딛히면 점수를 주고 바닥에 닿거나 파이프에 부딛히면 점수를 깍고 에피소드를 다시 시작한다.

관측하는 값은 자신의 Y 포지션과 가속도 (음 로컬이 문제인가….)

파이프와 파이프 사이의 거리는 커리큘럼 파라미터에 따라 달라진다. (60은 default)

저음 레벨이 낮을 경우에는 학습을 하고 있다고 느낄 정도로 정말 잘하지만

점점 가면 갈 수록 학습의 능률이 떨어지고 포기하는 경우의 수가 많아진다.

아마 인공지능의 컨트롤로 극복할 수 없는 환경이 되어서 포기하는 듯 하다. (내가 플레이 해도 못 깬다 ㅋㅋ )

Heuristic(휴리스틱-직접 컨트롤, 환경을 테스트 해볼 수 있다.)은 딜레이가 좀 있어서 미세한 컨트롤은 무리…

ML-Agents 를 사용하는 방법이 어렵다기 보다는 환경을 구성하는 부분에서 가장 많은 시간을 잡아먹었다. (교육에는 환경이 중요하다@!)

이번에 ML-Agent의 기본적인 사용법을 익힌 것이 가장 큰 수확

커리큘럼 파라미터 (Curriculum Parameter)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
behaviors:
FlyBird:
trainer_type: ppo
hyperparameters:
batch_size: 256
buffer_size: 4096
learning_rate: 0.0003
beta: 0.005
epsilon: 0.2
lambd: 0.95
num_epoch: 3
learning_rate_schedule: constant
network_settings:
normalize: false
hidden_units: 256
num_layers: 2
vis_encode_type: simple
reward_signals:
extrinsic:
gamma: 0.95
strength: 1.0
keep_checkpoints: 5
max_steps: 9000000
time_horizon: 128
summary_freq: 20000
environment_parameters:
LevelUp:
curriculum:
- name: Lesson0
completion_criteria:
measure: progress
behavior: FlyBird
signal_smoothing: true
min_lesson_length: 100
threshold: 0.10
value: 100
- name: Lesson1
completion_criteria:
measure: progress
behavior: FlyBird
signal_smoothing: true
min_lesson_length: 100
threshold: 0.15
value: 95
- name: Lesson2
completion_criteria:
measure: progress
behavior: FlyBird
signal_smoothing: true
min_lesson_length: 100
threshold: 0.20
value: 90
- name: Lesson3
completion_criteria:
measure: progress
behavior: FlyBird
signal_smoothing: true
min_lesson_length: 100
threshold: 0.25
value: 85
- name: Lesson4
completion_criteria:
measure: progress
behavior: FlyBird
signal_smoothing: true
min_lesson_length: 100
threshold: 0.30
value: 80
- name: Lesson5
completion_criteria:
measure: progress
behavior: FlyBird
signal_smoothing: true
min_lesson_length: 100
threshold: 0.35
value: 75
- name: Lesson6
completion_criteria:
measure: progress
behavior: FlyBird
signal_smoothing: true
min_lesson_length: 100
threshold: 0.4
value: 70
- name: Lesson7
completion_criteria:
measure: progress
behavior: FlyBird
signal_smoothing: true
min_lesson_length: 100
threshold: 0.45
value: 65
- name: Lesson9
value: 60
behaviors: FlyBird: trainer_type: ppo hyperparameters: batch_size: 256 buffer_size: 4096 learning_rate: 0.0003 beta: 0.005 epsilon: 0.2 lambd: 0.95 num_epoch: 3 learning_rate_schedule: constant network_settings: normalize: false hidden_units: 256 num_layers: 2 vis_encode_type: simple reward_signals: extrinsic: gamma: 0.95 strength: 1.0 keep_checkpoints: 5 max_steps: 9000000 time_horizon: 128 summary_freq: 20000 environment_parameters: LevelUp: curriculum: - name: Lesson0 completion_criteria: measure: progress behavior: FlyBird signal_smoothing: true min_lesson_length: 100 threshold: 0.10 value: 100 - name: Lesson1 completion_criteria: measure: progress behavior: FlyBird signal_smoothing: true min_lesson_length: 100 threshold: 0.15 value: 95 - name: Lesson2 completion_criteria: measure: progress behavior: FlyBird signal_smoothing: true min_lesson_length: 100 threshold: 0.20 value: 90 - name: Lesson3 completion_criteria: measure: progress behavior: FlyBird signal_smoothing: true min_lesson_length: 100 threshold: 0.25 value: 85 - name: Lesson4 completion_criteria: measure: progress behavior: FlyBird signal_smoothing: true min_lesson_length: 100 threshold: 0.30 value: 80 - name: Lesson5 completion_criteria: measure: progress behavior: FlyBird signal_smoothing: true min_lesson_length: 100 threshold: 0.35 value: 75 - name: Lesson6 completion_criteria: measure: progress behavior: FlyBird signal_smoothing: true min_lesson_length: 100 threshold: 0.4 value: 70 - name: Lesson7 completion_criteria: measure: progress behavior: FlyBird signal_smoothing: true min_lesson_length: 100 threshold: 0.45 value: 65 - name: Lesson9 value: 60
behaviors:
  FlyBird:
    trainer_type: ppo
    hyperparameters:
      batch_size: 256
      buffer_size: 4096
      learning_rate: 0.0003
      beta: 0.005
      epsilon: 0.2
      lambd: 0.95
      num_epoch: 3
      learning_rate_schedule: constant
    network_settings:
      normalize: false
      hidden_units: 256
      num_layers: 2
      vis_encode_type: simple
    reward_signals:
      extrinsic:
        gamma: 0.95
        strength: 1.0
    keep_checkpoints: 5
    max_steps: 9000000
    time_horizon: 128
    summary_freq: 20000
environment_parameters:
  LevelUp:
    curriculum:
      - name: Lesson0
        completion_criteria:
          measure: progress
          behavior: FlyBird
          signal_smoothing: true
          min_lesson_length: 100
          threshold: 0.10
        value: 100
      - name: Lesson1
        completion_criteria:
          measure: progress
          behavior: FlyBird
          signal_smoothing: true
          min_lesson_length: 100
          threshold: 0.15
        value: 95
      - name: Lesson2
        completion_criteria:
          measure: progress
          behavior: FlyBird
          signal_smoothing: true
          min_lesson_length: 100
          threshold: 0.20
        value: 90
      - name: Lesson3
        completion_criteria:
          measure: progress
          behavior: FlyBird
          signal_smoothing: true
          min_lesson_length: 100
          threshold: 0.25
        value: 85
      - name: Lesson4
        completion_criteria:
          measure: progress
          behavior: FlyBird
          signal_smoothing: true
          min_lesson_length: 100
          threshold: 0.30
        value: 80
      - name: Lesson5
        completion_criteria:
          measure: progress
          behavior: FlyBird
          signal_smoothing: true
          min_lesson_length: 100
          threshold: 0.35
        value: 75
      - name: Lesson6
        completion_criteria:
          measure: progress
          behavior: FlyBird
          signal_smoothing: true
          min_lesson_length: 100
          threshold: 0.4
        value: 70
      - name: Lesson7
        completion_criteria:
          measure: progress
          behavior: FlyBird
          signal_smoothing: true
          min_lesson_length: 100
          threshold: 0.45
        value: 65
      - name: Lesson9
        value: 60

BirdAgent.cs

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Actuators;
using UnityEngine.Events;
public class BirdAgent : Agent
{
public GameMain GameMain;
EnvironmentParameters m_ResetParams;
public Rigidbody2D rBody;
public float jumpForce = 25f;
private bool Diecheck = false;
public UnityAction onDIe;
public override void Initialize()
{
m_ResetParams = Academy.Instance.EnvironmentParameters;
this.rBody = this.gameObject.GetComponent<Rigidbody2D>();
ConfigureAgent();
}
public override void OnEpisodeBegin()
{
this.Diecheck = false;
this.transform.localPosition = new Vector3(-40f, 15f, 0f);
}
public override void CollectObservations(VectorSensor sensor)
{
sensor.AddObservation(this.gameObject.transform.localPosition.y); // 1
//sensor.AddObservation(StepCount/MaxStep); // 1
sensor.AddObservation(this.rBody.velocity.y); // 1
}
public override void OnActionReceived(ActionBuffers actions)
{
this.AddReward(1 / (float)this.MaxStep);
var discreteActions = actions.DiscreteActions;
if (discreteActions[0] == 1)
{
this.rBody.velocity = Vector2.up * this.jumpForce;
}
}
public override void Heuristic(in ActionBuffers actionsOut)
{
var discreteActions = actionsOut.DiscreteActions;
if (Input.GetKey(KeyCode.Space))
{
discreteActions[0] = 1;
}
else
{
discreteActions[0] = 0;
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Target")
{
Debug.Log("Target");
this.AddReward(0.02f);
Destroy(collision.gameObject);
}
else
{
if (!Diecheck)
{
this.Diecheck = true;
AddReward(-0.3f);
this.onDIe();
EndEpisode();
}
}
}
void ConfigureAgent()
{
this.GameMain.Level =(int)m_ResetParams.GetWithDefault("LevelUp", 60);
}
private void FixedUpdate()
{
this.ConfigureAgent();
}
}
using System.Collections; using System.Collections.Generic; using UnityEngine; using Unity.MLAgents; using Unity.MLAgents.Sensors; using Unity.MLAgents.Actuators; using UnityEngine.Events; public class BirdAgent : Agent { public GameMain GameMain; EnvironmentParameters m_ResetParams; public Rigidbody2D rBody; public float jumpForce = 25f; private bool Diecheck = false; public UnityAction onDIe; public override void Initialize() { m_ResetParams = Academy.Instance.EnvironmentParameters; this.rBody = this.gameObject.GetComponent<Rigidbody2D>(); ConfigureAgent(); } public override void OnEpisodeBegin() { this.Diecheck = false; this.transform.localPosition = new Vector3(-40f, 15f, 0f); } public override void CollectObservations(VectorSensor sensor) { sensor.AddObservation(this.gameObject.transform.localPosition.y); // 1 //sensor.AddObservation(StepCount/MaxStep); // 1 sensor.AddObservation(this.rBody.velocity.y); // 1 } public override void OnActionReceived(ActionBuffers actions) { this.AddReward(1 / (float)this.MaxStep); var discreteActions = actions.DiscreteActions; if (discreteActions[0] == 1) { this.rBody.velocity = Vector2.up * this.jumpForce; } } public override void Heuristic(in ActionBuffers actionsOut) { var discreteActions = actionsOut.DiscreteActions; if (Input.GetKey(KeyCode.Space)) { discreteActions[0] = 1; } else { discreteActions[0] = 0; } } private void OnCollisionEnter2D(Collision2D collision) { if (collision.gameObject.tag == "Target") { Debug.Log("Target"); this.AddReward(0.02f); Destroy(collision.gameObject); } else { if (!Diecheck) { this.Diecheck = true; AddReward(-0.3f); this.onDIe(); EndEpisode(); } } } void ConfigureAgent() { this.GameMain.Level =(int)m_ResetParams.GetWithDefault("LevelUp", 60); } private void FixedUpdate() { this.ConfigureAgent(); } }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Actuators;
using UnityEngine.Events;

public class BirdAgent : Agent
{
    public GameMain GameMain;
    EnvironmentParameters m_ResetParams;


    public Rigidbody2D rBody; 
    public float jumpForce = 25f;
    private bool Diecheck = false;

    public UnityAction onDIe;

    public override void Initialize()
    {
        m_ResetParams = Academy.Instance.EnvironmentParameters;
        this.rBody = this.gameObject.GetComponent<Rigidbody2D>();
        ConfigureAgent();
    }

    public override void OnEpisodeBegin()
    {
        this.Diecheck = false;
        this.transform.localPosition = new Vector3(-40f, 15f, 0f);

    }

    public override void CollectObservations(VectorSensor sensor)
    {
        sensor.AddObservation(this.gameObject.transform.localPosition.y); // 1
        //sensor.AddObservation(StepCount/MaxStep); // 1
        sensor.AddObservation(this.rBody.velocity.y); // 1
    }

    public override void OnActionReceived(ActionBuffers actions)
    {
        this.AddReward(1 / (float)this.MaxStep);

        var discreteActions = actions.DiscreteActions;

        if (discreteActions[0] == 1)
        {
            this.rBody.velocity = Vector2.up * this.jumpForce;
        }     
    }

    public override void Heuristic(in ActionBuffers actionsOut)
    {
        var discreteActions = actionsOut.DiscreteActions;

        if (Input.GetKey(KeyCode.Space))
        {
            discreteActions[0] = 1;

        }
        else
        {
            discreteActions[0] = 0;
        }
    }



    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.tag == "Target")
        {
            Debug.Log("Target");
            this.AddReward(0.02f);
            Destroy(collision.gameObject);
        }
        else
        {
            if (!Diecheck)
            {
                this.Diecheck = true;
                AddReward(-0.3f);
                this.onDIe();
                EndEpisode();
            }
        }
    }


    void ConfigureAgent()
    {
       this.GameMain.Level =(int)m_ResetParams.GetWithDefault("LevelUp", 60);
    }

    private void FixedUpdate()
    {
        this.ConfigureAgent();
    }


}

GameMain.cs

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameMain : MonoBehaviour
{
public GameObject env;
public GameObject pipePrefabs;
private Pipe pipe;
public BirdAgent birdAgent;
public GameObject GroundPrefabs;
private Ground ground;
private List<GameObject> pipesList = new List<GameObject>();
private List<GameObject> GroundList = new List<GameObject>();
public GameObject backGround;
private SpriteRenderer backGroundRender;
public int DieCount = 0;
public float pipe_groundSpeed = 40f;
public int Level = 80;
public float pipeInitTIme = 1.5f;
private void Awake()
{
Application.runInBackground = true;
StartGameInit();
this.backGroundRender = this.backGround.GetComponent<SpriteRenderer>();
}
void Start()
{
StartCoroutine(CreatePipeRoutine());
this.birdAgent.onDIe = (() => {
this.DieCount++;
Debug.Log(this.DieCount);
this.birdAgent.OnEpisodeBegin();
// Destroy(birdGO);
this.StartGameInit();
StartCoroutine(BackGroundCoroutine());
});
}
public void StartGameInit()
{
foreach (var item in this.pipesList)
{
if (item != null)
{
Destroy(item.gameObject);
}
}
foreach (var item in this.GroundList)
{
if (item != null)
{
Destroy(item.gameObject);
}
}
this.pipesList = new List<GameObject>();
this.GroundList = new List<GameObject>();
var groundGO = Instantiate<GameObject>(this.GroundPrefabs);
groundGO.transform.SetParent(this.env.transform);
groundGO.transform.localPosition = new Vector3(100f, 10f, -1f);
this.ground = groundGO.GetComponent<Ground>();
this.ground.ChangeGroundSpeed(this.pipe_groundSpeed); // 땅 속도 변경
this.GroundList.Add(groundGO);
groundGO = Instantiate<GameObject>(this.GroundPrefabs);
groundGO.transform.SetParent(this.env.transform);
groundGO.transform.localPosition = new Vector3(312f, 10f, -1f);
this.ground = groundGO.GetComponent<Ground>();
this.ground.ChangeGroundSpeed(this.pipe_groundSpeed); // 땅 속도 변경
this.GroundList.Add(groundGO);
groundGO = Instantiate<GameObject>(this.GroundPrefabs);
groundGO.transform.SetParent(this.env.transform);
groundGO.transform.localPosition = new Vector3(150f, 10f, -1f);
this.ground = groundGO.GetComponent<Ground>();
this.ground.ChangeGroundSpeed(this.pipe_groundSpeed); // 땅 속도 변경
this.GroundList.Add(groundGO);
}
private IEnumerator CreatePipeRoutine()
{
while (true)
{
int num = 150 - this.Level;
int randfirst = Random.Range(3, num);
int randsecond = num - randfirst;
var topGO = Instantiate<GameObject>(this.pipePrefabs);
topGO.transform.SetParent(this.env.transform);
this.pipe = topGO.GetComponent<Pipe>();
this.pipe.SettingPipe(Pipe.eDirType.UP, randfirst);
this.pipe.removePipe = ((pipe) => {
pipesList.Remove(pipe); } );
this.pipe.ChangePipeSpeed(this.pipe_groundSpeed);
this.pipesList.Add(topGO);
topGO.transform.localPosition = new Vector3(71f, -22f, -0.5997626f);
topGO = Instantiate<GameObject>(this.pipePrefabs);
topGO.transform.SetParent(this.env.transform);
this.pipe = topGO.GetComponent<Pipe>();
this.pipe.SettingPipe(Pipe.eDirType.Down, randsecond);
this.pipe.removePipe = ((pipe) => {
pipesList.Remove(pipe);
});
topGO.transform.localPosition = new Vector3(71f, 31f, -0.5997626f);
this.pipe.ChangePipeSpeed(this.pipe_groundSpeed);
this.pipesList.Add(topGO);
yield return new WaitForSeconds(this.pipeInitTIme);
}
}
private IEnumerator BackGroundCoroutine()
{
this.backGroundRender.color = new Color(255f, 0, 0f);
yield return new WaitForSeconds(0.3f);
this.backGroundRender.color = new Color(255f, 255f, 255f);
}
}
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameMain : MonoBehaviour { public GameObject env; public GameObject pipePrefabs; private Pipe pipe; public BirdAgent birdAgent; public GameObject GroundPrefabs; private Ground ground; private List<GameObject> pipesList = new List<GameObject>(); private List<GameObject> GroundList = new List<GameObject>(); public GameObject backGround; private SpriteRenderer backGroundRender; public int DieCount = 0; public float pipe_groundSpeed = 40f; public int Level = 80; public float pipeInitTIme = 1.5f; private void Awake() { Application.runInBackground = true; StartGameInit(); this.backGroundRender = this.backGround.GetComponent<SpriteRenderer>(); } void Start() { StartCoroutine(CreatePipeRoutine()); this.birdAgent.onDIe = (() => { this.DieCount++; Debug.Log(this.DieCount); this.birdAgent.OnEpisodeBegin(); // Destroy(birdGO); this.StartGameInit(); StartCoroutine(BackGroundCoroutine()); }); } public void StartGameInit() { foreach (var item in this.pipesList) { if (item != null) { Destroy(item.gameObject); } } foreach (var item in this.GroundList) { if (item != null) { Destroy(item.gameObject); } } this.pipesList = new List<GameObject>(); this.GroundList = new List<GameObject>(); var groundGO = Instantiate<GameObject>(this.GroundPrefabs); groundGO.transform.SetParent(this.env.transform); groundGO.transform.localPosition = new Vector3(100f, 10f, -1f); this.ground = groundGO.GetComponent<Ground>(); this.ground.ChangeGroundSpeed(this.pipe_groundSpeed); // 땅 속도 변경 this.GroundList.Add(groundGO); groundGO = Instantiate<GameObject>(this.GroundPrefabs); groundGO.transform.SetParent(this.env.transform); groundGO.transform.localPosition = new Vector3(312f, 10f, -1f); this.ground = groundGO.GetComponent<Ground>(); this.ground.ChangeGroundSpeed(this.pipe_groundSpeed); // 땅 속도 변경 this.GroundList.Add(groundGO); groundGO = Instantiate<GameObject>(this.GroundPrefabs); groundGO.transform.SetParent(this.env.transform); groundGO.transform.localPosition = new Vector3(150f, 10f, -1f); this.ground = groundGO.GetComponent<Ground>(); this.ground.ChangeGroundSpeed(this.pipe_groundSpeed); // 땅 속도 변경 this.GroundList.Add(groundGO); } private IEnumerator CreatePipeRoutine() { while (true) { int num = 150 - this.Level; int randfirst = Random.Range(3, num); int randsecond = num - randfirst; var topGO = Instantiate<GameObject>(this.pipePrefabs); topGO.transform.SetParent(this.env.transform); this.pipe = topGO.GetComponent<Pipe>(); this.pipe.SettingPipe(Pipe.eDirType.UP, randfirst); this.pipe.removePipe = ((pipe) => { pipesList.Remove(pipe); } ); this.pipe.ChangePipeSpeed(this.pipe_groundSpeed); this.pipesList.Add(topGO); topGO.transform.localPosition = new Vector3(71f, -22f, -0.5997626f); topGO = Instantiate<GameObject>(this.pipePrefabs); topGO.transform.SetParent(this.env.transform); this.pipe = topGO.GetComponent<Pipe>(); this.pipe.SettingPipe(Pipe.eDirType.Down, randsecond); this.pipe.removePipe = ((pipe) => { pipesList.Remove(pipe); }); topGO.transform.localPosition = new Vector3(71f, 31f, -0.5997626f); this.pipe.ChangePipeSpeed(this.pipe_groundSpeed); this.pipesList.Add(topGO); yield return new WaitForSeconds(this.pipeInitTIme); } } private IEnumerator BackGroundCoroutine() { this.backGroundRender.color = new Color(255f, 0, 0f); yield return new WaitForSeconds(0.3f); this.backGroundRender.color = new Color(255f, 255f, 255f); } }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class GameMain : MonoBehaviour
{
    public GameObject env; 

    public GameObject pipePrefabs;
    private Pipe pipe;

    public BirdAgent birdAgent;


    public GameObject GroundPrefabs;
    private Ground ground;

    private List<GameObject> pipesList = new List<GameObject>();
    private List<GameObject> GroundList = new List<GameObject>();

    public GameObject backGround;
    private SpriteRenderer backGroundRender;
    public int DieCount = 0;


    public float pipe_groundSpeed = 40f;
    public int Level = 80;
    public float pipeInitTIme = 1.5f;



    private void Awake()
    {
        Application.runInBackground = true;
        StartGameInit();
        this.backGroundRender = this.backGround.GetComponent<SpriteRenderer>();
    }

    void Start()
    {
        StartCoroutine(CreatePipeRoutine());

        this.birdAgent.onDIe = (() => {
            this.DieCount++;
            Debug.Log(this.DieCount);
            this.birdAgent.OnEpisodeBegin();
            // Destroy(birdGO);
            this.StartGameInit();

            StartCoroutine(BackGroundCoroutine());

        });
    }

    public void StartGameInit()
    {
        foreach (var item in this.pipesList)
        {
            if (item != null)
            {
                Destroy(item.gameObject);
            }
        }

        foreach (var item in this.GroundList)
        {
            if (item != null)
            {
                Destroy(item.gameObject);
            }
        }

        this.pipesList = new List<GameObject>();
        this.GroundList = new List<GameObject>();
        
        var groundGO = Instantiate<GameObject>(this.GroundPrefabs);
        groundGO.transform.SetParent(this.env.transform);
        groundGO.transform.localPosition = new Vector3(100f, 10f, -1f);
        this.ground = groundGO.GetComponent<Ground>();
        this.ground.ChangeGroundSpeed(this.pipe_groundSpeed); // 땅 속도 변경
        this.GroundList.Add(groundGO);

        groundGO = Instantiate<GameObject>(this.GroundPrefabs);
        groundGO.transform.SetParent(this.env.transform);

        groundGO.transform.localPosition = new Vector3(312f, 10f, -1f);
        this.ground = groundGO.GetComponent<Ground>();
        this.ground.ChangeGroundSpeed(this.pipe_groundSpeed); // 땅 속도 변경
        this.GroundList.Add(groundGO);
        groundGO = Instantiate<GameObject>(this.GroundPrefabs);
        groundGO.transform.SetParent(this.env.transform);

        groundGO.transform.localPosition = new Vector3(150f, 10f, -1f);
        this.ground = groundGO.GetComponent<Ground>();
        this.ground.ChangeGroundSpeed(this.pipe_groundSpeed); // 땅 속도 변경
        this.GroundList.Add(groundGO);



    }

    private IEnumerator CreatePipeRoutine()
    {

        while (true)
        {
            int num = 150 - this.Level;

            int randfirst = Random.Range(3, num);


            int randsecond = num - randfirst;

            var topGO = Instantiate<GameObject>(this.pipePrefabs);
            topGO.transform.SetParent(this.env.transform);
            this.pipe = topGO.GetComponent<Pipe>();
            this.pipe.SettingPipe(Pipe.eDirType.UP, randfirst);
            this.pipe.removePipe = ((pipe) => {
                pipesList.Remove(pipe); } );
            this.pipe.ChangePipeSpeed(this.pipe_groundSpeed);
            this.pipesList.Add(topGO);
            topGO.transform.localPosition = new Vector3(71f, -22f, -0.5997626f);
            

            topGO = Instantiate<GameObject>(this.pipePrefabs);
            topGO.transform.SetParent(this.env.transform);
            this.pipe = topGO.GetComponent<Pipe>();
            this.pipe.SettingPipe(Pipe.eDirType.Down, randsecond);
            this.pipe.removePipe = ((pipe) => {
                pipesList.Remove(pipe);
            });
            topGO.transform.localPosition = new Vector3(71f, 31f, -0.5997626f);
            this.pipe.ChangePipeSpeed(this.pipe_groundSpeed);
            this.pipesList.Add(topGO);
            yield return new WaitForSeconds(this.pipeInitTIme);

        }
    }

    private IEnumerator BackGroundCoroutine()
    {
        this.backGroundRender.color = new Color(255f, 0, 0f);

        yield return new WaitForSeconds(0.3f);

        this.backGroundRender.color = new Color(255f, 255f, 255f);
    }

}

Pipe.cs

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using UnityEngine;
using UnityEngine.Events;
public class Pipe : MonoBehaviour
{
public enum eDirType { UP = 1, Down = -1 };
public eDirType dirType = eDirType.UP;
public int[] arr = { 10, 20, 30, 40, 50, 60, 70, 80, 90 };
public GameObject headGO;
public GameObject bodyGO;
public float moveSpeed = 20;
public GameObject target;
public UnityAction<GameObject> removePipe;
// Update is called once per frame
void Update()
{
this.transform.Translate(Vector3.left * moveSpeed * Time.deltaTime);
if (this.transform.localPosition.x < -70f)
{
removePipe(this.gameObject);
Destroy(this.gameObject);
}
}
public void SettingPipe(eDirType Type, int rand)
{
//rand += level;
this.dirType = Type;
var localScale = this.bodyGO.transform.localScale;
// localScale.y = (int)this.dirType * this.arr[rand];
localScale.y = (float)this.dirType * rand;
this.bodyGO.transform.localScale = localScale;
//this.headGO.transform.localPosition = new Vector3(this.headGO.transform.localPosition.x,
//(int)this.dirType * ((float)arr[rand]/10) * 3, this.headGO.transform.localPosition.z);
this.headGO.transform.localPosition = new Vector3(this.headGO.transform.localPosition.x,
((((int)this.dirType) * ((float)rand / 10) * 3)) + ((int)this.dirType * 1.5f), this.headGO.transform.localPosition.z);
if (Type == eDirType.Down)
{
Destroy(this.target.gameObject);
}
else
{
this.target.transform.localPosition = new Vector3(this.headGO.transform.localPosition.x, this.headGO.transform.localPosition.y + 12f, this.headGO.transform.localPosition.z);
}
}
public void ChangePipeSpeed(float speed)
{
this.moveSpeed = speed;
}
}
using UnityEngine; using UnityEngine.Events; public class Pipe : MonoBehaviour { public enum eDirType { UP = 1, Down = -1 }; public eDirType dirType = eDirType.UP; public int[] arr = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; public GameObject headGO; public GameObject bodyGO; public float moveSpeed = 20; public GameObject target; public UnityAction<GameObject> removePipe; // Update is called once per frame void Update() { this.transform.Translate(Vector3.left * moveSpeed * Time.deltaTime); if (this.transform.localPosition.x < -70f) { removePipe(this.gameObject); Destroy(this.gameObject); } } public void SettingPipe(eDirType Type, int rand) { //rand += level; this.dirType = Type; var localScale = this.bodyGO.transform.localScale; // localScale.y = (int)this.dirType * this.arr[rand]; localScale.y = (float)this.dirType * rand; this.bodyGO.transform.localScale = localScale; //this.headGO.transform.localPosition = new Vector3(this.headGO.transform.localPosition.x, //(int)this.dirType * ((float)arr[rand]/10) * 3, this.headGO.transform.localPosition.z); this.headGO.transform.localPosition = new Vector3(this.headGO.transform.localPosition.x, ((((int)this.dirType) * ((float)rand / 10) * 3)) + ((int)this.dirType * 1.5f), this.headGO.transform.localPosition.z); if (Type == eDirType.Down) { Destroy(this.target.gameObject); } else { this.target.transform.localPosition = new Vector3(this.headGO.transform.localPosition.x, this.headGO.transform.localPosition.y + 12f, this.headGO.transform.localPosition.z); } } public void ChangePipeSpeed(float speed) { this.moveSpeed = speed; } }
using UnityEngine;
using UnityEngine.Events;

public class Pipe : MonoBehaviour
{
    public enum eDirType { UP = 1, Down = -1 };
    public eDirType dirType = eDirType.UP;
    public int[] arr = { 10, 20, 30, 40, 50, 60, 70, 80, 90 };
    public GameObject headGO;
    public GameObject bodyGO;
    public float moveSpeed = 20;
    public GameObject target;

    public UnityAction<GameObject> removePipe;


    // Update is called once per frame
    void Update()
    {
        this.transform.Translate(Vector3.left * moveSpeed * Time.deltaTime);

        if (this.transform.localPosition.x < -70f)
        {
            removePipe(this.gameObject);
            Destroy(this.gameObject);
        }
    }

    public void SettingPipe(eDirType Type, int rand)
    {
        //rand += level;
        this.dirType = Type;
        var localScale = this.bodyGO.transform.localScale;
        // localScale.y = (int)this.dirType * this.arr[rand];
        localScale.y = (float)this.dirType * rand;
        this.bodyGO.transform.localScale = localScale;
        //this.headGO.transform.localPosition = new Vector3(this.headGO.transform.localPosition.x,
        //(int)this.dirType * ((float)arr[rand]/10) * 3, this.headGO.transform.localPosition.z);
        this.headGO.transform.localPosition = new Vector3(this.headGO.transform.localPosition.x,
        ((((int)this.dirType) * ((float)rand / 10) * 3)) + ((int)this.dirType * 1.5f), this.headGO.transform.localPosition.z);

        if (Type == eDirType.Down)
        {
            Destroy(this.target.gameObject);
        }
        else
        {
            this.target.transform.localPosition = new Vector3(this.headGO.transform.localPosition.x, this.headGO.transform.localPosition.y + 12f, this.headGO.transform.localPosition.z);
        }
    }

    public void ChangePipeSpeed(float speed)
    {
        this.moveSpeed = speed;
    }

}

Test.cs

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
public GameObject envPrefabs;
void Start()
{
int x = 0;
int y = 0;
for (int i = 0; i < 10; i++)
{
Instantiate<GameObject>(this.envPrefabs).transform.position = new Vector3(x, y, 0);
x += 300;
if (x >= 1500)
{
x = 0;
y += 300;
}
}
}
}
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Test : MonoBehaviour { public GameObject envPrefabs; void Start() { int x = 0; int y = 0; for (int i = 0; i < 10; i++) { Instantiate<GameObject>(this.envPrefabs).transform.position = new Vector3(x, y, 0); x += 300; if (x >= 1500) { x = 0; y += 300; } } } }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
    public GameObject envPrefabs;
    void Start()
    {
        int x = 0;
        int y = 0;

        for (int i = 0; i < 10; i++)
        {

            Instantiate<GameObject>(this.envPrefabs).transform.position = new Vector3(x, y, 0);

            x += 300;

            if (x >= 1500)
            {
                x = 0;
                y += 300;
            }
        }
    }
}

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다