C#/수업내용

0830 좀비 시민 구분해서 쏘기

버스창문 2022. 8. 30. 15:51

 

동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.

완성본

 

 

만들었던 과정

우선 이 ray를 보자.
원랜 훨씬 듬성듬성한 기본 상태였다.

그래서 좀 빠져나가는 좀비들이 있었고, 그걸 개선하려고 거의 다 완성된 상태였을때 레이 개수를 늘렸다.

그러면 안됬다.

 

동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.

다시 영상을 찍으려하니 그저 에러나 뜨고말지만 아까전엔 그동안 했던 교육을 싹 다 까먹고 총을 난사했다.

 

그리고 원래는 몹 스폰시간이 훨씬 빨랐다.

하지만 보다시피, 이친구는 총을 한발만 쏜다는 개념이 없고, 총을 쐈다하면 스프레드로 쏴버린다.

 

 

플래피버드를 만들때도 느꼈지만, 얘네의 action전달법은 뭔가 많이 이상하다.

그냥 단순히 0 1 0 1 이런식으로 숫자를 전달하는게 아니라, 1을 전달하면 1111111111111111111이런식으로 전달되어 개작살이 나는것같다.

 

 

동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.

20배의 속도로 훈련을 돌릴땐 분명 적재적소에 한발씩만 쏘면서 평균점수도 9점대로 잘나오는걸 알수있다.

 

근데 직접 원래 속도로 돌릴땐 저렇게 때려박는걸 보아. action전달 방식이 getkeyDown이 아닌 getkey인것같다.

 

 

tenser board 그래프이다. 계속 한번떨어졌다가 더 높게 올라가는걸 볼수있는데, 나는 애초에 커리큘럼식으로 만들지 않았다.

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Actuators;

public class ShotAgent : Agent
{
    public GameObject bulletPrefab;
    private List<GameObject> bullets;

    public RayPerceptionSensorComponent3D sensor;

    // Start is called before the first frame update
    void Start()
    {
        this.bullets = new List<GameObject>();
    }

    // Update is called once per frame
    void Update()
    {
        /*if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            if (!(this.transform.localPosition.x < -2))
            {
                Debug.Log("왼");
                this.transform.Translate(Vector3.left * 2);
            }
        }
        if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            if (!(this.transform.localPosition.x > 2))
            {
                Debug.Log("오른");
                this.transform.Translate(Vector3.right * 2);
            }
        }
        if (Input.GetKeyDown(KeyCode.Space))
        {
            var bul = Instantiate(this.bulletPrefab, this.transform.position + Vector3.forward, Quaternion.identity);
            this.bullets.Add(bul);
        }*/
    }
    public override void CollectObservations(VectorSensor sensor)
    {
        //관찰내용
        sensor.AddObservation(this.transform.localPosition.x);

    }
    public override void OnActionReceived(ActionBuffers actions)
    {
        //매 스탭

        /*RayPerceptionInput rayInput = this.sensor.GetRayPerceptionInput();
        RayPerceptionOutput output = RayPerceptionSensor.Perceive(rayInput);
        RayPerceptionOutput.RayOutput[] arr = output.RayOutputs;
        //Debug.Log(arr.Length);
        foreach (var rayOutput in arr)
        {
            Debug.LogFormat("-----> {0}", rayOutput.HitGameObject);
        }*/

        if (actions.DiscreteActions[0] == 0)
        {
            if (!(this.transform.localPosition.x < -2))
            {
                //Debug.Log("왼");
                this.transform.Translate(Vector3.left * 2);
            }
        }
        else if (actions.DiscreteActions[0] == 2)
        {
            if (!(this.transform.localPosition.x > 2))
            {
                //Debug.Log("오른");
                this.transform.Translate(Vector3.right * 2);
            }
        }
        if (actions.DiscreteActions[1] == 1)
        {
            //AddReward(-1f);
            var bul = Instantiate(this.bulletPrefab, this.transform.position + Vector3.forward, Quaternion.identity);
            bul.GetComponent<Bullet>().shotNoOne = () => {
                AddReward(-0.1f);
            };
            this.bullets.Add(bul);
        }

    }
    public override void OnEpisodeBegin()
    {
        //시작할떄
        //Debug.Log("tlwkr");
        this.transform.localPosition = new Vector3(-3, 0, -8);
    }
    public override void Heuristic(in ActionBuffers actionsOut)
    {
        //직접 컨트롤
        /*actionsOut.DiscreteActions.Array[0] = (int)Input.GetAxisRaw("Horizontal") + 1;
        actionsOut.DiscreteActions.Array[1] = Input.GetKeyDown(KeyCode.Space) ? 1 : 0;*/
    }
    public void GetScore()
    {
        AddReward(1f);
    }

    public void BadEnd()
    {
        AddReward(-1f);
        foreach (var a in this.bullets)
        {
            Destroy(a.gameObject);
        }
        EndEpisode();
    }

    public void GoodEnd()
    {
        Debug.Log("고수");
        //AddReward(10f);
        foreach(var a in this.bullets)
        {
            Destroy(a.gameObject);
        }
        EndEpisode();
    }
}

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class Bullet : MonoBehaviour
{
    public float moveSpeed = 20f;
    public UnityAction shotNoOne;

    private float pos;
    private void Start()
    {
        this.pos = this.transform.position.z;
    }
    // Update is called once per frame
    void Update()
    {
        this.transform.Translate(Vector3.forward * Time.deltaTime * this.moveSpeed);
        if (this.transform.position.z - this.pos > 8)
        {
            this.shotNoOne();
            Destroy(this.gameObject);
        }
    }
    private void OnCollisionEnter(Collision collision)
    {
        Destroy(this.gameObject);
    }
}

보다시피, 총알이 아무에게도 맞지않아 사라질때, shotNoOne이라는 대리자를 전달했고, 그 내용은 점수 0.1점 깎기였다.

 

그래서 탄을 난사하지않고 적재적소에 쏘게끔 훈련되었고, 한번씩 떨어지는 이유는 얘가 총점을 더 높게 받기위해 총알을 아끼다가 실수할때마다 점수가 떨어졌기때문이다. 그렇게 세부조정과정을 거칠때마다 점수는 더 높게 올라가는걸 볼수있었다.

 

 

 

'C# > 수업내용' 카테고리의 다른 글

0825 전방 사물 인식해서 그에 맞게 찾아가기_2  (0) 2022.08.25
0824 커리큘럼 머신러닝  (0) 2022.08.24
0823 머신러닝  (0) 2022.08.23
0822 머신러닝  (0) 2022.08.22
0816 polybrush 안되는 거 해결방법  (0) 2022.08.16