C#/과제

2020.05.24. 과제 - 로그인 -> 캐릭터 선택 -> 레이캐스트를 이용한 이동, 자동공격 -> 죽으면 팝업 및 재시작 -> 로그인..반복

dev_sr 2020. 5. 24. 19:36

DataManager, 매핑 클래스는 생략했습니다.

 

어려웠던 것..

비동기화로 씬 로드하는 것과

대리자는 어느정도 사용하기 좀더 수월해진 것 같은데

애니메이션이 아직도 매끄럽게 사용하기 어려워서 더 연습해야 할 것 같습니다. ㅠㅠ

 

 

EventSystem.current.IsPointerOverGameObject() 

GameObject들 위의 UI를 클릭했을 때 true

GameObject들을 클릭했을 때 false를 반환해준다.

 

*UI 오브젝트에 raycast가 체크되어있어야하고

해당 씬에 Hierachy에 EventSystem오브젝트가 있어야한다. 

 

1. Login 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Login : MonoBehaviour
{
    public UILogin uiLogin;
    public UIPopUpLogin uiPopupLogin;
 
    void Start()
    {
        Debug.Log("1.Login::Start");
        this.Init();   
    }
 
    public void Init()
    {
        Debug.Log("2.Login::Init");
 
        this.uiLogin.Init();
        this.uiPopupLogin.Init();
 
        this.uiLogin.OnClickLoginBtn = () =>
        {
            Debug.Log("Login::uiLogin.OnClickLoginBtn 델리게이트 실행");
            this.uiPopupLogin.Show();
        };
 
        this.uiPopupLogin.closeBtn.onClick.AddListener(() =>
        {
            Debug.Log("uiPopupLogin::closeBtn: 닫기 버튼 누르기");
            this.uiPopupLogin.Hide();
        });
 
    }
    
}
 

 

 

2. UILogin 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class UILogin : MonoBehaviour
{
    public Button btn;
    public System.Action OnClickLoginBtn;
 
    public void Init()
    {
        Debug.Log("3.UILogin::Init");
 
        this.btn.onClick.AddListener(() =>
        {
            Debug.Log("UILogin::btn: 로그인 버튼 누르기");
            Debug.Log("UILogin::OnClickLoginBtn: 델리게이트 호출");
 
            this.OnClickLoginBtn();
 
           
        });
        
    }
}
 

 

 

3. UIPopUpLogin  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
using System.Collections;
using System.Collections.Generic;
using System.Runtime.ExceptionServices;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityEngine.Video;
 
public class UIPopUpLogin : MonoBehaviour
{
    public Button closeBtn;
    public Button signUpBtn;
    public Button forgetPWBtn;
    public Button loginBtn;
    public Button rememberOnBtn;
    public Button rememberOffBtn;
 
    public InputField emailInputField;
    public InputField pwInputField;
 
    private string emailTxt;
    private string pwTxt;
    private bool isRememberUser;
 
    private void Awake()
    {
        //DontDestroyOnLoad(this);
    }
 
    public void Init()
    {
        Debug.Log("4.UIPopUpLogin::Init");
 
        this.isRememberUser = true;
 
        this.signUpBtn.onClick.AddListener(() =>
        {
            Debug.Log("UIPopUpLogin::signUp 버튼 클릭");
            Debug.Log("회원가입 하기");
        });
 
        this.forgetPWBtn.onClick.AddListener(() =>
        {
            Debug.Log("UIPopUpLogin::forgetPWBtn 버튼 클릭");
            Debug.Log("패스워드 찾아주기");
        });
 
        this.rememberOnBtn.onClick.AddListener(() =>
        {
            Debug.Log("UIPopUpLogin::rememberOnBtn 버튼 클릭");
            Debug.Log("사용자 기억안하기");
            this.rememberOffBtn.gameObject.SetActive(true);
            this.rememberOnBtn.gameObject.SetActive(false);
            this.isRememberUser = false;
        });
 
        this.rememberOffBtn.onClick.AddListener(() =>
        {
            Debug.Log("UIPopUpLogin::rememberOffBtn 버튼 클릭");
            Debug.Log("사용자 기억하기");
            this.rememberOnBtn.gameObject.SetActive(true);
            this.rememberOffBtn.gameObject.SetActive(false);
            this.isRememberUser = true;
        });
 
 
 
        //사용자의 아이디, 비밀번호, 기억할 건지 여부 저장
        this.loginBtn.onClick.AddListener(() =>
        {
            Debug.Log("UIPopUpLogin::loginBtn 버튼 클릭");
            Debug.Log("로그인하기");
 
            if (this.emailTxt != null)
            {
                Debug.LogFormat("이메일 아이디: {0}",this.emailTxt);
            }
            if(this.pwTxt != null)
            {
                Debug.LogFormat("패스워드: {0}",this.pwTxt);
            }
 
            Debug.LogFormat("유저 기억 여부{0}",this.isRememberUser);
 
 
            //로비씬으로 넘김
            var asyncOper = SceneManager.LoadSceneAsync("Lobby");
            asyncOper.completed += (obj) =>
             {
                 var Lobby = GameObject.FindObjectOfType<Lobby>();
                 Lobby.Init(this.emailTxt, this.pwTxt, this.isRememberUser);
                 //Object.Destroy(this.gameObject);
 
             };
 
        });
 
    }
 
