728x90
반응형

 

내가 좋아하는 그림을 열고 Edit -> Define Brush Preset 를 엽니다

 

그러면 등록할수 있게 이름을 설정하고 저장할수 있습니다

 

 

 

 

저장하고 브러시를 사용 합니다

 

Brush Settings 를 여시면 브러시가 등록 되어 있는 것을 확인 할수 있습니다

반응형
728x90
반응형

포토샵 도구 툴바 중에 사각 툴을 이용하여 이미지 부분을 드래그합니다 

 

그리고 상단의 Select -> Inverse 를 눌러서 부드럽게 할 바깥쪽 이미지를 선택합니다 단축키는 Shift +Ctrl +i입니다

 

 

 

그리고 CTRL+ALT + R 키를 눌러서 아래 사진과 같이 Feather를 조정하여 부드럽게 할 수치를 올립니다

 

안쪽 사각 영역이 매끄러운 사각 영역으로 변합니다

 

 

 

DEL 키를 눌러서 바깥 부분을 삭제시킵니다 

 

Ctrl + D 키를 눌러서 사각 영역을 해제합니다 

반응형
728x90
반응형

 

 

바이 패드를 뼈대로 심고 스킨 한 모습입니다

 

 

 

 

그냥 랜더링하여 이미지를 뽑으면 바이 패드가 보이게 됩니다

 

그래서 모니터 모양의 아이콘을 클릭하고 Bone Objects를 클릭합니다

 

 

다시 랜더링 하면 바이 패드가 안 보이는 이미지를 뽑을 수 있습니다 

 

반응형
728x90
반응형

 

 

 

Game Over 텍스트를 만들어서 게임 오버 환경을 만들겠습니다

하이라키 뷰에 Canvas 를 선택하고 오른쪽 마우스버튼을 눌러 UI -> Text를 만듬니다

 

새로 생긴 Text 오브젝트를 이름을 tetGameOver 로 바꾸고 속성을 아래 그림과 같이 바꿈니다

 

 

 

txtGameOver  오브젝트를 선택하고 Window -> Animation -> Animation 을 선택합니다

 

 

Animation 창이 나오면 Create 버튼을 누릅니다

 

저장할 Animation 폴더를 만들고 이름을 GameOver 라 하고 저장합니다

 

 

 

Animation 창에 Add Property 를 눌러서 Color + 를 선택하여 애니메이션 의 키를 줍니다 

 

애니며여션 창의 Preview 옆의 빨간 버튼을 누르고  첫 프레임의 키를 선택하여 GameOver 텍스쳐의 알파 값을 0 으로 하고  마지막 프레임을 선택하여 알파값을 255 로 줍니다

 

 

 

그리고 Animator 창으로 돌아가서 GameOver 애니메이션의 Loop Time을 체크 해제 합니다

 

그리고 빈 State 를 만들고 선택하여 Set as Layer Defult State 를 선택합니다

 

 

 

Animator 창에 Parameters를 선택하여  Trigger를 만들고 이름을 show 라 합니다

 

Start 와 GameOver  State 에 화살푤르 연결하고  has Exit Time 을 체크 해제하고 Conditons를 show를 선택합니다

 

UIManager 스크립트를 선택하고 스크립트를 수정합니다

 

 

 

   public Text gameOver;
   Animator animGameOver;

.

.

.

.

 private void Start()
    {
        animGameOver = gameOver.gameObject.GetComponent<Animator>();
        gameOver.enabled = false;
    }

    public void ShowGameOver()
    {
        gameOver.enabled = true;
        animGameOver.SetTrigger("show");
    }

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIManager : MonoBehaviour
{
    // 언제 어디서나 쉽게 접금할수 있도록 하기위해 만든 정적변수
    public static UIManager instance;

    public Text playerName;
    public Text playerMoney;
    public Image playerHPBar;

    public Text gameOver;

    Animator animGameOver;
    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
    }

    private void Start()
    {
        animGameOver = gameOver.gameObject.GetComponent<Animator>();
        gameOver.enabled = false;
    }

    public void ShowGameOver()
    {
        gameOver.enabled = true;
        animGameOver.SetTrigger("show");
    }

    public void UpdatePlayerUI(PlayerParams playerParams)
    {
        playerName.text = playerParams.name;
        playerMoney.text = "Coin : " + playerParams.money.ToString();
        playerHPBar.rectTransform.localScale = 
            new Vector3((float)playerParams.curHp / (float)playerParams.maxHp, 1f, 1f);

    }
    void Update()
    {
        
    }
}

 

 

