はじめに
プログラミングを学び続けると、繰り返し使用する処理を一塊に纏めて再利用したくなります♪
その最初のステップは、関数になるでしょう。
同じ処理をしている箇所を抜き出し、名前を付けて、プログラム内で呼び出せるようにする。
関数を使いこなせると、プログラムがスッキリした形で書けるようになります。
さらにステップアップしたい時に学ぶのが、今回紹介するクラスでしょう。
クラスは、Pythonを始めとするオブジェクト指向プログラミングの重要な要素です。
このクラスを使いこなすことで、プログラムは更に洗練されていきます。
しかし、このクラスを初めの人は、ちょっと取っ付きにくく感じるかもしれません。
(実際、私もよく分かりませんでした・・・)
今回は、「クラスを初めて学ぶ」、「よく分からなくて苦手」という人向けに、取っ付きやすい例を使って説明します。
クラスとは何か?
Wikipediaによると、次のように説明されています。
オブジェクト指向プログラミングにおけるクラス(英: class)とは、オブジェクトを生成するための設計図あるいはひな形に相当するものである。抽象データ型の一つ。クラスから生成したオブジェクトの実体のことをインスタンスという。
https://ja.wikipedia.org/wiki/クラス_(コンピュータ)
クラスには、クラス自身またはクラスのインスタンスが保持するデータと、データに関連したオブジェクトの振る舞いを記述できる。プログラミング言語によっては、それぞれにアクセス修飾子(英語版)を指定できる。統一モデリング言語 (UML) のクラス図では、データのことを「属性」、振る舞いのことを「操作」と呼ぶ。Javaなどでは、データのことを「フィールド」、振る舞いのことを「メソッド」と呼ぶ。C++などでは、データのことを「メンバー変数」、振る舞いのことを「メンバー関数」と呼ぶ。
・・・(以降は割愛)・・・
この説明を読んで「なるほど!」と思う人は、既にクラスに対して、深い理解がある方だと思います。
ただ、初学者には分かりにくいですよね・・・
そのため、この説明からポイントを抜き出してみましょう。
(2) クラスは、データ型の1つである。
(3) クラスは、「データ」と「処理」でできている。
ゲームのキャラクターを生成する「クラス」
クラスの説明には、様々な例(鋳物、たい焼き、、、など)が用いられます。
(私の感性の問題ですが)これらの例では「設計図/雛形」や「データ」は何となく理解できます。
しかし、「処理」についてはよく分かりませんでした。
・・・たい焼きの処理ってナニ??
そこで、私は具体例として「ゲームのキャラクター」を使って説明することにしました。
まず、ゲームのキャラクターに必要な要素を「データ」と「処理」の観点で考えてみましょう。
「データ」では、名前、体力(HP)、攻撃力、防御力、経験値などなど
「処理」では、攻撃する、防御する、レベルアップなどなど
主人公、仲間、敵、などを限りなくシンプルに考えると、根本は同じように思えます。
※敵は倒されて終わりなので、レベルアップしませんが・・・
つまり、「キャラクター」という設計図(雛形)を作り、その設計図を使って主人公も、仲間も、敵も作れればプログラムがとてもシンプルになります。
サンプルプログラム
イメージに触れたところで、早速プログラミングに入りましょう!!
全体像
このプログラムでは、Characterクラスを作成しています。
そして、Characterクラスから、主人公(mainChar)とヒロイン(heroineChar)というインスタンスを作っています。
class Character() :
# クラス変数
charaName = ''
hitPoint = 0
attackPoint = 0
defensePoint = 0
# コンストラクター
def __init__(self):
self.charaName = input('キャラクタ-の名前を入力してください:')
print('- - - キャラクタ-作成完了 - - -')
print(f'キャラクタ-の名前は「{self.charaName}」に設定されました。')
self.hitPoint = 100
self.attackPoint = 10
self.defensePoint = 10
self.showStatus()
# ステータス表示
def showStatus(self):
print(f'「{self.charaName}」のステータスは、体力:{self.hitPoint}、攻撃力:{self.attackPoint}、防御力:{self.defensePoint}です。')
# 敵に攻撃する
def attackEnemy(self, enemyName, enemyDefensePoint):
# 自分の攻撃は、「自分の攻撃力 - 敵の防御力」
# ※ただし、マイナスの場合は「0」となる
attack = max(0, self.attackPoint - enemyDefensePoint)
# 結果を表示
print(f'{self.charaName} は、{enemyName} に、「{attack}」の攻撃!')
# 敵から攻撃を受ける
def defenseEnemy(self, enemyName, enemyAttackPoint):
# 相手の攻撃は、「敵の攻撃力 - 自分の防御力」
attack = max(0, enemyAttackPoint - self.defensePoint)
# 攻撃を受けたら、体力が減少
self.hitPoint -= attack
# 結果を表示
print(f'{self.charaName} は、{enemyName} から、「{attack}」の攻撃を受けた・・・')
self.showStatus()
#================
# メイン処理
#================
print(' - - - - - 主人公を作成して戦闘 - - - - - ')
mainChar = Character()
# モンスター(防御力:4)に攻撃する
mainChar.attackEnemy('モンスター', 4)
# モンスター(攻撃力:15)から攻撃を受ける
mainChar.defenseEnemy('モンスター', 15)
print(' - - - - - ヒロインを作成して戦闘 - - - - - ')
# ヒロインを作成
heroineChar = Character()
# モンスター(防御力:6)に攻撃する
heroineChar.attackEnemy('モンスター', 6)
# モンスター(攻撃力:20)から攻撃を受ける
heroineChar.defenseEnemy('モンスター', 20)
print(' - - - - 戦闘後にステータスを確認 - - - - ')
mainChar.showStatus()
heroineChar.showStatus()
ポイントの解説
クラスの定義
クラスを定義するには、「class [クラス名]([引数1], [引数2], ・・・):」と記述します。
※関数と似ていますね。
class Character() :
クラス変数
クラス変数とは、クラスに紐付けて使用できる変数です。
ここでは、変数を初期化するために「空白」や「0」を代入しています。
# クラス変数
charaName = ''
hitPoint = 0
attackPoint = 0
defensePoint = 0
クラスメソッド(クラス関数)
クラスメソッドとは、クラスに紐付けて使用できる処理(関数)です。
クラスメソッドは、通常の関数と同様に「def [処理名](self, [引数1], [引数2], ・・・):」と記述します。
# 敵に攻撃する
def attackEnemy(self, enemyName, enemyDefensePoint):
# 自分の攻撃は、「自分の攻撃力 - 敵の防御力」
# ※ただし、マイナスの場合は「0」となる
attack = max(0, self.attackPoint - enemyDefensePoint)
# 結果を表示
print(f'{self.charaName} は、{enemyName} に、「{attack}」の攻撃!')
クラスメソッドの中には、インスタンス生成時に自動実行される「コンストラクター」、インスタンス削除時に自動実行される「デストラクター」という特別なクラスメソッドがあります。
コンストラクターは「def __init__(self):」、デストラクターは「def __del__(self):」
# コンストラクター
def __init__(self):
self.charaName = input('キャラクタ-の名前を入力してください:')
print('- - - キャラクタ-作成完了 - - -')
print(f'キャラクタ-の名前は「{self.charaName}」に設定されました。')
self.hitPoint = 100
self.attackPoint = 10
self.defensePoint = 10
self.showStatus()
インスタンスの生成(クラスの呼び出し)
クラスとは、所詮は設計図に過ぎません。
そのため、設計図を元に実体(インスタンス)を作り出さなければ、使い物になりません。
以下の処理では、Characterクラスを使って、mainCharインスタンスを作っています。
print(' - - - - - 主人公を作成して戦闘 - - - - - ')
mainChar = Character()
これによって、mainCharインスタンスは、名前(name)やHP(hitPoint)などのクラス変数、攻撃する(attackEnemy)などのクラスメソッドが使えるようになりました。
# モンスター(防御力:4)に攻撃する
mainChar.attackEnemy('モンスター', 4)
# モンスター(攻撃力:15)から攻撃を受ける
mainChar.defenseEnemy('モンスター', 15)
プログラムの実行
VSCodeの機能を使って、実際にプログラムを実行してみます。
このプログラムでは、Characterクラスを使って、主人公を作って戦闘(攻撃/防御)をしました。
さらに、ヒロインを作って戦闘(攻撃/防御)をして、最後にステータスを確認しています。
Characterクラスという共通の設計図を使って、2つのキャラクターを作り、戦闘をさせることができました。
最後に
クラスが苦手な人には、「クラスを使わなくてもプログラムを作る」と思っている方もいるでしょう。たしかにその通りで、古いプログラミング言語にはクラスという概念すらない物もあります。
しかし、クラスは先人たちがプログラムをシンプルで美しく書くために考え出した方法です。
改善を続けて産まれた物なので、これを使わない手はないでしょう!
今回の記事が、みなさんがクラスを使うきっかけになってくれると嬉しいです。
最後の最後に、このゲームキャラクターは、固定の設定が多くて物足りないですよね(笑)
キャラクター生成時のステータスは、乱数を使ってバラツキを持たせると面白いでしょう。
攻撃/防御も乱数を使ったり、水や炎など「属性(タイプ)」の影響も加えたいです。
何より、戦ってもレベルが上がらないのではモチベーションも湧きません。
ぜひ、このプログラムを改造して、自分だけのゲームを作ってみてください!
コメント