    public void Show()
    {
        Debug.Log("UIPopUpLogin::Show");
        this.gameObject.SetActive(true);
    }
 
    public void Hide()
    {
        Debug.Log("UIPopUpLogin::Hide");
        this.gameObject.SetActive(false);
    }
 
    private void Update()
    {
        this.emailTxt = this.emailInputField.text;
        this.pwTxt = this.pwInputField.text;
    }
}
 

 

 

4. Lobby 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Lobby : MonoBehaviour
{
    public UILobby uiLobby;
    private string emailTxt;
    private string pwTxt;
    private bool isRememberUser;
 
    private void Start()
    {
        DataManager.GetInstance().Load();
 
        this.uiLobby.Init();
    }
 
    //this.emailTxt, this.pwTxt, this.isRememberUser
    public void Init(string emailTxt, string pwTxt, bool isRememberUser)
    {
        this.emailTxt = emailTxt;
        this.pwTxt = pwTxt;
        this.isRememberUser = isRememberUser;
 
        Debug.LogFormat("Lobby::Init  email: {0}, pw: {1}, 기억여부: {2}"
this.emailTxt, this.pwTxt, this.isRememberUser);
    }
}
 
 

 

 

5. UILobby 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
 
public class UILobby : MonoBehaviour
{
    public Transform contentsTrans;
    private GameObject listItemPrefabs;
 
