メむンコンテンツぞスキップ
芋出し画像

pyxelゲヌム制䜜TIPS_芋䞋ろし圢RPG颚

はじめに

このnoteはpythonのレトロゲヌム゚ンゞン「pyxel」でのゲヌム制䜜に圹立぀かもしれない小さなサンプルプログラムのTIPSです。
以䞋の環境で䜜成・動䜜させおいたす。
・OSWindows11
・開発環境Visual Studio Code(Ver.1.88.1)
・pyxelのバヌゞョン2.0.12

蚘事内のコヌドはご自由にお䜿いください。むメヌゞ等もファむルは添付しおいたせんが、暡写(?)しお䜿っおいただいお構いたせん。
たた、pyxelの動䜜環境や各関数の詳现な説明はpyxel公匏GitHubをご参照ください。

芋䞋ろし圢RPGっお

昔懐かしい芋䞋ろし圢RPG。れルダの䌝説の初期や携垯機ではこの圢態の䜜品が倚かった気がしたす。ちょっず毛色は違うけど、颚来のシレンずか。ドラゎンク゚スト・ファむナルファンタゞヌなんかもバトルシヌン以倖は「芋䞋ろし圢」ず蚀っおいいんじゃないでしょうか。
マップを描画し、キャラクタヌを動かす。今回の蚘事ではここたでを目暙ずしたすが、それでも達成感はなかなかのもの。この骚組みさえできれば、あずは戊闘だったりむベントだったり、思うがたたに付け足しおいけばいいのです。

䜜っおいきたしょう

それでは始めたしょう。
たずはpyxelアプリケヌションの基本的な型を曞いおしたいたす。これだけ曞けばずりあえず画面は衚瀺されたすから、おいおい足しおいきたしょう。

import pyxel


class App:
    def __init__(self):
        #ここで起動時の凊理をしたす
        pyxel.init(128, 128)        
        pyxel.run(self.update, self.draw)

    def update(self):
        #ここで毎フレヌムの曎新䜜業をしたす
        pass

    def draw(self):
        #ここで毎フレヌムの描画䜜業をしたす
        pyxel.cls(0)
        pyxel.text(40, 60, "Hello, Pyxel!", pyxel.frame_count % 16)        


App()

今回は128*128の画面サむズで䜜りたす。実行するずビカビカ光る文字が衚瀺されるはずです。凊理の順番ずしおは毎フレヌム「update→draw」の関数が実行されたす。

さお、ここたで出来たら早速芁玠を远加しおいきたす。
たずは「マップの衚瀺」です。
Pyxel Editorを起動しおタむルマップを䜜成したしょう。

画像
▲むメヌゞバンク2にタむルマップ甚の画像を䜜成。
簡単な感じで土ず草、岩です。
画像
▲タむルマップ゚ディタに切り替えおマップ䜜補。
呚りは岩で囲っお、なんか建物っぜいのも配眮。草は気分で。

さあ、マップができたした。pyxelのタむルマップは1マスが8*8でできおいたす。これが䞊の画面だず16*16マスありたす。ずいう事はこのマップを衚瀺するのには16*8=128、瞊暪128ドット必芁になりたす。なので今回は128*128の画面サむズにしたわけですね。

このマップを衚瀺させるためにコヌドに以䞋の蚘述を付け足したす。

    def __init__(self):
        #ここで起動時の凊理をしたす                                
        pyxel.init(128, 128)        
        pyxel.load('./sample01.pyxres')             
        pyxel.run(self.update, self.draw)

たずはpyxel.loadで䜜成したpyxresを読み蟌みたす。ファむルパスやファむル名は適宜倉曎しおください。

    def draw(self):
        #ここで毎フレヌムの描画䜜業をしたす
        pyxel.cls(0)
        pyxel.bltm(0, 0, 0, 0, 0, 128, 128)       

draw関数にpyxel.bltmを远加しおタむルマップを描画させたす。実行しおみたしょう。

画像
▲タむルマップが衚瀺されたした。

良い感じですね。次はここにキャラクタヌを配眮しおみたしょう。たずはPyxel Editorで画像を䜜りたす。1マス8*8なので同じサむズで䜜りたしょう。
サむズがあっおいればどんなキャラクタヌでも倧䞈倫です。

画像
▲猫だか犬だかわからない䜕かを䜜成。

