PygameでRPG制作　ーーそれっぽい画面を作ってみよう

この記事は、岩手県八幡平市のプログラミング教室「アクセルキャンプ」の公開教材です。
[アクセルキャンプ(フリースペースプラウド)のリンク](https://freespaceproud.com)
教材の作成依頼等も承っております。ご意見等は、リンク先の問い合わせ欄からお願いします。
教材の転用・利用等は自由です。

# 寒くなってきたぜ！　　
風邪ひかないようにね！先生は天才なので、いつ風邪をひくかいつもひやひやしています。それに加えてイケメンなので、気が気じゃありません。　　

# PygameでRPG風な画面を作ってみよう。  
今の君たちに言っても全然伝わらない可能性があるけど、先生の時代はファミコンからスーパーファミコンに切り替わったり、初代プレイステーションがでて、「すげー！ＣＧやべえ！！ゲームすげー！！！」てなった時代です。中学生になってＦＦ１０が出たときなんかもう、グラフィックがきれいすぎてぶったまげたもんです。今のゲームと比べると全然ですが、なんていうか、そういう感動が今のゲームにはない気がします。　　

今日みんなに作ってもらいたいのは、こういう感じの、いわゆる「ドット絵」風な、１９８０年代くらいのゲーム「風な」画面です。
　　
これに、今後動きを付けたり、戦闘の描写を付けたりしていきます。　　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2732489/fc37df75-c260-cb78-b026-f4ebf32c263d.png)

「なにこれ、だっさ」とか言ったそこの君！廊下に立ってなさい！！ドット絵のすばらしさについて３時間お説教の刑です！　　
冗談ですが。やっていくうちに「ドット絵のゲームでさえこんなだから、実際のゲーム作ってる人ってすごいんだなぁ」みたいな感覚はもってほしいです.   
  
# ①まずは呪文から
pygame初期状態の呪いの呪文を唱えましょ
```python
import pygame
from pygame.locals import *
import sys

def main():
    pygame.init()                                   # Pygameの初期化
    screen = pygame.display.set_mode((400, 300))    # 400 x 300の大きさの画面を作る
    pygame.display.set_caption("クソゲー")              # 画面上部に表示するタイトルを設定

    while (1):
        screen.fill((0,0,0))        # 画面を黒色に塗りつぶし
        pygame.display.update()     # 画面を更新
        # イベント処理
        for event in pygame.event.get():
            if event.type == QUIT:  # 閉じるボタンが押されたら終了
                pygame.quit()       # Pygameの終了(画面閉じられる)
                sys.exit()


if __name__ == "__main__":
    main()
```
これ、いちいち打つの超めんどいですよね？  
こういうとき、いつも授業で使ってるpycharmでは、ライブテンプレートという機能が使えます。
詳しくは[ここ](https://y0m0r.hateblo.jp/entry/20130822/1377180840)とかを見るといいと思いますが、pygameと入力しただけで、この初期状態のコードがまるっと出てくるわけです。  
  
ではまず、スライムくんの画像を表示しましょう。  
ここで、pythonプロジェクトのディレクトリについて、話しておく必要があります。  

# ②フォルダの使い方：
  
pycharmの左側を見てみましょう。こんなのが表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2732489/772f93b0-ef3e-39af-786d-779187f0ba7d.png)


ここには、作成したプロジェクトの中にどんなパーツが入っているかが書いてあります。 
ゲームを作るには、ソースコードだけではできませんよね。スライムや勇者の画像、音楽などのパーツをおいておき、それらを使いたいときに使えるように、整理しておいておくのがいいですね。例えば、画像のファイルが音楽のファイルと一緒になっていたら、それをソースコードから使いたいときに、ちょっと面倒ですよね。  
  
ソースコードは、ゲームを作るのに必要なパーツの一つでしかありません。一般的に「フォルダ」と言われるものが、プログラミング的には「ディレクトリ」と呼ばれたりします。  
では、プロジェクトディレクトリ（一番大きいでディレクトリ）の下にimgディレクトリを作って、その中にスライムの画像を入れてみましょう。画像のファイル名は「slyme.png」という名前にしましょう。すると、こんな感じの後世になります。

## slyme.pngはどこ？  

ここで、main.pyの気持ちになって、slyme.pngを探してみてください。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2732489/3387ccbd-f398-a7f4-0d8d-d50e7e73477d.png)


main.pyさんの住んでいる部屋には、imgという小部屋があります。そのなかに、slyme.pngさんがいます。すると、  
「imgの部屋のなかのslyme.pngさん」というふうに指定すると、会いたい人（ほしいデータ）に出会えそうですね。そのことを意識したうえで、次のコードを、メインループの前に追加してみましょう。

```python
import pygame
from pygame.locals import *
import sys

def main():
    pygame.init()                                   # Pygameの初期化
    screen = pygame.display.set_mode((800,600))    # 400 x 300の大きさの画面を作る
    pygame.display.set_caption("いけめんがつくったげえむ")              # 画面上部に表示するタイトルを設定
    
    #追加部分
    slyme_image = pygame.image.load("image/slyme.png")
    # 以下省略
```
slyme.pngという画像ファイルの情報を、slyme_imageという変数に入れます。loadって、ゲームで見たことないですかね？「now loading(ロード中)」とかってやつです。load=読み込み 的な意味です。これで画像をいつでも使える準備ができました。
  
ここの、"image/slyme.png"というところに注目です。ここの / は、「～ディレクトリのなかの～」というのを表しています。たとえば "A / B / C" となると、「AディレクトリのなかのBディレクトリの中のC」となります。
  
## 画像の表示：screen.blit(画像, 座標)
では、この画像を表示してみましょう。
画像などのデータを表示するには。次のメソッドを使います。
```python
screen.blit(表示したい画像,(表示したい座標))
```
ここでちょっと気をつけなくちゃいけないのが、表示したい座標についてです。ここでは、画像の中心ではなく、左上をこの座標に合わせることになるので、狙った場所に画像を出すには、その画像の縦幅・横幅の半分だけずらして表示する必要があります。このsylme.pngはたて・よこともに４００のサイズになっていますので、どまんなかやや上に表示してRPGっぽく表示するには、こんな感じになります。
```python
screen.blit(slyme_image, (400-(400 / 2), 0))
```
これを、メインループ内に追加します。  
※ちなみに、画像の縦横の長さを取得する方法もあるのですが、ややこしくなってしまうのでここでは省略します。
![img_4.png](img_4.png)

では、画面下部に文字を表示するための枠線を描画しましょう。  
長方形の枠線を描画するには、以下のメソッドを使います。
```python
pygame.draw.rect(screen,(255, 255, 255),Rect(20, 400, 760, 180), 10)
```
255が三つ並んでる時点で、「お！これ絶対RGBじゃん！白い枠線じゃん！」みたいになった人は、ちゃんと勉強してますね！恐ろしい子！

<img src="https://pbs.twimg.com/media/EvpVJAHXIAo72YY.jpg" width=30%>  

このpygame.draw.rect（）メソッドには４つの引数があります。
①どの画面に出力するか・・・この場合は１つしかないscreenですね 
②枠線のRGB
③Rect型のオブジェクト 
④枠線の太さ  
  
この中で一番イミフなのは、③番じゃないでしょうか？Rectは、英語で長方形を意味するRectanfular(レクタンギュラー)の略です。この中にさらに４つの引数がありますが、それぞれ  
>①左上の角のｘ座標
②左上の角のy座標
③横（x方向）の長さ
④縦（ｙ方向）の長さ

となっています。
※（長さはそれぞれ自分で計算しなくてもいいのですが、コードが長くなるために事前に計算してあります。）

実行すると、こんな感じで枠線が出ます。


あとは、文字だけですね。




# ③文字の表示方法  
文字の表示には、少し特殊な作業が必要になります。  
まず、ひとくちに文字といっても、いろんな文字がありますね？きれいな字でピシッと書いた書道のような字や、パソコンで表示される機会みたいな字、お化け屋敷の看板みたいな字がありますよね。それらの文字の種類のことを「**フォント**」といいます。フォント次第で、ゲームやチラシなどの雰囲気がまるで変わってきます。

## フォントの選択

今回使うのは、DragonQuestFCというフォントです。フォントファイルを調べてみて、気づいた人がいるかもしれません、そう、漢字に対応していないのです。昔のゲームの画像で、
「リッキーに、３００の　攻撃！」としたいところを
「りっきーに　３００の　こうげき！」などとしているのを、見たことないですか？昔はゲームのハード(ファミコンとかプレステとかの、ゲームを動かすための機械)の容量がとても小さくて、文字をきれいにするために容量を割けなかったんです。そういうのにしっかり容量を割けるようになってきたのって、プレステ2くらいかなぁ。今回はその雰囲気に慣れてもらうために、わざとこのフォントを選びました。  
フォントはここからダウンロードできるので、imgフォルダと同じように、fontフォルダをプロジェクトフォルダの下に作成して、その中に入れましょう。  
  
では、このフォントを使って、文字を表示していきます。
文字を表示するには、
①使うフォントを決める
②フォントから作成したい文字列を画像に変換する
③画像を表示する
という3つのステップを踏みます。「リッキー」という文字を表示したい場合は、リッキーという文字の「画像」を作成して、それを表示するんですね。  
  
フォントを決めるには、「どこのフォルダにある、なんていうフォントを使うか」を指定してあげる必要があります。
先ほどのファイルの指定方法を思い出してみて下さい。
```python
font = pygame.font.Font("font/DragonQuestFC.ttf", 30)
```
これで、第一引数にフォントファイルの場所、第二引数に文字の大きさを指定します。今のところフォントはこの一種類しか使わないですが、メインループの直前に書いてあげましょう。

## 文字の「画像」を作る

次に、フォントの情報と、表示したい文字列の情報を与えて、それらを一枚の画像としてtextという変数に入れましょう。  
```python
text = font.render("りっきーが　あらわれた！", True, (255, 255, 255))
```
第一引数では、表示したい文字列
第二引数は、アンチエイリアスの設定
第三引数は、文字のRGB
アンチエイリアスは、「文字をきれいに表示するための機能」とだけ言っておきます。とりあえずtrueにしとけばOKです。

# 画像を出力（表示）する 475

変数名がtextとなってるので混乱するかもしれませんが、これは画像データとして考えましょう。画像を出力するので、↑のスライムの画像の出力を参考にすればイチコロです。  
  
```python
screen.blit(text, (40, 420))
```

pygame に慣れていないと、これらの処理をどこに書いたらいいか、最初は難しいと思いますが、
「用意しておくデータはメインループの前」
「ゲーム中に行いたい処理はメインループの中」
と考えればいいです。

コード全体はこんな感じです。
```python
import pygame
from pygame.locals import *
import sys

def main():
    pygame.init()                                   # Pygameの初期化
    screen = pygame.display.set_mode((800,600))    # 400 x 300の大きさの画面を作る
    pygame.display.set_caption("いけめんがつくったげえむ")              # 画面上部に表示するタイトルを設定

    slyme_image = pygame.image.load("image/slyme.png")

    font = pygame.font.Font("font/DragonQuestFC.ttf", 30)
    while (1):
        screen.fill((0,0,0))  # 画面を黒色に塗りつぶし
        screen.blit(slyme_image, (400 - (400 / 2), 0))

        pygame.draw.rect(screen,(255, 255, 255), Rect(20, 400, 760, 180), 10)
        text = font.render("りっきーが　あらわれた！", True, (255, 255, 255))
        screen.blit(text, (40, 420))
        pygame.display.update()     # 画面を更新
        # イベント処理
        for event in pygame.event.get():
            if event.type == QUIT:  # 閉じるボタンが押されたら終了
                pygame.quit()       # Pygameの終了(画面閉じられる)
                sys.exit()


if __name__ == "__main__":
    main()
```
おまけとして、座標を計算する部分で、自分で計算しないでプログラムで計算するようにすると、こんなかんじになります。  

```python
import pygame
from pygame.locals import *
import sys

def main():
    pygame.init()                                   # Pygameの初期化
    screen = pygame.display.set_mode((800,600))    # 400 x 300の大きさの画面を作る
    pygame.display.set_caption("いけめんがつくったげえむ")              # 画面上部に表示するタイトルを設定

    rect_x = 20 #長方形左上のｘ座標
    rect_y = 400  #長方形左上のｘ座標
    rect_width = 800 - (rect_x * 2)  #長方形の幅
    rect_height = 600 - (rect_y + 20) #長方形の高さ
    slyme_image = pygame.image.load("image/slyme.png")

    font = pygame.font.Font("font/DragonQuestFC.ttf", 30)
    while (1):
        screen.fill((0,0,0))  # 画面を黒色に塗りつぶし
        screen.blit(slyme_image, (400 - (400 / 2), 0))

        pygame.draw.rect(screen,(255, 255, 255), Rect(rect_x, rect_y, rect_width, rect_heithg), 10)
        text = font.render("りっきーが　あらわれた！", True, (255, 255, 255))
        screen.blit(text, (40, 420))
        pygame.display.update()     # 画面を更新
        # イベント処理
        for event in pygame.event.get():
            if event.type == QUIT:  # 閉じるボタンが押されたら終了
                pygame.quit()       # Pygameの終了(画面閉じられる)
                sys.exit()


if __name__ == "__main__":
    main()
```

***
今週は課題なしです！どんなゲームになるか楽しみにしながら、また来週！