Canvas의 txtGameOver 오브젝트를 선택하고 UIManager 스크립트의 연결합니다 

 

PalyerFSM 스크립트를 선택하고 수정합니다

 

UIManager.instance.ShowGameOver();    public void ChangeToPlayerDead()
    {
        print("player was dead");
        ChangeState(State.Dead, PlayerAni.ANI_DIE);

        UIManager.instance.ShowGameOver();
    }

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

public class PlayerFSM : MonoBehaviour
{  
    public enum State
    {
        Idle,
        Move,
        Attack,
        AttackWait,
        Dead
    }
    //idle 상태를 기본 상태로 지정
    public State currentState = State.Idle;

    //마우수 클릭 지점,플레이어가 이동할 목적지의 좌표를 저장할 예정
    Vector3 curTargetPos;

    GameObject curEnemy;

    public float rotAnglePerSecond = 360f; //1초에 플레이어의 방향을 360도 회전한다

    public float moveSpeed = 2f; //초당 2미터의 속도로 이동

    float attackDelay = 2f; // 공격을 한번하고 다시 공격할때 까지의 지연시간

    float attackTimer = 0f; //공격을 하고 난 뒤에 경과되는 시간을 계산하기 위한 변수

    float attackDistance = 1.5f; // 공격 거리 (적과의 거리)

    float chaseDistance = 2.5f; // 전투 중 적이 도망가면 다시 추적을 시작 하기 위한 거리

    PlayerAni myAni;

    PlayerParams myParams;

    EnemyParams curEnemyParams;
    void Start()
    {
        myAni = GetComponent<PlayerAni>();
        //  myAni.ChangeAni(PlayerAni.ANI_WALK);

        myParams = GetComponent<PlayerParams>();

        myParams.InitParams();

        myParams.deadEvent.AddListener(ChangeToPlayerDead);

        ChangeState(State.Idle, PlayerAni.ANI_IDLE);

        curEnemy = GameObject.FindGameObjectWithTag("Enemy");
    }

    public void ChangeToPlayerDead()
    {
        print("player was dead");
        ChangeState(State.Dead, PlayerAni.ANI_DIE);

        UIManager.instance.ShowGameOver();
    }

    public void CurrentEnemyDead()
    {
        ChangeState(State.Idle, PlayerAni.ANI_IDLE);
        print("enemy was killed");

        curEnemy = null;
    }

    public void AttackCalculate()
    {
        if (curEnemy == null)
        {
            return;
        }

        print("Attack" + curEnemy.name +"...");

        curEnemy.GetComponent<EnemyFSM>().ShowHitEffect();

        int attackPower = myParams.GetRandomAttack();
        curEnemyParams.SetEnemyAttack(attackPower);

        //플레이어가 공격할때 나는 소리
        SoundManager.instance.PlayHitSound();
    }

    // 적을 공격하기 위한 함수 
    public void AttackEnemy(GameObject enemy)
    {
        if (curEnemy != null && curEnemy == enemy)
        {
            return;
        }

        //적(몬스터)의 파라미터를 변수에 저장
        curEnemyParams = enemy.GetComponent<EnemyParams>();

        if (curEnemyParams.isDead == false)
        {
            curEnemy = enemy;
            curTargetPos = curEnemy.transform.position;

            GameManager.instance.ChangeCurrentTarget(curEnemy);

            ChangeState(State.Move, PlayerAni.ANI_WALK);
        }
        else
        {
            curEnemyParams = null;
        }
  
    }
    void ChangeState(State newState, int aniNumber)
    {
        if (currentState == newState)
        {
            return;
        }
        myAni.ChangeAni(aniNumber);
        currentState = newState;
    }

    //캐릭터의 상태가 바뀌면 어떤 일이 일어날지 를 미리 정의
    void UpdateState()
    {
        switch (currentState)
        {
            case State.Idle:

                IdleState();

                break;
            case State.Move:

                MoveState();

                break;
            case State.Attack:

                AttackState();

                break;
            case State.AttackWait:

                AttackWaitState();

                break;
            case State.Dead:

                DeadState();

                break;
            default:
                break;
        }
    }
   void IdleState()
    {

    }

    void MoveState()
    {
        TurnToDestination();
        MoveToDestination();
    }
    void AttackState()
    {
        attackTimer = 0f;

        //transform.LookAt(목표지점 위치) 목표지점을 향해 오브젝트를 회전 시키는 함수
        transform.LookAt(curTargetPos);
        ChangeState(State.AttackWait, PlayerAni.ANI_ATKIDLE);
    }
    void AttackWaitState()
    {
        if (attackTimer > attackDelay)
        {
            ChangeState(State.Attack, PlayerAni.ANI_ATTACK);

        }

        attackTimer += Time.deltaTime;
    }
    void DeadState()
    {

    }

    //MoveTo(캐릭터가 이동할 목표 지점의 좌표)
   public void MoveTo(Vector3 tPos)
    {
        //사망 하였을때 움직임 리턴 처리 (여기서 끝냄)
        if (currentState == State.Dead)
        {
            return;
        }
        curEnemy = null;
        curTargetPos = tPos;
        ChangeState(State.Move, PlayerAni.ANI_WALK);
    }
    void TurnToDestination()
    {
        // Quaternion lookRotation(회전할 목표 방향) : 목표 방향은 목적지 위치에서 자신의 위치를 빼면 구함
        Quaternion lookRotation = Quaternion.LookRotation(curTargetPos - transform.position);

        //Quaternion.RotateTowards(현재의 rotation값, 최종목표rotation 값, 최대 회전각)
        transform.rotation = Quaternion.RotateTowards(transform.rotation, lookRotation, Time.deltaTime * rotAnglePerSecond);
    }

    void MoveToDestination()
    {
        //Vector3.MoveTowards(시작지점, 목표지점,최대이동거리)
        transform.position = Vector3.MoveTowards(transform.position, curTargetPos,moveSpeed * Time.deltaTime);

        if (curEnemy == null)
        {
            //플레이어의 위치와 목표지점의 위치가 같으면, 상태를 Idle 상태로 바꾸라는 명령
            if (transform.position == curTargetPos)
            {
                ChangeState(State.Idle, PlayerAni.ANI_IDLE);
            }
        }
        else if (Vector3.Distance(transform.position,curTargetPos) < attackDistance)//Vector3.Distance(A,B):A와B사이의 거리
        {
            ChangeState(State.Attack, PlayerAni.ANI_ATTACK);
        }
    }
    void Update()
    {
        UpdateState();
    }
}

 

 

 

EnemyFSM스크립트를 선택하고 수정합니다

 void AttackState()
    {
        if (player.GetComponent<PlayerFSM>().currentState == PlayerFSM.State.Dead)
        {
            ChangeState(State.NoState, EnemyAni.IDLE);
        }
        if (GetDistanceFromPlayer() > reChaseDistance)
        {
            attackTimer = 0f;
            ChangeState(State.Chase, EnemyAni.WALK);
        }
        else
        {
            if (attackTimer > attackDelay)
            {
                transform.LookAt(player.position);
                myAni.ChangeAni(EnemyAni.ATTACK);

                attackTimer = 0f;

                //몬스터가 공격할때 나는 소리
                SoundManager.instance.PlayEnemyAttack();
            }

            attackTimer += Time.deltaTime;
        }
    }

 

 

 

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

public class EnemyFSM : MonoBehaviour
{
    public enum State
    {
        Idle,  //정지
        Chase,  //추적
        Attack,  //공격
        Dead,   //사망
        NoState  //아무 일도 없는 상태
    }

    public State currentState = State.Idle;

    EnemyParams myParams;

    EnemyAni myAni;

    Transform player;

    PlayerParams playerParams;

    CharacterController controller;

    float chaseDistance = 5f; // 플레이어를 향해 몬스터가 추적을 시작할 거리
    float attackDistance = 2.5f; // 플레이어가 안쪽으로 들오오게 되면 공격을 시작
    float reChaseDistance = 3f; // 플레이어가 도망 갈 경우 얼마나 떨어져야 다시 추적

    float rotAnglePerSecond = 360f; // 초당 회전 각도
    float moveSpeed = 1.3f; // 몬스터의 이동 속도

    float attackDelay = 2f;
    float attackTimer = 0f;

    public ParticleSystem hitEffect;

    public GameObject selectMark;

    //리스폰 시킬 몬스터를 담을 변수 
    GameObject myRespawnObj;

    //리스폰 오브젝트에서 생성된 몇번째 몬스터에 대한 정보
    public int spawnID { get; set; }


    //몬스터가 처음 생성될때의 위치를 저장
    Vector3 originPos;

    void Start()
    {
        myAni = GetComponent<EnemyAni>();
        myParams = GetComponent<EnemyParams>();
        myParams.deadEvent.AddListener(CallDeadEvent);

        ChangeState(State.Idle, EnemyAni.IDLE);

        controller = GetComponent<CharacterController>();

        player = GameObject.FindGameObjectWithTag("Player").transform;
        playerParams = player.gameObject.GetComponent<PlayerParams>();

        hitEffect.Stop();
        HideSelection();
    }

    //몬스터가 리스폰 될때 초기화 상태로 함
    public void AddToWorldAgain()
    {
        //  리스폰 오브젝트에서 처음 생성될때의 위치와 같게 함
        transform.position = originPos;

        GetComponent<EnemyParams>().InitParams();
        GetComponent<BoxCollider>().enabled = true;
    }
    public void HideSelection()
    {
        selectMark.SetActive(false);
    }

    public void ShowSelection()
    {
        selectMark.SetActive(true);
    }

    // 몬스터가 어느 리스폰 오브젝트로부터 만들었졋는지에 대한 정보를 전달 받을 함수
    public void SetRespawnObj(GameObject respawnObj, int spawnID,Vector3 originPos)
    {
        myRespawnObj = respawnObj;
        this.spawnID = spawnID;
        this.originPos = originPos;
    }

    //몬스터가 죽는 순간 처리 명령어
    void CallDeadEvent()
    {
        ChangeState(State.Dead, EnemyAni.DIE);

        //몬스터가 죽은후 아이템 및 동전을 생성한다
        ObjectManager.instance.DropCoinToPosition(transform.position, myParams.rewardMoney);

        player.gameObject.SendMessage("CurrentEnemyDead");

        //몬스터가 사망했을때 나는 소리
        SoundManager.instance.PlayEnemyDie();

        StartCoroutine(RemoveMeFromWorld());
    }

    IEnumerator RemoveMeFromWorld()
    {
        yield return new WaitForSeconds(1f);

        ChangeState(State.Idle, EnemyAni.IDLE);

        //리스폰 오브젝트에 자기 자신을 제거해 달라는 요청
        myRespawnObj.GetComponent<RespawnObj>().RemoveMonster(spawnID);
    }

    public void ShowHitEffect()
    {
        hitEffect.Play();
    }

    public void AttackCalculate()
    {
        playerParams.SetEnemyAttack(myParams.GetRandomAttack());
    }

    void UpdateState()
    {
        switch (currentState)
        {
            case State.Idle:
                IdleState();
                break;
            case State.Chase:
                ChaseState();
                break;
            case State.Attack:
                AttackState();
                break;
            case State.Dead:
                DeadState();
                break;
            case State.NoState:
                NoState();
                break;          
        }
    }

    public void ChangeState(State newState, string aniName)
    {
        if (currentState == newState)
        {
            return;
        }

        currentState = newState;
        myAni.ChangeAni(aniName);
    }
    void IdleState()
    {
        if (GetDistanceFromPlayer() < chaseDistance)
        {
            ChangeState(State.Chase, EnemyAni.WALK);
        }
    }

    void ChaseState()
    {
        //몬스터가 공격 가능 거리 안으로 들어가면 공격 상태
        if (GetDistanceFromPlayer() < attackDistance)
        {
            ChangeState(State.Attack, EnemyAni.ATTACK);
        }
        else
        {
            TurnToDestination();
            MoveToDestination();
        }   
    }

    void AttackState()
    {
        if (player.GetComponent<PlayerFSM>().currentState == PlayerFSM.State.Dead)
        {
            ChangeState(State.NoState, EnemyAni.IDLE);
        }
        if (GetDistanceFromPlayer() > reChaseDistance)
        {
            attackTimer = 0f;
            ChangeState(State.Chase, EnemyAni.WALK);
        }
        else
        {
            if (attackTimer > attackDelay)
            {
                transform.LookAt(player.position);
                myAni.ChangeAni(EnemyAni.ATTACK);

                attackTimer = 0f;

                //몬스터가 공격할때 나는 소리
                SoundManager.instance.PlayEnemyAttack();
            }

            attackTimer += Time.deltaTime;
        }
    }
    void DeadState()
    {
        GetComponent<BoxCollider>().enabled = false;
    }
    void NoState()
    {

    }

    void TurnToDestination()
    {
        Quaternion lookRotation = Quaternion.LookRotation(player.position - transform.position);

        transform.rotation = Quaternion.RotateTowards(transform.rotation, lookRotation, Time.deltaTime * rotAnglePerSecond);
    }

    void MoveToDestination()
    {
        // transform.position = Vector3.MoveTowards(transform.position, player.position, moveSpeed * Time.deltaTime);

        //몬스터의 이동을 캐릭터 컨트롤러로 바꿈 몬스터가 전방으로 moveSpeed  만큼의 빠르기로 이동하게 됨
        controller.Move(transform.forward * moveSpeed * Time.deltaTime);
    }

    //플레이어와 거리을 재는 함수
    float GetDistanceFromPlayer()
    {
        float distance = Vector3.Distance(transform.position, player.position);
        return distance;
    }

    // Update is called once per frame
    void Update()
    {
        UpdateState();
    }
}

 

 

게임을 실행하고 플레이어가 죽으면  GameOver 텍스쳐가 잘나오는지 확인 합니다

 

 

RPG_Game_Project.z01
10.00MB
RPG_Game_Project.z02
10.00MB
RPG_Game_Project.z03
10.00MB
RPG_Game_Project.z04
10.00MB
RPG_Game_Project.zip
8.63MB

반응형
728x90
반응형

XML.zip
0.47MB

엑셀에서 캐릭터의 능력치 데이터를 만들고 유니티에서 엑셀 데이터를 파싱 하여 캐릭터의 능력치를 나타내는 작업을 하겠습니다 

먼저 엑셀 파일로 캐릭터의 데이터를 작성합니다

 

 

만든 엑셀 데이터를 복사 합니다

 

 

사이트  https://shancarter.github.io/mr-data-converter/ 를 가서 엑셀에서 복사한 윗 빈칸에 데이터를 붙여 넣기 하고  아래 Output as를 XML-Nodes로 변경합니다

그러면 XML-Nodes 데이터가 나옵니다

 

 

 

XML-Nodes 데이터를 복사합니다 

 

 

 

메모장을 열어 데이터를 붙여 넣기 합니다

 

파일을 저장하는데 이름을 적고 확장자를  xml로 바꾸고 인코딩 방식을 UTF-8 코드로 하고 저장합니다

 

저장하면 모양이 아래 그림과 같이 됩니다 Windows 7 환경