    private void Awake()
    {
        //LoadSceneAsync 쓰면 파괴해줘야함
        //파괴안하면 히어로가 죽고 다시 시작할때
        //UILobby만 세개 생겨서 히어로 안보임..
        //DontDestroyOnLoad(this.gameObject);
    }
 
 
    public void Init()
    {
 
        this.listItemPrefabs = Resources.Load("Prefabs/UI/ui_listItem_Hero"as GameObject;
 
        var characterDatas = DataManager.GetInstance().GetCharacterDatas();
        foreach(var data in characterDatas)
        {
            var listItemGo = Instantiate(this.listItemPrefabs) as GameObject;
            var listItem = listItemGo.GetComponent<UI_ListItem_Hero>();
 
            string uiModelPrefabsName = string.Format("Prefabs/UI/ui_{0}", data.res_name);
            var uiModelPrefab = Resources.Load(uiModelPrefabsName) as GameObject;
 
            var uiModel = Instantiate<GameObject>(uiModelPrefab);
 
            listItem.Init(data.id,data.res_name,uiModel);
 
 
 
 
            listItem.btn.onClick.AddListener(() =>
            {
                Debug.LogFormat("selected character ID : {0}", data.id);
 
                AsyncOperation asynOper = SceneManager.LoadSceneAsync("InGame");
                asynOper.completed += (obj) =>
                {
                    var inGame = GameObject.FindObjectOfType<InGame>();
                    Object.Destroy(GameObject.Find("scrollview"));
                    inGame.Init(data.id);
                };
 
 
            });
 
 
            listItem.transform.SetParent(this.contentsTrans, false);
 
 
        }
    }
 
}
 

 

 

6. UI_ListItem_Hero

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class UI_ListItem_Hero : MonoBehaviour
{
    public Text txtId;
    public Button btn;
    public Text txtName;
 
    private GameObject uiModel;
 
    public void Init(int id, string name, GameObject uiModel)
    {
        this.txtId.text = id.ToString();
        this.txtName.text = name;
 
        this.uiModel = uiModel;
        this.uiModel.transform.SetParent(this.transform, false);
    }
}
 

 

 

7. UIHeroState 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class UIHeroState : MonoBehaviour
{
    public Image ImgThumb;
    public Slider sliderHp;
    public Slider sliderExp;
    public Text txtProgress;
    public Text txtLevel;
    public Text txtName;
 
    private int maxHp;
 
    public void Init(Sprite spThumb, int curretHp, int maxHp, int currentExp, int targetExp, int level, string name)
    {
        this.maxHp = maxHp;
 
        var strProgress = string.Format("{0}/{1}", curretHp, maxHp);
        this.txtProgress.text = strProgress;
        this.txtLevel.text = level.ToString();
        this.txtName.text = name;
        this.ImgThumb.sprite = spThumb;
 
        this.sliderHp.value = (float)curretHp / (float)maxHp;
        this.sliderExp.value = (float)currentExp / (float)targetExp;
 
    }
 
    public void changeHpGauge(int currentHp)
    {
        var strProgress = string.Format("{0}/{1}", currentHp, this.maxHp);
        this.txtProgress.text = strProgress;
 
        this.sliderHp.value = (float)currentHp / (float)maxHp;
 
    }
}
 

 

 

8. UIInGame 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.UI;
 
public class UIInGame : MonoBehaviour
{
    public UIHeroState uiHeroState;
    public Sprite[] arrThumbsIcons;
    public SpriteAtlas uiInGameAtlas;
    public Button autoBtn;
    public Button noAutoBtn;
    public UIResultPopUp uiResultPopUp;
 
 
    public void Init(string Name, string ThumbName, int CurrentHp, 
        int MaxHp, int CurrentExp, int TargetExp, int Level)
    {
        Sprite spthumb = null;
        
        spthumb = this.uiInGameAtlas.GetSprite(ThumbName);
 
        this.uiHeroState.Init(spthumb, CurrentHp, MaxHp, 
            CurrentExp, TargetExp, Level, Name);
 
        GameObject popupPrefabs = Resources.Load<GameObject>("Prefabs/UI/UIResultPopup");
        GameObject popupGo = Instantiate(popupPrefabs) as GameObject;
        this.uiResultPopUp = popupGo.GetComponent<UIResultPopUp>();
        popupGo.SetActive(false);
 
 
    }
 
 
}
 

 

 

9. UIResultPopUp 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
 
public class UIResultPopUp : MonoBehaviour
{
    public Text inputText;
    public Button btn;
 
   
    //여기 Init은 히어로가 죽은 시점에서 호출됨
    public void Init(int count)
    {
        this.inputText.text = count.ToString();
 
        this.btn.onClick.AddListener(() =>
        {
            var asyncOper = SceneManager.LoadSceneAsync("Login");
            asyncOper.completed += (obj) =>
             {
                 Login login = GameObject.FindObjectOfType<Login>();
                 login.Init();
                 
             };
        });
 
    }
}
 

 

 

10. InGame 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
using System.Collections;
using System.Collections.Generic;
using System.Net;
using TMPro;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
 
public class InGame : MonoBehaviour
{
    
    private int selectedHeroId;
    private CharacterData selectedCharacterData;
    private Hero hero;
    private GameObject monsterShell;
    private GameObject monsterGo;
    private Monster monster;
    private float monsterX; // -5~5
    private float monsterZ; // -5~5
    private int defeatCount;    //영웅이 몬스터를 쓰러트린 횟수
    private bool isAuto;
    private GameObject fx02prefabs;
 
    public UIInGame uiInGame;
    public GameObject flagGo;
    public bool isAutoOn;
    //public System.Action <Transform,string> OnClickAutoBtn;
 
 
    private void Start()
    {
        DataManager.GetInstance().Load();
        
    }
 
