[유니티 AI] 행동: 영리한 움직임(1) - 행위 템플릿 만들기

3 분 소요 No newline at end of file

들어가며

본 글와 앞으로 작성될 글들은 PACKT에서 출판한 호르헤 팔리오시스의 저서 [유니티로 배우는 게임 인공지능 : 게임 개발 필수 70가지 인공지능 패턴]을 공부하면서, 해당 내용을 후에 참고할 수 있도록 작성한 것이다. 원 서적은 유니티 5.1.2버전으로 작성되었으나 나는 보다 이후 버전이자 현재 사용하고 있는 유니티 2017.2.3로 본 실습을 진행하고자 한다.

이 책은 게임에서 주로 사용되는 70가지의 게임 인공지능 패턴을 유니티로 구현하는 방식에 대하여 서술한 책이다.아마도? 아직 읽기 전이지만 유니티로 개발을 진행하면서 보다 유기적으로 움직일 수 있는 인공지능에 대하여 생각하게 되었고, 공부를 좀더 유익하고 나와 남들에게 보다 도움이 될 수 있도록 블로그를 개설하고 이 글을 작성하게 되었다. 완결할 수 있도록 이 글을 읽는 분들은 부디 나를 응원해주길 바란다. 참고로 내가 이미 알고 있는 내용은 굳이 적지 않을 것이다. 빈 부분이 궁금하신 분은 꼭 책을 사서 보시길.

1장 : 행동 : 영리한 움직임

행위 탬플릿 만들기

앞으로 인공지능 분야에서 가장 기초적이면서 기반이 되는 이동 알고리즘에 대하여 공부해볼 것이다. 이러한 기초 알고리즘은 후에 작성될 고급 알고리즘들의 기반이 된다.

본격적으로 인공지능을 만들기에 앞서, 앞으로 작성될 코드들을 보다 쉽게 작성하고 관리할 수 있도록 디딤돌이 되는 행위 탬플릿을 작성할 것이다.

우선 기반이 되는 Steering, Agent, AgentBehaviour라는 세 가지 클래스를 만든다.


Steering


using UnityEngine;

public class Steering {

    //이동 및 회전을 저장하기 위한 데이터유형 클래스

    public float angular;
    public Vector3 linear; 
    public Steering() // 생성자
    {
        angular = 0.0f;
        linear = new Vector3();
    }

}

Steering이란 자동차 등의 이동수단에서 사용하는 조종장치를 뜻한다. 즉 핸들이라고 보면 된다. 이 클래스는 두 개의 변수와 생성자만을 가지는 데이터 유형 클래스로, 후에 에이전트의 이동 및 회전값을 저장하기 위하여 작성한다. 단순히 데이터를 저장하는 용도이기 때문에 일반적인 유니티 스크립트들이 사용하는 MonoBehaviour을 상속하지 않는다는 점을 유의하자.


Agent

using UnityEngine;

public class Agent : MonoBehaviour {

    public float maxSpeed; //최대 속도
    public float maxAccel; //최대 가속도
    public float orientation; //방향
    public float rotation; //회전
    public Vector3 velocity; //속도
    protected Steering steering; //핸들

    private void Start()
    {
        velocity = Vector3.zero; //속도 초기화
        steering = new Steering(); //핸들 초기화
    }

    public void SetSteering(Steering steering)
    {
    //외부에서 이 객체에게 핸들(steering)을 조작할 수 있도록 작성한 함수
        this.steering = steering;
    }

    public virtual void Update() //값에 따른 이동 처리
    {
    	//속도에 따른 프레임 담 이동량
        Vector3 displacement = velocity * Time.deltaTime;
        //회전 값에 따른 프레임당 방향의 변화를 적용
        orientation += rotation * Time.deltaTime;

        //회전 값을 0~360도 사이로 제한
        if(orientation < 0.0f)
            orientation += 360.0f;
        else if(orientation > 360.0f)
            orientation -= 360.0f;

        //이동, 회전
        transform.Translate(displacement, Space.World);
        transform.rotation = new Quaternion(); // 회전값 초기화
        transform.Rotate(Vector3.up, orientation); //y축에 대하여 회전
    }

    public virtual void LateUpdate() //다음 프레임 움직임 갱신
    {
        velocity += steering.linear * Time.deltaTime;
        rotation += steering.angular * Time.deltaTime;
        //속도 제한
        if(velocity.magnitude > maxSpeed)
        {
            velocity.Normalize(); //방향만 남김
            velocity = velocity * maxSpeed; //최대값으로 만듦
        }
        if (steering.angular == 0.0f)
            rotation = 0.0f; //각도변화량이 0인경우 회전값을 0으로 조정
        if (steering.linear.sqrMagnitude == 0.0f)
            velocity = Vector3.zero; //속도가 0인 경우 이동값 0으로 조정

        steering = new Steering(); //핸들 초기화
    }
}

Agent클래스는 인공지능 객체에 움직임을 주는 가장 주요한 컴포넌트다. 이 컴포넌트에서 만들어진 기초적인 움직임을 토대로 보다 복합적인 움직임을 만들어 낸다.

앞서 작성한 Steering클래스를 이용해 에이전트를 이동시킨다. 이러한 이동값은 전역함수인 SetSteering을 통해 외부에서 지정된다. 이 함수는 뒤에 작성될 AgentBehaviour에 의해서 지정될 것이다.

Update이후에 실행될 LateUpdate에서 다음 프레임의 움직임값을 전달받은 steering에서 받아와 지역변수에 할당해준다.

Update함수에서는 이전 프레임에서 할당받은 움직임값을 실제로 움직이고, 다시 값을 초기화한다.


AgentBehaviour

using UnityEngine;

public class AgentBehaviour : MonoBehaviour {

    public GameObject target;
    protected Agent agent;
    public virtual void Awake()
    {
        agent = gameObject.GetComponent<Agent>();
    }

    public virtual Steering GetSteering()
    {
        return new Steering();
    }

    public virtual void Update()
    {
        //매프레임마다 에이전트에 steering을 할당
        agent.SetSteering(GetSteering());
    }

}

AgentBehaviour는 에이전트를 컨트롤하는 클래스로, 대부분의 행위가 이 클래스를 상속하여 작성될 것이다. 현재는 Update에서 매 프레임마다 에이전트에 steering값을 전달해주는 코드만 작성되어있다. 후에 오버라이드하여 사용할 것으로 보인다.


스크립트 실행 순서 지정하기

위에서 작성된 스크립드들이 원하는 순서에 맞게 작동되게 하려면 MonoManager에서 스크립트 실행 순서를 지정해주어야 한다.

실행되는 순서는 다음과 같다.

  • 에이전트 스크립트
  • 행위 스크립트
  • 이전 행위나 스크립트에 기반한 행위 또는 스크립트

현재는 우선 작성된 코드가 따로 없기 때문에 굳이 수정하지 않지만, 후에 코드를 상속한 경우 Edit / Project Settings / Script Exeution Order에서 위의 원칙에 맞게 순서를 지정해주자. 이 부분은 아직 뭔지 잘 모르겠다

태그: ,

카테고리: ,

업데이트:

댓글남기기