では画面䞊に衚瀺させおみたす。今回のマップは1マスが8*8、぀たり8ドット区切りになっおいたす。キャラクタヌを配眮する際は座暙が8の倍数になるようにするずきれいに収たるはずです。

    def draw(self):
        #ここで毎フレヌムの描画䜜業をしたす
        pyxel.cls(0)        
        pyxel.bltm(0, 0, 0, 0, 0, 128, 128)       
        pyxel.blt(16, 16, 0, 0, 0, 8, 8, 14)

draw関数にpyxel.bltを远加したす。今回最埌の匕数に「14」を指定したしたが、これは透過させる色の指定です。䞊の画像で背景色にしおいるピンク?っぜい色を透過させおいたす。
たた、曞かれた呜什は䞊から実行されおいくので、マップの描画の前にキャラクタヌの描画呜什を曞いおしたうず、䞊からマップで塗り぀ぶされおしたいたす。順番には泚意したしょう。
では実行しおみたしょう。

画像
▲巊䞊あたりにキャラクタヌが描画されたした。

ゲヌムっぜさがでおきたした。぀いでだからキヌボヌドで動かせるようにしちゃいたしょう。
動かせるようにするずいう事は、キャラクタヌの座暙を可倉にするずいう事。たずはそのための倉数を甚意したす。

    def __init__(self):
        #ここで起動時の凊理をしたす                                
        pyxel.init(128, 128)        
        pyxel.load('./sample01.pyxres')    
        self.player_pos = [16, 16]         
        pyxel.run(self.update, self.draw)

self.player_posずいう倉数を䜜成したした。リスト型でキャラクタヌのx座暙・y座暙を栌玍したす。
では次にキヌボヌドを抌した際にこの倀が倉わるようにしたしょう。

    def update(self):
        #ここで毎フレヌムの曎新䜜業をしたす
        #コントロヌル郚分###################
        if pyxel.btnp(pyxel.KEY_RIGHT):
            self.player_pos[0] += 8
            
        elif pyxel.btnp(pyxel.KEY_LEFT):
            self.player_pos[0] -= 8

        elif pyxel.btnp(pyxel.KEY_UP):
            self.player_pos[1] -= 8

        elif pyxel.btnp(pyxel.KEY_DOWN):
            self.player_pos[1] += 8

if pyxel.btnp(pyxel.キヌ名):でキヌボヌドの抌䞋刀定ができたす。今回は䞊䞋巊右のキヌで刀定したす。それぞれ「右ボタンが抌されたらx座暙を+8」「巊ボタンが抌されたらx座暙を-8」ずいう颚に䜜っおいきたす。
䞊䞋のy座暙は泚意が必芁で、pyxelでは䞋がに行くほどy座暙が倧きくなりたす。そのため「䞊ボタンが抌されたらy座暙を-8」「䞋ボタンが抌されたらy座暙を+8」ずいうようにキヌ操䜜ず逆になりたす。

最埌に珟圚は決め打ちになっおいるキャラクタヌの描画䜍眮を倉数を䜿う圢に改良したしょう。

    def draw(self):
        #ここで毎フレヌムの描画䜜業をしたす
        pyxel.cls(0)        
        pyxel.bltm(0, 0, 0, 0, 0, 128, 128)       
        pyxel.blt(self.player_pos[0], self.player_pos[1], 0, 0, 0, 8, 8, 14)

pyxel.bltで指定しおいる座暙をself.player_posから取埗するようにしたした。これでupdate関数での倉曎を描画時に反映させるこずができたす。

画像
▲ぐりぐり動いおいたす。

ただ、珟状では障害物の圓たり刀定がないので岩のマスも通過しおしたいたす。これではマップずいうよりただの画像なので、圓たり刀定を远加しおいきたしょう。

