Character의 Move, Attack, MoveAttack 구현

C#/과제 2019. 4. 8. 21:16

1. Champion(애니비아)가 Monster(바론남작)을 향해 Move, Attack, MoveAttack(어택땅)하는 것을 구현

2. Vector를 이용하여 이동 속도, 이동 거리, 사거리 계산 및 구현

3. Json을 통하여 저장 및 불러오기가 가능




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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
 
namespace CharacterSystem
{
    public class Character
    {
        public int Hp { get; set; }
        public int Damage { get; set; }
        public int AttackRange { get; set; }
        public string Name { get; set; }
        public float MoveSpeed { get; set; }
 
        public Vector2 position { get; set; }
        public Vector2 targetPosition { get; set; }
        private Vector2 movePoint;
 
        //매개변수 3개 생성자
        public Character(int hp, int damage, int attackRange)
        {
            this.Hp = hp;
            this.Damage = damage;
            this.AttackRange = attackRange;
        }
 
        //이동 메서드
        public virtual void Move(Vector2 movePoint)
        {
            this.movePoint = movePoint;
            var distanceVector = new Vector2(this.movePoint.x - this.position.x, this.movePoint.y - this.position.y); //거리벡터(C)
            var normalizationVector = Vector2.Nomrmalization(distanceVector); //거리벡터의 단위벡터(방향벡터)
            var speedVector = new Vector2(normalizationVector.x * this.MoveSpeed, normalizationVector.y * this.MoveSpeed); //A벡터가 방향벡터로 이동하는 속도벡터
 
            while (true)
            {
                Thread.Sleep(300);
                this.position += speedVector;
                Console.WriteLine("{0}의 현재위치 : ({1}, {2})"this.Name, this.position.x, this.position.y);
                distanceVector = new Vector2(this.movePoint.x - this.position.x, this.movePoint.y - this.position.y); //거리벡터(C)
                if (distanceVector.x <= 0 && distanceVector.y <= 0)
                {
                    this.position = new Vector2(movePoint.x, movePoint.y);
                    Console.WriteLine("도착지점에 도착했습니다.");
                    Console.WriteLine("{0}의 현재위치 : ({1}, {2})"this.Name, this.position.x, this.position.y);
                    break;
                }
                else
                {
                    continue;
                }
            }
        }
 
        //공격 메서드
        public virtual void Attack(Character target, int attackCount)
        {
            var distanceVector = new Vector2(target.position.x - this.position.x, target.position.y - this.position.y);
            var distance = Vector2.GetLenght(distanceVector);
            if (distance <= this.AttackRange)
            {
                for(int i=0; i<attackCount; i++)
                {
                    target.TakeDamage(this.Damage);
                    Console.WriteLine("{0}회차 공격! {1}에게 {2}의 데미지를 입혔습니다!", i+1, target.Name, this.Damage);
                    Thread.Sleep(300);
                    Console.WriteLine("{0}의 남은 체력 : {1}", target.Name, target.Hp);
                }
            }
            else
            {
                Console.WriteLine("사거리가 닿지 않습니다.");
            }
 
        }
 
        //피해 메서드
        public virtual void TakeDamage(int damage)
        {
            this.Hp -= damage;
        }
 
        //이동공격 메서드
        public virtual void MoveAttack(Character target)
        {
            this.targetPosition = target.position;
            var distanceVector = new Vector2(target.position.x - this.position.x, target.position.y - this.position.y); //거리벡터
            var normalizationVector = Vector2.Nomrmalization(distanceVector); //거리벡터의 단위벡터
            var speedVector = new Vector2(normalizationVector.x * this.MoveSpeed, normalizationVector.y * this.MoveSpeed); //A벡터가 이동하는 속도벡터
            var distance = Vector2.GetDistance(this.targetPosition, this.position);
            var selectAttackContinue = ConsoleKey.D1;
 
            while (selectAttackContinue != ConsoleKey.N)
            {
                Thread.Sleep(300);
                distance = Vector2.GetDistance(this.targetPosition, this.position);
                if(target.Hp <= 0)
                {
                    Console.WriteLine("{0}가 죽었습니다.", target.Name);
                    break;
                }
                if (distance <= this.AttackRange)
                {
                    Console.WriteLine("{0}이 {1}의 공격사거리안에 들어왔습니다.\n공격을 시작합니다.", target.Name, this.Name);
                    for(int i=0; target.Hp > 0; i++)
                    {
                        target.Hp -= this.Damage;
                        Console.WriteLine("\n{0}회차 공격! {1}에게 {2}의 데미지를 입혔습니다!", i + 1, target.Name, this.Damage);
                        Console.WriteLine("{0}의 남은 체력 : {1}", target.Name, target.Hp);
                        Console.Write("계속 공격하시겠습니까? (Y/N) : ");
                        selectAttackContinue = Console.ReadKey().Key;
                        if(selectAttackContinue != ConsoleKey.Y)
                        {
                            Console.WriteLine("공격을 중지합니다.");
                            Thread.Sleep(1000);
                            break;
                        }
                    }
                }
                else if(distance >= this.AttackRange)
                {
                    Console.WriteLine("사거리가 닿지 않아 타겟을 향해 이동합니다.");
                    this.position += speedVector;
                }
            }
        }
    }
}
 
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace CharacterSystem
{
    public class Champion : Character
    {
 
        //매개변수 3개 생성자
        public Champion(int hp, int damage, int attackRange) : base(hp, damage, attackRange)
        {
 
        }
    }
}
 