저장한 파일을 유니티에 Resources폴더를 만들고 드래그하여 옮깁니다

 

 

 

 

하이 라키 뷰에 XMLManager 오브젝트를 만들고 XMLManager 스크립트를 만들어 붙입니다

 

 

 

XMLManager 스크립트 작성

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Xml;
using System;
public class XMLManager : MonoBehaviour
{
    public static XMLManager instance;

    //xml 파일
    public TextAsset enemyFileXml;

    //여러개의 변수들을 넣어서 구조체 하나를 한개의 상자처럼 간주하고 사용할수 있음
    struct MonParams
    {
        //xml 파일로 부터 각각의 몬스터의 대해서 이들 파라미터 값을 읽어 들이고 구조체 내부 변수에 저장하고 구조체를 이용하여 각 몬스터에게 파라미터 값으 전달함
        public string name;
        public int level;
        public int maxHp;
        public int attackMin;
        public int attackMax;
        public int defense;
        public int exp;
        public int rewardMoney;
    }

    //딕셔너리의 키값으로 적의이름을 사용할 예정이므로 string타입으로 하고 데이터 값으로는 구조체를 이용함 MonParams로 지정
    Dictionary<string, MonParams> dicMonsters = new Dictionary<string, MonParams>();
    void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }        
    }

    private void Start()
    {
        MakeMonsterXML();
    }

    //XML로부터 파라미터 값 읽어 들이기
    void MakeMonsterXML()
    {
        XmlDocument monsterXMLDoc = new XmlDocument();
        monsterXMLDoc.LoadXml(enemyFileXml.text);

        XmlNodeList monsterNodeList = monsterXMLDoc.GetElementsByTagName("row");

        //노드 리스트로부터 각각의 노드를 뽑아냄
        foreach ( XmlNode monsterNode in monsterNodeList)
        {
            MonParams monParams = new MonParams();

            foreach (XmlNode childNode in monsterNode.ChildNodes)
            {
                if (childNode.Name == "name")
                {
                    //<name>smallspider</name>
                    monParams.name = childNode.InnerText; 
                }

                if (childNode.Name == "level")
                {
                    //<level>1</level>    Int16.Parse() 은 문자열을 정수로 바꿔줌
                    monParams.level = Int16.Parse( childNode.InnerText);
                }

                if (childNode.Name == "maxHp")
                {
                    monParams.maxHp = Int16.Parse(childNode.InnerText);
                }

                if (childNode.Name == "attackMin")
                {
                    monParams.attackMin = Int16.Parse(childNode.InnerText);
                }

                if (childNode.Name == "attackMax")
                {
                    monParams.attackMax = Int16.Parse(childNode.InnerText);
                }

                if (childNode.Name == "defense")
                {
                    monParams.defense = Int16.Parse(childNode.InnerText);
                }

                if (childNode.Name == "exp")
                {
                    monParams.exp = Int16.Parse(childNode.InnerText);
                }

                if (childNode.Name == "rewardMoney")
                {
                    monParams.rewardMoney = Int16.Parse(childNode.InnerText);
                }

                print(childNode.Name + ": " + childNode.InnerText);
            }
            dicMonsters[monParams.name] = monParams;
        }
    }

    //외부로부터 몬스터의 이름과, EnemyParams 객체를 전달 받아서 해당 이름을 가진 몬스터의 
    //데이터(XML 에서 읽어 온 데이터)를 전달받은 EnemyParams 객체에 적용하는 역할을 하는 함수
    public void  LoadMonsterParamsFromXML(string monName, EnemyParams mParams)
    {
        mParams.level = dicMonsters[monName].level;
        mParams.curHp = mParams.maxHp = dicMonsters[monName].maxHp;
        mParams.attackMin = dicMonsters[monName].attackMin;
        mParams.attackMax = dicMonsters[monName].attackMax;
        mParams.defense = dicMonsters[monName].defense;
        mParams.exp = dicMonsters[monName].exp;
        mParams.rewardMoney = dicMonsters[monName].rewardMoney;
    }


    void Update()
    {
        
    }
}

 

 

 

 

