読者です 読者をやめる 読者になる 読者になる

Green Man GamingにてCIV6を購入した

civ6 ゲーム

猛烈にciv6が欲しくなったので購入。

gmgが23%引きでSid Meier’s Civilization® VI Deluxe Editionを販売していたので、久々に鍵屋さんでゲームを買った。

もしかしたらsteamに登録出来ないんじゃ…とか、日本語で出来ないって情報も散見されていたので、戦々恐々して購入したのですが、普通にsteamでアクティベート出来て、なおかつ日本語でした。

61.79$ 大体7000円ですね。数年後には10$以下で買えそうですが、我慢できなかったw

東山奈央さんの助言が耳に優しい。ほそぼそとプレイしてきたいです。

セキセイインコがPBFDから陰転しました!

PBFD インコ

久しぶりのブログ更新。私、インコ飼っているんですがその子がPBFDという病気でした。それがこの度陰転したので嬉しいという話。

PBFDはインコ界においては割りと洒落にならない病気で、治療法が無くエイズみたいな病気なのです。

症状としては羽が細く、発達不良になる。羽毛が抜ける。他の病気にかかりやすくなる。などです

症状が出てから2ヶ月くらい経ってから病院に行って、はじめて病気なんだと知りました。PBFDでググってみると、悪魔の病気とか、回復は難しいとか絶望的なワードが並んでました。

それから、半年くらい。インターフェロンという免疫力を高める薬と、後粉薬(クソ高い)。それと3日一度くらいのケージ消毒。地道な治療を続けた結果…

なんと、血液検査で陰性になりました。喜び!

