mieki256's diary



2021/10/04(月) [n年前の日記]

#1 [pygame] PygameでタイルマップBGを描画

Python + Pygame でタイルマップのBGを描画できるか試してみた。

環境は、Windows10 x64 21H1 + Python 3.9.7 64bit + Pygame 2.0.1。

こんな感じになった。800x600ドットのウインドウ上で描画。カーソルキー、あるいはWASDキーでスクロールができる。




手抜きをして、タイルチップ単位 = 8x8ドット単位でスクロールさせてるから、一般的な2Dゲームのようにドット単位で動かすにはもうちょっとアレコレ処理を入れないといかんのだけど…。でもまあ、とりあえず、Pygame を使った場合でも、こういった描画はできそうだと分かった。

ただ、このやり方では、1280x720のウインドウサイズで描画した際に60FPSにならなかった…。AMD Ryzen 7 1700 (3GHz,8コア,16スレッド) + GeForce GTX 1060 6GB の環境で、2D、しかもBGを1枚しか表示してないのに、60FPSが出ないのはダメだよな…。相変わらず、Python + Pygame は遅い…。

もっとも、8x8ドット単位で処理してるのがいかんのではという気もする。32x32ドットや64x64ドットにして、ループ回数を減らすべきかも。もしくは、BG描画用の大きな Surface を用意して、スクロールに応じて書き換えが必要な部分だけ変更して、ウインドウへの描画はそのBG用Surfaceを使って行う、てな感じの処理にすれば負荷が違ってくるのかもしれない。

ソースと使用画像。 :

ソースは以下。

_02_tilemapbg.py
import json
import pygame
import sys

SCRW, SCRH = 800, 600

pygame.init()
screen = pygame.display.set_mode((SCRW, SCRH), pygame.DOUBLEBUF)

# load Tiled json file
bglayout = "road_layout.json"
with open(bglayout, 'r') as f:
    data = json.load(f)

map_w = int(data["width"])
map_h = int(data["height"])
tile_w = int(data["tilewidth"])
tile_h = int(data["tileheight"])

# get tilemap, convert start ID 1 to 0.
bgtilemap = list(map(lambda x: x-1, data["layers"][0]["data"]))

# load bg chip image
imgname = "road_chip.png"
img = pygame.image.load(imgname).convert_alpha()

# split bg chip image
bgchips = []
w, h = tile_w, tile_h
xc = img.get_width() // w
yc = img.get_height() // h
for yi in range(yc):
    for xi in range(xc):
        x, y = xi * w, yi * h
        bgchips.append(img.subsurface(pygame.Rect(x, y, w, h)))

xofs, yofs = 0, 0
xofs_max = max(0, map_w - (SCRW // tile_w))
yofs_max = max(0, map_h - (SCRH // tile_h))

running = True

clock = pygame.time.Clock()

# Main loop
while running:

    # update
    
    # check event
    for ev in pygame.event.get():
        if ev.type == pygame.QUIT:
            running = False
        if ev.type == pygame.KEYDOWN:
            if ev.key == pygame.K_ESCAPE or ev.key == pygame.K_q:
                # Push ESC or Q key
                running = False

    # scroll BG
    pygame.event.pump()
    pressed = pygame.key.get_pressed()
    if pressed[pygame.K_LEFT] or pressed[pygame.K_a]:
        xofs -= 1
        if xofs < 0:
            xofs = 0
    if pressed[pygame.K_RIGHT] or pressed[pygame.K_d]:
        xofs += 1
        if xofs > xofs_max:
            xofs = xofs_max
    if pressed[pygame.K_UP] or pressed[pygame.K_w]:
        yofs -= 1
        if yofs < 0:
            yofs = 0
    if pressed[pygame.K_DOWN] or pressed[pygame.K_s]:
        yofs += 1
        if yofs > yofs_max:
            yofs = yofs_max

    # draw start
    screen.fill((40, 60, 200))   # clear screen

    # draw tilemap BG
    xc = SCRW // tile_w
    yc = SCRH // tile_h
    for yi in range(yc):
        for xi in range(xc):
            xii = xi + xofs
            yii = yi + yofs
            if xii >= map_w or yii >= map_h:
                continue
            i = bgtilemap[yii * map_w + xii]
            x = xi * tile_w
            y = yi * tile_h
            screen.blit(bgchips[i], (x, y))

    pygame.display.flip()
    clock.tick_busy_loop(60)
    
    cap = "Tilemap BG - %5.2f FPS" % (clock.get_fps())
    pygame.display.set_caption(cap)

pygame.quit()
sys.exit()

処理としては、以下のようなことをしている。
  • マップエディタ Tiled からエクスポートした json を読み込んで、タイルマップの配列(一次元配列)を得る。
  • タイルセット画像を読み込んで、8x8ドット単位で分割。
  • タイルマップ配列に基づいて、8x8ドット単位で、タイルセット画像を描画。

使用画像は以下。

road_chip.png
_road_chip.png

読み込むタイルマップデータ(.json)は以下。Tiled で配置して、json でエクスポートした。

_road_layout.json

Tiled で編集し直したい場合は、以下の Tiled用ファイルを使えばよいかと…。

_road_layout.tmx
_road_chip.json

ソース、画像、Tiled用ファイルは、CC0 / Public Domain ってことで。

余談。今後の課題。 :

こういった感じのタイルマップを自動生成できるようにしたいのだけど、さて、何をどうすればいいのやら。うーん。

道路の自動生成ができれば、道路が無い部分にビルを配置することだってできそうだなと。更に、2Dで道路やビルを配置できるなら、ソレを3Dで処理して…。例えば blender + Python で、道路+ビル街を生成するスクリプトを書けたりしないかなと。要するに、POV-Ray 用の CityGen みたいなことができないかと。

いやまあ、blenderなら、めっちゃリアルでゴイスなビル街を生成してくれる有償アドオンがあるらしいのだけど…。

_Blender の都市生成アドオン「SceneCity」 - 100光年ダイアリー
_SceneCity: 3D city generator addon for Blender 2.9+

この手のツール、アドオン、プラグインは結構作られているようで…。

_3Dソフトで都市を自動生成 - 100光年ダイアリー

ゴイスな映像を作りたいなら、買って使ったほうが早いはず。

以上です。

過去ログ表示

Prev - 2021/10 -
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

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project