    public void Init(int selectedHeroId)
    {
        this.selectedHeroId = selectedHeroId;
        this.selectedCharacterData = DataManager.GetInstance().GetCharacterDatas(this.selectedHeroId);
 
        string Name = selectedCharacterData.res_name;
        string ThumbName = selectedCharacterData.thumb_name;
        int CurrentHp = selectedCharacterData.hp;
        int MaxHp = selectedCharacterData.hp;
        int CurrentExp = 50;
        int TargetExp = 100;
        int Level = 1;
 
        this.uiInGame.Init(Name, ThumbName, CurrentHp, MaxHp, CurrentExp, TargetExp, Level);
 
        this.uiInGame.autoBtn.onClick.AddListener(() =>
        {
            Debug.Log("자동공격 비활성화");
            this.isAuto = false;
            this.uiInGame.autoBtn.gameObject.SetActive(false);
            this.uiInGame.noAutoBtn.gameObject.SetActive(true);
            this.hero.isAutoMove = false;
            this.hero.isAutoAttack = false;
        });
 
        this.uiInGame.noAutoBtn.onClick.AddListener(() =>
        {
            Debug.Log("자동공격 활성화");
            this.isAuto = true;
            this.uiInGame.autoBtn.gameObject.SetActive(true);
            this.uiInGame.noAutoBtn.gameObject.SetActive(false);
            this.hero.AutoMove();
 
        });
 
 
 
        //몬스터 처음 랜덤하게 생성하기
        this.CreateNewMonster();
        
 
        //캐릭터 생성하기
        string path = string.Format("Prefabs/{0}"this.selectedCharacterData.res_name);
 
        GameObject heroShell = new GameObject();
        heroShell.name = "Hero";
        this.hero = heroShell.AddComponent<Hero>();
 
        GameObject heroPrefabs = Resources.Load(path) as GameObject;
        GameObject heroGo = Instantiate(heroPrefabs) as GameObject;
 
        heroGo.transform.SetParent(heroShell.transform);
        this.hero.Init(heroGo, this.monsterShell, CurrentHp);
 
 
        //타격 타이밍에 이펙트 생성하기
 
        GameObject fx01prefabs = Resources.Load("Prefabs/fx01"as GameObject;
        this.fx02prefabs = Resources.Load("Prefabs/fx02"as GameObject;
 
        this.hero.OnImpact = () =>
        {
            GameObject fx01Go = Instantiate<GameObject>(fx01prefabs);
 
            Vector3 heroGoPos = this.hero.gameObject.transform.position;
 
            fx01Go.transform.position = new Vector3(heroGoPos.x, heroGoPos.y + 0.5f, heroGoPos.z + 0.2f);
        };
 
    }
 
    public void CreateNewMonster()
    {
        this.monsterShell = new GameObject();
        this.monsterShell.name = "Monster";
        this.monster = monsterShell.AddComponent<Monster>();
 
        GameObject monsterPrefabs = Resources.Load("Prefabs/StoneMonster"as GameObject;
        this.monsterGo = Instantiate(monsterPrefabs) as GameObject;
        this.monsterGo.transform.SetParent(monsterShell.transform);
 
        this.monsterX = Random.Range(-5.0f, 5.0f);
        this.monsterZ = Random.Range(-5.0f, 5.0f);
 
        this.monsterShell.transform.position = new Vector3(this.monsterX, monsterShell.transform.position.y, this.monsterZ);
 
 
        this.monster.Init(this.monsterGo);
    }
 
    public void ManualrayCastWork()
    {
        //Debug.LogFormat("down! {0}", Input.mousePosition); //x,y,z
 
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);    //스크린에 찍은 마우스 포인터 값을 광선 위치값으로 바꿔줌 
        Debug.DrawRay(ray.origin, ray.direction * 1000f, Color.red, 1f);    //광선 그리기
 
        RaycastHit hit; //레이캐스트로부터 정보를 받는 구조체
 
        if (Physics.Raycast(ray, out hit, 1000)) //사물과 충돌이 일어나면 true값을 반환해줌
        {
 
            this.flagGo.transform.position = hit.point; // 부딪힌 곳의 위치(벡터값,x,y,z)
 
            Collider target = hit.collider;  //누구와 충돌했는지 반환해준다
 
            Debug.LogFormat("충돌한 물체: {0}", target.gameObject.transform.root.name);
 
 
            if (this.monster != null)
            {
                if (target.gameObject.transform.root.name == this.monster.name)
                {
                    var monsterTrans = target.gameObject.transform.root;
                    var targetName = target.gameObject.transform.root.name;
                    //Debug.Log(targetName);
 
                    this.hero.FindTarget(monsterTrans, targetName);
                    this.hero.Move();
                }
                else
                {
                    this.hero.FindTarget(this.flagGo.transform, this.flagGo.name);
                    this.hero.Move();
                }
            }
 
        }
    }
 
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            //터치할때 UI와 inGame요소를 구분함
            //hierachy에 EventSystem오브젝트가 없으면 nullㅠㅠ
            if (!EventSystem.current.IsPointerOverGameObject()) 
            {
 
                if (!this.isAuto)
                {
                    
                    this.ManualrayCastWork();
                    
                }
 
                
            }
 
        }
 
        //몬스터의 위치를 계속 업데이트 해줌..
        if (this.isAuto)
        {
            this.hero.FindTarget(this.monsterShell.transform, monsterShell.name);
            
        }
 
 
 
        //몬스터가 죽었다고 알림
        this.monster.onMonsterDie = () =>
        {
            //기존 몬스터 삭제
            Object.Destroy(this.monsterShell);
            this.defeatCount++;
            Debug.LogFormat("몬스터를 쓰러트린 횟수 : {0}"this.defeatCount);
            this.CreateNewMonster();
 
            
        };
 
        this.monster.onMonsterImpact = () =>
        {
            GameObject fx02Go = Instantiate<GameObject>(fx02prefabs);
 
            Vector3 monsterGoPos = this.monster.gameObject.transform.position;
 
            fx02Go.transform.position = new Vector3(monsterGoPos.x, monsterGoPos.y + 0.5f, monsterGoPos.z + 0.2f);
        };
 
        this.hero.onDie = () =>
        {
            Object.Destroy(this.hero);
            this.uiInGame.uiResultPopUp.gameObject.SetActive(true);
            this.uiInGame.uiResultPopUp.Init(this.defeatCount);
            this.defeatCount = 0;
        };
    }
 
}
 

 

 

11. Hero 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
 
public class Hero : MonoBehaviour
{
    private GameObject model;
    private float speed;
    private float elapsedTime;
    private Animation anim;
    private Transform targetTrans;
    private bool isMove;
    private string targetName;
    private bool isAttack;
    private float distance;
    private AnimationState animStateAttack;
    private float impactTime;
    private float impactFrame = 8;
    private float elapsedTimeImpact;
    private float elapsedTimeAttack;
    private Monster monster;
    private bool isImpact;
    private float damage = 2;
    private float delayTime;
    private bool isDamage;
    private AnimationState animStateDamage;
    private float elapsedTimeDamage;
    private int currentHp;
    private UIHeroState uiHeroState;
    private bool isDead;
    private AnimationState animStateDie;
    private float elasedTimeDie;
 