元気になってよかった。そんな彼女は現在、私の技術書達を元気に噛みちぎって遊んでいます(泣

経路探索アルゴリズムのA*法を書いてみた

python プログラミング

ちょっと前の記事で、苦難の末ダイクストラアルゴリズムの実装に成功しました。

しかし、ダイクストラアルゴリズムは無駄が多い。必ず全ての経路を探索するからだ。

A*法という、ダイクストラアルゴリズムに指向性を持たせたような進化版があることは前から知っていた。実装方法についてがなんか難しそうだったので敬遠していたのだが、

「ゲーム開発者のためのAI入門」という本に、手取り足取り載っていたのでここぞとばかりに実装してみた。

def a_star(self):
    pos = [self.y, self.x]  # プレイヤーのタイル座標
    target_pos = [self.target_y, self.target_x] # 目的地のタイル座標
    eval_map = copy.deepcopy(self.elementary_field)  # 評価対象のマップ。2次元リスト
    open_list = [pos]  # 調査の必要があるタイル
    closed_list = list()  # 調査が終わったタイル
    scan_node = list()  # 8方向の座標を保持する。
    current_node = []  # 現在いるタイル
    for x in range(self.height):
        for y in range(self.width):
            if eval_map[x][y] != 0:
                eval_map[x][y] = 99999  # 最大値

    while len(open_list):
        # 現在のノード = オープンリストの最も安価なノード
        low = 9999999
        for x in open_list:
            if eval_map[x[0]][x[1]] < low:
                current_node = x
                low = eval_map[x[0]][x[1]]
        if current_node == target_pos:
            # 経路の完成
            closed_list.append(current_node)
            closed_list.remove(pos)
            return closed_list
        else:
            open_list.remove(current_node)
            closed_list.append(current_node)
            # 現在のノードに隣接する各ノードを調べる
            scan_node.append([current_node[0] - 1, current_node[1]])  # 上
            scan_node.append([current_node[0], current_node[1] + 1])  # 右
            scan_node.append([current_node[0] + 1, current_node[1]])  # 下
            scan_node.append([current_node[0], current_node[1] - 1])  # 左
            scan_node.append([current_node[0] - 1, current_node[1] - 1])  # 左上
            scan_node.append([current_node[0] - 1, current_node[1] + 1])  # 右上
            scan_node.append([current_node[0] + 1, current_node[1] - 1])  # 左下
            scan_node.append([current_node[0] + 1, current_node[1] + 1])  # 右下
            for x in scan_node:
                if x not in open_list\
                    and x not in closed_list\
                        and not eval_map[x[0]][x[1]] == 0:
                            # オープンリストに移してコスト計算をする
                            c_direction = x.copy()
                            h_direction = x.copy()
                            c = 0  # 開始タイルから、そこへ到達するためのコスト
                            h = 0  # 特定のタイルから、最終タイルまでの歩数を測定したコスト
                            open_list.append(x)
                            while not c_direction == pos:
                                if pos[0] > c_direction[0]:
                                    c_direction[0] += 1
                                elif pos[0] < c_direction[0]:
                                    c_direction[0] -= 1

                                if pos[1] > c_direction[1]:
                                    c_direction[1] += 1
                                elif pos[1] < c_direction[1]:
                                    c_direction[1] -= 1
                                if self.field.field[x[0]][x[1]] == 4:
                                    c += 99999
                                else:
                                    c += 1

                            while not h_direction == target_pos:
                                if target_pos[0] > h_direction[0]:
                                    h_direction[0] += 1
                                elif target_pos[0] < h_direction[0]:
                                    h_direction[0] -= 1

                                if target_pos[1] > h_direction[1]:
                                    h_direction[1] += 1
                                elif target_pos[1] < h_direction[1]:
                                    h_direction[1] -= 1
                                h += 1
                            eval_map[x[0]][x[1]] = c + h
            scan_node = list()
    return False

本には、ちゃんとしたソースコードは載って無くて、簡単な擬似言語と解説が載っているのみで、結構困ったりしたので乗せておく。

実際動かしてみると、目的地に向かってアルゴリズムが流れていくのが楽しいかも。速度も、ダイクストラ法と比べると0.003秒、大体48%早かった(1000回の平均を取った)

そう、この本を買えば今すぐ貴方もゲーム開発者に(w

そういえば、エロゲ作っているはずなんだけど、全然エロいコードとか書いてない。頭が痛くなるアルゴリズムばっかりだなぁ

頑張ろ…

画像からAAを生成するプログラムを作った

python プログラミング

自作のゲームに画像を表示したいと思ったんだけど、console画面なので、画像は使えない。ってことで、AAを表示してみようと思いついた。

そうは言っても、AAなんて作ったこと無いし、作る気力もない。 それなら、画像投げたら自動的にAA作ってくれる機能ないかなぁと思い、自作することにしました。

先人達を探すべく、ググっていると、

Python/PILによる画像のグレイスケール化とアスキーアート化

こちらの方のエントリーが非常に参考になりました。PILってなんか聞いたことあったけど、こう使うんだ。。と納得。

AAを画像で保存する感じだったので、そこら辺だけこちらの仕様に合わせて変更しました。

txtファイルにAAを出力するように改造し、とりあえず出来た。

from PIL import Image


def create_aa(in_img, w, h):
    input_pix = in_img.load()
    character = ""
    aa_list = []
    div = 32
    size = w // div
    for i in range(0, h, size):
        for j in range(0, w, size):
            r, g, b = input_pix[j, i]
            gray = r*0.2126 + g*0.7152 + b*0.0722
            if gray > 250:
                character = " "
            elif gray > 230:
                character = "`"
            elif gray > 200:
                character = "\""
            elif gray > 175:
                character = "+"
            elif gray > 150:
                character = "*"
            elif gray > 125:
                character = "#"
            elif gray > 50:
                character = "W"
            aa_list.append(character)
        aa_list.append("\n")
    return aa_list

if __name__ == "__main__":
    input_image = Image.open("画像パス")
    width = input_image.size[0]
    height = input_image.size[1]
    output_image = create_aa(input_image, width, height)
    with open("aa.txt", "wt", encoding='utf-8') as fout:
        for x in output_image:
            fout.write(x)

python3.6.0にupdateしてみた!

python プログラミング

python3.4.4から、python3.6.0に進化しました。

一番懸念していた、cx_freezeが動作するかどうかでしたが、こちらのサイトで配布しているwheelファイルからインストールしたら、無事動いてくれました!

特に動作がもっさりしたり、早くなったりもせず、安定しています。面倒だったけどアップデートしてよかった。

最後にcx_freezeの設定ファイルをメモ代わりに公開。一回書いたら大体消さないけど、すぐ忘れるので。

 

from cx_Freeze import setup, Executable

include = ["enemy.yml", "readme.txt", "item.py", "battle.py", "enemy.py", "equip.py",
           "map.py", "message.py", "npc.py", "parameter.py", "player.py", "game.py"]
base = None

setup(name="SQRogue",
      version="0.0.9",
      author="開発者名",
      author_email="メルアド",
      url="https://github.com/sakage24/roguelike",
      description="SQRogue develop version.",
      options={"build_exe": {"include_files": include}},
      executables=[Executable("main.py", base=base, targetName="rouge_dev.exe")])

ゲーム制作に疲れたので一服する

python プログラミング

製作中のゲームにセーブ/ロードシステムを(苦難の末)実装しました。

バグ地獄でキーボード破壊しそうになったけど今は昔です。常にアヴァンギャルドで居たいのです。

実際に作ってみると、セーブとロードの仕組みがわかった気がします。予想以上に保存する項目が多い。メインのスクリプトに適当に変数を散らばしてたら思った以上に痛い目に合いました。

ちなみにpythonでデータ構造そのまま保存したいなら、pickle(塩漬け)っていう組み込み関数使うと良いみたいです。

effective pythonにも乗ってました。こういうのシリアライズっていうみたいですね。知らなかった。

さて、作業は中断して、久しぶりにゆっくりネットサーフィンしてみました。youtubeで好きなもの垂れ流してボーっとしようと思っていましたが、検索するのはゲーム制作に関するものばかりでしたw

ローグライクを作る15のステップ

こちらの文章訳はGJです。ローグライクゲー作るなら一読すべきです。私はこの流れ通りにやっているとは言い難いですが、少なくともセーブ/ロードは早いうちにやるべきです。面倒くさがってやらないとマジ大変ですよ。

pythonでゲーム制作するのは正直オススメ出来ません。ライブラリが非常に少ないです。pygameの更新はもう止まってしまっています。私はとりあえずpython入門という本を持っていたのでpythonでやってみましたが、もっとゲーム関連のライブラリが多い言語の方がいいかもですね~。結構修羅の道ですよw

そんな逆風の中、pythonでのローグライクゲーム制作で使えそうなライブラリとか、機能、サイトを紹介してみます。

ダンジョン生成プログラムを作ってPyPiに登録した話

こちらの方が配布してくださっている、ダンジョン生成アルゴリズムは凄く便利です。

RogueBasin

ローグライクゲームの海外wikiです。めっちゃレベル高いです。意欲が向上するのでざっと見てみると良いかもしれません。

pickle

Python標準ライブラリです。オブジェクト階層をそのまま保存出来ます。プレイデータのセーブ、ロードなどに使える!

あと、エスケープシーケンスとかは使えると良いかもです。画面が綺麗になリます!

 

飽きた!以上!