XMLManager 스크립트에 xml 파일 enemy를 Enemy File Xml에 드래그하여 붙입니다

EnemyParams 스크립트를 열고 수정합니다

 

XMLManager.instance.LoadMonsterParamsFromXML(name, this);

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EnemyParams : CharacterParams
{
    public string name;
    public int exp { get; set; }
    public int rewardMoney { get; set; }

    public Image hpBar;
    public override void InitParams()
    {
        /*
        name = "Monster";
        level = 1;
        maxHp = 50;
        curHp = maxHp;
        attackMin = 2;
        attackMax = 5;
        defense = 1;

        exp = 10;
        rewardMoney = Random.Range(10, 31);
        */

        //XMLManager에서 넘겨 받은 이름을 해당하는 몬스터 파라미터를 찾아서 주요 파라미터값을 반영해 주게됨
        XMLManager.instance.LoadMonsterParamsFromXML(name, this);

        isDead = false;

        InitHpBarSize();
    }

    void InitHpBarSize()
    {
        //hpBar 의 사이즈를 원래 자신의 사이즈 ,1배의 사이즈로 초기와시켜 주게 됨
        hpBar.rectTransform.localScale = new Vector3(1f, 1f, 1f);
    }
    protected override void UpdateAfterReceiveAttack()
    {
        base.UpdateAfterReceiveAttack();

        hpBar.rectTransform.localScale = new Vector3((float)curHp / (float)maxHp, 1f, 1f);
    }
}

 

 

 

그리고 Enemy 오브젝트를 선택하여 활성화시키고  아래와 같이 속성을 바꾸고 프리 팹을 저장합니다

EnemyParams 스크립트에서 name의 spider 를 철자를 같게 합니다

왜냐 하면 enemy xml 파일의 데이터 노드에서  name 의 스펠링과 같게 해 주어야 하기 때문입니다

 

Enemy 오브젝트의 활성화를 꺼줍니다

 

그리고 Enemy 프리 팹을 선택하여 드래그해서 하이 라키 뷰에 올려놓습니다

 

 

하이 라키 뷰에 올려놓은 Enemy (1) 오브젝트를 기존의 프리 팹의 영향을 끊어야 하기 때문에 오브젝트를 선택하고 마우스 오른쪽 버튼을 눌러서 메뉴가 나오면  Unpack Prefab을 눌러서 프리 팹 연결을 끊습니다

 

Enemy (1) 오브젝트 이름을 EnemyBoss로 변경합니다

 

 

 

EnemyBoss 오브젝트를 선택하여 EnemyParams 스크립트의 name을 spiderboss로 타이핑합니다

그리고 메터리얼을 하나 만들어서 이름을 spiderBlack이라고 하고 인스팩터에서  Legacy Shaders/Diffuse를 선택한 다음 텍스쳐를 spider_01를 선택합니다 그리고 색을 아래 그림처럼 파란색으로 변경하여 어둠 게 합니다

 

 

 

 

EnemyBoss 오브젝트를 선택하여 자식으로 되어있는 Spider01 오브젝트의 아까 만든 spiderBlack 메터리얼을 연결합니다

 

EnemyBoss 오브젝트를 프리 팹 만듭니다  Prefabs 폴더에 드래그하여 프리팹을 만듬니다

 

 

 

하이 라키 뷰에 있는  EnemyBoss 오브젝트의 활성화를 끕니다

 

그리고 ResPawnObj 오브젝트를 선택하여 Ctrl + D를 눌러서 오브젝트를 복사합니다 

아래 그림과 같이 RespawnObj (1) 오브젝트가 생성되면 EnemyBoss 프리 팹을 연결하고 SpawnNumber를 2로 바꿉니다

 

 

 

게임을 실행하여 Xml 데이터에서 만든 캐릭터의 이름과 능력치가 제대로 나오는지 콘솔 창에서 확인합니다

0

반응형

+ Recent posts