---
# System prepended metadata

title: 類別 Class

---

# 類別 Class
回顧我們用 `dictionary` 做 RPG：

```python=
role_1 = {'hp':100, 'attack': 13, 'name':'kyle', 'magic':11}
role_2 = {'hp':123, 'attack': 34, 'name':'Steven',  'maxic':13}

print('%s has %s hp and his attack is %s.' % (role_1['name'], role_1['hp'], role_1['attack']))
```
用這個方法，我們可以存取 `role_1`、`role_2`的各類數值。但缺點一，若今天角色要新增`magic`這個參數，則全部都要新增，而且可能打錯字。缺點二，現在還看不出來xD

讓我們接著看如果用 `class` 會怎麼樣：
```python=
class role:
    def __init__(self, hp, attack, name, gender):
        self.hp = hp
        self.attack = attack
        self.name = name
        self.gender = gender

kyle = role(hp=100, attack=13, name='Kyle', gender='male')

print(kyle.hp)
# 100
```
我們的起手式是用關鍵字 `class` 後面定義名稱。
這邊先定義一個 `__init__`的函數，是初始化的意思，也就是說我們要建立一個 `role` 物件，需要哪些東西，就會在這邊定義。

第8行的地方，我們建立了一個 `role`，將其用參數 `kyle`儲存，並以相關參數來初始化他。

目前為止其實還看不太出來使用 `class` 優於 `dictionary` 的地方。

你可以試試看，如果今天建立一個 `role`，但沒有寫到 `gender` 參數會怎樣？應該是會報錯！
這是正確的！因為報錯你才知道要修改～藉由我們 `class` 的規定，你在寫程式時就不會忘記把 `role`的每個參數寫進去，因為沒寫或寫錯會報錯。

但如果好處僅於此好像也還好，讓我們再往下新增定義一個 `description` 的「方法」。
```python=
class role:
    coordinate = {'x':0, 'y':0}
    def __init__(self, hp, attack, name, gender):
        self.hp = hp
        self.attack = attack
        self.name = name
        self.gender = gender
        
    def description(self):
        if self.gender == 'male':
            print('%s has %s hp and his attack is %s.' % (self.name, self.hp, self.attack))
        elif self.gender == 'female':
            print('%s has %s hp and her attack is %s.' % (self.name, self.hp, self.attack))
        else:
            print('%s has %s hp and his/her attack is %s.' % (self.name, self.hp, self.attack))
            
kyle = role(hp=100, attack=13, name='Kyle', gender='male')

kyle.description()
```
如果你新增任何 `role` 都可以使用個方法。你只要事先寫好你要的模板即可。

再來我們可以增加更多的方法：
- `fight_with(oppent)` ：跟某人對打，輸出「贏」或是「輸」。
- `move(x,y)`：移動x座標x個單位、y座標y個單位。你會需要有一個參數儲存座標 `coordinate`。


```python=
class role:
    coordinate = {'x':0, 'y':0}
    def __init__(self, hp, attack, name, gender):
        self.hp = hp
        self.attack = attack
        self.name = name
        self.gender = gender
    
    def description(self):
        if self.gender == 'male':
            print('%s has %s hp and his attack is %s.' % (self.name, self.hp, self.attack))
        elif self.gender == 'female':
            print('%s has %s hp and her attack is %s.' % (self.name, self.hp, self.attack))
        else:
            print('%s has %s hp and his/her attack is %s.' % (self.name, self.hp, self.attack))

    def fight_with(self, oppent):
        myHp = self.hp
        hisHp = oppent.hp
        while(hisHp>0 and myHp>0):
            hisHp -= self.attack
            myHp -= oppent.attack
        if hisHp>0:
            print('Lose')
        else:
            print('Win')
            # upgrade
            self.hp += oppent.hp
            self.attack += oppent.attack
            print(f'Now your hp is {self.hp} and your attack is {self.attack}')
    
    def move(self, x, y):
        self.coordinate['x'] += x
        self.coordinate['y'] += y
        print('Step on (%2s, %2s)' % (self.coordinate['x'], self.coordinate['y']))
        



kyle = role(hp=100, attack=13, name='Kyle', gender='male')
steven = role(hp=123, attack=34, name='Steven', gender='male')
Amber = role(hp=10000, attack = 346, name = 'Amber', gender='female')
# hardcode
print('%s has %s hp and his attack is %s.' % (kyle.name, kyle.hp, kyle.attack))
print('%s has %s hp and his attack is %s.' % (steven.name, steven.hp, steven.attack))

# use function
kyle.description()
Amber.description()

# fight
kyle.fight_with(Amber)
Amber.fight_with(kyle)

# move
kyle.move(3,4)
kyle.move(31,41)

```

在 `class` 裡面定義方法時，你會發現很常把「`self`」加進去。他的意思就是「呼叫自己」。例如當你定義「`self.hp`」，那麼`kyle`使用就會變成 `kyle.hp`。

## 小練習
[用clss定義點跟線](https://replit.com/team/LinYeh/class-point-and-segment)

# RPG-class
- x座標移動a單位(a) 讓x座標增加a
- y座標移動b單位(b): 讓y座標增加b
- 與角色距離(角色): 回傳兩者距離
- 攻擊角色(角色): 敵方血量減少我方攻擊力
- 顯示資訊: 顯示角色名稱、位置、攻擊、血量