質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.36%

  • Python

    9102questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    7313questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

pythonのpygameでのゲーム作成について プログラムが応答しなくなります

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 640

kou_

score 2

orb.png
orb.png
player1.png
player1.png
player2.png
player2.png
grass.png および water.png の入手先

 前提・実現したいこと

現在、pythonでpygameモジュールを用いてミニゲームを作成しているのですが、
ある状況下でプログラムが応答しなくなってしまいます。
この原因の究明が出来なかったので、分かる方に原因と解決策をご教示いただきたいです。

 発生している問題・エラーメッセージ

以下のソースコードを実行し、スペースキー押下でゲーム開始→プレイヤーを衝突させてゲームが終了→タイトル画面に戻る→手順の初めに戻る、という手順を2ゲーム目まで行い、3ゲーム目開始時のスペースキー押下でプログラムが応答しなくなってしまいます。

 該当のソースコード

import pygame
from pygame.locals import *
import random
import copy
import sys
import os

SCREEN_WIDTH_SIZE = 608
SCREEN_HEIGHT_SIZE = 480

MSIZE = 32  # 1マスの大きさ

LEFT, DOWN, RIGHT, UP = 3, 2, 1, 0

TITLE, GAME, RESULT = 4, 5, 6

class Game_Title:  # タイトル画面の処理
    def __init__(self):
        self.titlefont = pygame.font.SysFont(None, 50)
        self.startfont = pygame.font.SysFont(None, 30)
        self.title_x, self.title_y = 202, 160
        self.start_x, self.start_y = 204, 400
        self.start_flame = 0
        self.start_flag = False
        self.finish = False

    def update(self):
        if self.start_flag:
            self.start_flame += 1
        if self.start_flame == 9000:  # スペースキー押下後、ある程度テキスト点滅したらタイトル画面は終了
            self.finish = True

    def draw(self, screen):
        title = self.titlefont.render("Orb Fighters", True, (255, 255, 255))
        start = self.startfont.render("Press Space to start", True, (255, 255, 255))
        screen.blit(title, (self.title_x, self.title_y))
        if self.start_flag:
            if self.start_flame % 2000 < 1000:  # スペースキーが押されたら押されたことをテキストの点滅で知らせる
                screen.blit(start, (self.start_x, self.start_y))
        else:
            screen.blit(start, (self.start_x, self.start_y))


