前の頁へ   トップ頁へ

老い学の捧げ物 Part Ⅰ

11.動き再現と効果音

今回はさらなる改良として、クリアまでのプレーヤーと荷物の動きを動画で再現します。また荷物が動いた時に音が出るようにしました。音源はネットから拾ってきました。「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を学ぶ方に少しでも参考になれば嬉しいです。

前の頁へ   トップ頁へ