「一歩戻る」処理を実装するためには、プレーヤーの一歩毎のキャラクタの座標を記憶しておかねばなりません。とはいえ、壁「#」と収納場所「*」は固定ですから、記憶する必要があるのはプレーヤーと荷物だけです。終了判定のために、収納場所に収納された荷物も記憶しておいた方がよいでしょう。それぞれの座標の履歴を配列に格納することで記憶したいと思います。Playerクラスに作成してもいいのですが、今回はMapクラスのインスタンス変数として作成します。mapStage.pyのコンストラクタに以下のように追加します。
def __init__(self): self.mapdata = [] # mapdataを作成 self.filename = 'microban.txt' self.blocks = [] # 壁座標(tuple)の List self.places = [] # 収納場所座標(tuple)の List self.bags = [] # 荷物座標(tuple)の List self.stored = [] # 格納座標(tuple)の List self.player = [] # プレーヤー座標(tuple)の List、要素数は1self.bagsHis = [] # 荷物座標(tuple)の履歴 List self.storedHis = [] # 格納座標(tuple)の履歴 List self.playerHis = [] # プレーヤー座標(tuple)の履歴 List self.stage = [] # 選択された面のデータ配列
そしてPlayerクラスに3つのキャラクタの履歴配列を作成するメソッドmakeHis()を作ります。
def makeHis(self, map): map.playerHis.append((self.dir, (self.x, self.y))) # 現在のplayerを履歴に追加 map.bagsHis.append(copy.deepcopy(map.bags)) # 現在のbagsを履歴に追加(荷物が移動しない場合でも) map.storedHis.append(copy.deepcopy(map.stored)) # 現在のstoredを履歴に追加(荷物が移動しない場合でも)
プレーヤーの履歴配列にはその時点でのdirとposのタプルが格納されます。dirも格納することで、プレヤーが後ずさりするように表示できます。プレーヤーは荷物を押すことなく移動する場面もあるので、その場合でも履歴配列に格納しています。荷物(bagsHis)と格納された荷物(storedHis)の履歴配列には、その時点における座標配列bags[]とstored[]が格納されます。つまり荷物の履歴配列は配列の配列となります。ディープコピーを使わないといけません。上のmakeHis()メソッドはプレーヤーが一歩移動する度に使われますから、Playerクラスのmove()メソッドの中で使います。
メインループのキーイベントに、何かのキーを押すと一歩戻る処理を加えることになりますが、その処理を考えましょう。先ずPlayerクラスのインスタンス変数に、プレーヤーの歩数を示すcounterを追加しました。画面にcounterの値を表示すれば、現在の歩数を知ることができます。また一歩戻る度にcounterをデクリメントすることで、counter値をインデックスとして履歴配列を検索できます。各履歴配列の最後の要素に一歩前の座標が格納されているので、一歩戻るメソッドは現在の座標を履歴配列の最後の要素で置換することになります。
001: # 一歩戻る 002: def playBack(self, map): 003: if self.counter > 0: 004: map.bagsHis.pop(-1) # 履歴配列最後の要素を削除 005: map.storedHis.pop(-1) 006: map.bags = copy.deepcopy(map.bagsHis[self.counter-1]) # 履歴配列最後の要素をbagsにコピー 007: map.stored = copy.deepcopy(map.storedHis[self.counter-1]) 008: self.dir = map.playerHis[self.counter][0] # dirを更新 009: (self.x, self.y) = map.playerHis[self.counter][1] # (x,y)を更新 010: map.playerHis.pop(-1) # 最後の要素を削除する 011: self.counter -= 1
コメントを見れば、処理内容を理解して頂けると思います。6-7行でもディープコピーを使っています。players.pyのうち追加・修正を加えたメソッドは以下のとおりです。追加・修正箇所を緑色で表示しています。
import copy def __init__(self, pos, dir): self.images = SI.splitImage(LI.load_image("../images/players.png"),4,4) self.image = self.images[0] # 描画中のイメージ self.dir = dirself.counter = 0 # playerの歩数 self.x = pos[0] self.y = pos[1] # 一歩戻るdef playBack(self, map): if self.counter > 0: map.bagsHis.pop(-1) # 履歴配列最後の要素を削除 map.storedHis.pop(-1) map.bags = copy.deepcopy(map.bagsHis[self.counter-1]) # 履歴配列最後の要素をbagsにコピー map.stored = copy.deepcopy(map.storedHis[self.counter-1]) self.dir = map.playerHis[self.counter][0] # dirを更新 (self.x, self.y) = map.playerHis[self.counter][1] # (x,y)を更新 map.playerHis.pop(-1) # 最後の要素を削除する self.counter -= 1 def move(self, dir, map): if dir == DOWN: if self.canMoveDown(map): self.dir = DOWNself.makeHis(map) # 履歴listに追加 self.counter += 1 self.y += 1 elif dir == LEFT: if self.canMoveLeft(map): self.dir = LEFTself.makeHis(map) # 履歴listに追加 self.counter += 1 self.x -= 1 elif dir == RIGHT: if self.canMoveRight(map): self.dir = RIGHTself.makeHis(map) # 履歴listに追加 self.counter += 1 self.x += 1 elif dir == UP: if self.canMoveUp(map): self.dir = UPself.makeHis(map) # 履歴listに追加 self.counter += 1 self.y -= 1
mapStage.pyはコンストラクタ以外に変更はありません。souko.pyは、main()メソッドを以下のように追加・修正します。一歩戻るにはback spaceキーを押すことにしました。
def main(self): map = Map() # Mapクラスのインスタンス作成 map.getData() # mapdata[][]の作成 map.stage = map.getStage(len(map.mapdata)) # 面の選択 self.screen.fill((0,0,0)) # ボタン画面消去 map.setChars(map.stage) # 選択した面に画像をセット pos = map.getPlayerPos(map.stage) player = Player(pos, DOWN)player.makeHis(map) # 履歴Listに最初の座標をセット clock = pygame.time.Clock() while (1): clock.tick(60) player.animate() self.drawChar(map, self.screen) player.draw(self.screen) # playerを描画 # イベント処理 for event in pygame.event.get(): # 終了用のイベント処理 if event.type == QUIT: # 閉じるボタンが押されたとき pygame.quit() sys.exit() if event.type == KEYDOWN and event.key == K_ESCAPE: # Escキーが押されたとき pygame.quit() sys.exit() # その他の処理if event.type == KEYDOWN and event.key == K_BACKSPACE: # 一歩戻る player.playBack(map) # プレイヤーの移動処理 if event.type == KEYDOWN and event.key == K_DOWN: player.move(DOWN, map) if event.type == KEYDOWN and event.key == K_LEFT: player.move(LEFT, map) if event.type == KEYDOWN and event.key == K_RIGHT: player.move(RIGHT, map) if event.type == KEYDOWN and event.key == K_UP: player.move(UP, map) pygame.display.update() self.screen.fill((0,0,0))
一歩戻る処理を実装できましたが、まだまだ物足りません。倉庫番ゲームを遊んでいると、その面を最初からやり直したいことがあります。また今のままでは、終了処理をしないと面選択のボタン画面を表示できません。クリアした時にもボタン画面を表示したいですし、既にクリアされた面であることがわかるような表示もしたいです。さらに、一度クリアした面にもう一度挑戦した時には、前回と歩数を比べたいものですね。こうした処理をこれから実装していきますが、まず情報を画面に表示することから始めましょう。
なお、現時点でのファイル構造とファイル内容を確認しておきます。以下のようなディレクトリ構造になっていると思います。
|-module | |-loadimage.py | |-splitimage.py |-images | |-bag.png | |-block.png | |-place.png | |-player.png | |-players.png | |-stored.png |-souko |-button.py |-mapStage.py |-microban.txt |-players.py |-souko.py
import pygame from pygame.locals import * import sys SCR_RECT = Rect(0, 0, 800, 480) # 画面サイズ GREEN = (34,150,34) BLACK = (0,0,0) pygame.init() sysfont = pygame.font.SysFont(None, 25) class Buttons: # stage選択の画面用 def __init__(self, num, x, y): self.num = num self.x = x # button左上 x座標 self.y = y # 四角の描画 def draw(self, GS, screen): pygame.draw.rect(screen, GREEN, Rect(self.x, self.y, GS, GS)) # fill pygame.draw.rect(screen, BLACK, Rect(self.x, self.y, GS, GS), 5) # 外枠は黒 # マウスクリック用 def getRect(self, GS): return pygame.Rect(self.x, self.y, GS, GS) # 数字を描画 def writeNum(self, screen): suu = sysfont.render(str(self.num), False, (255,255,0)) screen.blit(suu, (self.x+5, self.y+8)) # 5,8 = offset
import pygame from pygame.locals import * import sys sys.path.append("C:\myPython\module") import loadimage as LI import math from button import Buttons # Buttons classを import WIDTH = 800 HEIGHT = 480 SCR_RECT = Rect(0, 0, WIDTH, HEIGHT) GS = 32 class Map: pygame.init() screen = pygame.display.set_mode(SCR_RECT.size) blockImg = LI.load_image("../images/block.png", -1) bagImg = LI.load_image("../images/bag.png", -1) placeImg = LI.load_image("../images/place.png", -1) storedImg = LI.load_image("../images/stored.png", -1) playerImg = LI.load_image("../images/player.png", -1) def __init__(self): self.mapdata = [] # mapdataを作成 self.filename = 'microban.txt' self.blocks = [] # 壁座標(tuple)の List self.places = [] # 収納場所座標(tuple)の List self.bags = [] # 荷物座標(tuple)の List self.stored = [] # 格納座標(tuple)の List self.player = [] # プレーヤー座標(tuple)の List、要素数は1 self.bagsHis = [] # 荷物座標(tuple)の履歴 List self.storedHis = [] # 格納座標(tuple)の履歴 List self.playerHis = [] # プレーヤー座標(tuple)の履歴 List self.stage = [] # 選択された面のデータ配列 def getData(self): # self.mapdataの作成 flag = [] # '#'がある行は'0' mapdataに不要な行は'1' f = open(self.filename, 'r') while(True): # 一行ずつ読んで listに格納 line = f.readline() if '#' in line: flag.append('0') else: flag.append('1') if not line: break f.close() max = 0 # 面数を取得して初期化 for i in range(len(flag)): if flag[i] == '0' and flag[i+1] == '1': # 不要行の次に'#'を含む行があれば max += 1 self.mapdata = [[] for _ in range(max)] # mapdata[][]の初期化 f = open(self.filename, 'r') lines = f.readlines() # 全行の list f.close n = 0 for i in range(len(lines)): # 全行を調べる if '#' in lines[i]: self.mapdata[n].append(lines[i].rstrip('\n')) # 改行を削除して配列に追加 if flag[i] == '0' and flag[i+1] == '1': # 不要行の次に'#'を含む行があれば n += 1 # mapdata[n++] def getStage(self, num): # 面を番号として選択 num:マップデータの面の数 btS = round(math.sqrt(num)) # 画面短辺方向のボタンの数 if num == 2: # 2個の場合は2とする btS = 2 btPx = int(HEIGHT/btS) # ボタン一辺のピクセル数 buttons = [] for i in range(num): # numの数だけ x = i // btS # 横方向のボタン数 y = i % btS # 縦方向のボタン数 buttons.append(Buttons(i, x*btPx, y*btPx)) # Buttonsのインスタンスを配列に入れる for button in buttons: button.draw(btPx, self.screen) button.writeNum(self.screen) pygame.display.update() while(1): for event in pygame.event.get(): if event.type == MOUSEBUTTONDOWN and event.button == 1: for button in buttons: if button.getRect(btPx).collidepoint(event.pos): self.index = button.num stage = self.mapdata[self.index] return stage # stage[][]を返す def setChars(self, stage): self.blocks.clear() self.places.clear() self.bags.clear() self.stored.clear() self.player.clear() for i in range(len(stage)): # 行数 for j in range(len(stage[i])): # 文字数 if stage[i][j] =='#': self.blocks.append((j, i)) # 壁(x,y) if stage[i][j] =='.': self.places.append((j, i)) # 置き場(x,y) if stage[i][j] =='$': self.bags.append((j, i)) # 荷物(x,y) if stage[i][j] =='@': self.player.append((j, i)) # 荷物(x,y) if stage[i][j] =='*': self.stored.append((j, i)) # 収納済(x,y) self.bags.append((j, i)) # 壁(x,y) self.places.append((j, i)) # 置き場(x,y) def getPlayerPos(self, stage): for i in range(len(stage)): # 行数 for j in range(len(stage[i])): # 文字数 if stage[i][j] =='@': # Player.posを get return(j, i) break
; 1 #### # .# # ### #*@ # # $ # # ### #### ; 2 ###### # # # #@ # # $* # # .* # # # ###### ; 3 #### ### #### # $ # # # #$ # # . .#@ # ######### ; 4 ######## # # # .**$@# # # ##### # #### ; 5 ####### # # # .$. # ## $@$ # # .$. # # # ######## ; 6 ###### ##### # ### # # $$ #@# # $ #... # # ######## ##### ; 7 ####### # # # .$. # # $.$ # # .$. # # $.$ # # @ # ####### ; 8 ###### # ..@# # $$ # ## ### # # # # #### # # ## # # # # # # ### # ##### ; 9 ##### #. ## #@$$ # ## # ## # ##.# ### ; 10 ##### #. # #.# # #######.# # # @ $ $ $ # # # # # ### # # ######### ; 11 ###### # # # ##@## ### # $ # # ..# $ # # # # ###### #### ; 12 ##### # ## # $ # ## $ #### ###@. # # .# # # # ####### ; 13 #### #. ## #.@ # #. $# ##$ ### # $ # # # # ### #### ; 14 ####### # # # # # # #. $*@# # ### ##### ; 15 ### ######@## # .* # # # # #####$# # # # ##### ; 16 #### # #### # ## ## ## # #. .# @$## # # $$ # # .# # ########## ; 17 ##### # @ # #...# #$$$## # # # # ###### ; 18 ####### # # #. . # # ## ## # $ # ###$ # #@ # # # #### ; 19 ######## # .. # # @$$ # ##### ## # # # # # # #### ; 20 ####### # ### # @$$..# #### ## # # # # #### # # #### ; 21 #### # #### # . . # # $$#@# ## # ###### ; 22 ##### # ### #. . # # # # ## # # #@$$ # # # # ### #### ; 23 ####### # * # # # ## # ## #$@.# # # ##### ; 24 # ##### # # ###$$@# # ### # # # . . # ####### ; 25 #### # ### # $$ # ##... # # @$ # # ### ##### ; 26 ##### # @ # # # ###$ # # ...# # $$ # ### # #### ; 27 ###### # .# # ## ## # $$@# # # # #. ### ##### ; 28 ##### # # # @ # # $$### ##. . # # # ###### ; 29 ##### # ## # # ###### # ## #. # # $ $ @ ## # ######.# # # ########## ; 30 #### # ### # $$ # #... # # @$ # # ## ##### ; 31 #### ## # ##@$.## # $$ # # . . # ### # ##### ; 32 #### ## ### # # #.**$@# # ### ## # #### ; 33 ####### #. # # # $ # #. $#@# # $ # #. # # ####### ; 34 #### ### #### # # #@$***. # # # ######### ; 35 #### ## # #. $# #.$ # #.$ # #.$ # #. $## # @# ## # ##### ; 36 #### # ############ # $ $ $ $ $ @ # # ..... # ############### ; 37 ### ##### #.# # ###.# # $ #.# # $ $ # #####@# # # # ##### ; 38 ########## # # # ##.### # # # $$ . # # . @$## # ##### # ###### ; 39 ##### # #### # # # .# # $ ### ### #$. # # #@ # # # ###### # # ##### ; 40 ##### # # ## ## # $$$ # # .+. # ####### ; 41 ####### # # #@$$$ ## # #...# ## ## ###### ; 42 #### # # #@ # ####$.# # $.# # # $.# # ## ###### ; 43 #### # @# # # ###### .# # $ .# # $$# .# # #### ### # #### ; 44 'Duh!' ##### #@$.# ##### ; 45 ###### #... # # $ # # #$## # $ # # @ # ###### ; 46 ###### ## # # ## # # # $ # # * .# ## #@## # # ##### ; 47 ####### ### # # $ $ # # ### ##### # @ . . # # ### # ##### ##### ; 48 ###### # @ # # # ## # .# ## # .$$$ # # .# # #### # ##### ; 49 ###### # @ # # $# # # $ # # $ ## ### #### # # # #... # # # ####### ; 50 #### ### ##### # $ @..# # $ # # ### #### # # # ######## ; 51 #### # ### # ### # $*@ # ### .# # # # ###### ; 52 #### ### @# # $ # # *.# # *.# # $ # ### # #### ; 53 ##### ##. .## # * * # # # # # $ $ # ## @ ## ##### ; 54 ###### # # ##### . # ### ###. # # $ $ . ## # @$$ # . # ## ##### ###### ; 55 ######## # @ # # # # #####$ # # ### ## #$ ..# ## # ### #### ; 56 ##### # ### # $ # ##* . # # @# ###### ; 57 #### # # #@ # # # ### #### # * # # $ # #####. # #### ; 58 #### # #### #.*$ # # .$# # ## @ # # ## ##### ; 59 ############ # # # ####### @## # # # # # $ # # # $$ ##### # ### # # ...# #### # # ###### ; 60 ######### # # ##@##### # # # # # # # $.# # ##$##.# ##$## #.# # $ #.# # # ### ######## ; 61 ######## # # # #### # # #...@# # ###$### # # # # $$ $ # #### ## #.### ### ; 62 ########## #### ## # # $$$....$@# # ### # # #### #### ##### ; 63 ##### #### # ##### .# # $ ######## ### #### .$ @ # # # # #### # #### #### ##### ; 64 ###### ## # # $ # # $$ # ### .##### ##.# @ # #. $ # #. #### #### ; 65 ###### # # # $ # ####$ # ## $ $ # #....# ## # @ # ## # # ######## ; 66 ### #@# ###$### ## . ## # # # # # # # # # # # # # # # # # # # # ## $ $ ## ##. .## # # # # ##### ; 67 ##### # ## # # # #@$*.## ## . # # $# # ## # ##### ; 68 #### # ###### ## $ # # .# $ # # .#$##### # .@ # ###### ; 69 #### #### # #### # # # # # # # $## # . .#$ # #@ ## # $ # # . # # ########### ; 70 ##### # @ #### # # # $ $$ # ##$## # # #### # .. # ##.. # ### # #### ; 71 ########### # # ### # $@$ # . .# # ## ### ## # # # # # # # # # # # ######### # # # ############# ; 72 #### ## ##### # $ @ # # $# # #### ##### # # # # $ # # ..# # # .#### # ## #### ; 73 #### # ##### # $$ $ # # # ## ## ## #...#@# # ### ## # # # # # ######## ; 74 #### # ####### #$ @# .# ## #$$ .# # $ ##..# # # ##### ### # ##### ; 75 ####### ## ....## # ###### # $ $ @# ### $ $ # ### # ###### ; 76 ##### ## # # ##### # #.# # #@ #.# $ # # #.# ## # # # ## ##$$# ## # # #### #### ; 77 ########## # @ .... # # ####$## ## # $ $ # # $ # # ###### ##### ; 78 ####### ## ## # $ $ # # $ $ $ # ## ### #### #@ .....# ## ### ####### ; 79 ######### # # # ## $#$# # # .$.@ # # .# # ########## ; 80 #### # ####### # . ## .# # $# .# ## ## # .# # # # #### # # # @$ ### # $$ # # # ###### ; 81 ##### # # # . # ## * # # *## # @## ## $ # # # ##### ; 82 ##### # ### # . ## ##*#$ # # .# $ # # @## ## # # ####### ; 83 ###### # ## # $ $ ## ## $$ # # # # # ## ## # . .# # @. .# # #### #### ; 84 ######## # ... # # ### ## # # $ # ## #@$ # # # $ # # ### ##### # # # ### # ##### ##### ; 85 #### ####### # # $ # # $ $ # # ######## ## # . # # # # # # @ . ## ## # # # # . # ####### ; 86 #### ### ## ## $ # ## $ # # # @#$$ # # .. ### # ..### ##### ; 87 #### ###### # # # # ... .# ##$###### # $ # # $### ## $ # ## @ # ###### ; 88 #### ### # # # # # # #$ #.# # # # #$ #.# # # # ####$ #.# # @ # # # ## ######## ; 89 ########## # ## # # $ $@# # #### # $ # #.# ## #.# $# #. # #. # ###### ; 90 ######## # @ # # $ $ # ### ## ### # $..$ # # .. # ########## ; 91 ########### # .## # # $$@..$$ # # ##. # ########### ; 92 #### # # ##### # # # # # ######.# # #### $ . # # $$# ###.# # # # # # # ######### #@ ## # # #### ; 93 ######### ## # ## # # # # $ # $ # # *.* # ####.@.#### # *.* # # $ # $ # # # # ## # ## ######### ; 94 ######### # @ # # # $ $ # ##$### ## # ... # # # # ###### # #### ; 95 ######## #@ # # .$$. # # $..$ # # $..$ # # .$$. # # # ######## ; 96 ###### # # # # ##### # # #.##### # $@$ # #####.# # ## ## ## # $.# # ### ##### ; 97 #### # ######## #### $ $.....# # $ ###### #@### ### # $ # # $ # # ## # # # # ###### ; 98 ##### # ## #### # $ ### .# # $ $ .# ## $#####.# #### # $ # # .### # # # # .# @ # ### # # # #### ## ## ####### ; 99 ##### # # ####### ####### # # # # # # # # @ #### # #### # # ....## #### # # ##### ## $$ $ $ # ###### # # # ########## #### ; 100 ####### # @# # #.$ # #. # $## #.$# # #. # $ # # # # ######## ; 101 'Lockdown' ##### # # # # ####### # * # # ## ## # # # #* # ### # # # ### # *#$+ # # # ## ## # # * # ####### # # # # ##### ; 102 ########### #....# # # # $$ # # @ ## # # ##$ # ###### $ # # # ###### ; 103 ##### # . ## ### $ # # . $#@# # #$ . # # $ ### ## . # ##### ; 104 ##### ##### # # $ # # $#$#@# ### # # # ... # ### ## # # #### ; 105 #### #### ## ### ## # # # # # *. .* # ###$ $### # @ # ###$ $### # *. .* # # # # # ## ### ## #### #### ; 106 ######## # # #@ $ # ## ###$ # # .....### # $ $ $ # ###### # # # # ##### ; 107 ######## # # # $*** # # * * # # * * # # ***. # # @# ######## ; 108 #### ##### # ### # ## # # #$ $ # #..# ##### # # # @ # $ $ # #..# ## ## ######### ##### ; 109 ####### # # # # # # # # # @ $ # ### ### # # ### # # $ ##.# ## $ #.# ## $ .# # ## $#.# ## ## #.# ### # # ### ##### ; 110 #### # # # $#### ###. . # # $ # $ # # . .### ####$ # # @# #### ; 111 ###### # #### # ...# # ...# ###### # # # # # $$ ## # @$ # # $$ # ## $# # # # ###### ; 112 ##### ## #### # $$$ # # # $ # # $## ## ### #. # # # # ##### ### # # ## # @....# # # # # # ######## ; 113 ##### ## # ### # # # . # # ## ##### # . . # ## # # @ $ ### #####. # $ # #### $ # ## $ ## # ## # # #### ; 114 ###### # ### # # $ # # $ @ # ## ## ##### # #......# # $ $ $ $ # ## ###### ##### ; 115 ##### ##### #### # # # # #..... # ## ## # ### #$$@$$$ # # ### ####### ; 116 ##### ### # ####.....# # @$$$$$ # # # ## ##### # ##### ; 117 #### #### # ### ## # @ # ##..### # # # # #...#$ # # # ## $$ $ # # $ ### #### ### #### ; 118 ##### ## ## # $ ## # $ $ ## ###$# . ## # # . # ## ##. # # @ . ## # # # ######## ; 119 ###### # ## ## ## # # $$ # # # @$ # # # # # #### # # # ... ## # ## ####### ; 120 #### ####### # # $ ## # $##### # # @# # # ## ##.. # # # ..#### # $ ### # $### # # #### ; 121 ###### # . # ##$.# # # * # # ..### ##$ # ##### ## ## # # # #### # # # @ $ $ # ## # # ########## ; 122 ##### # ### # #$ # # $ # # $ $ # # $# # # @### ## ######## # ...# # # ########..# #### ; 123 ######## # # # $ $$ ######## ##### @##. . # #$ # . # # #. . ## #$# ## # # # # # ### ## # # #### #### ; 124 ############## # # # # $@$$ # . ..# ## ## ### ## # # # # # # # # # # # ######### # # # ############# ; 125 ##### # ## # $ # ######## #@## # . # $ $ # # $# # #...##### # ##### ##### ; 126 ########### ##....... # # $$$$$$$@ # # # # # ## # # # # # ####### ##### ; 127 ## #### #### #### # $ $. # ## # .$ # # ##.### # $ . # # @ # # # ###### #### ; 128 ######### ### # # # * $ . . # # $ ## ## ####*# # # @ ### # ### ##### ; 129 ######### ### @ # # # * $ *.. # # $ # # ####*# ### # ## # ### ##### ; 130 ##### ##### # ####.. # # $$$ # # $# .. # ### @# ## # # ## # ########## ; 131 ##### # # # . # #.@.### ##.# # # $ # # $ # ##$$ # # ### # # #### ; 132 #### # @### #.* ##### #..#$$ $ # ## # # # ## # # ##### ##### ; 133 ####### # . .### # . . . # ### #### # # @$ $ # # $$ $ # #### ### ##### ; 134 #### ######### # # ## $ # # $ ## # ### #. .# ## # #. .#$## # # # # # @ $ # # ####### #### ; 135 ####### # ##### # $$#@##..# # # # # $ # # # #### $ ..# ######## ; 136 ####### # # ## ###$## #.$ @ # # .. #$ # #.## $ # # #### ###### ; 137 #### ## ### #### # $ # # #### $ $ # # ..# #$ # # # @ ### ## #..# ### # ## # # # # ######## ; 138 #### ### # # ### # # . .# # @ ...#### # # # # ## # # $$ # ##### $ $ # ##$ # ## # # ###### ; 139 #### ## #### # ...# # ...# # # ## # #@ #### #### ##### $ ### # # ##$ $ # ### $$ # # $ ## ### # ###### ###### ; 140 ######## ##### # # ### # # ## $ # #.# @ ## $ ## #.# # $ ## #.# $ ## #. ## ##### ## # ###### ; 141 ######## # # . # # .*.# # # * # ####$##.## # $ # # $ ## $ # # @# # ########## ; 142 #### # # # #### ###$.$ # # .@. # # $.$### #### # # # #### ; 143 #### # #### # $ # # .# # # $# ## # . # #### # # # ### ### # $ # ## #$# ## # $ @ $ # # ..#.. # ### ### ##### ; 144 #### ### ##### # $$ # # # $ . .$$## # .. #. $ # ### #** . # # . **# ### # $ .# .. # ##$$.@. $ # # # $$ # ##### ### #### ; 145 ##### # @ # ## ## ###.$$$.### # $...$ # # $.#.$ # # $...$ # ###.$$$.### ## ## # # ##### ; 146 ####### ## . ## # .$$$. # # $. .$ # #.$ @ $.# # $. .$ # # .$$$. # ## . ## ####### ; 147 ##### ######## # #. . @#.# # ### # ## $ # # # $ ##### # $# # ## # # # ## ##### ; 148 'from (Original 18)' ########### # . # # # #. @ # # #..# ####### ## ## $$ $ $ # ## # ############# ; 149 'from (Boxxle 43)' #### ## ### #@$ # ### $ # # ###### # $....# # # #### ## # # # $# # # # # ### #### ; 150 'from (Original 47)' #### ##### # # $####### ## ## ..# ...# # $ $$#$ @ # # ### # ####### # #### #### ; 151 'from (Original 47)' #### # # ### # ## $ # # # # # #$$ ###### # # # .# # $ @ .# ### ####..# #### #### ; 152 ###### #### # # # #.## #$## # # # # # #$ # ### # # # # # # # # # #### # # # #. @ $ * . # ############### ; 153 ############# #.# @# # # #.#$$ # $ # #.# # $# # #.# $# # $## #.# # $# # #.# $# # $# #.. # $ # #.. # # # ############
import pygame from pygame.locals import * import sys sys.path.append("C:\myPython\module") import loadImage as LI # moduleの利用 import splitImage as SI # moduleの利用 import copy DOWN, LEFT, RIGHT, UP = 0, 1, 2, 3 SCR_RECT = Rect(0, 0, 800, 480) # 画面サイズ GS = 32 # 1マスの大きさ[px] screen = pygame.display.set_mode(SCR_RECT.size) class Player: animcycle = 24 # アニメーション速度 frame = 0 def __init__(self, pos, dir): self.images = SI.splitImage(LI.load_image("../images/players.png"),4,4) self.image = self.images[0] # 描画中のイメージ self.dir = dir self.counter = 0 # playerの歩数 self.x = pos[0] self.y = pos[1] def animate(self): # キャラクターアニメーション(frameに応じて描画イメージを切り替える) self.frame += 1 self.image = self.images[int(self.dir*4 + self.frame/self.animcycle%4)] def makeHis(self, map): map.playerHis.append((self.dir, (self.x, self.y))) # 現在のplayerを履歴に追加 map.bagsHis.append(copy.deepcopy(map.bags)) # 現在のbagsを履歴に追加(bagが移動しない場合でも) map.storedHis.append(copy.deepcopy(map.stored)) # 一歩戻る def playBack(self, map): if self.counter > 0: map.bagsHis.pop(-1) # 履歴配列最後の要素を削除 map.storedHis.pop(-1) map.bags = copy.deepcopy(map.bagsHis[self.counter-1]) # 履歴配列最後の要素をbagsにコピー map.stored = copy.deepcopy(map.storedHis[self.counter-1]) self.dir = map.playerHis[self.counter][0] # dirを更新 (self.x, self.y) = map.playerHis[self.counter][1] # (x,y)を更新 map.playerHis.pop(-1) # 最後の要素を削除する self.counter -= 1 def move(self, dir, map): if dir == DOWN: if self.canMoveDown(map): self.dir = DOWN self.makeHis(map) # 履歴listに追加 self.counter += 1 self.y += 1 elif dir == LEFT: if self.canMoveLeft(map): self.dir = LEFT self.makeHis(map) # 履歴listに追加 self.counter += 1 self.x -= 1 elif dir == RIGHT: if self.canMoveRight(map): self.dir = RIGHT self.makeHis(map) # 履歴listに追加 self.counter += 1 self.x += 1 elif dir == UP: if self.canMoveUp(map): self.dir = UP self.makeHis(map) # 履歴listに追加 self.counter += 1 self.y -= 1 def canMoveDown(self, map): if (self.x, self.y+1) in map.blocks: # 行先座標が壁 return False elif (self.x, self.y+1) in map.bags: # 行先座標が荷物 if (self.x, self.y+2) in map.blocks or (self.x, self.y+2) in map.bags: # さらにその先座標が壁 or 荷物 return False else: map.bags.remove((self.x, self.y+1)) # 行先座標をbagsから削除 if (self.x, self.y+1) in map.stored: # 行先座標が格納listにあれば map.stored.remove((self.x, self.y+1)) # 行先座標を格納listから削除 map.bags.append((self.x, self.y+2)) # その先座標をbagsに追加 if (self.x, self.y+2) in map.places: # その先座標が収納場所listにあれば map.stored.append((self.x, self.y+2)) # その先座標を格納listに追加 return True else: return True def canMoveUp(self, map): if (self.x, self.y-1) in map.blocks: # 行先座標が壁 return False elif (self.x, self.y-1) in map.bags: # 行先座標が荷物 if (self.x, self.y-2) in map.blocks or (self.x, self.y-2) in map.bags: # さらにその先座標が壁 or 荷物 return False else: map.bags.remove((self.x, self.y-1)) # 行先座標をbagsから削除 if (self.x, self.y-1) in map.stored: # 行先座標が格納listにあれば map.stored.remove((self.x, self.y-1)) # 行先座標を格納listから削除 map.bags.append((self.x, self.y-2)) # その先座標をbagsに追加 if (self.x, self.y-2) in map.places: # その先座標が収納場所listにあれば map.stored.append((self.x, self.y-2)) # その先座標を格納listに追加 return True else: return True def canMoveRight(self, map): if (self.x+1, self.y) in map.blocks: # 行先座標が壁 return False elif (self.x+1, self.y) in map.bags: # 行先座標が荷物 if (self.x+2, self.y) in map.blocks or (self.x+2, self.y) in map.bags: # さらにその先座標が壁 or 荷物 return False else: map.bags.remove((self.x+1, self.y)) # 行先座標をbagsから削除 if (self.x+1, self.y) in map.stored: # 行先座標が格納listにあれば map.stored.remove((self.x+1, self.y)) # 行先座標を格納listから削除 map.bags.append((self.x+2, self.y)) # その先座標をbagsに追加 if (self.x+2, self.y) in map.places: # その先座標が収納場所listにあれば map.stored.append((self.x+2, self.y)) # その先座標を格納listに追加 return True else: return True def canMoveLeft(self, map): if (self.x-1, self.y) in map.blocks: # 行先座標が壁 return False elif (self.x-1, self.y) in map.bags: # 行先座標が荷物 if (self.x-2, self.y) in map.blocks or (self.x-2, self.y) in map.bags: # さらにその先座標が壁 or 荷物 return False else: map.bags.remove((self.x-1, self.y)) # 行先座標をbagsから削除 if (self.x-1, self.y) in map.stored: # 行先座標が格納listにあれば map.stored.remove((self.x-1, self.y)) # 行先座標を格納listから削除 map.bags.append((self.x-2, self.y)) # その先座標をbagsに追加 if (self.x-2, self.y) in map.places: # その先座標が収納場所listにあれば map.stored.append((self.x-2, self.y)) # その先座標を格納listに追加 return True else: return True def draw(self, screen): # playerの描画 screen.blit(self.image, (self.x*GS+200, self.y*GS))
import pygame from pygame.locals import* import sys sys.path.append("C:\myPython\module") import loadImage as LI # moduleの利用 from mapStage import Map # Mapクラスのインポート from players import Player DOWN, LEFT, RIGHT, UP = 0, 1, 2, 3 SCR_RECT = Rect(0, 0, 800, 480) GS = 32 class Souko: pygame.init() screen = pygame.display.set_mode(SCR_RECT.size) def __init__(self): pass def drawChar(self, map, screen): # mapを渡す for i in map.blocks: screen.blit(map.blockImg, (i[0]*GS+200, i[1]*GS)) # Mapクラスの変数の利用 for i in map.bags: screen.blit(map.bagImg, (i[0]*GS+200, i[1]*GS)) for i in map.places: screen.blit(map.placeImg, (i[0]*GS+200, i[1]*GS)) for i in map.stored: screen.blit(map.storedImg, (i[0]*GS+200, i[1]*GS)) pygame.display.update() def main(self): map = Map() # Mapクラスのインスタンス作成 map.getData() # mapdata[][]の作成 map.stage = map.getStage(len(map.mapdata)) # 面の選択 self.screen.fill((0,0,0)) # ボタン画面消去 map.setChars(map.stage) # 選択した面に画像をセット pos = map.getPlayerPos(map.stage) player = Player(pos, DOWN) player.makeHis(map) # 履歴Listに最初の座標をセット clock = pygame.time.Clock() while (1): clock.tick(60) player.animate() self.drawChar(map, self.screen) player.draw(self.screen) # playerを描画 # イベント処理 for event in pygame.event.get(): # 終了用のイベント処理 if event.type == QUIT: # 閉じるボタンが押されたとき pygame.quit() sys.exit() if event.type == KEYDOWN and event.key == K_ESCAPE: # Escキーが押されたとき pygame.quit() sys.exit() # その他の処理 if event.type == KEYDOWN and event.key == K_BACKSPACE: # 一手戻る player.playBack(map) # プレイヤーの移動処理 if event.type == KEYDOWN and event.key == K_DOWN: player.move(DOWN, map) if event.type == KEYDOWN and event.key == K_LEFT: player.move(LEFT, map) if event.type == KEYDOWN and event.key == K_RIGHT: player.move(RIGHT, map) if event.type == KEYDOWN and event.key == K_UP: player.move(UP, map) pygame.display.update() self.screen.fill((0,0,0)) if __name__ == "__main__": souko = Souko() souko.main()