class Player(pygame.sprite.Sprite):  # プレイヤークラス
    animcycle = 20  # アニメーション速度
    frame = 0  # アニメーションのフレーム
    target_x, target_y = -1, -1  # 移動時の移動先マスのx, y座標
    move_flag = False  # グリッド間の移動判定用フラグ
    has_orbs = 0  # オーブ所持数
    result = ""  # 勝者か敗者か

    def __init__(self, filename, pos_x, pos_y, direction, player):  # プレイヤーオブジェクトの初期化処理
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.direction = direction
        self.pos_x, self.pos_y = pos_x, pos_y
        self.target_x, self.target_y = pos_x * MSIZE, pos_y * MSIZE
        self.images = split_chara_image(load_image(filename))
        self.image = self.images[self.direction][1]
        self.rect = self.image.get_rect(topleft=(pos_x*MSIZE, pos_y*MSIZE))
        self.other_player = player

    def update(self, map):
        # キャラクターアニメーションおよびオーブ獲得数の更新
        self.frame += 1
        self.image = self.images[self.direction][int(self.frame / self.animcycle) % 3]  # 20フレーム毎に足踏み
        if self.move_flag:
            if self.rect.x < self.target_x:
                self.rect.x += 1
            if self.rect.y > self.target_y:
                self.rect.y -= 1
            if self.rect.x > self.target_x:
                self.rect.x -= 1
            if self.rect.y < self.target_y:
                self.rect.y += 1
        if self.rect.x == self.target_x and self.rect.y == self.target_y:
            self.move_flag = False
            self.pos_x, self.pos_y = int(self.rect.x / MSIZE), int(self.rect.y / MSIZE)
        self.get_orb(map)

    def draw(self, screen):  # キャラの描写
        screen.blit(self.image, self.rect)

    def move(self, dir, map):  # キャラのグリッド移動

        if self.rect.x == self.target_x and self.rect.y == self.target_y:
            if dir == LEFT:
                self.direction = LEFT
                if map.map[self.pos_y][self.pos_x - 1] == 0:
                    self.move_flag = True
                    self.target_x -= MSIZE
            if dir == DOWN:
                self.direction = DOWN
                if map.map[self.pos_y + 1][self.pos_x] == 0:
                    self.move_flag = True
                    self.target_y += MSIZE
            if dir == RIGHT:
                self.direction = RIGHT
                if map.map[self.pos_y][self.pos_x + 1] == 0:
                    self.move_flag = True
                    self.target_x += MSIZE
            if dir == UP:
                self.direction = UP
                if map.map[self.pos_y - 1][self.pos_x] == 0:
                    self.move_flag = True
                    self.target_y -= MSIZE
        if self.collision_player():
            self.game_set()

    def get_orb(self, map):  # 移動してきたマスにオーブがあれば獲得
        if not self.move_flag:
            if map.orb_map[self.pos_y][self.pos_x] == 0:
                map.orb_map[self.pos_y][self.pos_x] = 1
                self.has_orbs += 1

    def collision_player(self):  # プレイヤー同士の衝突判定
        if self.other_player is None:
            pass
        else:
            if self.direction == LEFT:
                if self.pos_y == self.other_player.pos_y and self.pos_x - 1 == self.other_player.pos_x:
                    return True
                else:
                    return False
            if self.direction == DOWN:
                if self.pos_y + 1 == self.other_player.pos_y and self.pos_x == self.other_player.pos_x:
                    return True
                else:
                    return False
            if self.direction == RIGHT:
                if self.pos_y == self.other_player.pos_y and self.pos_x + 1 == self.other_player.pos_x:
                    return True
                else:
                    return False
            if self.direction == UP:
                if self.pos_y - 1 == self.other_player.pos_y and self.pos_x == self.other_player.pos_x:
                    return True
                else:
                    return False

    def game_set(self):  # ゲームの勝敗がついたとき
        if self.has_orbs > self.other_player.has_orbs:
            self.result += "WINNER"
            self.other_player.result += "LOSER"
        elif self.has_orbs < self.other_player.has_orbs:
            self.result += "LOSER"
            self.other_player.result += "WINNER"
        else:
            self.result += "DRAW"
            self.other_player.result += "DRAW"


class Text_Orbs:  # プレイヤーのオーブ所持数のテキスト
    def __init__(self, player, map):
        self.sysfont = pygame.font.SysFont(None, 25)
        self.player = player
        if player.pos_x == 1 and player.pos_y == 1:
            self.x, self.y = (player.pos_x - 1) * MSIZE, (player.pos_y - 1) * MSIZE
        elif player.pos_x == map.col - 2 and player.pos_y == map.row - 2:
            self.x, self.y = (map.col - 5) * MSIZE, (map.row - 1) * MSIZE

    def draw(self, screen):
        text = self.sysfont.render("You got " + str(self.player.has_orbs) + " orbs.", True, (255,140,0))
        screen.blit(text, (self.x, self.y))




# 以下掲載しきれないので追記します

 試したこと

生成していたオブジェクトをdel文で削除し、ガベージコレクトで解放したメモリの回収を行ってみましたが、相変わらず問題は改善しませんでした。

 補足情報(FW/ツールのバージョンなど)

python 3.2
pygame 1.9.2pre

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • umyu

    2018/05/05 05:16

    grass.png orb.png water.png player1.png player2.pngのファイルがないため、実行しても実行エラーになります。

    キャンセル

  • kou_

    2018/05/05 13:10

    加工等で作成した画像の添付と、原物の画像が提示された入手先のリンクの追加を行わせていただきました。引き続き、よろしければお願い致します。

    キャンセル

回答 2

checkベストアンサー

+2

400行に渡る力作ソースですね。。
問題の再現手順はゲームスタート→ゲームプレイ→オーブを全部取得で次のゲームを2回という手順でいいですか?

結果→手元の環境では再現しませんでした。
python 3.6.5
pygame 1, 9, 3
OS:Windows 10

コードを見て気になった点を指摘します。
a,Playerクラスのgame_set関数の処理はプレイヤーが衝突時に無限に文字列を加算(result)するので、メモリが枯渇する可能性があるのでまずいのではないでしょうか?

    def game_set(self):  # ゲームの勝敗がついたとき
        if self.has_orbs > self.other_player.has_orbs:
            self.result += "WINNER"
            self.other_player.result += "LOSER"
        elif self.has_orbs < self.other_player.has_orbs:
            self.result += "LOSER"
            self.other_player.result += "WINNER"
        else:
            self.result += "DRAW"
            self.other_player.result += "DRAW"

Playerクラスに情報を持たせずに、Judgeクラスを作成してそちらで勝敗を管理する方がよいと思います。

b,2重ループの処理はitertools.productが使えます。
c,コード内に移動方向に対応する加減算処理が多いので、移動方向(ベクトル)を表すdirectionsを作成してみてはー。

    directions = {LEFT: (0, -1), DOWN: (1, 0), RIGHT: (0, +1), UP: (-1, 0)}
    print(directions)

コード修正する作業はバグを入れやすいので、テストロジックやPyCharmを使用しているなら、
メニューのバージョン管理→Local History機能を使って修正点を確認しなが作業するのをオススメします。


以下は憶測です。
反応がなくなるという特微から無限ループになっているのではと予想しました。
作成されたゲームで、無限ループになりそうな箇所のはMapクラスのgenerate_map
while (wall_flag)の判定とwhile(plus_land_yet)の判定です。
1,whileが確実に抜ける事を確認してくださいな。
2,オーブを全部取得したら、次のMAP生成のためにgenerate_mapが呼ばれますが、プレイヤーがいる位置を生成時に考慮していないように見受けられます。

画像で見ていただいた方が分かりやすいと思うので、これだとPlayer2が動けないMAPを生成してます。
イメージ説明

title関数 -> main関数 -> (2回目のプレイ)title関数 -> main関数この時
map.generate_map()  # ランダムマップ生成
map.generate_orb_map()  # 生成したマップをもとにオーブを配置
が呼ばれるのでは?


map.generate_map() の次行にprint('generate_map')を追加して確認してみましたが、
表示されないことからmap.generate_map()の処理で無限ループになってますね。
キーボードが反応しない原因はこれですね。
まず2重ループはやめて、itertools#productを使ったループにしてください。

from itertools import product
for i, j in product(range(self.row), range(self.col)):


こうすることでループのネストが1段減ります。

次にcontinue文を使う事で、ネストを一段へらします。

        for i, j in product(range(self.row), range(self.col)):
            print(i, j) # printでiとjの値を表示する。(デバック用)
            wall_flag = True
            if i == 0 or i == self.row - 1 or j == 0 or j == self.col - 1 or self.map[i][j] == 0:
                continue
            if i == 2 and j % 2 == 0 and self.map[i][j] == 1:
                while (wall_flag):
                    direction = random.randint(0, 100) % 4


でこれで実行してみると
4 12の出力で止まるので、5行目13列で問題が発生して無限ループになったことが分かります。
止まる出力メッセージは質問者様の環境で違うはずです。
ポイントはprintの出力がMAPの最後の行と列まで出力されていないので、無限ループになっているという事が確定したことです。

< まとめ >
原因:無限ループによってキーボードの入力を受付なかった。
発生条件:map.generate_map関数のwall_flagがFalseにならない。


generate_map関数の
1,direction = random.randint(0, 100) % 4の方の
if direction == UP:wall_flag = Falseの設定がないです。
2,direction = random.randint(0, 100) % 3で生成される値は0~2ですが、
LEFT, DOWN, RIGHT, UP = 3, 2, 1, 0で定義されているので。
IF文で判定しているのはRIGHT:1,DOWN:2,LEFT:3です。
生成している乱数源が正しくないかと。

そもそも論としてこのwhile wall_flagは不要なのでは?
迷路生成(棒倒し法)でググって出てきたページを見る限りでもiとjだけで実装できると思いますが。


原因:maporb_maporb_map_checkrow 、colの変数がクラス変数で宣言されていたため。
MAP情報が2回目以降初期化されていなかった。以下のコードで前回のMAPデータが表示されるのが分かると思います。

    def generate_map(self): 
        from pprint import PrettyPrinter
        pp = PrettyPrinter()
        pp.pprint(Map.map)


そのため2回目以降のgenerate_map関数が条件によって無限ループになった。
◇条件
行が4以上で2の倍数かつ2の倍数列で周りの4マスが全部オーブを取得した(Map情報を1にした)。
この時、wall_flagFalseにならず無限ループとなる。
◇対策方法
インスタンス変数にしてくださいな。あと以下の行も忘れずに
self.row = len(self.map)
self.col = len(self.map[0])
最後に変数名mapとクラス名Mapは標準の命名とかぶるため、list/mapなどは避けて
BoardやFieldかMapDataなどの名前に変更することをオススメいたします。


解決してよかったです。
最初は誰でもそーいうものなのです。
あんまりデバックしていないですが、コードを置いておきます
ご参考まで。

from itertools import product
DIRECTIONS = {LEFT: (0, -1), DOWN: (1, 0), RIGHT: (0, +1), UP: (-1, 0)}
# ↑Game_Titleの前に宣言
    def generate_map(self):  # マップ生成
        from pprint import PrettyPrinter
        pp = PrettyPrinter()
        pp.pprint(Map.map)
        # まず棒倒し法で迷路生成
        START_ROW = 2
        for i, j in product(range(START_ROW, self.row - 2, 2), range(2, self.col - 2, 2)):
            data = [LEFT, DOWN, RIGHT]
            # 最初の行は上にも倒せる。
            if i == START_ROW:
                data.append(UP)
            random.shuffle(data)
            while len(data) > 0:
                direction = data.pop(0)
                px, py = [x + y for (x, y) in zip([i, j], DIRECTIONS[direction])]
                if self.map[px][py] == 0:
                    self.map[px][py] = 1
                    break

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/05 19:31

    ご回答ありがとうございます。
    問題の再現手順についてですが、読み返してみると書き方が悪かったように思えました、申し訳ありません。
    起こった問題についてですが、スペースキー押下でゲーム開始→プレイヤーを衝突させてゲームが終了→タイトル画面に戻る→手順の初めに戻る、という手順を2ゲーム目まで行い、3ゲーム目開始時のスペースキー押下でプログラムが応答しなくなってしまいます。
    何度もプログラムを実行してみたのですが、応答しなくなるのが決まって2ゲームが終了した後に、3ゲーム目の始めでスペースキーを押下した瞬間、ということは確認できました。

    問題に関しまして、引き続きアドバイスいただけると助かります。よろしくお願いいたします。

    また、コードに関してあまりスッキリしていないと感じておりましたので、a, b, c のアドバイスをもとにコードの改良も行ってみようと考えております。アドバイスありがとうございます。

    最後に憶測の2に関して、関数の命名の仕方がややこしくて申し訳ないのですが、オーブを全て取得時に呼び出される関数が generate_orb_map で、こちらはマップ情報をもとにオーブを再配置する関数となっており、マップ自体を作り替えることはないので恐らくこちらで問題は起こらないかと考えております。

    キャンセル

  • 2018/05/05 21:07

    >kou_さんへ
    質問文の再現手順をコメントしていただいた内容に修正していただいても宜しいでしょうか。
    コメントの手順で問題が再現したので、デバックしてみますねー。

    キャンセル

  • 2018/05/05 22:12

    >umyu様
    ご指摘ありがとうございます。質問の再現手順の部分、修正させていただきました。

    マップ生成の件ですが、現在のプログラムでのマップ生成だと、稀にプレイヤー2の動けないマップを生成してしまう可能性のあるプログラムとなってしまっていることが確認出来ていましたので、ゲームの骨格が出来上がり次第、修正を考える予定でした。こちらに関してもご指摘いただき感謝申し上げます。

    キャンセル

  • 2018/05/06 02:25

    >umyu様
    まとめ の1に関して、棒倒し法の1段目以外の核となる部分のUP以外に棒を倒す、という部分を先に書いて、コピーアンドペーストで1段目の処理も作ってしまったため、その際にwall_flagの更新を書くことを忘れてしまっていました。
    次に2に関して、初めに方向を示す定数を定義する際に、 LEFT, DOWN, RIGHT, UP = 0, 1, 2, 3 と定義していたところを、後に現在の形に書き換えてしまっていたために生成した乱数値が条件文の条件から外れてしまう、ということが起きてしまっておりました。

    また、wall_flagを使用していたことに関して、生成した乱数方向に既に棒を倒し壁が立っていた場合に、壁は立たないのでもう一度while文を回す必要がある…と考えて壁を立てている、という意味でのフラグwall_flagを作ったつもりでした。
    しかし、ご指摘いただき気づきましたが、確かにフラグを使わずとも棒を倒した瞬間にbreak文にてループを抜け出せば良い話でした。

    さらに、Mapクラスの変数としていたマップのデータ map 、その他のクラス変数の未初期化の件について、自分の今までの解釈では、main関数で map = Map() として呼び出した時点で変数も初期化されている、と勘違いしていたのが原因でした。
    他のクラス同様にMapクラスにも__init__メソッドを実装し、毎回クラス変数を全て初期化出来るように書き換えたところ、何度か試した限りでは無限ループには陥らなくなりました。

    最後に、ループの深さを減らす方法について、とても参考になる手法でしたので、今後のプログラミング練習にも活かしたいと思います。また、Mapなどの名称が標準にあるため、他の標準と被らないように命名する旨、参考にさせていただき、この後に修正させていただこうと考えております。

    まだまだ拙いプログラミング力ですが、今回の件で得たものを今後に活かして、さらに力を磨いていけるよう頑張りたいと思います。

    長々とお時間を取らせてしまい、申し訳ありませんでした。丁寧に対応いただきとても助かりました、心より感謝申し上げます。

    キャンセル

  • 2018/05/06 03:06

    >umyu様
    コードサンプルの掲載、ありがとうございます。
    randomモジュールのshuffle関数など、初めて見る手法が様々見られるので、とても勉強になります。
    こちらのコードを参考にリファレンスなども調べつつ、より綺麗なコーディングに仕上げていけるように頑張りたいと思います。

    キャンセル

0

ソースコードの追記

class Map:  # マップクラス

    # mapは 0が陸地, 1が水 orb_map,orb_map_checkは 0がオーブが残っており, 1がオーブがなくなっている(もしくは元からない)
    map = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
           [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
           [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
           [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
           [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
           [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
           [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
           [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
           [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
           [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
           [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
           [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
           [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
           [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
           [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
    orb_map = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
               [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
               [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
    orb_map_check = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
    row, col = len(map), len(map[0])  # マップの行数,列数を取得
    imgs = [None] * 256  # マップチップ
    orb_img = None
    direction = -1

    # マップの描画
    def draw(self, screen):
        for i in range(self.row):
            for j in range(self.col):
                screen.blit(self.imgs[self.map[i][j]], (j * MSIZE, i * MSIZE))
                if self.orb_map[i][j] == 0:
                    screen.blit(self.orb_img, (j * MSIZE, i * MSIZE))

    def generate_map(self):  # マップ生成
        for i in range(self.row):  # まず棒倒し法で迷路生成
            for j in range(self.col):
                wall_flag = True
                if i == 0 or i == self.row - 1 or j == 0 or j == self.col - 1 or self.map[i][j] == 0:
                    pass
                elif i == 2 and j % 2 == 0 and self.map[i][j] == 1:
                    while (wall_flag):
                        direction = random.randint(0, 100) % 4
                        if direction == RIGHT:
                            if self.map[i][j + 1] == 0:
                                self.map[i][j + 1] = 1
                                wall_flag = False
                        if direction == DOWN:
                            if self.map[i + 1][j] == 0:
                                self.map[i + 1][j] = 1
                                wall_flag = False
                        if direction == LEFT:
                            if self.map[i][j - 1] == 0:
                                self.map[i][j - 1] = 1
                                wall_flag = False
                        if direction == UP:
                            if self.map[i - 1][j] == 0:
                                self.map[i - 1][j] = 1
                elif i % 2 == 0 and j % 2 == 0 and self.map[i][j] == 1:
                    while(wall_flag):
                        direction = random.randint(0, 100) % 3
                        if direction == RIGHT:
                            if self.map[i][j + 1] == 0:
                                self.map[i][j + 1] = 1
                                wall_flag = False
                        if direction == DOWN:
                            if self.map[i + 1][j] == 0:
                                self.map[i + 1][j] = 1
                                wall_flag = False
                        if direction == LEFT:
                            if self.map[i][j - 1] == 0:
                                self.map[i][j - 1] = 1
                                wall_flag = False
        for i in range(self.row):  # 生成した迷路の陸地をランダムでつなげて回路づくり
            for j in range(self.col):
                if i == 0 or i == self.row - 1 or j == 0 or j == self.col - 1:
                    pass
                else:
                    if self.map[i][j] == 1:
                        create_land = random.randint(0, 100) % 4
                        if create_land == 0:
                            self.map[i][j] = 0
                    if self.map[i][j] == 0:
                        plus_land_yet = True
                        count = 0
                        water = [False, False, False, False]
                        if self.map[i - 1][j] == 1:
                            count += 1
                            water[UP] = True
                        if self.map[i][j - 1] == 1:
                            count += 1
                            water[LEFT] = True
                        if self.map[i + 1][j] == 1:
                            count += 1
                            water[DOWN] = True
                        if self.map[i][j + 1] == 1:
                            count += 1
                            water[RIGHT] = True
                        # 生成した陸地がどの陸地とも陸続きでないとき、どこかと陸続きにする
                        if count >= 3:  # == 4 だと直線の浮島ができる >= 3 だと枠ギリギリまで陸が出来てしまう
                            while(plus_land_yet):
                                plus_land = random.randint(0, 100) % 4
                                if plus_land == UP and water[UP] and i - 1 != 0:
                                    self.map[i - 1][j] = 0
                                    plus_land_yet = False
                                elif plus_land == LEFT and water[LEFT] and j - 1 != 0:
                                    self.map[i][j - 1] = 0
                                    plus_land_yet = False
                                elif plus_land == DOWN and water[DOWN] and i + 1 != self.row - 2:
                                    self.map[i + 1][j] = 0
                                    plus_land_yet = False
                                elif plus_land == RIGHT and water[RIGHT] and j + 1 != self.col -2:
                                    self.map[i][j + 1] = 0
                                    plus_land_yet = False
                    # count(陸地が隣接する水辺の数) >= 3 で枠ギリギリに陸が出来ないように修正
                    if i == 1:
                        self.map[i - 1][j] = 1
                    if i == self.row - 2:
                        self.map[i + 1][j] = 1
                    if j == 1:
                        self.map[i][j - 1] = 1
                    if j == self.col - 2:
                        self.map[i][j + 1] = 1

    def generate_orb_map(self):  # どこにオーブがあるかのマップデータ
        self.orb_map = copy.deepcopy(self.map)
        self.orb_map[1][1] = 1
        self.orb_map[self.row - 2][self.col - 2] = 1

    def check_orb_is_empty(self):  # マップ上にオーブがなくなったかの判定
        if self.orb_map == self.orb_map_check:
            return True
        else:
            return False

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/05 03:58

    # 上記に続きさらに追記です

    def load_image(filename, colorkey=None): # 画像データの読み込み
    filepath = os.path.join(os.getcwd(), filename)
    image = pygame.image.load(filepath) # この出来上がった方のimageはSurfaceオブジェクト
    image = image.convert()
    if colorkey is not None:
    if colorkey is -1:
    colorkey = image.get_at((0,0))
    image.set_colorkey(colorkey, RLEACCEL)
    return image


    def split_chara_image(image): # プレイヤーキャラの画像を切り抜きリストに
    image_list = []
    chara_size = 32
    for i in range(0, 128, chara_size):
    tmp_list = []
    for j in range(0, 96, chara_size):
    surface = pygame.Surface((chara_size, chara_size))
    surface.blit(image, (0, 0), (j, i, chara_size, chara_size))
    surface.set_colorkey(surface.get_at((0, 0)), RLEACCEL)
    surface.convert()
    tmp_list.append(surface)
    image_list.append(tmp_list)
    return image_list


    def title(screen): # タイトル画面の処理
    game_title = Game_Title() # ゲームタイトルオブジェクトの生成
    while True:
    screen.fill((0, 0, 0))
    game_title.update()
    game_title.draw(screen)
    pygame.display.update()
    for event in pygame.event.get(): # イベント処理
    if event.type == QUIT: # 閉じるボタンが押されると終了
    pygame.quit()
    sys.exit()
    if event.type == KEYDOWN and event.key == K_ESCAPE: # エスケープキーでも終了
    pygame.quit()
    sys.exit()
    if event.type == KEYDOWN and event.key == K_SPACE and not game_title.start_flag: # スペースキーでスタート
    game_title.start_flag = True
    break
    if game_title.finish:
    break


    def main(screen): # ゲーム中の処理
    maptips = ["grass.png", "water.png"]
    Map.imgs[0] = load_image(maptips[0])
    Map.imgs[1] = load_image(maptips[1])
    Map.orb_img = load_image("orb.png", -1)
    map = Map()
    map.generate_map() # ランダムマップ生成
    map.generate_orb_map() # 生成したマップをもとにオーブを配置

    all = pygame.sprite.RenderUpdates() # スプライトをまとめて扱う
    Player.containers = all

    player1 = Player("player1.png", 1, 1, DOWN, None)
    player2 = Player("player2.png", 17, 13, UP, player1)
    player1.other_player = player2
    player1_score = Text_Orbs(player1, map)
    player2_score = Text_Orbs(player2, map)

    clock = pygame.time.Clock()

    while True:
    clock.tick(60)
    all.update(map)
    map.draw(screen)
    all.draw(screen)
    player1_score.draw(screen)
    player2_score.draw(screen)
    if map.check_orb_is_empty():
    map.generate_orb_map()
    pygame.display.update()
    pressed_key = pygame.key.get_pressed() # get_pressed()だと長押し判定が可能
    if pressed_key[K_LEFT]:
    player1.move(LEFT, map)
    if pressed_key[K_DOWN]:
    player1.move(DOWN, map)
    if pressed_key[K_RIGHT]:
    player1.move(RIGHT, map)
    if pressed_key[K_UP]:
    player1.move(UP, map)
    if pressed_key[K_a]:
    player2.move(LEFT, map)
    if pressed_key[K_s]:
    player2.move(DOWN, map)
    if pressed_key[K_d]:
    player2.move(RIGHT, map)
    if pressed_key[K_w]:
    player2.move(UP, map)
    for event in pygame.event.get(): # イベント処理
    if event.type == QUIT: # 閉じるボタンが押されると終了
    pygame.quit()
    sys.exit()
    if event.type == KEYDOWN and event.key == K_ESCAPE: # エスケープキーでも終了
    pygame.quit()
    sys.exit()
    if player1.result != "": # ゲームの勝敗がついていたらリザルト
    print("Player1 is " + player1.result + ", Player2 is " + player2.result)
    break


    if __name__ == "__main__":
    while True:
    pygame.init() # 初期化
    screen = pygame.display.set_mode((SCREEN_WIDTH_SIZE, SCREEN_HEIGHT_SIZE)) # 描写スクリーンの準備
    pygame.display.set_caption("Orb Fighters") # ウィンドウのタイトル
    title(screen) # タイトル画面
    main(screen) # ゲームのメインループ

    キャンセル

  • 2018/05/05 04:00

    コメントにての追記でインデントが崩れてしまってます。分かりづらくて申し訳ありません。

    キャンセル

  • 2018/05/05 04:03

    このサイトは質問の編集機能あるので、そっちでやってくださいな。この回答も読みづらいので、ぜんぶそっちにまとめてください

    キャンセル

  • 2018/05/05 11:42

    申し訳ありません。
    読みづらいのは重々承知しておりますが、質問やその他の回答、コメントの文字制限が10000字までとなっているようで、ソースコードがどうやってもひとまとめに掲載出来ませんでした。
    何かしらの代替の方法がありますでしょうか…
    ソースコードのファイルを添付する、という方法も考えたのですが、ファイルを添付する欄等もなかったため、このような読みづらい掲載方法になってしまいました…

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.36%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Python

    9102questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    7313questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。