今回はさらなる改良として、クリアまでのプレーヤーと荷物の動きを動画で再現します。また荷物が動いた時に音が出るようにしました。音源はネットから拾ってきました。「move.wav」という名前でsoukoフォルダに保存しておきましょう。move.wav
souko.pyに以下のメソッドを作ります。
001: def videoPlay(self, map, player): 002: for i in range(len(map.clearedList)): 003: if map.index == map.clearedList[i][0]: # 再挑戦のときに 004: nowList = map.clearedList[i][2] # 選択面のplayerHisをnowListに入れる 005: break 006: for i in range(len(nowList)): # nowListの歩数だけ繰り返す 007: time.sleep(0.3) # 0.3秒待つ 008: screen.fill((0,0,0)) 009: player.x = nowList[i][1][0] # x座標を取得 010: player.y = nowList[i][1][1] # y座標を取得 011: player.move(nowList[i][0], map) # playerを動かして 012: player.drawChar(map, screen) # player以外を描画 013: player.draw1(screen) # playerを描画 向きも正しく 014: pygame.display.update() 015: time.sleep(1) # 1秒待つ 016: map.stage.clear() # stage[]クリア 017: clearFlag = 0 # clearFlagを初期値に戻す 018: self.main()
2-5行では、クリア面の配列clearedList[]から現在開いている面をクリアした時のプレーヤー座標配列playerHis[]を取得し、一時的にnowList[]配列にコピーしています。この場合はディープコピーを使わなくてもいいようです。6行以後はnowList[]配列を使ってプレーヤーの動きを再現・表示しています。動きのスピードは 7行目の数値を調整して下さい。13行目で、新しいメソッドdraw1()を使っています。このメソッドは、以下のようにPlayerクラスに作りました。15行では1秒間だけ再現終了時の画面を表示し、その後ボタンの選択画面になります。なおsleep()メソッドを使っているので、souko.pyにimport timeを追加してくださいね。
def draw1(self,screen): # playerの描画 self.image = self.images[int(self.dir*4 + self.frame/self.animcycle%4)] screen.blit(self.image, (self.x*GS+OFFSET, self.y*GS))
上のメソッドは、Playerクラスにあるdraw()メソッドにanimate()メソッドにある一行を追加しただけです。これで再現時におけるプレーヤーの向きを変化させることができます。再挑戦時に「V」キーを押したら今回作ったメソッドが実行されるようにしましょう。souko.pyのメインループに以下を追加します。
if event.type == KEYDOWN and event.key == K_v: # video player self.videoPlay(map, player) ************************************************************* if player.reFlag == 1: # rePlay時の表示 replay = sysfont.render('oldCounter:'+ str(player.oldCounter), True, (0,255,255)) screen.blit(replay, (0, 160))vplay = sysfont.render('video player : "V" key', True, (0,255,255)) screen.blit(vplay, (0, 190))
次は効果音です。先ずplayers.pyにfrom pygame import mixerとしてインポートしてください。次に荷物を動かすときに音を出すメソッドを作ります。たった3行だけです。そしてこのメソッドを使うのは、荷物を動かすときだけですから、canMoveDown()メソッドなどに追加します。
def bagMoveSound(self): mixer.init() mixer.music.load('move.wav') mixer.music.play(1)
完成したplayers.pyは以下のようになります。players.py
ファイル名:players.py 001:import pygame 002:from pygame.locals import * 003:from pygame import mixer 004:import sys 005:sys.path.append("C:\myPython\module") 006:import loadImage as LI # moduleの利用 007:import splitImage as SI # moduleの利用 008:import copy 009: 010:DOWN, LEFT, RIGHT, UP = 0, 1, 2, 3 011:SCR_RECT = Rect(0, 0, 800, 480) # 画面サイズ 012:OFFSET = 300 013:GS = 32 # 1マスの大きさ[px] 014:screen = pygame.display.set_mode(SCR_RECT.size) 015: 016:class Player: 017: animcycle = 24 # アニメーション速度 018: frame = 0 019: pos = [] 020: 021: def __init__(self, pos, dir): 022: self.pos = pos 023: self.images = SI.splitImage(LI.load_image("images/players.png"),4,4) 024: self.image = self.images[0] # 描画中のイメージ 025: self.dir = dir 026: self.counter = 0 # playerの歩数 027: self.x = pos[0] 028: self.y = pos[1] 029: self.reFlag = 0 030: self.oldCounter = 0 # 前クリア時の歩数 031: 032: # リセット用メソッド 033: def resetStage(self, map): 034: self.counter = 0 035: map.bags = copy.deepcopy(map.bagsHis[0]) 036: map.stored = copy.deepcopy(map.storedHis[0]) 037: self.dir = map.playerHis[0][0] # playerの向きを初期に戻す 038: (self.x, self.y) = map.playerHis[0][1] # playerの座標を初期位置に戻す 039: del map.bagsHis[1:] # index1 を残して全部削除 040: del map.storedHis[1:] # index1 を残して全部削除 041: del map.playerHis[1:] # index1 を残して全部削除 042: 043: # キャラクターアニメーション(frameに応じて描画イメージを切り替える) 044: def animate(self): 045: self.frame += 1 046: self.image = self.images[int(self.dir*4 + self.frame/self.animcycle%4)] 047: 048: # 履歴listを作成 049: def makeHis(self, map): 050: map.playerHis.append((self.dir, (self.x, self.y))) # 現在のplayerを履歴に追加 051: map.bagsHis.append(copy.deepcopy(map.bags)) # 現在のbagsを履歴に追加(bagが移動しない場合でも) 052: map.storedHis.append(copy.deepcopy(map.stored)) # 現在のstoredを履歴に追加(bagが移動しない場合でも) 053: 054: # 一歩戻る 055: def playBack(self, map): 056: if self.counter > 0: 057: map.bagsHis.pop(-1) # 履歴配列最後の要素を削除 058: map.storedHis.pop(-1) 059: map.bags = copy.deepcopy(map.bagsHis[self.counter-1]) # 履歴配列最後の要素をbagsにコピー 060: map.stored = copy.deepcopy(map.storedHis[self.counter-1]) 061: self.dir = map.playerHis[self.counter][0] # dirを更新 062: (self.x, self.y) = map.playerHis[self.counter][1] # (x,y)を更新 063: map.playerHis.pop(-1) # 最後の要素を削除 064: self.counter -= 1 065: 066: def move(self, dir, map): 067: if dir == DOWN: 068: if self.canMoveDown(map): 069: self.dir = DOWN 070: self.makeHis(map) # 履歴listに追加 071: self.counter += 1 072: self.y += 1 073: elif dir == LEFT: 074: if self.canMoveLeft(map): 075: self.dir = LEFT 076: self.makeHis(map) # 履歴listに追加 077: self.counter += 1 078: self.x -= 1 079: elif dir == RIGHT: 080: if self.canMoveRight(map): 081: self.dir = RIGHT 082: self.makeHis(map) # 履歴listに追加 083: self.counter += 1 084: self.x += 1 085: elif dir == UP: 086: if self.canMoveUp(map): 087: self.dir = UP 088: self.makeHis(map) # 履歴listに追加 089: self.counter += 1 090: self.y -= 1 091: 092: def canMoveDown(self, map): 093: if (self.x, self.y+1) in map.blocks: # 行先座標が壁 094: return False 095: elif (self.x, self.y+1) in map.bags: # 行先座標が荷物 096: if (self.x, self.y+2) in map.blocks or (self.x, self.y+2) in map.bags: # さらにその先座標が壁 or 荷物 097: return False 098: else: 099: map.bags.remove((self.x, self.y+1)) # 行先座標をbagsから削除 100:self.bagMoveSound() # 効果音を鳴らす 101: if (self.x, self.y+1) in map.stored: # 行先座標が格納listにあれば 102: map.stored.remove((self.x, self.y+1)) # 行先座標を格納listから削除 103: map.bags.append((self.x, self.y+2)) # その先座標をbagsに追加 104: if (self.x, self.y+2) in map.places: # その先座標が収納場所listにあれば 105: map.stored.append((self.x, self.y+2)) # その先座標を格納listに追加 106: return True 107: else: 108: return True 109: 110: def canMoveUp(self, map): 111: if (self.x, self.y-1) in map.blocks: # 行先座標が壁 112: return False 113: elif (self.x, self.y-1) in map.bags: # 行先座標が荷物 114: if (self.x, self.y-2) in map.blocks or (self.x, self.y-2) in map.bags: # さらにその先座標が壁 or 荷物 115: return False 116: else: 117: map.bags.remove((self.x, self.y-1)) # 行先座標をbagsから削除 118:self.bagMoveSound() # 効果音を鳴らす 119: if (self.x, self.y-1) in map.stored: # 行先座標が格納listにあれば 120: map.stored.remove((self.x, self.y-1)) # 行先座標を格納listから削除 121: map.bags.append((self.x, self.y-2)) # その先座標をbagsに追加 122: if (self.x, self.y-2) in map.places: # その先座標が収納場所listにあれば 123: map.stored.append((self.x, self.y-2)) # その先座標を格納listに追加 124: return True 125: else: 126: return True 127: 128: def canMoveRight(self, map): 129: if (self.x+1, self.y) in map.blocks: # 行先座標が壁 130: return False 131: elif (self.x+1, self.y) in map.bags: # 行先座標が荷物 132: if (self.x+2, self.y) in map.blocks or (self.x+2, self.y) in map.bags: # さらにその先座標が壁 or 荷物 133: return False 134: else: 135: map.bags.remove((self.x+1, self.y)) # 行先座標をbagsから削除 136:self.bagMoveSound() # 効果音を鳴らす 137: if (self.x+1, self.y) in map.stored: # 行先座標が格納listにあれば 138: map.stored.remove((self.x+1, self.y)) # 行先座標を格納listから削除 139: map.bags.append((self.x+2, self.y)) # その先座標をbagsに追加 140: if (self.x+2, self.y) in map.places: # その先座標が収納場所listにあれば 141: map.stored.append((self.x+2, self.y)) # その先座標を格納listに追加 142: return True 143: else: 144: return True 145: 146: def canMoveLeft(self, map): 147: if (self.x-1, self.y) in map.blocks: # 行先座標が壁 148: return False 149: elif (self.x-1, self.y) in map.bags: # 行先座標が荷物 150: if (self.x-2, self.y) in map.blocks or (self.x-2, self.y) in map.bags: # さらにその先座標が壁 or 荷物 151: return False 152: else: 153: map.bags.remove((self.x-1, self.y)) # 行先座標をbagsから削除 154:self.bagMoveSound() # 効果音を鳴らす 155: if (self.x-1, self.y) in map.stored: # 行先座標が格納listにあれば 156: map.stored.remove((self.x-1, self.y)) # 行先座標を格納listから削除 157: map.bags.append((self.x-2, self.y)) # その先座標をbagsに追加 158: if (self.x-2, self.y) in map.places: # その先座標が収納場所listにあれば 159: map.stored.append((self.x-2, self.y)) # その先座標を格納listに追加 160: return True 161: else: 162: return True 163: 164: def drawChar(self, map, screen): # payer以外の描画 165: for i in map.blocks: 166: screen.blit(map.blockImg, (i[0]*GS+OFFSET, i[1]*GS)) 167: for i in map.bags: 168: screen.blit(map.bagImg, (i[0]*GS+OFFSET, i[1]*GS)) 169: for i in map.places: 170: screen.blit(map.placeImg, (i[0]*GS+OFFSET, i[1]*GS)) 171: for i in map.stored: 172: screen.blit(map.storedImg, (i[0]*GS+OFFSET, i[1]*GS)) 173: 174: def draw(self, screen): # playerの描画 175: screen.blit(self.image, (self.x*GS+OFFSET, self.y*GS)) 176: 177: def draw1(self,screen): # playerの描画 178: self.image = self.images[int(self.dir*4 + self.frame/self.animcycle%4)] 179: screen.blit(self.image, (self.x*GS+OFFSET, self.y*GS)) 180: 181:def bagMoveSound(self): 182: mixer.init() 183: mixer.music.load('move.wav') 184: mixer.music.play(1) 185:
今回変更のあったsouko.pyも提示しておきます。souko.py
さらなる改良のアイデアが出ませんので、このシリーズはこれで終了となります。Gの拙いコードですが、Pythonを学ぶ方に少しでも参考になれば嬉しいです。