    public bool isAutoMove;
    public bool isAutoAttack;
    public System.Action OnImpact; //마이크로 소프트에서 만든 대리자 (이렇게도 쓸수 있다!)
    public UnityAction OnReachTarget; //유니티에서 만든 대리자
    public UnityAction onDie;
 
    public void Init(GameObject model, GameObject monsterShell, int currentHp)
    {
        Debug.Log("Hero::Init");
        this.speed = 1f;
        this.model = model;
        this.anim = this.model.GetComponent<Animation>();
 
        this.animStateAttack = this.anim["attack_sword_01"];
        float totalFrame = this.animStateAttack.length * this.animStateAttack.clip.frameRate;
        this.impactTime = this.impactFrame * this.animStateAttack.length / totalFrame;
 
        this.monster = monsterShell.GetComponent<Monster>();
        this.isImpact = true;
 
        this.animStateDamage = this.anim["damage"];
 
 
        this.uiHeroState = GameObject.Find("UIHeroState").GetComponent<UIHeroState>();
        this.currentHp = currentHp;
 
        this.animStateDie = this.anim["die"];
        this.isDead = false;
        
 
    }
 
    public void Stop()
    {
        this.anim.Play("idle@loop");
        Debug.Log("Hero::Stop");
        //this.isDamage = false;
    }
 
    public void Attack()
    {
        Debug.Log("Hero::Attack");
        this.anim.Play("attack_sword_01");
 
        this.isMove = false;
        this.isImpact = false;
        this.isAttack = true;
        this.isDamage = false;
 
        //this.monster.Damage();
    }
 
 
    public void Move()
    {
        Debug.Log("Hero::Move");
        this.anim.Play("run@loop");
 
        this.isMove = true;
 
    }
 
    public void FindTarget(Transform targetTrans, string targetName)
    {
        GameObject monsterGo = GameObject.Find("Monster");
        this.monster = monsterGo.GetComponent<Monster>();
        this.targetName = targetName;
        this.targetTrans = targetTrans;
        this.transform.LookAt(this.targetTrans);
    }
 
    public void AutoMove()
    {
        this.anim.Play("run@loop");
        this.isAutoMove = true;
    }
 
    public void Damage()
    {
        Debug.Log("Hero::Damage");
        this.anim.Play("damage");
        this.isDamage = true;
        this.isAttack = false;
        this.currentHp -= this.monster.damage;
        this.uiHeroState.changeHpGauge(this.currentHp);
 
        if(this.currentHp <=0)
        {
            this.currentHp = 0;
            this.Die();
 
        }
 
    }
 
    public void Die()
    {
        Debug.Log("Hero::Die");
        this.anim.Play("die");
 
        this.isMove = false;
        this.isAutoMove = false;
        this.isAttack = false;
        this.isAutoAttack = false;
        this.isDamage = false;
        this.isImpact = true;
 
        this.isDead = true;
        
 
    }
 
    void Update()
    {
 
        if (this.isMove)
        {
            this.elapsedTime = Time.deltaTime;
            this.distance = Vector3.Distance(this.transform.position, this.targetTrans.position);
 
            this.transform.Translate(this.speed * this.elapsedTime * Vector3.forward);
 
            if (distance <= 0.05f)
            {
 
                this.Stop();
                this.isMove = false;
 
 
                if (this.targetName == "Monster")
                {
                    this.Attack();
                }
 
 
            }
 
        }
 
        if (this.isAttack)
        {
            this.elapsedTimeAttack += Time.deltaTime;
 
            if (this.elapsedTimeAttack >= this.animStateAttack.length)
            {
                this.Stop();
                this.elapsedTimeAttack = 0;
                this.isAttack = false;
            }
 
 
        }
 
        if (!this.isImpact)
        {
            this.elapsedTimeImpact += Time.deltaTime;
 
            if (this.elapsedTimeImpact >= this.impactTime)
            {
 
                this.elapsedTimeImpact = 0;
                this.monster.Damage(this.damage);
                this.isImpact = true;
                
 
                //인게임에서 이펙트를 생성해줄 대리자 호출할거임
                //null인거 안걸러내면 null reference 오류ㅜㅜ
                if (this.OnImpact != null)
                {
                    this.OnImpact();
                }
            }
        }
 
        //자동 이동 -> 자동 공격
        if (this.isAutoMove)
        {
 
            this.elapsedTime = Time.deltaTime;
            this.distance = Vector3.Distance(this.transform.position, this.targetTrans.position);
 
            this.transform.Translate(this.speed * this.elapsedTime * Vector3.forward);
 
            if (distance <= 0.05f)
            {
                this.Stop();
                this.isAutoMove = false;
                this.isAutoAttack = true;
 
            }
        }
 
        //자동 공격 -> 자동 이동
        if (this.isAutoAttack)
        {
            this.delayTime += Time.deltaTime;
 
            if (this.delayTime >= 2.5f)
            {
                this.Attack();
                this.delayTime = 0;
            }
            //몬스터가 죽었다고 알리는 대리자 한개를 InGame과 hero에서 동시에 부르면
            //여기서만 동작해서 새로 만듬
            this.monster.onMonsterDieNotiHero = () =>
            {
                this.isAutoAttack = false;
                this.AutoMove();
            };
 
        }
        
        if(this.isDamage)
        {
            this.elapsedTimeDamage += Time.deltaTime;
 
            if(this.elapsedTimeDamage>=this.animStateDamage.length)
            {
                this.Stop();
                this.elapsedTimeDamage = 0;
                this.isDamage = false;
            }
        }
 
        if(this.isDead)
        {
            this.elasedTimeDie += Time.deltaTime;
 
            if(this.elasedTimeDie >=this.animStateDie.length)
            {
                this.elasedTimeDie = 0;
                this.isDead = false;
 
                if(this.onDie !=null)
                {
                    this.onDie();
                }
            }
        }
       
 
    }
}
 

 

 

12. Monster 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
 
public class Monster : MonoBehaviour
{
    private float hp;   //몬스터의 체력
    private float exp;  //몬스터가 주는 경험치
    private Animation anim;
    private AnimationState animState;
    private float impactTime;
    private bool isImpact;
    private float elapsedTimeDamage;
    private bool isDamage;
    private float elapsedTimeImpact;
    private bool isDead;
    private AnimationState animStateDead;
    private float elapsedTimeDead;
    private float elapsedTimeAttack;
    private AnimationState animStateAttack;
    private bool isAttack;
    private GameObject heroGo;
    private Hero hero;
    private UIHeroState uiHeroState;
    private float impactAttackTime;
    private float imapctAttackFrame = 19;
    private bool isImpactAttack;
    private float elapsedTimeImpactAttack;
 
    public int damage = 100;
    public UnityAction onMonsterDie;            //몬스터가 죽었음을 InGame에 알림
    public UnityAction onMonsterDieNotiHero;    //몬스터가 죽었음을 Hero에게 알림
    public UnityAction onMonsterImpact;
   
    void Start()
    {
        
    }
 
    public void Init(GameObject model)
    {
        this.hp = 10;
        this.exp = 5;
        this.anim = model.GetComponent<Animation>();
 
        this.uiHeroState = GameObject.FindObjectOfType<UIHeroState>();
       
 
        this.animState = this.anim["Anim_Damage"];
 
        float impactFrame = 6;
        float totalFrame = this.animState.length * this.animState.clip.frameRate;
 
        this.impactTime = impactFrame * this.animState.length / totalFrame;
 
        this.isImpact = true;
        this.animStateDead = this.anim["Anim_Death"];
 
 
        this.animStateAttack = this.anim["Anim_Attack"];
        float totalFrameAttack = this.animStateAttack.length * this.animStateAttack.clip.frameRate;
        this.impactAttackTime = this.imapctAttackFrame * this.animStateAttack.length / totalFrameAttack;
 
        this.isImpactAttack = true;
 
    }
 
    public void Damage(float damage)
    {
        this.heroGo = GameObject.Find("Hero");
        this.hero = heroGo.GetComponent<Hero>();
        this.transform.LookAt(this.heroGo.transform);
 
 
        this.anim.Play("Anim_Damage");
 
        this.isDamage = true;
        this.isImpact = false;
        this.hp -= damage;
 
        Debug.LogFormat("몬스터가 입은 데미지: {0}, 몬스터의 남은 체력: {1}", damage, this.hp);
 
        if(this.hp <= 0)
        {
            this.hp = 0;
 
            this.Die();
        }
 
        
    }
 
    public void Die()
    {
        this.anim.Play("Anim_Death");
        this.isImpact = true;
        this.isDamage = false;
        this.isDead = true;
 
    }
 
    public void Stop()
    {
        this.anim.Play("Anim_Idle");
        this.isDamage = false;
        this.isAttack = false;
    }
 
    public void Attack()
    {
        this.anim.Play("Anim_Attack");
        this.isAttack = true;
        this.isImpactAttack = false;
    }
 
    void Update()
    {
        if (this.isAttack)
        {
            this.elapsedTimeAttack += Time.deltaTime;
            
            if (this.elapsedTimeAttack >= this.animStateAttack.length)
            {
                this.Stop();
                this.elapsedTimeAttack = 0;
            }
        }
 
 
        if(!this.isImpactAttack)
        {
            this.elapsedTimeImpactAttack += Time.deltaTime;
 
            if(this.elapsedTimeImpactAttack >= this.impactAttackTime)
            {
                this.isImpactAttack = true;
                this.hero.Damage();
                this.elapsedTimeImpactAttack = 0;
                
                if(this.onMonsterImpact !=null)
                {
                    this.onMonsterImpact();
                }
            }
        }
 
        if (this.isDamage)
        {
            this.elapsedTimeDamage += Time.deltaTime;
            if(elapsedTimeDamage>=this.animState.length)
            {
                
                this.elapsedTimeDamage = 0;
                this.Attack();
                this.isDamage = false;
            }
        }
 
 
        if (!this.isImpact)
        {
            this.elapsedTimeImpact += Time.deltaTime;
 
            if (this.elapsedTimeImpact >= this.impactTime)
            {
 
                this.elapsedTimeImpact = 0;
 
                this.isImpact = true;
 
                
 
            }
        }
 
        if(this.isDead)
        {
            this.elapsedTimeDead += Time.deltaTime;
 
            if (this.elapsedTimeDead >= this.animStateDead.length)
            {
                this.elapsedTimeDead = 0;
                this.isDead = false;
 
                if(this.onMonsterDie !=null)
                {
                    this.onMonsterDie();
                }
                if (this.onMonsterDieNotiHero != null)
                {
                    this.onMonsterDieNotiHero();
                }
            }
        }
    }
}