各キヌのコントロヌル郚分に圓たり刀定のチェックロゞックを付けおもいいのですが、こういったいろいろなずころで䜿いそうなものは関数化するず䟿利です。

    def move_check(self, x, y):
        if pyxel.tilemaps[0].pget(x//8, y//8) == (0, 1):
            return False
        else:
            return True

move_check関数を䜜りたした。呌び出す際の匕数ずしおxずyがあり、その座暙が岩であればFalse、それ以倖はTrueを返したす。タむルマップの皮類の取埗にはpyxel.tilemaps[t].pgetの呜什を䜿いたすが、タむルマップは8ドットで1マスなので実際の座暙を8で割るこずでタむルマップのどのマスかを特定できたす。先ほどの䟋だず座暙は[16, 16]なので8で割っお[2, 2]のマスずいう事になりたす。

それではこの関数をキヌコントロヌルの郚分で呌び出しおみたしょう。

    def update(self):
        #ここで毎フレヌムの曎新䜜業をしたす
        #コントロヌル郚分###################
        if pyxel.btnp(pyxel.KEY_RIGHT):
            if self.move_check(self.player_pos[0]+8, self.player_pos[1]):
                self.player_pos[0] += 8
            
        elif pyxel.btnp(pyxel.KEY_LEFT):
            if self.move_check(self.player_pos[0]-8, self.player_pos[1]):
                self.player_pos[0] -= 8

        elif pyxel.btnp(pyxel.KEY_UP):
            if self.move_check(self.player_pos[0], self.player_pos[1]-8):
                self.player_pos[1] -= 8

        elif pyxel.btnp(pyxel.KEY_DOWN):
            if self.move_check(self.player_pos[0], self.player_pos[1]+8):
                self.player_pos[1] += 8

if self.move_check(self.player_pos[0]+8, self.player_pos[1]):のような圢で呌び出したす。これでmove_check関数がTrueを返したずきのみ、移行の凊理が流れたす。チェックするマスは「キャラクタヌが今いるマス」ではなく「これから移動しようずしおいるマス」である点を泚意しおください。

画像
▲きちんず岩のマスは進めなくなりたした

さあこれで「マップの描画」「キャラクタヌの描画」「キャラクタヌの移動」ができたした。これをベヌスに䜕を䜜りたしょうか

・キャラクタヌが1぀ずいうのは寂しいのでNPCを増やす。
→移動の刀定ずかは今回䜜ったものが参考になりそうです。
・もっず倧きなマップを䜜っおみる。
→マップを倧きくするずスクロヌルの問題が出おきたす。pyxel.cameraの呜什が圹に立぀かもしれたせん。
・移動先のマスによっお挙動を倉えおみる。
→pyxel.tilemaps[t].pgetでマスの皮類が分かるのは䞊蚘の通りです。マスによっおむベントを蚭定したりするのも良いですね。

ぜひ色々ず詊しおいただければず思いたす。個人的には広いマップずいうのはやはりロマンですね。

最埌にすべお぀なげた゜ヌスを茉せお終わりにしようず思いたす。

import pyxel


class App:
    def __init__(self):
        #ここで起動時の凊理をしたす                                
        pyxel.init(128, 128)        
        pyxel.load('./sample01.pyxres')    
        self.player_pos = [16, 16]         
        pyxel.run(self.update, self.draw)

    def update(self):
        #ここで毎フレヌムの曎新䜜業をしたす
        #コントロヌル郚分###################
        if pyxel.btnp(pyxel.KEY_RIGHT):
            if self.move_check(self.player_pos[0]+8, self.player_pos[1]):
                self.player_pos[0] += 8
            
        elif pyxel.btnp(pyxel.KEY_LEFT):
            if self.move_check(self.player_pos[0]-8, self.player_pos[1]):
                self.player_pos[0] -= 8

        elif pyxel.btnp(pyxel.KEY_UP):
            if self.move_check(self.player_pos[0], self.player_pos[1]-8):
                self.player_pos[1] -= 8

        elif pyxel.btnp(pyxel.KEY_DOWN):
            if self.move_check(self.player_pos[0], self.player_pos[1]+8):
                self.player_pos[1] += 8

    def move_check(self, x, y):
        if pyxel.tilemaps[0].pget(x//8, y//8) == (0, 1):
            return False
        else:
            return True

    def draw(self):
        #ここで毎フレヌムの描画䜜業をしたす
        pyxel.cls(0)        
        pyxel.bltm(0, 0, 0, 0, 0, 128, 128)       
        pyxel.blt(self.player_pos[0], self.player_pos[1], 0, 0, 0, 8, 8, 14)


App()

ここたで読んでいただきありがずうございたした。

※有料゚リアですが、特に䜕もありたせん。蚭定しおいるだけですので、お気に召したしたら賌入いただけるず嬉しいです。

 
 
出版瀟のしがない瀟内SE。 ここでは䞻に趣味のプログラミングやゲヌム制䜜に぀いお曞いおいたす。䜜ったゲヌムは https://koidemizu.github.io/ で公開しおいるのでよかったら遊んでください。 ゲヌム倧奜きむンドア掟。

あなたぞのおすすめ