cs



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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
 
namespace CharacterSystem
{
    public class Anivia : Champion
    {
 
        //매개변수 3개 생성자
        public Anivia(int hp, int damage, int attackRange) : base(hp, damage, attackRange)
        {
            this.Name = "애니비아";
            this.MoveSpeed = 1.5f;
            this.position = new Vector2(00);
            Console.WriteLine("애니비아 데미지 {0}"this.Damage);
        }
 
        //JsonConstructor
        [JsonConstructor]
        public Anivia(Vector2 position, Vector2 targetPosition, int hp, int damage, int attackRange, string name, float moveSpeed) : base(hp, damage, attackRange)
        {
            this.position = position;
            this.targetPosition = targetPosition;
            this.Name = name;
            this.MoveSpeed = moveSpeed;
        }
    }
}
 
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace CharacterSystem
{
    public class Monster : Character
    {
 
        //매개변수 3개 생성자
        public Monster(int hp, int damage, int attackRange) : base (hp, damage, attackRange)
        {
 
        }
    }
}
 
cs



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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
 
namespace CharacterSystem
{
    public class BaronNashor : Monster
    {
 
        //매개변수 3개 생성자
        public BaronNashor(int hp, int damage, int attackRange) : base(hp, damage, attackRange)
        {
            this.Name = "내셔남작";
            this.position = new Vector2(1515);
            this.targetPosition = new Vector2(00);
        }
 
        //저장된 데이터 기반 생성자
        public BaronNashor(int hp, int damage, int attackRange, string name, Vector2 position) : base(hp, damage, attackRange)
        {
            this.Name = name;
            this.position = position;
        }
 
        public override void Move(Vector2 movePoint)
        {
            Console.WriteLine("{0}은 이동할 수 없습니다.");
        }
 
        [JsonConstructor]
        public BaronNashor(Vector2 position, Vector2 targetPosition, int hp, int damage, int attackRange, string name, float moveSpeed) : base(hp, damage, attackRange)
        {
            this.position = position;
            this.targetPosition = targetPosition;
            this.Name = name;
            this.MoveSpeed = moveSpeed;
        }
    }
}
 
