Nyan でプログラミング

[qnote Advent Calendar 2020](https://qiita.com/advent-calendar/2020/qnote) の17日目です。

# はじめに

私は猫が大好きで、[会社](https://www.qnote.co.jp/)にも、自宅にも、実家にも、ついでに姉の家や祖母の家にも猫がいるのですが、プログラムの中でも猫に関わっていたい…  と常々思っていました。
今回はそんなときに出会った **[Nyan](https://github.com/ducaale/nyan)** という Python ライブラリをご紹介したいと思います。

# Nyan とは
https://github.com/ducaale/nyan
https://pypi.org/project/nyan/
> Nyan - a fork of Python Play - is an open-source code library for the Python programming language that makes it as easy as possible to start making games.

Nyan は Python Play というプロジェクトを fork して作成された Python 用のオープンソースコードライブラリで、ゲーム作りが簡単に始められるよ。というものらしいです。
README が充実しているので、詳しくは上記サイトをご参照ください。
ソースコードに **nyan** が溢れていて幸せになります :cat: 

## 使い方
python と pip が導入済であれば、下記のインストールコマンドを打つだけで導入完了です。

```console
$ pip install nyan
```

※ 私の場合 python も pip もバージョンが古くエラーが出てしまったので、**python を 3.7.9**、**pip を 20.1.1** にバージョンアップしたら上手くいきました。

まず試しにサンプルを動かしてみます。

```python:sample.py
import nyan

cat = nyan.new_text('=^.^=', font_size=70)

@nyan.repeat_forever
async def move_cat():
    cat.x = nyan.random_number(-200, 200)
    cat.y = nyan.random_number(-200, 200)
    cat.color = nyan.random_color()
    
    cat.show()

    await nyan.sleep(seconds=0.4)

    cat.hide()

    await nyan.sleep(seconds=0.4)

@cat.when_clicked
def win_function():
    cat.show()
    cat.text = 'You won!'

nyan.start_program()
```

サンプルコードをコピペした py ファイルを作成し、python コマンドで実行。

```console
$ python sample.py
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
```

が、起動して pygame のウィンドウは立ち上がるものの、何も表示されません。。

![freeze.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320080/87fe4d3f-3919-74d0-f19a-9cb42d263ec8.png)

調べてみたところ、**Mojave 以降の Mac OS** で **Python 3.7.x** と **pygame 1.9.6** だとこの現象が起こるらしいです。
**pygame を 2.0.0** にアップデートしたところ、ちゃんと動いてくれました。

```console
$ python sample.py
pygame 2.0.0 (SDL 2.0.12, python 3.7.9)
Hello from the pygame community. https://www.pygame.org/contribute.html
```

![sample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320080/a2646793-c590-cb25-10de-8a7604de81ee.gif)

# 猫社員に変えてみた
クリック対象を **[弊社猫社員](https://www.qnote.co.jp/qnote_cats/)[^1]** の画像に変更し、クリックされたら猫社員の名前とクリックされるまでに掛かった秒数を表示するようなゲームに変更してみました。

※ 全猫社員をコンプリートしようと奮闘したところ動画が大変長くなってしまったため一部カット編集した都合で、途中カーソルがワープしたりクリア秒数がおかしかったりしますがそこは無視してください。。

![qnote_cats.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320080/2e6b0f64-2508-6080-09ac-2f663dd64ccb.gif)

ソースコード全文は以下になります。

```python:qnote_cats.py
import nyan

# 画像用意
cats = {
    'ふたば': 'images/futaba.png',
    'みるく': 'images/milk.png',
    'はな': 'images/hana.png',
    'ちまき': 'images/chimaki.png',
    'りぼん': 'images/ribon.png',
    'さくら': 'images/sakura.png',
    'みぃ': 'images/mii.png',
    'ごまお': 'images/gomao.png',
    'チャコ': 'images/chaco.png',
    'ミーシャ': 'images/misha.png'
}
key = next(iter(cats))
cat = nyan.new_image(cats[key])

# メッセージ用意
msg = nyan.new_text(text='', x=0, y=-270, font_size=50, font='fonts/font.ttf')

# タイマー用意
timer = nyan.new_timer()

# 初期化処理
def init():
    cat.hide()
    msg.hide()
    timer.reset()

# 初期化してスタート
init()

# 画像の表示/非表示を繰り返す
@nyan.repeat_forever
async def move_cat():
    if msg.is_hidden:
        # ランダムで画像を指定
        global key
        key = nyan.random_item(list(cats.keys()))
        cat.image = cats[key]
        # ランダムでサイズを指定
        cat.size = nyan.random_number(30, 70)
        # ランダムで表示位置を指定
        cat.x = nyan.random_number(-200, 200)
        cat.y = nyan.random_number(-200, 200)
        # たまにドアップ
        if nyan.random_number(1, 30) == 1:
            cat.size = 200
            cat.x = 0
            cat.y = 0

        # 画像表示
        cat.show()
        await nyan.sleep(seconds=0.5)

    if msg.is_hidden:
        # 画像非表示
        cat.hide()
        await nyan.sleep(seconds=0.5)

# 画像がクリックされたらクリアタイムを表示
@cat.when_clicked
def clear():
    if msg.is_hidden:
        cat.size = 175
        cat.x = 0
        cat.y = 30
        cat.show()
        msg.text = '(ΦωΦ) ' + key + ' < ' + str(timer.seconds) + '秒!'
        msg.color = nyan.random_color()
        msg.show()

# メッセージがクリックされたらリスタート
@msg.when_clicked
def restart():
    init()

nyan.start_program()
```

画像とフォントファイルに関しては、プロジェクト内に `assets` ディレクトリを作成してその中に格納しておく必要があります。
※今回は `assets` 配下に更に `fonts`、`images` ディレクトリを作成していますが、`assets` 直下にファイル直置きでも大丈夫です。

```console:ディレクトリ構成
project_dir
├── qnote_cats.py
└── assets
    ├── fonts
    │   └── font.ttf
    └── images
        ├── chaco.png
        ├── chimaki.png
        ├── futaba.png
        ├── gomao.png
        ├── hana.png
        ├── mii.png
        ├── milk.png
        ├── misha.png
        ├── ribon.png
        └── sakura.png
```

## 軽く解説
### 画像表示
**[nyan.new_image()](https://github.com/ducaale/nyan#nyannew_image)** で画像を配置できます。
今回は `# 画像用意` の部分で一度スプライトを定義しておき、`# 画像の表示/非表示を繰り返す` 内で `image(画像ファイル)`, `size(サイズ)`, `x/y(表示位置)` を毎回ランダムに指定する形で使用しています。
表示/非表示は `sprite.show()` / `sprite.hide()` で制御できます。

### テキスト表示
**[nyan.new_text()](https://github.com/ducaale/nyan#nyannew_text)** でテキストを配置できます。
今回は `# メッセージ用意` の部分で一旦 `x/y(表示位置)`, `font_size(サイズ)`, `font(フォント)` を指定したスプライトを定義しておき、`# 画像がクリックされたらクリアタイムを表示` 内で `text(テキスト文字列)` に猫社員の名前とクリアタイム、 `color(文字色)` に **[nyan.random_color()](https://github.com/ducaale/nyan#nyanrandom_color)** で取得したランダムな色を指定する形で使用しています。
表示/非表示は画像と同様 `sprite.show()` / `sprite.hide()` で制御できます。

### タイマー
**[nyan.new_timer()](https://github.com/ducaale/nyan#nyannew_timer)** でタイマーを生成し、`timer.seconds` / `timer.milliseconds` で経過時間を取得できます。
また、`timer.reset()` でタイマーをリセットできます。
今回は `# 初期化処理` 内でタイマーをリセットし、`# 画像がクリックされたらクリアタイムを表示` 内で経過秒数をテキストに表示する形で使用しています。

### 繰り返し処理
**[@nyan.repeat_forever](https://github.com/ducaale/nyan#nyanrepeat_forever)** と記述することで処理を繰り返し実行させることができます。
今回は画像の表示/非表示処理を繰り返し実行させる形で使用しています。

### クリック時の処理
**[@sprite.when_clicked](https://github.com/ducaale/nyan#spritewhen_clicked)** と記述することでスプライトがクリックされた時に処理を実行させることができます。
今回は画像がクリックされた時はメッセージを表示、メッセージがクリックされた時は初期化処理を実行させる形で使用しています。

# さいごに
今回は使用しませんでしたが、Nyan にはオーディオやキー入力等の制御も用意されています。
鳴き声とかも入れたら面白いかなと思ったのですが、素材集めが大変そうだったので断念しました…
いつか素材が集まったら反映してみたいと思います。

[^1]: 2020年12月現在、弊社には10匹の猫社員が在籍しています。ごまお、チャコ、ミーシャについては[猫社員紹介ページ](https://www.qnote.co.jp/qnote_cats/)への掲載が追いついていませんが、twitter 等の SNS には登場していますので、猫社員が気になった方はよろしければそちらもご覧ください :cat2: