0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

マップを作る

Last updated at Posted at 2025-01-20

この記事はaidiaryさんのコードを参考にして書かれてます。

記事全体の目次へ移動

リストでマップを作る

ここをクリックしてください

マップ.png

import pygame
from pygame.locals import *
import sys
import os
 
COL = 3  # マップ全体のヨコのサイズ(3マス)
GS = 32  # ひとつのマスのサイズ(ピクセル)

map_list = [1,0,1]# 0:草地
       
def draw_map(screen):
    """マップを描画する"""
    for c in range(COL):
        if map_list[c] == 0:
            screen.blit(grassImg, (c*GS, 0))
        elif map_list[c] == 1:
            screen.blit(seaImg, (c*GS, 0))
            
width, height = 96, 32 
pygame.init()
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("マップを作る")
 
# 草原の画像をロード
grassImg = pygame.image.load(パス)
# 海の画像をロード
seaImg = pygame.image.load(パス)
 
while True:
    draw_map(screen)  # マップ描画
    pygame.display.update()
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

COL = 3
マップ全体の列数です。ピクセル単位ではなく、グリッドの数です。

GS = 32
ひとつのマスのサイズ(ピクセル単位)です。

map_list = [1, 0, 1]
マップを描き分けるためのリストです。0は草地、1は海を表します。

def draw_map(screen):
マップを描画する

for c in range(COL):
繰り返し処理です。COLは3なので、0~2の数字を作ります。

if map_list[c] == 0:
リストのインデックスに合わせて、描画を判定します。
map_listのインデックスが1のとき、数字が0なので描画します。

screen.blit(grassImg, (c * GS, 0))
インデックスが1のとき、c * GSは1 * 32なので、描画する座標は(32, 0)で真ん中です。

elif map_list[c] == 1:
map_listのインデックスが0と2のとき、数字が1なので描画します。

screen.blit(seaImg, (c * GS, 0))
インデックスが0のとき、c * GSは0 * 32なので、描画する座標は(0, 0)で左端です。
インデックスが2のとき、c * GSは2 * 32なので、描画する座標は(64, 0)で右端です。

2次元配列でマップを作る

ここをクリックしてください

スクリーンショット (822).png

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

ROW = 3  # マップ全体のタテのサイズ(3マス)
COL = 3  # マップ全体のヨコのサイズ(3マス)
GS = 32  # ひとつのマスのサイズ(ピクセル)

map_array2d = [[1,1,1],
            [1,0,1],
            [1,1,1]]
       
def draw_map(screen):
    """マップを描画する"""
    for r in range(ROW):
        for c in range(COL):
            if map_array2d[r][c] == 0:
                screen.blit(grassImg, (c*GS, r*GS))
            elif map_array2d[r][c] == 1:
                screen.blit(seaImg, (c*GS, r*GS))
            
width, height = 96, 96 
pygame.init()
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("マップを作る")
 
# 草原の画像をロード
grassImg = pygame.image.load(パス)
# 海の画像をロード
seaImg = pygame.image.load(パス)
 
while True:
    draw_map(screen)  # マップ描画
    pygame.display.update()
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

map_array2d = [[1,1,1],
[1,0,1],
[1,1,1]]

変数名がちょっとややこしいですが、array2dは2次元配列のことです。
map()という関数があるようなので付け足してみました。

2次元配列はリストの中にリストが入っていると解釈して大丈夫だと思います。

for r in range(ROW):
for c in range(COL):

2重のループです。
まず1行目を横に描画していって、
2行目、3行目と描画していく感じです。

if map_array2d[r][c] == 0:

2次元配列の行と列のインデックスを指定して、判定しています。
繰り返し処理でこんな風に変化していきます。
map_array2d[0][0],map_array2d[0][1],map_array2d[0][2],
map_array2d[1][0],map_array2d[1][1],map_array2d[1][2],
map_array2d[2][0],map_array2d[2][1],map_array2d[2][2],

array2d.png

リストに画像を格納してマップを作る

ここをクリックしてください
import pygame
from pygame.locals import *
import sys
import os

ROW = 3  # マップ全体のタテのサイズ(3マス)
COL = 3  # マップ全体のヨコのサイズ(3マス)
GS = 32  # ひとつのマスのサイズ(ピクセル)

map_array2d = [[1,1,1],
            [1,0,1],
            [1,1,1]]
       
def draw_map(screen):
    """マップを描画する"""
    for r in range(ROW):
        for c in range(COL):
            screen.blit(map_list[map_array2d[r][c]], (c*GS, r*GS))
            
width, height = 96, 96 
pygame.init()
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("マップを作る")
 
# 草原の画像をロード
grassImg = pygame.image.load(パス)
# 海の画像をロード
seaImg = pygame.image.load(パス)

map_list = []

map_list.append(grassImg)
map_list.append(seaImg)

while True:
    draw_map(screen)  # マップ描画
    pygame.display.update()
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

#草原の画像をロード
grassImg = pygame.image.load(パス)
#海の画像をロード
seaImg = pygame.image.load(パス)

map_list = []

map_list.append(grassImg)
map_list.append(seaImg)

画像データをリストに入れてます。

map_array2d = [[1,1,1],
[1,0,1],
[1,1,1]]

def draw_map(screen):
"""マップを描画する"""
for r in range(ROW):
for c in range(COL):
screen.blit(map_list[map_array2d[r][c]], (cGS, rGS))

map_array2dのインデックスを指定して要素取得して、それをmap_listのインデックスとして使用して、
画像データを取得してます。

array2d.png

具体例を示すと、map_array2d[0][0]は2次元配列の左上なので、1です。
map_listには2つの画像が格納されてます。草原の画像が先にリストに追加されてますので、インデックス0は草原の画像で、インデックス1が海の画像です。
map_array2d[0][0]は1なので、海の画像が描画されます。

テキストファイルをロードしてマップを作る

ここをクリックしてください

pythonスクリプトと同じところにdataフォルダを用意する必要があります。
dataフォルダには草原の画像、海の画像を入れます。どちらともpngファイルです。
さらにtxtファイルを入れてください。

テキストファイル.png

1行目が行数と列数です。

スクリーンショット (822).png


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

width, height = 96, 96
GS = 32

def main():
    pygame.init()
    screen = pygame.display.set_mode((width, height))
    pygame.display.set_caption("マップのロード")
    # マップチップをロード
    Map.images[0] = load_image("grass")  # 草地
    Map.images[1] = load_image("sea")  # 海
    # マップの作成
    map = Map("マップ")
    while True:
        map.draw(screen)
        pygame.display.update()
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

def load_image(filename):
    filename = os.path.join("data", filename + ".png")
    image = pygame.image.load(filename)
    image = image.convert()
    return image

class Map:
    images = [None] * 2  
    def __init__(self, name):
        self.name = name
        self.row = -1  # 行数
        self.col = -1  # 列数
        self.map = []  # マップデータ(2次元リスト)
        self.load()
    def draw(self, screen):
        """マップを描画する"""
        for r in range(self.row):
            for c in range(self.col):
                screen.blit(self.images[self.map[r][c]], (c*GS,r*GS))
    def load(self):
        """ファイルからマップをロード"""
        file = os.path.join("data", self.name + ".txt")
        # テキスト形式のマップを読み込む
        with open(file) as fp:
            lines = fp.readlines()
            row_str, col_str = lines[0].split()  # 行数と列数
            self.row, self.col = int(row_str), int(col_str)
            for line in lines[1:]:
                line = line.rstrip()
                line = list(line)
                self.map.append([int(x) for x in line])

if __name__ == "__main__":
    main()

Map.images[0] = load_image("grass") # 草地
Map.images[1] = load_image("sea") # 海

load_image関数を使って画像をロードした後、インデックスを指定してリストに入れています。
("grass") は草原の画像のファイル名と一致させてください。
("sea")は海の画像のファイル名と一致させてください。
違うファイル名を使いたいときは、書き換えてください。

map = Map("マップ")

インスタンスを生成しています。引数の"マップ"はファイル名です。

map.draw(screen)

マップの描画です。

def load_image(filename):
filename = os.path.join("data", filename + ".png")
image = pygame.image.load(filename)
image = image.convert()
return image

マップ画像をロードする関数です。
2行目は、フォルダ名とファイル名を区切り文字をつけて連結してます。
ここでは相対パスが使われています。dataフォルダはpythonスクリプトと同じところにないといけません。
4行目では画像を最適化しています。ゲーム内で多くの画像を頻繁に描画する場合、このような最適化は非常に重要です。

class Map:
images = [None] * 2 # マップチップ(番号->イメージ)
def init(self, name):
self.name = name
self.row = -1 # 行数
self.col = -1 # 列数
self.map = [] # マップデータ(2次元リスト)
self.load()

2行目でリスト内のNoneを2つにしています。[None,None]
このNoneは画像データに置き換えられます。
このコードでは、画像データが2つなのでNoneも2つですが、画像データの種類が増えるとNoneも増やす必要があります。
self.nameはファイル名です。
self.rowとself.colは行数と列数です。ここではまだ設定されてません。
self.mapはリストを入れるためのリストです。2次元配列のためです。
self.load()はインスタンス生成時にdef loadを実行するためにここに書いてあります。

スクリーンショット (823).png

def load(self):
"""ファイルからマップをロード"""
file = os.path.join("data", self.name + ".txt")
# テキスト形式のマップを読み込む
with open(file) as fp
lines = fp.readlines()
row_str, col_str = lines[0].split() # 行数と列数
self.row, self.col = int(row_str), int(col_str)
for line in lines[1:]:
line = line.rstrip()
line = list(line)
self.map.append([int(x) for x in line])

テキストファイルをロードするメソッドです。2次元配列のためです。
with open(file) as fp
withは自動でファイルを閉じるためです。
open()でファイルを開きます。fileはファイルのパスです。
as fp で変数に割り当てています。
readlines()で行ごとに読み込みます。各行がひとつの文字列になります。文字列はリストに入ってます。改行文字のある状態です。
['3 3\n', '111\n', '101\n', '111']
row_str, col_str = lines[0].split() # 行数と列数
lines[0],つまり'3 3\n'をインデックスで指定して、文字列を分割してリストに入れています。
.split()は引数に区切り文字を指定しますが、からの場合はデフォルトでスペース,改行文字などを区切り文字にします。
'3 3\n'には、3と3の間にスペースがあります。
['3', '3']

これがアンパッキングされているので、各変数に文字列の'3'が格納されています。
self.row, self.col = int(row_str), int(col_str)
int()で、各変数が整数の3になっています。

for line in lines[1:]:
line = line.rstrip()
line = list(line)
self.map.append([int(x) for x in line])

linesリストのインデックス1から3まで処理を繰り返します。
line = line.rstrip()で行末の改行文字を削除します。
'111\n'が'111'になります。
list(line)で反復可能なオブジェクトをリストにしています。
["1","1","1"]

[int(x) for x in line]リスト内法表記で文字列の'1'を整数にしています。
[1,1,1]
self.map.append()でリストに格納されています。
[[1,1,1]]
全ての処理が終わるとこうなります。
[[1, 1, 1], [1, 0, 1], [1, 1, 1]]
2次元配列のできあがりです。改行したものとは見た目が異なりますが、内容は全く同じです。

ここをクリックしてください


ここをクリックしてください


0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?