Ren'Pyで2D RPGを作る(1)

# 概要
こんにちは、しがないエロゲーマー蟹丸です。今回は[**Ren'Py**](https://www.renpy.org/)というオープンソースのビジュアルノベル制作エンジンを使って2D RPGを作っていきたいと思います。
まだRen'Pyでどこまでできるのかがわかっていないので途中で挫折する可能性はありますが、失敗のメモも大事なので残しておこうと思います。

**本記事の範囲**
Ren'Pyを選んだ理由、Ren'Py導入、RPG用Cookbookを試すところまで

# 背景：なぜRen'Py？
introductionで述べたようにRen'Pyはビジュアルノベル制作エンジンです。じゃあなんでRPGを作るのにこれを選んだの？という話をします。端的に言えば「**Pythonで書けるの神では？**」に尽きるので、読み飛ばしてもらっていいです。

まずゲーム制作といえば有名なものがいくつかあります。

- [ツクール](https://tkool.jp/products/index.html)
- [WOLF RPGエディター(ウディタ)](https://www.silversecond.com/WolfRPGEditor/)
- [Unity](https://unity.com/)
- [Unreal Engine](https://www.unrealengine.com/)

などなど。あとは今回紹介するRen'Pyや、[HSP](https://hsp.tv/index2.html)などの独自言語系でしょうか。Ren'Pyはあまり有名ではないイメージでしたが、[ドキドキ文芸部](https://games.renpy.org/game/ddlc)に興味を持った方は知っているかもしれません。

この中で2D RPGとなるとRPGツクール、ウディタ、Unity 2Dあたりになってくると思います。
自分が調べた範囲での特徴（といっても触ったことがあるのはUnityだけなので他は印象程度です）は以下の通り。

- RPGツクール：最強RPG制作ツール。高いけどよくセールをしている。**javascript**で高度なカスタマイズが可能
- ウディタ：**プログラミングを必要とせず**が豊富なカスタマイズが可能。無料。自分が前にプレイした「このシステムどうやって作ってるんだろ……」と思ったゲームはウディタ製だった。
- Unity：言わずもがなアクションに強いがRPGでは手間が多い。アセットも出ているがだいたい有料でとっつきづらい。**Unity C#**で高度な操作が可能。本体は無料。
- Ren'Py：ビジュアルノベルが簡単に作れる。ユーザによってRPG用Cookbookが公開されている。**Python**で高度なカスタマイズが可能。オープンソースで無料。

自分は**Pythonで書けるかつ無料**に惹かれました。我々は月末金曜日のためにお金をためておかなければならないのです……というのは置いておいて、普段使っている言語で趣味開発が簡単に試せるというわけです。Cookbookを除いてみるとRPGに使えそうなものもありますし、Pythonで書けるなら多少の無茶はできそうです。というわけでRen'PyでRPG開発スタートです。

# 1. Ren'Pyを使う
以下Windows10環境での説明になります。ほかの環境でもたぶんそう変わらないと思います。

1. まずは[公式サイト](https://www.renpy.org/)からRen'Pyをダウンロードしてきます。自己解凍EXEなので解凍します。インストールは無しで使えます。
2. renpy.exeを起動します。右下の設定から言語を変えられます。日本語のゲームを作るには日本語設定にしておく必要があります。![SnapCrab_Ren'Py Launcher_2020-7-24_14-40-32_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679910/dc29bcb9-aaa0-bf7f-b7b4-f43aad0449c9.png)
3. Tutorial(Ren'Pyの説明書)やThe Question(選択肢分岐の実装例)を選んで「プロジェクトを起動」し、デフォルトでできることを確認します。

# 2. 新規プロジェクトを作る
1. ランチャーの「+新規プロジェクトの作成」から新規プロジェクトを作成します。ランチャーの指示に従うだけなのでここは割愛します。
2. 作成されたプロジェクトはランチャー左に表示されるようになるので、プロジェクトを起動してみます。
3. タイトル画面を経て見覚えのある画面が出てくるようになりました。デフォルトでここまであるならビジュアルノベル制作がとても楽そうな感じがしてきますね。![SnapCrab_test_2020-7-24_14-59-47_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679910/69bde7c7-8613-4234-294d-1b366ddcf77f.png)
![SnapCrab_test_2020-7-24_14-48-50_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679910/de5b5206-13ac-37a8-c8b3-e928d177c66a.png)

**エディタについて**
Ren'Pyダウンロードページやランチャー初回起動時にATOM, Editra, jEditをダウンロードすることができます。おそらくSyntax highlightingや補完が利くようになるのだと思います。入れたい場合は入れましょう。
自分はSublime Text 3ユーザなのでこちらのパッケージを入れました：https://packagecontrol.io/packages/Renpy%20Language

# 3. RPGっぽくしてみる
この状態だと背景はマップではなく一枚絵で、マップ上をキャラクターが動くということはできません。そこで[RPG Overworld Engine](https://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=29964)を使ってマップ上を動いたりNPCと会話したりできるようにします。
これに限らず[Ren'Py Cookbook](https://lemmasoft.renai.us/forums/viewforum.php?f=51)にいろいろなcookbookが投稿されているので見てみると面白いです。投稿者によってライセンスが異なるので注意しましょう。

## デフォルトのまま起動してみる
新たに作成したプロジェクトのgameフォルダをPRG Overworld Engineのgameフォルダに置き換えて起動してみると、既に

- キャラクターをカーソルキーもしくはWASDで操作
- 止まっているNPC、動くNPC、それらとの会話
- 敵とのエンカウント
- マップの通行設定

などなどRPGの基本が確認できます。すごい！
Forumやソースコードを見るともっといろいろ実装されています。

## 少し不便なところをいじる
RPG Overworld Engineをそのまま使っていると以下の問題が見えてきます。

- Enter押しても何も反応しないじゃん！
- 歩くのが遅い！

こちらについてチュートリアルとしていじってみます。
### Enter押しても反応しない問題
こちら理由は簡単で、会話などのアクションがシフトとスペースに割り当てられているからです。海外のRPGだとエンターキーあんまり使わないんですかね？
シフトは他に割り当てたいものがあるので、スペースとエンターに割り当てます。
他のキーにしたい場合の指定方法は[pygameのドキュメント](https://www.pygame.org/docs/ref/key.html)を参照のこと。

```python:overworld.rpy
# playerクラスのevent関数内
if ev.type == pygame.KEYDOWN and not self.player.caught and not self.talking:
    
    if ev.key == pygame.K_UP or ev.key == pygame.K_w:
        self.player.facing, self.player.up = 'up', True
        self.player.walking = True

    if ev.key == pygame.K_RIGHT or ev.key == pygame.K_d:
        self.player.facing, self.player.right = 'right', True
        self.player.walking = True

    if ev.key == pygame.K_LEFT or ev.key == pygame.K_a:
        self.player.facing, self.player.left = 'left', True
        self.player.walking = True
        
    if ev.key == pygame.K_DOWN or ev.key == pygame.K_s:
        self.player.facing, self.player.down = 'down', True
        self.player.walking = True

    # ここを修正
    # if ev.key in [pygame.K_RSHIFT, pygame.K_LSHIFT, pygame.K_SPACE] and not self.talking and not self.goTo:
    if ev.key in [pygame.K_SPACE, pygame.K_RETURN] and not self.talking and not self.goTo:
        for vil in self.sceneryList:
            self.talk(vil)
```
これでエンターキーで会話したり調べたりできるようになりました。

### 歩くのが遅い問題
ダッシュがないRPGでつきものの問題ですね。イライラするのでダッシュ機能をつけましょう。
RPG Overworld Engineではインスタンス変数で歩行中(`walking`)、会話中(`talking`)などの状態を切り替えています。これにならってplayerクラスに走行中(`running`)というインスタンス変数を追加します。

```python:overworld.rpy
class Player():
    def __init__(self, x, y, facing, sprites):
        ### 中略 ###
        self.walking = False
        self.running = False # この行を追加
```
先ほどアクションへの割り当てを外したシフトキーをダッシュに割り当てます。キーボードのシフトキーが押されたら`running = True`にし、離されたときに`running = False`にします。

```python:overworld.rpy
# playerクラスのevent関数内
if ev.type == pygame.KEYDOWN and not self.player.caught and not self.talking:
    # 以下を追加
    if ev.key in [pygame.K_RSHIFT, pygame.K_LSHIFT]:
        self.player.running = True
### 中略 ###
if ev.type == pygame.KEYUP:
    # 以下を追加
    if ev.key in [pygame.K_RSHIFT, pygame.K_LSHIFT]:
        self.player.running = False
```
最後に`running = True`のとき歩く速度を変えます。適当に1.5倍速くらいに設定します。

```python:overworld.rpy
# Playerクラスのupdate関数内
#set velocity according to movement direction
    # 以下を修正
    # vel = 8
    if self.running:
        vel = 12
    else:
        vel = 8
```

これでシフトキーを押している間ダッシュできるようになりました。

## 自分がやりたかったことができそうか確認する
RPGといえば「マップ上イベント」がほしいですよね。RPGの最初で家で寝ている主人公がお母さんに起こされる、みたいなやつです。正式な呼び方は知りません。
コードを見るとプレイヤーがNPCに話しかけると会話が起こるようにはなっていますが、上述のようなプレイヤーの行動に無関係に引き起こされるイベントはなさそうです。作りましょう。
といってもプレイヤーが行動せずともプレーヤーが会話状態(`talking = True`)になっていればいいだけなので、そこを追加するだけです。

```python:overworld.rpy
# Playerクラスのinit関数
# talkingを渡せるように修正
def __init__(self, map_layout = None, tileList = None, portals = None, portal_tiles = None, enemy_layout =None, enemySprites = None, NPCSprites = None, groundLayout = None, playerSprites = None, playerX = None, playerY = None, scrolling = True, talking = False):
### 中略 ###
    # 以下を修正
    # self.talking = False
    self.talking = talking    
```
`talking = False`を渡せば普通のマップ表示, `talking = True`を渡せばイベント、と切り替えられるようになりました。

```python:script.rpy
ui.add(OverworldDisplayable(map_layout = moordell_layout, tileList = moordell_tiles,
    portals = moordell_portals, portal_tiles = moordell_portal_tiles,
    enemy_layout = moordell_enemies_layout, enemySprites = moordell_enemies, 
    NPCSprites = moordell_villagers, #villagers, uses the same layout as enemies
    groundLayout = moordell_ground,
    playerSprites = ken_sprites, playerX = playerX, playerY = playerY,
    scrolling = True, talking = True)) # 最後のtalkingを適宜変える
```

# 結論と今後
Ren'Py + cookbookの力でRPGっぽいゲームが作れることがわかりました。ダッシュ機能やイベント機能の追加も楽々でした。

RPGにはパーティー、ステータス、バトルなどまだまだ欠かせないものがありますので、今後はそちらを進めていきたいと思います。
次回：[Ren'Pyで2D RPGを作る(2)―パーティーとステータス](https://qiita.com/salt_crab/items/6d9db298f9bd457ed412)

# ライセンス等補足
本記事のコードはRPG Overworld Engineのライセンス（Attribution-NonCommercial 3.0 United States (CC BY-NC 3.0 US) license）に準じます。
この記事にRPG Overworld Engineのゲーム画面の画像がないのは画像の権利が不明瞭だったためです……。