cs



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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace CharacterSystem
{
    public class Vector2
    {
        public float x;
        public float y;
 
        //생성자
        public Vector2(float x, float y)
        {
            this.x = x;
            this.y = y;
        }
 
        //Vector2 Class Operator Overload
        public static Vector2 operator+(Vector2 a, Vector2 b)
        {
            return new Vector2(a.x + b.x, a.y + b.y);
        }
        public static Vector2 operator -(Vector2 a, Vector2 b)
        {
            return new Vector2(a.x - b.x, a.y - b.y);
        }
        public static Vector2 operator *(Vector2 a, Vector2 b)
        {
            return new Vector2(a.x * b.x, a.y * b.y);
        }
        public static Vector2 operator /(Vector2 a, Vector2 b)
        {
            return new Vector2(a.x / b.x, a.y / b.y);
        }
 
        //Distance
        public static float GetDistance(Vector2 position, Vector2 targetPosition)
        {
            return (float)Math.Sqrt(Math.Pow(position.x - targetPosition.x, 2+ Math.Pow(position.y - targetPosition.y, 2));
        }
 
        //Nomalization
        public static Vector2 Nomrmalization(Vector2 vector)
        {
            return new Vector2(vector.x / Vector2.GetLenght(vector), vector.y / Vector2.GetLenght(vector));
        }
 
        //Lenght
        public static float GetLenght(Vector2 vector)
        {
            return (float)Math.Sqrt((vector.x * vector.x) + (vector.y * vector.y));
        }
    }
}
 
cs



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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Threading;
using System.IO;
 
namespace CharacterSystem
{
    public class GameLauncher
    {
        public ConsoleKey menuKey;
        public ConsoleKey secondMenuKey;
        private DataStorage dataStorage;
 
        private BaronNashor baron;
        private Anivia anivia;
 
        //생성자
        public GameLauncher(DataStorage dataStorage)
        {
            Console.WriteLine("GameLauncher 생성자 호출");
            this.dataStorage = dataStorage;
        }
 
        //게임실행 메서드
        public void Start()
        {
            while (menuKey != ConsoleKey.D3)
            {
                Console.WriteLine("바론남작 죽이기 게임");
                Console.WriteLine("1.새로하기 2.불러오기 3.종료하기");
                menuKey = Console.ReadKey().Key;
                if(menuKey == ConsoleKey.D3)
                {
                    Console.WriteLine("바론남작 죽이기 게임을 종료합니다.");
                    break;
                }
                else if(menuKey == ConsoleKey.D1 || menuKey == ConsoleKey.D2)
                {
                    this.CreateData(menuKey);
                    Console.WriteLine("게임을 시작합니다.");
                    Thread.Sleep(1000);
                }
                else
                {
                    Console.WriteLine("잘못된 입력입니다.");
                    continue;
                }
                while(secondMenuKey != ConsoleKey.D7)
                {
                    this.ChoiceSecondMenu();
                    switch(secondMenuKey)
                    {                        
                        case ConsoleKey.D1:
                            Console.WriteLine("현재 {0}의 위치 : ({1}, {2})"this.baron.Name, this.baron.position.x, this.baron.position.y);
                            Console.WriteLine("나와의 거리 : {0}", Vector2.GetDistance(this.anivia.position, this.baron.position));
                            Console.ReadKey();
                            break;
                        case ConsoleKey.D2:
                            Console.WriteLine("현재 나의 위치 : ({0}, {1})"this.anivia.position.x, this.anivia.position.y);
                            Console.WriteLine("바론과의 거리 : {0}", Vector2.GetDistance(this.anivia.position, this.baron.position));
                            Console.ReadKey();
                            break;
                        case ConsoleKey.D3:
                            Console.Write("어디까지 이동하시겠습니까?(x y공백으로 구분하여 입력) : ");
                            int x, y;
                            var tempStr = Console.ReadLine();
                            string[] tempStrArr = tempStr.Split(' ');
                            Int32.TryParse(tempStrArr[0], out x);
                            Int32.TryParse(tempStrArr[1], out y);
                            anivia.Move(new Vector2(x, y));
                            break;
                        case ConsoleKey.D4:
                            Console.Write("몇회 공격하시겠습니까? (최대 10회) : ");
                            int attackCount;
                            if (Int32.TryParse(Console.ReadLine(), out attackCount))
                            {
                                anivia.Attack(baron, attackCount);
                            }
                            else
                            {
                                Console.WriteLine("잘못된 입력입니다.");
                            }
                            break;
                        case ConsoleKey.D5:
                            this.anivia.MoveAttack(baron);
                            break;
                        case ConsoleKey.D6:
                            this.UpdateData();
                            var aniviaJson = JsonConvert.SerializeObject(this.anivia);
                            File.WriteAllText("./data/anivia_data.json", aniviaJson, Encoding.UTF8);
                            var baronJson = JsonConvert.SerializeObject(this.baron);
                            File.WriteAllText("./data/baron_data.json", baronJson, Encoding.UTF8);
                            //this.UpdateData();
                            //var json = JsonConvert.SerializeObject(this.dataStorage.listCharacter);
                            //File.WriteAllText("./data/character_data.json", json, Encoding.UTF8);
                            //Console.WriteLine("저장을 완료했습니다! 게임을 종료합니다.");
                            Thread.Sleep(1000);
                            secondMenuKey = ConsoleKey.D7;
                            menuKey = ConsoleKey.D3;
                            break;
                        default:
                            Console.WriteLine("잘못된 입력입니다.");
                            break;
                    }
                }
                
            }
 
 
 
        }
 
        //데이터 생성 Method
        public void CreateData(ConsoleKey menuKey)
        {
            if(menuKey == ConsoleKey.D1)
            {
                //새로하기일 경우 초기값의 인스턴스 생성
                this.baron = new BaronNashor(1000010010);
                Console.WriteLine("{0}생성, 체력:{1}, 데미지:{2}, 사거리:{3}", baron.Name, baron.Hp, baron.Damage, baron.AttackRange);
                this.anivia = new Anivia(550255);
                Console.WriteLine("{0}생성, 체력:{1}, 데미지:{2}, 사거리:{3}", anivia.Name, anivia.Hp, anivia.Damage, anivia.AttackRange);
                Directory.CreateDirectory("./data/");
            }
            else if(menuKey == ConsoleKey.D2)
            {
                if(!(File.Exists("./data/anivia_data.json"|| File.Exists("./data/baron_data.json")))
                {
                    Console.WriteLine("저장된 데이터가 없습니다.");
                    Directory.CreateDirectory("./data/");
                    this.baron = new BaronNashor(1000010010);
                    Console.WriteLine("{0}생성, 체력:{1}, 데미지:{2}, 사거리:{3}", baron.Name, baron.Hp, baron.Damage, baron.AttackRange);
                    this.anivia = new Anivia(550255);
                    Console.WriteLine("{0}생성, 체력:{1}, 데미지:{2}, 사거리:{3}", anivia.Name, anivia.Hp, anivia.Damage, anivia.AttackRange);
                }
                else
                {
                    //애니비아 데이터 불러오기
                    var aniviaStr = File.ReadAllText("./data/anivia_data.json");
                    var aniviaArr = JsonConvert.DeserializeObject<Anivia>(aniviaStr);
                    this.anivia = aniviaArr;
 
                    //바론 데이터 불러오기
                    var baronStr = File.ReadAllText("./data/baron_data.json");
                    var baronArr = JsonConvert.DeserializeObject<BaronNashor>(baronStr);
                    this.baron = baronArr;
 
                    //생성 확인
                    Console.WriteLine("{0}생성, 체력:{1}, 데미지:{2}, 사거리:{3}", baron.Name, baron.Hp, baron.Damage, baron.AttackRange);
                    Console.WriteLine("{0}생성, 체력:{1}, 데미지:{2}, 사거리:{3}", anivia.Name, anivia.Hp, anivia.Damage, anivia.AttackRange);
                }
            }
        }
 
        //공격, 이동, 어택땅 선택 Method
        public void ChoiceSecondMenu()
        {
            Console.WriteLine("1.바론위치보기 2.내위치보기 3.이동하기 4.공격하기 5.어택땅 6.저장하고 돌아가기");
            this.secondMenuKey = Console.ReadKey().Key;
        }
 
        //데이터 업데이트 Method
        public void UpdateData()
        {
            this.dataStorage.listCharacter.Add(this.anivia);
            this.dataStorage.listCharacter.Add(this.baron);
        }
    }
}
 
cs



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;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace CharacterSystem
{
    public class App
    {
        private GameLauncher gameLauncher;
        private DataStorage dataStorage;
        public App()
        {
            Console.WriteLine("App 생성자 호출");
            this.DataLoad();
            this.gameLauncher = new GameLauncher(this.dataStorage);
        }
 
        public void Start()
        {
            this.gameLauncher.Start();
        }
 
        public void DataLoad()
        {
            this.dataStorage = DataStorage.GetDataStorage();
        }
    }
}
 
cs





Anivia Class 와 BaronNashor Class에서 [JsonConstructor]라는 것이 있다.

이는 Newtonsoft.Json에서 지원하는 기능 중 하나로, JsonFile을 로드하여 그 File의 값을 통해 인스턴스를 생성할 때,

그에 맞는 Json전용 Constructor(생성자)를 선언할 수 있게 해주는 도구이다.



JsonConstructorAttribute (NewtonJson)

https://www.newtonsoft.com/json/help/html/JsonConstructorAttribute.htm


'C# > 과제' 카테고리의 다른 글

롤 구현하기  (0) 2019.04.10
Inventory + Singleton  (0) 2019.04.07
Hash란?  (0) 2019.04.04
13. 인벤토리 구현하기  (0) 2019.03.27
12. WoW 캐릭터 생성 과제 (2단계+α 까지 완료)  (0) 2019.03.27
: