前の頁へ   次の頁へ

老い学の捧げ物 Part Ⅰ

7.一歩戻る

「一歩戻る」処理を実装するためには、プレーヤーの一歩毎のキャラクタの座標を記憶しておかねばなりません。とはいえ、壁「#」と収納場所「*」は固定ですから、記憶する必要があるのはプレーヤーと荷物だけです。終了判定のために、収納場所に収納された荷物も記憶しておいた方がよいでしょう。それぞれの座標の履歴を配列に格納することで記憶したいと思います。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、要素数は1
      self.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 = dir
      self.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 = 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

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
ファイル名:button.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

ファイル名:mapStage.py
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
ファイル名:microban.txt
; 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

#############
#.# @#  #   #
#.#$$   # $ #
#.#  # $#   #
#.# $#  # $##
#.#  # $#  #
#.# $#  # $#
#..  # $   #
#..  #  #  #
############
ファイル名:players.py
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))
ファイル名:souko.py
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()
前の頁へ   次の頁へ