ゲーム作成に役立つオブジェクト指向6
はじめに
前回のInterpreterパターンは、
そのままではゲームに使うことはできません。
それは、
Nodeクラスに、キャラの行動パターンを記述しなければならない
からです。
それを回避する方法がVisitorパターンです。
Visitorパターンとは?
Visitorとは、「訪問者」のことです。
今回の例で言えば、敵オブジェクト(Enemy)が「訪問者」です。
そして、その受け入れ先が、構文解析クラス(Node以下)となります。
EnemyがNodeをぐるぐる回りながら、スクリプトの命令を実行する、
というようなイメージになります。
クラス図は?
前回との大きな違いは、
- ITaskインターフェース、Enemyクラスの追加
- NondeのparseメソッドのパラメータにEnemyを追加
ということになります。
ITaskというのは、タスクシステムの「タスク」ですね。
これを継承してEnemyクラスを実装します。
parseメソッドのパラメータにEnemyがあるのは、
Nodeの中をぐるぐる回るためですね。
さて、ほかにもクラスが増えていますが、
TopNode/RepeatingNodeは、「NonterminalNode」にあたり、
AttackingNode/MovingNode/ExplodingNodeは「TerminalNode」にあたります。
処理の流れは?
- Enemyクラスの生成
- Contextクラスを生成し、スクリプトを読み込ませる
- TopNodeクラスを生成し、parseメソッドにContext、thisポインタを渡す。
というのがNodeの入り口までの流れです。
そうしてNodeの中をぐるぐる回っているうちに、
「TerminalNode」に達します。
そうした場合には、パラメータのenemy.execScriptメソッドに、thisポインタを渡します。
これにより、Enemyが動き出すわけです。
なぜ、「TerminalNode」のthisポインタを渡すのかというと、
まず、
- 処理の振り分けができる
ということがあります。
(まあ、ここらへんは好みの問題ではあります。
たとえば、「TerminalNode」を1つにして、if〜else if〜で分けるという手もあります)
さらに、
例えば、攻撃したりする場合には、
「どの攻撃方法で攻撃するか?」
という情報や、
移動する場合には、
「どこに移動するのか?」
という情報が必要になります。
それを自フィールドに詰めてあげれば、
Enemy.execSpript内でパラメータを覗くことができるようになるわけです。
ということで、Visitorパターンでしたー。
Pythonで画像処理8
輪郭抽出です。
大きめの画像でやると、そこそこキレイに抽出できますね。
import pygame import math _gSrc = None pygame.init() pygame.display.set_mode((150, 150), 0, 32) pygame.display.set_caption("輪郭抽出") _gScr = pygame.display.get_surface() tBuf = pygame.image.load("kenmo.jpg").convert() tblGray = [] # グレースケールテーブル作成 for j in range(tBuf.get_height()): w = [] for i in range(tBuf.get_width()): colorA = tBuf.get_at((i, j)) gray = (colorA[0] + colorA[1] + colorA[2]) / 3 w.append(gray) tblGray.append(w) # 輪郭抽出(グラディエント法) for j in range(tBuf.get_height() - 1): for i in range(tBuf.get_width() - 1): # 微分、というか差分 dx = tblGray[j][i+1] - tblGray[j][i] dy = tblGray[j+1][i] - tblGray[j][i] #tblGray[j][i] = math.sqrt(dx ** 2 + dy ** 2) tblGray[j][i] = abs(dx) + abs(dy) # 高速化 # 2値化 AMP = 5 # 出力レベル BLACK = (0, 0, 0, 255) WHITE = (255, 255, 255, 255) for j in range(tBuf.get_height() - 1): for i in range(tBuf.get_width() - 1): if(tblGray[j][i] > AMP): tBuf.set_at((i, j), WHITE) else: tBuf.set_at((i, j), BLACK) while True: _gScr.blit(tBuf, (0, 0), tBuf.get_rect()) pygame.display.update() pygame.time.wait(10)
ノイズが多い場合は出力レベルを上げるとキレイになりますよー。