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

pyxelゲヌム制䜜TIPS_RPGの村颚

はじめに

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

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

RPGの村ずいえば

シヌムレスに移動出来たり、ワヌルドマップからアむコンに入ったりずいろいろですが、たあおおむね「店があり」「宿屋があり」「情報を集めお」「なんかむベントも起こったり」ずいった具合でしょうか。基本的には戊闘が起きない区域なのですが、ここをあえお䟵すこずでむベントの衝撃床を高めおいる䜜品もありたすね。
今回は以䞋のnoteで䜜った芋䞋ろし圢RPGの基本構造を流甚しお、「マップぞのむベントの配眮」「建物に入る(堎面転換をする)」の2点を䜜っおみたいず思いたす。

䜜っおいきたしょう

それでは始めたしょう。

たずは画面の衚瀺、キャラクタヌの移動たでのコヌドをペタッず。

import pyxel


class App:
    def __init__(self):
        #ここで起動時の凊理をしたす                                
        pyxel.init(128, 128)        
        pyxel.load('./sample02.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()
画像
▲実行するず画面が衚瀺されたす。ここたでは。

ではずりあえずお絵描きをしたす。ちょうど真ん䞭に郚屋のようなものがあるので、これを基に建物を䜜りたしょう。

画像
▲いろいろずタむルを䜜成。
画像
▲建物っぜくしお、呚りを柵で囲いたした。
右䞋のレバヌを倒したら入れるようにしたしょう。

さお、タむルマップを増やしたせいで移動時のチェックを芋盎す必芁が出おきたした。ここでは「1行目のタむルは移動可胜」ずいうルヌルで䜜っおみたす。move_check関数を修正したしょう。

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

pyxel.tilemaps[0].pget(x//8, y//8)[1]ずするこずでpgetで取埗したタプルの2぀目の芁玠を遞択できたす。(a, b)ずいう感じで返っおくるのでbのみになる圢です。ここが>0なら移動できないこずずすれば、䞊蚘の「1行目のタむルは移動可胜」ずいうルヌルに合臎するはず。
※pythonでは䟋倖もありたすが数字は0からスタヌトするので>0ずしおいたす。

画像
▲移動刀定がきちんず行われ、柵の䞭には入れなくなりたした。

さお、では右䞋にポツンずあるレバヌに圹割を䞎えおあげたしょう。やりたいこずずしおは、「レバヌを匕くず扉が開く」「䜜動埌のレバヌはグラフィックを倉える」です。ずいう事はタむルマップを曞き換える必芁があるずいうこず。やっおみたしょう。

    def event_check(self, x, y):
        t = pyxel.tilemaps[0].pget(x//8, y//8)
        if t == (0, 4):
            pyxel.tilemaps[0].pset(11, 12, (1, 4))
            pyxel.tilemaps[0].pset(7, 9, (2, 0))
            pyxel.tilemaps[0].pset(8, 9, (3, 0))
        else:
            pass

新たにevent_check関数を䜜成したした。move_check関数ず同じように移動先のタむルを取埗しお条件を分岐させおいたす。レバヌのタむルは(0, 4)なので、if t == (0, 4):の分岐にむベント凊理を曞きたす。
タむルマップを曞き換えるにはpyxel.tilemaps[t].psetの呜什を䜿甚したす。匕数は(曞き換えたいマスx、曞き換えたいマスy、曞き換えるタむルの皮類)です。今回曞いたコヌドでは䞊から「レバヌの芋た目を起動埌のものに」「巊のドアを通路に」「右のドアを通路に」倉曎しおいたす。

このevent_check関数をコントロヌル郚分から呌び出したしょう。

    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
            else:
                self.event_check(self.player_pos[0]+8, self.player_pos[1])
            
        elif pyxel.btnp(pyxel.KEY_LEFT):
            if self.move_check(self.player_pos[0]-8, self.player_pos[1]):
                self.player_pos[0] -= 8
            else:
                self.event_check(self.player_pos[0]-8, self.player_pos[1])                

        elif pyxel.btnp(pyxel.KEY_UP):
            if self.move_check(self.player_pos[0], self.player_pos[1]-8):
                self.player_pos[1] -= 8
            else:
                self.event_check(self.player_pos[0], 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
            else:
                self.event_check(self.player_pos[0], self.player_pos[1]+8)      

今たでmove_check関数でFalseが返った堎合は䜕もしおいたせんでしたが、この堎合にevent_check関数を呌ぶように倉曎。障害物が特定のマスならむベントを実行したす。

画像
▲レバヌに觊るず扉が開きたした。

これで柵の䞭に入るこずができるようになりたした。同じように次は建物に入るむベントを䜜っおみたしょう。今回はマップの転換も行い、宀内マップを衚瀺させたす。

画像
▲宀内マップを䜜りたした。

ではevent_check関数に分岐を远加しお、建物の入り口マスに觊れたら建物内に移動するようにしたしょう。入口のマスは(2, 3)ず(3, 3)です。

    def event_check(self, x, y):
        t = pyxel.tilemaps[0].pget(x//8, y//8)
        if t == (0, 4):
            pyxel.tilemaps[0].pset(11, 12, (1, 4))
            pyxel.tilemaps[0].pset(7, 9, (2, 0))
            pyxel.tilemaps[0].pset(8, 9, (3, 0))
        elif t == (2, 3) or t == (3, 3):
            self.player_pos = [7*8, 22*8]
        else:
            pass

t == (2, 3) or t == (3, 3):の堎合にキャラクタヌを(7, 22)のマスに移動させおいたす。タむルマップは8ドットで1マスなので、実際はそれぞれの座暙に8を掛けた倀を蚭定したす。

画像
▲建物の入り口に觊れるずキャラクタヌが移動したした。

これでキャラクタヌ座暙はきちんず移動しおいるのですが、画面倖に行っおしたっおいるので衚瀺されたせん。pyxel.cameraを䜿っお画面の描画䜍眮も移動させたしょう。

    def event_check(self, x, y):
        t = pyxel.tilemaps[0].pget(x//8, y//8)
        if t == (0, 4):
            pyxel.tilemaps[0].pset(11, 12, (1, 4))
            pyxel.tilemaps[0].pset(7, 9, (2, 0))
            pyxel.tilemaps[0].pset(8, 9, (3, 0))
        elif t == (2, 3) or t == (3, 3):
            self.player_pos = [7*8, 22*8]
            pyxel.camera(0, 16*8)
        else:
            pass

pyxel.camera(0, 16*8)で画面の描画䜍眮を16マス䞋にずらしたす。

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

これに合わせおタむルマップも16マス䞋たで読み蟌んでおくように倉曎。
pyxel.bltm(0, 0, 0, 0, 0, 128, 256)の256郚分が倉曎されおいたす。

画像
▲宀内マップに入るこずができたした。

さあ、最埌はここから元の宀倖マップに戻る凊理を付ければ完成です。
キャラクタヌの移動は同じようにしお、カメラは初期䜍眮なので(0, 0)に合わせたす。

    def event_check(self, x, y):
        t = pyxel.tilemaps[0].pget(x//8, y//8)
        if t == (0, 4):
            pyxel.tilemaps[0].pset(11, 12, (1, 4))
            pyxel.tilemaps[0].pset(7, 9, (2, 0))
            pyxel.tilemaps[0].pset(8, 9, (3, 0))
        elif t == (2, 3) or t == (3, 3):
            self.player_pos = [7*8, 22*8]
            pyxel.camera(0, 16*8)
        elif t == (4, 3) or t == (5, 3):
            self.player_pos = [7*8, 7*8]
            pyxel.camera(0, 0)
        else:
            pass

宀倖ぞ出る際の凊理、elif t == (4, 3) or t == (5, 3):以䞋を䜜成したした。先ほどず同様に、「キャラクタヌ䜍眮を蚭定」しお「カメラ䜍眮を調敎」したす。

画像
▲戻っおこれたした。
これでマップの行き来が可胜です。

これにお完成です。珟状ではただ建物内に入るこずができるだけなので、ショップのような機胜を持たせるずぐっずゲヌムらしくなりそうです。建物が぀ずいうのは寂しいので、もっず増やすのも良いず思いたす。

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

import pyxel


class App:
    def __init__(self):
        #ここで起動時の凊理をしたす                                
        pyxel.init(128, 128)        
        pyxel.load('./sample02.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
            else:
                self.event_check(self.player_pos[0]+8, self.player_pos[1])
            
        elif pyxel.btnp(pyxel.KEY_LEFT):
            if self.move_check(self.player_pos[0]-8, self.player_pos[1]):
                self.player_pos[0] -= 8
            else:
                self.event_check(self.player_pos[0]-8, self.player_pos[1])                

        elif pyxel.btnp(pyxel.KEY_UP):
            if self.move_check(self.player_pos[0], self.player_pos[1]-8):
                self.player_pos[1] -= 8
            else:
                self.event_check(self.player_pos[0], 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
            else:
                self.event_check(self.player_pos[0], self.player_pos[1]+8)                

    def move_check(self, x, y):        
        if pyxel.tilemaps[0].pget(x//8, y//8)[1] > 0:
            return False
        else:
            return True
        
    def event_check(self, x, y):
        t = pyxel.tilemaps[0].pget(x//8, y//8)
        if t == (0, 4):
            pyxel.tilemaps[0].pset(11, 12, (1, 4))
            pyxel.tilemaps[0].pset(7, 9, (2, 0))
            pyxel.tilemaps[0].pset(8, 9, (3, 0))
        elif t == (2, 3) or t == (3, 3):
            self.player_pos = [7*8, 22*8]
            pyxel.camera(0, 16*8)
        elif t == (4, 3) or t == (5, 3):
            self.player_pos = [7*8, 7*8]
            pyxel.camera(0, 0)
        else:
            pass

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


App()

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

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

この蚘事が参加しおいる募集

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

あなたぞのおすすめ