BioErrorLog Tech Blog

試行錯誤の記録

Godot EngineでBoids Flockingを実装する | 人工生命

Boids FlockingシミュレーションをGodot Engineで実装します。

はじめに

Boids Flocking (ボイドモデル / ボイド群衆アルゴリズム) をGodot Engineで実装してみました。

エサを追いかけるような、可愛げのあるboidsたちの動きがなかなかのお気に入りです。


今回は、これらの実装方法のメモを残します。

※追記

今回実装したBoids Flockingをもとに、Boids達から逃げるちょっとしたゲームを作って公開しました。

ブラウザですぐ触れるので、良ければぜひ遊んでみてください。

Boids Flockingとは

まずは、Boids Flockingアルゴリズムについておさらいします。

Boidsとは、鳥の群れの動きをシミュレートする人工生命プログラムです。
"Bird-oid"、「鳥っぽいもの」という意味で、Boidsと名づけられました。 クレイグ・レイノルズが開発し、論文は1987年に発表されています。

画像はクレイグ・レイノルズの論文より引用: Flocks, Herds, and Schools: A Distributed Behavioral Model, Craig W. Reynolds, 1987, Computer Graphics

このBoids Flockingアルゴリズムでは、以下の3つのシンプルな法則によって群れを形成します:

  • Separation: 分離
  • Alignment: 整列
  • Cohesion: 結合


Separation: 分離は、近隣のオブジェクトと近づきすぎないよう距離をとる力です。

Separation: 分離 | 画像はWikipediaより


Alignment: 整列は、近隣のオブジェクトと同じ方向に進もうとする力です。

Alignment: 整列 | 画像はWikipediaより


Cohesion: 結合は、近隣のオブジェクト集合の中心地に向かおうとする力です。

Cohesion: 結合 | 画像はWikipediaより


この3つの力の組み合わせで、オブジェクトの集合が鳥の群れのような挙動をとるようになります。 単純な法則から複雑な現象が沸き起こるところは、生き物の醍醐味ですね。

それでは、以下Godot EngineによるBoids Flockingシミュレーションの実装を見ていきます。

実装

最終的なソースコードは以下のGitHubに置いていますので、良ければまずはそちらをご覧ください。
以下の章では、各要素ごとの実装を取り上げて見ていきます。 github.com

Separation

まず、Separationの実装を見ていきます。 言語はGodot Engineの標準スクリプト言語のGDScriptです。

func process_seperation(neighbors):
    var vector = Vector2()
    var close_neighbors = []
    for boid in neighbors:
        if position.distance_to(boid.position) < perception_radius / 2:
            close_neighbors.push_back(boid)
    if close_neighbors.empty():
        return vector
    
    for boid in close_neighbors:
        var difference = position - boid.position
        vector += difference.normalized() / difference.length()
    
    vector /= close_neighbors.size()
    
    return steer(vector.normalized() * move_speed)

大きく二つの処理からなっています。
一つ目は近隣boidsの取得、
二つ目は近隣boidsからSeparateする力の算出です。

近隣boidsの取得は、以下のコードで行っています:

   var close_neighbors = []
    for boid in neighbors:
        if position.distance_to(boid.position) < perception_radius / 2:
            close_neighbors.push_back(boid)

もともとこの関数に渡されるneighbors自体、一定の範囲perception_radiusを基準に算出された近隣boidsを指しています。 しかし、Separation力の算出源をさらに近い位置にいるboidたちに絞るため、perception_radius / 2以内にいるboidsをclose_neighborsとして登録しています。

そしてこれらclose_neighborsから、以下のようにしてSeparationの力を算出しています:

   for boid in close_neighbors:
        var difference = position - boid.position
        vector += difference.normalized() / difference.length()
    
    vector /= close_neighbors.size()

こうして算出したSeparation力を、本体boidの移動ベクトルに加算するという流れです。

Alignment

続いて、Alignmentを見ます。

func process_alignments(neighbors):
    var vector = Vector2()
    if neighbors.empty():
        return vector
        
    for boid in neighbors:
        vector += boid.velocity
    vector /= neighbors.size()
    
    return steer(vector.normalized() * move_speed)

Alignment力の算出はシンプルです。 neighborsの現在の進行ベクトルの平均をもとにAlignment力を算出し、本体boidの移動ベクトルに返却します。


Cohesion

続いてCohesionです。

func process_cohesion(neighbors):
    var vector = Vector2()
    if neighbors.empty():
        return vector
    for boid in neighbors:
        vector += boid.position
    vector /= neighbors.size()
    
    return steer((vector - position).normalized() * move_speed)

こちらもシンプルで、neighborsの平均座標と本体boidの差分をもとにCohesion力を返却しています。

ここまでが、Boids FlockingモデルにおけるSeparation / Alignment / Cohesionの実装です。 次には補足として、エサを追いかける動作の実装を見ます。

エサを追いかける動作

エサを追いかける動作として、単純にあるポイントへの求心力を算出しています。

func process_centralization(centor: Vector2):
    if position.distance_to(centor) < centralization_force_radius:
        return Vector2()
        
    return steer((centor - position).normalized() * move_speed)   

この引数centorとしてエサの座標を渡すことで、エサへ向かう力を算出できます。 ただし、エサに近過ぎる場合は空Vectorを返却することで、エサにboidが収束してしまうのを防いでいます。


以上、ここまで見てきたそれぞれの力をフレームごとに計算し、以下のように合算して移動ベクトルをとることで、boidsの振る舞いが定義できます。

func _process(delta):
    var neighbors = get_neighbors(perception_radius)
    
    acceleration += process_alignments(neighbors) * alignment_force
    acceleration += process_cohesion(neighbors) * cohesion_force
    acceleration += process_seperation(neighbors) * seperation_force
    acceleration += process_centralization(prey_position) * centralization_force
        
    velocity += acceleration * delta
    velocity = velocity.clamped(move_speed)
    rotation = velocity.angle()
    
    translate(velocity * delta)

おわりに

以上、Boids FlockingシミュレーションをGodot Engineで実装する際のメモを書きました。

処理効率等を考慮したプログラムではありませんので高度な利用はできませんが、彼らが動き出した時の感動はなかなかのものでした。

Boids Flockingは人工生命モデルの中でもシンプルかつ有名なものですが、今後はもっと複雑なモデルを動かせると楽しいだろうなとワクワクしています。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

参考

Flocks, Herds, and Schools: A Distributed Behavioral Model, Craig W. Reynolds, 1987, Computer Graphics

GitHub - codatproduction/Boids-simulation: A flocking simulation with obstacle avoidance made in Godot!

Code That: Boids - YouTube

Boids - Wikipedia

GitHub - alifelab/alife_book_src: 「作って動かすALife - 実装を通した人工生命モデル理論入門」サンプルコード

GDScriptにおけるドルマーク"$"の意味と使い方 | Godot Engine

GDScriptにおけるドルマーク$の意味と使用方法をまとめます。

はじめに

Godot Engineを触り始めた頃、以下のようなGDScriptコードの意味が分かりませんでした。

var sprite = $Sprite

ドルマーク$がGoogle検索で引っ掛からないこともあり、暫くドキュメントを探し回ったものです。

今回は、GDScriptにおけるドルマーク$の意味と、その使い方を整理します。

ドルマーク$get_node()の略記である

GDScriptにおいて、ドルマーク$get_node()の略記を意味します。

以下ドキュメントの引用です。

Literal Type
$NodePath Shorthand for get_node("NodePath")

このようにget_node("NodePath")$NodePathとして表記することができます。

※ドルマーク$略記が開発された経緯は、こちらのissueで見ることが出来ます:
Shorthand for get_node() · Issue #4309 · godotengine/godot · GitHub

それでは、いくつかの基本的な使い方を見ていきます。

使用例

子Nodeの取得

通常の子Nodeの取得は、次のように行います。

var node = $ChildNode


ただし、Node名にスペースや$#などの特殊文字を含む場合は、ダブルクォーテーション""またはシングルクォーテーション''で囲む必要があります。

var node = $"Child Node"


また子Node以降の孫Nodeは、パスを指定することで取得できます。

var node = $ChildNode/GrandChildNode

親Nodeの取得

親Nodeは、次のように取得できます。

var node = $".."

親のパスを意味する .. を利用しています。
$.で始まるパスを与える場合は、ダブルクォーテーション (or シングルクォーテーション)で囲む必要があります。

※なお、get_parent()でも同様に親Nodeを取得できます。

同階層Nodeの取得

同階層のNodeは、親Nodeから辿ることで取得できます。

var node = $"../FrendNode"

自Nodeの取得

自Nodeは、以下で取得できます。

var node = $"."

現在パスを意味する . を利用しています。

絶対パスでの取得

rootからの絶対パスでNodeを取得するには、次のようにします。

var node = $"/root/Node0/Node1"

/rootから始まる絶対パスを指定することで、該当のNodeを取得できます。
$/で始まるパスを与える場合、ダブルクォーテーション (or シングルクォーテーション)で囲む必要があります。

おわりに

以上、Godot Engine: GDScriptにおけるドルマーク$の意味と使用例を整理しました。

私自身、Godot Engineは触り始めたばかりです。
まだ使いこなせてはいない状態ですが、UnityやUnreal Engineに比べてシンプルな哲学・使用感が気に入っています。

これからも、折を見て初心者としての軌跡を残していく所存です。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

参考

GDScript reference — Godot Engine (stable) documentation in English

Shorthand for get_node() · Issue #4309 · godotengine/godot · GitHub

godot/modules/gdscript/gdscript_parser.cpp at 95cfa9bf74774110ba01a3987a22c9d7d616c1c6 · godotengine/godot · GitHub

Unityのゲーム画面を動画出力する

Unity Recorderを用いて、Unityゲームプレイ画面を動画出力する方法を整理します。


はじめに

こんにちは、@bioerrorlogです。

Unityで作成したゲームプレイ画面を動画に出力してみたくなりました。

最近Unityをはじめて触ってみたのですが、せっかくならコードだけでなくゲームシーンの再生動画も記録として残しておきたいなーと思ったからです。

今回は、Unity Recorderのインポートから、動画を出力するまでの方法を備忘録として残します。

作業環境

Unityバージョン:
2019.4.13.f1 LTS

OSはWindows10上で作業しています。

>ver
Microsoft Windows [Version 10.0.18363.900]

Unityのゲーム画面を動画出力する

Unity Recorderのインポート

以前はAsset Storeからインポートできたようですが、今はもうこちらからはインポートできません。

Unfortunately, Unity Recorder is no longer available.

代わりに、Package Managerから以下の手順でインポートします。

  1. ツールバーから Window > Package Manager を選択
  2. Package Managerウィンドウから Advanced > Show preview packages を選択
  3. 確認ウィンドウで Yes を選択
  4. Package Managerウィンドウから Unity Recorder を選択
  5. Install ボタンを押下

Package ManagerからUnity Recorderをインストール

Unity Recorderの設定

それでは、Unity Recorderを使ってゲームプレイ画面を動画出力します。

まず、以下の手順でRecorder Windowを表示します。

ツールバー: Window > General > Recorder > Recorder Window

Recorder Window

次に、Movie Recorderを追加し、各種設定を行います。

  • Recorderの追加:
    • + Add New Recorders > Movie
  • 設定:
    • Format: MP4
    • FIle Name: ファイル名の重複を避けるため、Wildcardsを設定する
    • Take Number: 1
    • Capture: Game View
    • Output Resolution: 任意
    • Capture Audio: 任意
    • Quality: 任意

Recorderの設定

ゲーム画面の録画

ここまできたら、いよいよゲーム画面を録画します。

START RECORDING を押すと録画がはじまり、STOP RECORDING で終了します。

これで、動画ファイルは設定画面のPathに指定したところに出力されています。

おわりに

以上、Unity Recorderを用いたゲーム画面の動画出力方法を簡単に記しました。

せっかくUnityを触るのであれば、目に見える動画という形で記録を残していくと、後から見返しやすそうです。

これから何かしらUnityで作っときは、動画の記録を残していこうと思います。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

参考

Unity Recorder V1.0 User Manual | Package Manager UI website

Unity Recorder Tutorial 2019 - How To Record HD Video In Unity | YouTube

人工生命をつくりたい - 思うところとアプローチのメモ | ALife

生き物をつくりたい、そのモチベーションと必要そうな知識 / アプローチのメモを書き残します。


こんにちは、@bioerrorlogです。

まず冒頭に、今回の記事を書くに至った個人的所感、背景を書き出します。 必要に応じて本編まで飛ばしてください。

思うところ/個人的背景

個人的な話ですが、幼い頃から虫が好きでした。 道端や空き地に住んでいる彼らは小さく愛らしい一方、不気味で予測不能なところが時間を忘れるほど面白いものでした。

この生き物への興味を持ったまま、大学ではその一分野を研究しました。 面白いデータに出会ったときや膨大な数字の中からパターンを解析したときなど、大いに感動・勉強になった経験がたくさんあります。

しかし、小さい頃に感じたような腹が浮き上がるような好奇心までは感じられなかった、というのが正直なところでした。 その理由のひとつは恐らく、還元主義的な考え方に疑問があったからだと今振り返って思います。

「生物を形作るひとつひとつの遺伝子機能を解明しても、その集合結果たる生物そのものを理解することはできないのでは」ということです。

ある遺伝子の機能をひとつ明らかにすることは、もちろん人類の叡知を一歩拡大する素晴らしいことです。 自分の研究が形になったときは、大きな喜びと充実感が溢れました。

しかし、何万と解明されている遺伝子の機能に何万一個目を追加しても、生命がこの手に感じられるとは思えなかったのもまた事実です。


さて、のちに私はITの世界に飛び込みました。 何でも自分のロジックで作ることができるというのは、この世界の強みです。

材料費も、(生物のような)交配時間も必要なく、知識や情報さえあれば何でも作ることが出来ます。 コンピュータのパワーは、年々掛け算の速度で高まっています。 新しい技術も、日進月歩で進化しています。


ここでひとつ思ったことがあります。

つまり、「生き物も作れるのでは」ということです。

前置きが長くなりましたが、伝えたかったのはこのことです。

生き物をつくりたいのです。

要素ごとに分割し、その一つ一つを解明しても生命を感じられないのであれば、作ればいいのではないか。 目覚ましい技術・研究の進歩は、それを可能な範囲にまで呼び寄せているのではないか。


とはいえ、現時点での私は何の背景知識も、良い考えもありません。 そこで今回は第一歩として、生き物をつくるために着目すべき分野/キーワード/アプローチを思いつくままに書き並べていき、頭の中を整理していきます。

聖書の世界観では、神が最初の人類を創造する | ミケランジェロ 「アダムの創造」 / Public domain

アプローチ

人工生命

まずは何より、人工生命という研究分野を調べる必要があります。

人工生命 (Artificial Life, A-Life, ALife, AL)とは、その言葉を生み出し、第一回人工生命国際会議を主催したクリストファー・ラングトンによると*1

The term Artificial Life literally means "life made by humans rather than by nature."

文字通り、自然によってではなく人間によって作られた生命のことです。

クリストファー・ラングトン | Wikipediaより

面白いのは、ここでいう「生命」という言葉のとらえ方です。 これは、地球上に「すでに存在する生命(life-as-we-know-it)」だけを指しているのではなく、現実世界では生まれ出ることのなかった「ありえたはずの生命(life-as-it-could-be)」をも含んだ言葉として使われているのです。

つまり、私たちが目にしている「すでに存在する生命」は、無数に存在する生命の可能性のひとつに過ぎない、という解釈です。

漠然と新鮮な切り口を求めていた私としては、これはとても魅惑的な考え方でした。


この人工生命という分野にどのような研究があるか、その方位を描くとすれば、次のような二つの軸がわかりやすいと個人的に思っています。

一つ目は、「弱い」人工生命 /「強い」人工生命という軸です*2

「弱い」人工生命は、生命の一側面をシミュレートしようとする考え方です。 「すでに存在する生命」あるいは「ありえたはずの生命」をシミュレートし、それらをより深く理解しようとすることを主眼に置きます。

一方、「強い」人工生命は、文字通り人間の手によって「生きている」生物を作ろうとするものです。

私としてはどちらも大いに興味があるので、隔てなく調べる価値があると思っています(特に後者の研究がどれほど進んでいるのかには興味があります)。


二つ目の軸は、人工生命を実現する手段です。 これによって、ハードウェア / ソフトウェア / ウェットウェアの3つの区分に分けることが出来ます*3

ハードウェアを用いた人工生命は、ロボットやコンピュータアーキテクチャを対象としています。

ソフトウェアを用いた人工生命は、コンピュータ上でのモデルを対象としています。

ウェットウェアを用いた人工生命は、生化学的手法を対象としています。

私としては、ソフトウェアを対象とした人工生命にスポットを当てていきたいと思っています。 ハードウェア/ウェットウェアももちろん興味ありますが、自分一人でやるのには時間・費用が間に合いません。


今はこの分野に対してこのようなぼんやりしたイメージですが、キーとなる研究や書籍にあたっていくことで、少しずつ何かが得られればという思いです。


有名な人工生命モデル、"Tierra"を実行してみた動画:

複雑系

次は複雑系という分野についてです。

この分野については正直何も知らないのですが、生命の本質を語るには避けて通れない考え方のようです。


生命はどのような状態に生じうるのか。
クリストファー・ラングトンは情報の複雑性に着目し、「カオス」と「秩序」の中間点「カオスの淵」に生命はあると考えたそうです。

クリストファー・ラングトンによる複雑性の分類。図はnode99.orgより引用

この図について、スティーブン・レビーの書籍「人工生命-デジタル生物の創造者たち」の解説を引用します。

左側は情報が凍り、何もが生きられない場合。 右に進むと結晶が生じるようなより柔軟性のある領域があるが、情報の移動は限られ、ここでも生命は維持できない。 右端まで行ってしまうと、情報があまりに自由に動きすぎてその構造が維持不能になり、あまりに無秩序なので生命は維持できない。 中央部の「スイート・スポット」といえる部分だけで、情報はその発信構造を維持できるほど安定し、発信できる程度にゆるやかだ。 生命はそこにいる。

完全なカオスでもなく、結晶のように規則的でもない、その中間点に生命は存在する、という話は、直感的にうなずけます。

しかし、私には直感的にしかわかりません。

複雑系という考え方、その原理や既知の事項を知れば、生命とは何ぞやという疑問に対して、情報という側面からの見方ができるようになると感じています。


人工知能

いま流行りの人工知能ですが、人工生命とも密接に関わっていくのではと感じています。

実際、ディープラーニングのパイオニアとして有名なジェフリー・ヒントンや、UberのAI研究所トップであるケネス・スタンリーなど、いま大活躍している人工知能研究者の中にも人工生命から影響を受けた方が多くいます*4

また、2020年のALife conferenceのテーマが “New frontiers in AI: What can ALife offer AI?” であるところを見るに、人工生命側からの人工知能への関心も高まってきているようです。

2020年 ALife conferenceの表紙。画像はカンファレンスホームページより引用


また個人的には、OpenAIのIgor Mordatchの研究が強く印象に残っています。

複数の人工知能エージェントの相互作用を用いた数々の研究を行っており、最近ではエージェントにかくれんぼをやらせる研究が面白かったです。 鬼と子に分かれたエージェントが対戦を繰り返して上達していくうちに、想定されていなかった方法でエージェントがふるまい始めるようになります。

鬼(赤)のエージェントが自ら箱に乗ったまま箱を移動させるという予想外の方法を見出した。Emergent Tool Use From Multi-Agent Autocurricula, Bowen Baker et al., 2019, Fig. 1より引用

設計者の意図しなかったふるまいを始めるというのは、まるで世代を跨ぐ生物の進化のような、単なる最適化で終わらない面白さが伺われます。


人工知能は大きな研究分野ですが、ところどころをピックアップして調べていくと面白そうです。


コンピューターウイルス

コンピューターウイルスは、人工生命をもっともよく体現している具体例のひとつと言えるのではないでしょうか。

これらは自己増殖し、変異し、複雑で、しばしば制御不能です。

実際、人工生命とコンピュータ-ウイルスを結び付けた研究も数多く行われてきたようです。 Google Scholarでちょっと調べただけでも、多くの論文が見当たります。

偶然にも、コンピューターセキュリティについては好きで少し調べていたこともあります

コンピューターウイルスの原理を理解することで、人工生命の具体的なイメージの一例が得られるかも知れません。


近年猛威を奮ったランサムウェア "WannaCry" | Wikipediaより

アート

最後は、アートの世界についてです。

人工生命には、ハードウェア / ソフトウェア / ウェットウェアの3つやり方があると前述しましたが、4つ目のフィールドとしてアートを掲げる向きもあるようです*5

実際、2018年のALife conferenceでは、アートアワードが開催されています。

Lenia – Mathematical Life Forms from Bert Chan on Vimeo.

例えばこの "Lenia – Mathematical Life Forms" はアートアワード受賞作品の一つで、連続的時空間による二次元セルオートマトンです。 論文ソースコードも公開されているので、ぜひ自分でも触ってみたいものです。


個人的には最近、ジェネラティブ・アート(Generative Art)というものにも注目しています。

ジェネラティブ・アートとは、自分の手で絵を描くのではなく、プログラムなどを用いて与えられたアルゴリズムをもとに、生成的に描かれるアート作品です。

簡単なアルゴリズムから生まれる複雑で予想外に美しい絵は、見ていても、作っていても、時間を忘れられるほど面白いものです。

最近描いたジェネラティブアート作品のひとつ。ふわふわな感じが面白い。

私が特に好きなのは、ジェネラティブ・アートの根底にある考え方です。 マット・ピアソンは著書「ジェネラティブ・アート - Processingによる実践ガイド」で、繰り返しジェネラティブ・アートとカオスとの関係性に触れています。

私の考えでは、ジェネラティブ・アートは、光とピクセルのバレエで表されるような、自然な調和をひねりだそうとするカオスと秩序の力の間の、永遠で巨大な戦いの副産物にすぎません。


私たちは、有機性(オーガニック)と機械性(メカニカル)の間、カオスと秩序の間の、ちょうど良くバランスがとれたスイートスポットを探しています。

「カオスと秩序の間のスイートスポット」という考えは、まさしくクリストファー・ラングトンの提唱したカオスの淵、生命のいる場所と一致しています。 一見関係ない二つの分野でこのような同じ考え方が見られるのは、心躍ることです。


このようにアートは、人工生命の有効な出力形式であり、生命を肌に感じる良いアプローチなのでは、と感じています。


人工生命モデルのひとつ、セルオートマトンを利用して描いた絵

おわりに

生き物をつくるために必要そうな知識やアプローチを、思いつくままに書き並べました。

これは、第一歩時点での感情を書き残した、メモのようなものにすぎません。

やりたいことはたくさんありますので、肩の力を抜いて気軽にやっていきます。

関連記事

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

参考

*1:Artificial life: An overview, CG Langton, 1997 を参照

*2:人工生命-デジタル生物の創造者たち, スティーブン・レビー, 1996 を参考にしました

*3:作って動かすALife, 岡瑞樹 et al., 2018 を参考にしています

*4:Introduction to Artificial Life for People who Like AI, Lana Sinapayen, 2019, The Gradientを参照

*5:再び、Introduction to Artificial Life for People who Like AI, Lana Sinapayen, 2019, The Gradientを参照

Generative Art 自作品まとめ - Processing

こんにちは、@bioerrorlogです。

主にProcessingで制作したGenerative artの作品/サンプルを、こちらにリストアップしていきます。
ソースコード/出力結果は各詳細ページにて記述しています。

Processingというプログラミング言語に聞き覚えがない、という方は是非こちらもご参考ください:
www.bioerrorlog.work

作品リスト

GenerativeArtNFT

https://cdn-ak.f.st-hatena.com/images/fotolife/B/BioErrorLog/20220702/20220702181725.png

GenerativeArtNFTで使ったアート画像生成ロジックをまとめています。

TokenIdをinputとして無限で多様なGenerative Artを生成する、というのがやりたかったことです。

www.bioerrorlog.work


Boids Flocking

エサを追いかけるような、可愛げのあるboidsたちの動きがなかなかのお気に入りです。

※こちらはProcessingの実装ではなく、Godot Engineを用いた実装です。詳しい実装は以下の記事をご覧ください。

www.bioerrorlog.work


Generative #14

序盤の規則的な四角い造形から、斜め方向に走るパターンが現れ、徐々に雨降る道路の水たまりのような、複雑な状態になっていく過程が面白いところです。

www.bioerrorlog.work


Generative #13

せわしなく動くクラゲの大群のような、あるいは解像度の低い煙のような雰囲気が面白いです。

www.bioerrorlog.work


Generative #12

生き物の初期胚が必死さが見えるような、少し神秘的でどこか微笑ましい雰囲気が気に入っています。

www.bioerrorlog.work


Generative #11

粒子が中央に集まったあともそのまま通り過ぎては拡散し、そしてまた中央へ収縮をはじめる、という繰り返しが気持ちいいです。

www.bioerrorlog.work


Generative #10

滑らかな樹の表面のような質感が好きです。パラメータをいじることで多様な絵を出力しています。

www.bioerrorlog.work


Generative #9

一つ一つの線の長さやノイズにかけ合わせる数の大きさによって、出力の雰囲気が大きく異なるのも面白いところです。

www.bioerrorlog.work


Generative #8

写真をもとに、油絵のような雰囲気の出力を出しました。 様々な画風も演出できそうで面白いです。

www.bioerrorlog.work


Generative #7

モデル全体がまるで生きているような、一定の拍動を打つのが面白いところです。 静止画として切り出すと、各タイミングで全く違った絵になるのも不思議なもの。

www.bioerrorlog.work


Generative #6

脳の染色画像のような、あるいは悪い夢を見ているときのような、不思議で不気味なパターンが面白いところです。

www.bioerrorlog.work


Generative #5

えんぴつで描き殴ったような、予測不能なパターンに風情を感じます。 www.bioerrorlog.work


Generative #4

sinやcosを利用して線を薄く重ねることで、綺麗なパターンが現れてきます。

www.bioerrorlog.work


Generative #3

チェスのポーンの駒のような、滑らかながら唐突な変化を見せる表面のパターンが好きです。

www.bioerrorlog.work


Generative #2

シルクの布のような、滑らかで涼しげなパターンがお気に入りです。

www.bioerrorlog.work


Generative #1

薄く、細くらせんを重ね合わせたシンプルなモデルです。 各要素にrandom()やnoise()を使い、ランダムでふわふわに見える中にもある特定のパターンが表れてくるのが面白いところでした。

www.bioerrorlog.work


関連URL

ソースコードはGitHubにもまとめています: github.com

作成した動画作品はYouTubeにまとめています:
www.youtube.com

高解像度の出力結果はこちらPixivにまとめています: www.pixiv.net


初心者がPythonでゼロからゲームを作ってみた | デザインから実装まで

Pythonでゲームを自作してみました。 ゲーム制作にあたって行った準備から、実装時にハマった注意点、出来上がったゲームのデザインまでを記録します。

はじめに

何かを作りたい

何かを作ってみたいと思いました。

ここ最近、初心者ながらコードの書き方がだんだんわかってきたので、さっそく何か新しいものを作りたくなったのです。

プログラミングで作るもの、として真っ先に思い付いたのが、ゲームでした。 私はそこまで大のゲーム好きという訳ではありませんが、ゲームは身近でイメージしやすく、作るのも楽しそうです。

そんなわけで、ゲームを自作することに決めました。


なぜPythonを選んだのか

このゲーム作りにPythonを選んだ理由は、Pythonがとても書きやすい言語だと思ったからです。

Pythonは文法がシンプルで、一つの実装にごちゃごちゃとコードを書く必要がありません。

例えばJavaとPythonを比べてみると、「ゲームウィンドウを表示する」という同じ目的でコードを書いても、必要なコード量が全然違います。

かわりにPythonは比較的処理が遅く、ゲーム制作用としては不人気のようです。 しかし、コードを簡単に書けるというのは、私のような初心者にはとても重要なことです。

また、Unityのようなゲームエンジンを使うことも考えましたが、今回は自分の手でゲームを作ることが目的だったので、不採用としました。

Pythonにはゲーム制作用のライブラリ"pygame"があります。 今回はこれを使って、ゲームを自作しました。


作業環境

Pythonバージョン情報 ↓

Python 3.7.2  
pygame 1.9.5

Windows10上で開発しました。

※Pythonのインストール方法
はじめてのPython | Windows環境構築 - Atom - BioErrorLog Tech Blog


ゲーム概要

こちらが、最終的なゲームの概要です。


ゲーム自体はitch.ioで配布しています。
もしよければ軽く触ってみてください:


ソースコードはGitHubに置いています。
ソースコードからゲームを実行するには、以下の手順をご参考ください。

# pygameをインストール
pip install pygame

# ソースコードをクローン
git clone https://github.com/bioerrorlog/CellForRest_Pygame.git

# ゲームを実行
cd CellForRest_Pygame/game/
python CellForRest.py


何を作ったのか、どのようにして作ったのか、どこにつまずいたのかを、順を追ってこの記事内で書き出していきます。

なお、私はプログラミングを始めて間もない初心者ですので、私の書いたコードが最善のやり方であることはまずないと思います。 書いてるときは常に、もう少しマシなやり方はないものかと苦悩してました。

かといって、悩み続けていてもゲームは完成しません。 初心者がとりあえず動くものを作ることを目的に書き上げたものだと思ってもらえれば幸いです。

それでは、ここまでの過程を一つ一つ振り返っていきます。


[関連記事] Devlog #1 ChatGPTを使ったゲームを作る実験をはじめる


Pythonでゲームを作る

Python / pygameの基本を知る

チュートリアルをやってみる

まずは、Pythonでのゲーム制作の基本を調べるところから始めました。

ゲームを作りたい、といきなり思い立っても、作り方が全く分かりません。 どうやってウィンドウを表示すればいいのか、動く画面はどうやって実装するのかなど、ゲーム作りの基本を一つも知らなかったのです。

そこでまずは、ネット上にあるチュートリアルを通して最低限の基本を身につけることにしました。 私は文章よりも動画で見る方が好きなので、Youtubeで「Python game dev」などで検索して、一番再生されてそうなsentdex氏のチュートリアル動画をやりました。

英語の動画になってしまいますが、ソースコードと書き方の手順がわかりやすく、あまり聞き取れなくても問題なく基本を追えるチュートリアルとなっていました。 また、ネットの情報は圧倒的に英語のものが多いので、早いうちに英語に慣れるという意味でもちょうどいいチュートリアルだったと思います。

チュートリアルを通して、

・ゲームウィンドウの表示
・画像の表示
・ゲームループの実装
・スタート画面 -> ゲーム画面/メニュー画面の流れ
・テキスト/ボタン表示の実装
・マウス/キーボードイベントの検知

など、基本となるゲーム実装のやり方を知ることができました。

私のように知識ゼロの状態からゲームを作ろうと思っている方は、どれでもいいのでチュートリアルをさらっとやることをお勧めします。 自分で一つのゲームを作ることに対して、勇気と希望を抱くことができます。


参考になったゲーム制作関連の情報

次に、制作を進める中で参考になった情報を紹介します。 早めに知っていればもっとスムーズに作れたなあと思ったので、ご参考までに。


1.初心者のためのpygameガイド

これは、pygame公式の初心者ガイドの日本語訳です。 初心者が知っておくべき13の心得が紹介されています。

私も後で説明しますが、処理スピードの話などは特に重要なポイントでしたので、早めに目を通しておくと良いかと思います。


2.Game Programming Patterns

ゲームプログラミングについてのデザインパターンが書かれた記事(英語)です。 日本語訳されたものは書籍として出版されていますが、英語のhtml版はネットで公開されています。

私には内容が高度に感じたのであまり真面目には読んでませんが、暇なときに読んでみると、たまに重要なヒントが得られました。 英語に慣れる練習にもなります。


3.redditのpygame板

redditは、海外の有名な掲示板です。 そこのpygame板では、毎日pygameユーザーによる議論が行われています。

もちろん、本当は日本語のpygameコミュニティーがあればよかったのですが、動いている日本のpygameコミュニティーを私は見つけられませんでした。 代わりにこのredditに入って、同じくゲームを作っている人を見てました。 モチベーションを高めるためにも、何かしらのコミュニティーを探すといいと思います。

振り返って特に参考になったと感じるのはこの3つです。 とはいえ、恐らくまだまだネット上にはたくさんの有益な情報が溢れていると思いますので、あくまで参考までにどうぞ。


[関連記事] Godot EngineでBoids Flockingシミュレーションを実装する | 人工生命


ゲームデザインを考える

デザインはどんどん変わっていった

ある程度ゲームのつくり方が理解できたら、つぎは自分がどんなゲームを作るのかを考えました。

とはいっても、作り始める前に考えていたデザインは、ほとんど跡形もなく変更してしまいました。 実装を進める中で、やっぱりデザインを変更しよう、別の方法で実装しよう、などとやってるうちに、当初作っていたものとは完全に別物になったわけです。

逆に今思えば、作り始める前にゲーム性を確定しようとするのは愚かだったと思います。 私はプログラミングの経験が浅く、どのような実装が難しいのかを把握しきれていません。 さらにはゲーム制作も初めてなので、どんなゲームにしたいのかも、現物を見ないとイメージできません。

なので、気楽にスケッチを描き始めるような感覚で、気軽に実装を進めることにしました。 まず書き始め、気に入らなければ躊躇なく変更し、頭の中のイメージに近づけていきます。

恐らくは個人が趣味で作るときのみに許される、自由で楽しい作り方です。 おかげで楽しくゲームを作り上げることができました。


最終的なゲームデザイン

さて、肝心の最終的なゲームの形ですが、クッキークリッカーのようなものに落ち着きました。

クッキークリッカーとは、Wikipediaの説明を借りると、

画面に現れるクッキーを1回クリックするごとに1枚(アイテムで1クリックあたりの枚数を増やすことができる)クッキーを焼くことができる。焼いたクッキーはクッキーの生産施設購入費用に充てることができ、次第に大量のクッキーが手に入るようになる仕組みをとっている。

つまり、クッキーを増やすだけのシンプルなゲームです。
ゲームを進めるにつれ指数的にクッキーが増えていく様子には、ある種のレベルアップ中毒のようなものがあり、私もえらくハマったのを覚えています。


今回出来上がったのは、3つのステージを行き来しながら、クッキーならぬ「Leaf」という値を増やしていくゲームです(Fig. 1)。

Fig. 1 ゲームの全体像
スタート画面からゲームをスタートし、「Cellステージ」「Treeステージ」「Caveステージ」をボタンで行き来しながらゲームを進めていきます。


Cellステージ(Fig. 2)、Treeステージ(Fig. 3)、Caveステージ(Fig. 4)には、それぞれ異なった役割があります。

Cellステージから順に、軽くゲーム画面を説明します。

Fig. 2 Cellステージ
Cellステージでは、手動クリックによる採取によって「Leaf」が獲得されます。

①: ステージ移動ボタン
  ->ほかのステージに移動する。
②: Leaf
  ->「Leaf」の残高が表示される。
③: Gate
  ->クリックで「Cell」を生成する。
  ->「Cell」の生成には「Leaf」を消費する。
④: Cell
  ->うねうね動き回る緑色のやつ
  ->ある程度動いた後に出芽して「Bud」になる。
  ->出芽する前に1回分裂して「Cell」を生む。
⑤: Bud
  ->「Cell」の成れ果て
  ->クリックで採取できる。
  ->採収すると「Leaf」が獲得される。


Fig. 3 Treeステージ
Treeステージにある「Tree」のレベルに応じて、「Leaf」が自動的に増えていきます。 その増加幅は「Human」の数に応じて倍増します。
※語呂の関係で、ステージ遷移ボタンでの名称は「Tree」ではなく「Forest」となっています。

①: ステージ移動ボタン
  ->ほかのステージに移動する。
②: Leaf
  ->「Leaf」の残高が表示される。
③: Tree
  ->レベルに応じて「Leaf」を自動加算する。
  ->レベルに応じて大きくなる。
  ->レベルアップには「Leaf」を消費する。
④: House
  ->クリックで「Human」を生成する。
  ->「Human」の生成には「Leaf」を消費する。
⑤: Human
  ->数に応じて「Tree」の効果が倍増する。
  ->地面を動き回る。


Fig. 4 Caveステージ
Caveステージにある「BlueGem」のレベルに応じて、Cellステージでの「Leaf」獲得量が倍増します。

①: ステージ移動ボタン
  ->ほかのステージに移動する。
②: Leaf
  ->「Leaf」の残高が表示される。
③: BlueGem
  ->上下にゆらゆら揺れる。
  ->レベルに応じてCellステージでの「Leaf」獲得量が倍増する。
  ->レベルアップには「Leaf」を消費する。
  ->レベルに応じて周りの青いやつが増える。

今回出来上がったゲームは以上のような感じです。


[関連記事] 人工生命をつくりたい - 思うところとアプローチのメモ | ALife


実装する

それではここから、ソースコードについての注意点を書き出していきます。 どのようなことに苦労したのか、将来の自分に向けてメモを残すつもりでやっていきます。

ソースコードはGitHubに置いてあります。

ソースコードの全体像

まずは、ソースコード全体の構造(Fig. 5)をまとめます。

Fig. 5 ソースコード全体像
gameInit()メソッドによってスタート画面を表示し、スタート画面でStartボタンが押されるとgameLoop()メソッドが開始します。gameLoop()メソッドの中ではゲームループがまわり続け、ゲームが進行していきます。

ゲームループの中では、3つのステージそれぞれに対応するLayerManagerクラスのオブジェクトが動いています。LayerManagerクラスは、それぞれのステージで登場するキャラクターのオブジェクトを生成・保持・削除します。

button()メソッドやtextDisplay()メソッドなど、ゲームを通して使用するメソッドはクラス外で宣言し、各クラスが使用するようにしました。

全体像はざっとこんな感じです。 ここからは部分部分について、注意が必要だったところのメモを残していきます。


ゲームループ

ゲームループとは、ゲームを静止画ではなく動画として表現するための仕組みです。

一つのwhileループ内でゲーム処理と描画処理を実行し、ループを繰り返します。

今回私は次のように実装しました。
以下gameLoop()メソッド部分のみの切り抜きです。

# Game loop: event.get() -> update() -> draw() -> display.update() -> clear()
# Close button: Quit game
# m button: Menu
# Left click: Inform each game layer via setMouseEventUp()
def gameLoop():
    global intro
    intro = False
    game_exit = False

    cellLayerManager = CellLayerManager()
    treeLayerManager = TreeLayerManager()
    caveLayerManager = CaveLayerManager()

    while not game_exit:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                gameQuit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_m:
                    menu()
            elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
                # cellLayerManeger uses pygame.mouse.get_pressed()
                treeLayerManager.setMouseEventUp(True)
                caveLayerManager.setMouseEventUp(True)

        cellLayerManager.update()
        treeLayerManager.update()
        caveLayerManager.update()

        if cell_layer == True:
            cellLayerManager.draw()
        elif tree_layer == True:
            treeLayerManager.draw()
        elif cave_layer == True:
            caveLayerManager.draw()

        pygame.display.update()
        clock.tick(30)

        cellLayerManager.clear()
        treeLayerManager.clear()
        caveLayerManager.clear()

流れとしては、各ステージに対応したLayerManagerクラスのオブジェクトをそれぞれ一つずつ生成してからループに入り、

1.イベントの取得: pygame.event.get()
2.更新処理: update()
3.描画処理: draw()
4.ディスプレイ更新: pygame.display.update()
5.更新後処理: clear()

これをループで繰り返しました。

イベントの取得では、キーボードやマウスのボタンイベントを取得します。 ここについては少し注意が必要でしたので、別途後述したいと思います。

update()をループごとに必ず一度呼び出されるメソッドにして、各ステージの数値更新が主に行わせました。 一方draw()は3つあるステージのうち表示中のステージのみで実行されるようにしました。

pygameによるディスプレイの更新では、clock.tick()でfpsを指定できます。 fpsとはframes per secondのことで、一秒間に何回画面を更新するかの単位です。
今回私は30fpsにしました。 ゲームが進んで処理オブジェクトが増えても、30fpsを下ることはあまりなかったからです。 逆にこれを60fpsとかに設定してしまうと、処理オブジェクトが増えていったときに処理の低下が目立ってしまいます。

更新後処理clear()も定義して、ディスプレイの更新後に値を初期化するときなどに使いました。


3つのLayerManagerクラスに以上のupdate()メソッド、draw()メソッド、 clear()メソッドを必ず持たせて、それらをゲームループでフレームごとに順番に呼び出させるという訳です。

以上が、今回作ったゲームループでした。


クリックイベントが検出されない原因と対処

開発途中に、なぜかマウスのクリックが検出されないという事態にハマりました。 左クリックを検出するコードを書いたのに、2回に1回ほどしか認識されなかったのです。 この原因と対処法について、メモを残します。

まず、マウスやキーボードの入力を検出するには、二つの方法があります。
初心者のためのpygameガイドには、次のように書いてあります。

最初の方法は、入力デバイスの状態を直接チェックすることだ。 これは、たとえば pygame.mouse.get_pos() や pygame.key.get_pressed() なんかを呼ぶことで実現できる。 これは その関数を呼んだ時点での 入力デバイスの状態を 教えてくれるだろう。

このようなpygame.mouse.get_pressed()などを使うやり方は、クリックをしている間ずっと検出し続けるので、検出漏れはありません。 しかし一方で、一度のクリックで何回分もクリックが検出されてしまうので、場合によっては使い勝手がよくありません。

例えば、ボタン押下でレベルアップを行う処理を行う場合、1回だけレベルアップしたつもりが、何回も(限界まで)レベルアップが行われてしまう、ということになります。


1回のクリックで1回のクリック検出を行いたいときは、二つ目の方法で実装する必要があります。

2番目の方法は SDL のイベントキューを使うことだ。 このキューはイベントのリスト -- イベントが 検出されると、リストに追加される -- になっている。 そしてこれらのイベントは取り出されるとリストから消える。

こちらはpygame.event.get()を利用する方法です。 これを使うときに注意しなければいけないのは、pygame.event.get()を呼び出すたびに"イベントが取り出されてリストから消える"ということです。

つまり、複数の場所でpygame.event.get()を書いてしまい、一つのゲームループの中で複数回pygame.event.get()を呼び出してしまうと、検出漏れが起きてしまうということです。

そこで、今回私は次のようにゲームループの中で1回pygame.event.get()を呼び出し、その結果を各LayerManagerに渡すというやり方をしました。

def gameLoop():
・
・中略
・
    while not game_exit:
        for event in pygame.event.get():
            if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
                # cellLayerManeger uses pygame.mouse.get_pressed()
                treeLayerManager.setMouseEventUp(True)
                caveLayerManager.setMouseEventUp(True)

for event in pygame.event.get():とすることで、各マウスクリックやキーボードのボタン押下状態を一つずつ取り出して検証することができます。 今回の場合だと、event.type == pygame.MOUSEBUTTONUPでマウスボタンがUPしたことを検出し、event.button == 1でそれが左クリックであることを認識しています。

それを各LayerManagerに作成したsetMouseEventUp()メソッドにTrueとして渡しているのはとてもダサいですが、動くのでまあ良しとしました。

同様のやり方でキーボード押下や閉じるボタンの処理を記述することができます。 詳しくはソースコードや、pygameのドキュメントをご参考ください。


画像ファイルの読み込み

画像ファイルの読み込みにも、すこし注意が必要でした。

当初、私は単純に次のようにして画像を読み込んでいました。

img = pygame.image.load('img.png')

しかし、これはあまり上手いやり方ではありません。 convert()を使っていないからです。

初心者のためのpygameガイドにも、次のようにあります。

最初に surface.convert() の説明を読んだとき、 ぼくはそれがそんなに気にかけるほどのものだとは思わなかった。 「自分は png しか使わないから、ぼくが扱うものはすべて 同一の形式になるはずだ、だから convert() なんか必要ない」 -- でもこれは激しく間違っていることがわかった。

私もまったく同じ状況でした。

convert()の機能は、pygameドキュメントによると、

何も引数を定しなかった場合は、SurfaceはディスプレイのSurfaceと同じピクセル形式になります。この方法を行うと、常に使用ディスプレイ環境での画像描写に最も高速化された形式となります。画像描写処理を行う前には、Surface.convert()命令でピクセル形式を最適な状態に変更するとよいでしょう。

あまりよく分かりませんが、「ピクセル形式」をディスプレイと同じに変えることで、画像描写処理を高速化してくれるそうです。

convert()を適用するには、次のようにして画像を読み込みます。

img = pygame.image.load('img.png').convert()

末尾に.convert()をつけるだけです。 ちなみに、png画像などで透明度を保持する必要がある場合は.convert_alpha()を使います。

私の場合、背景もpng画像で表示していたため、このconvert()/convert_alpha()を適用することで画像描写処理が劇的に改善しました。 fpsで言えば、大体3倍以上の違いが出ました。

画像の読み込み時にはconvert()を忘れないことが大切です。


キャラクターの作画と描画

キャラクターの作画と描画処理についても、少し書いておきます。

まず、絵描きツールは、次の二つを使いました。

Inkscape
無料のベクターグラフィックツール。
ペイントツールでフリーハンドで書くよりも、Inkscapeで図形や線・曲線を組み合わせて描いた方が絵心の無さがごまかせるので、こちらをメインに使っていました。

FireAlpaca
無料のペイントツール。
こちらでキャラクターそのものを書くことは少なかったですが、レイヤーエフェクトをかけるのがとても簡単なので時折使っていました。

基本的にはInkscapeでキャラクターを描き、FireAlpacaでエフェクトをかける、ということをしていました。

エフェクトをかける、というと大げさですが、画像全体の色味を少し変えるという程度の話です。 マウスオーバー時にキャラクターが少し明るくなるような仕様にしたかったため、各キャラクターに色違いの画像を用意しました(Fig. 6)。

Fig. 6 マウスオーバー時に表示する画像を変える

マウスオーバー時に表示画像を入れ替える描画処理は、CellTreeなどのキャラクタークラスのdraw()メソッドに、次のようにして実装しました。

def draw(self):
    mouse = pygame.mouse.get_pos()
    if self.x+self.width > mouse[0] > self.x and self.y+self.height > mouse[1] > self.y:
        game_display.blit(self.act_img, (self.x, self.y))
    else:
        game_display.blit(self.inact_img, (self.x, self.y))

mouse = pygame.mouse.get_pos()でマウス位置を取得し、X方向mouse[0]とY方向mouse[1]が画像位置内に収まっていればマウスオーバー用の画像act_imgを、そうでなければ元の画像inact_imgblit()で表示させるのです。

このキャラクタークラスのdraw()メソッドはLayerManagerクラスのdraw()メソッドが呼び出し、そして今度はゲームループがLayerManagerクラスのdraw()メソッドを呼び出すことで、画面にキャラクターが描画されるというやり方をとりました。

反省点

今回のこのプロジェクトの目的は、とりあえず何かを作ってみる、ということでした。 なので、出来上がったものにはたくさんの反省点があります。

まず、ゲームバランスの調整をほとんどやってないことです。 作ることが目的だったために、誰かに遊ばれることを想定していません。 なので、ゲームの肝となるゲームバランス調整には、ほとんど時間を割いていません。

加えて、このゲームにはセーブ機能がありません。 このような放置系ゲームにおいては致命的でしょう。 pygameでセーブ機能を実装するのは少し厄介そうだったので、断念しました。 志が湧いてきたら、挑戦してみるのも面白いかもしれません。

コードについては見返すたびに反省点が浮かびますが、まずはソースコードを一つのファイルに詰め込んだのはよくなかったと思います。 参考にしたゲーム制作チュートリアルがオブジェクト指向でなかったため、そのまま中途半端な感じになってしまいました。 各クラス間の依存関係を薄くして、それぞれファイルを分けた方が見やすいですし、再利用もしやすいでしょう。

また、今回はクラス継承という機能を利用しませんでした。 似たようなクラスがあるにも関わらず、それぞれが特に親クラスを持っていないため、共通項が取れずにコードが読みずらくなっています。

次また何か作るときは、改善していきたいです。


おわりに

今回は、Pythonでゲームを自作してみました。

プログラミング練習のようなものではなく、自分の頭で考えて作った初めてのものになります。 おかげでいろいろと面白い経験ができました。

思えば結構な時間がかかりました。
朝にコーヒーを飲みながらのコーディングは、ささやかな楽しみでもありました。

今回の記事はかなり長いものになってしまいました。
やりたいことは他にもたくさんあります。
この辺でこのゲームに区切りをつけ、次に行きたいと思います。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

参考

YouTube

初心者のための pygame ガイド

A Newbie Guide to pygame — pygame v2.5.0 documentation

Table of Contents · Game Programming Patterns

Reddit - Dive into anything

クッキークリッカー - Wikipedia

event - Pygameドキュメント 日本語訳

surface - Pygameドキュメント 日本語訳

Draw Freely | Inkscape

フリー ペイントツール(Mac/Windows 両対応)FireAlpaca[ファイア アルパカ]

Android Studioで実機が認識されないときの対処法

Android Studioで実機が認識されない問題が起きました。
いろいろ試した末に解決したので、対処法を整理します。

はじめに

こんにちは、@bioerrorlogです。

Android Studioでスマホ実機とPCを繋ごうとしたとき、実機が認識されない問題が発生しました。

Fig. 1 Android Studioでプログラム実行時に表示されたウィンドウ。実機が認識されない。

USBで実機をつないでいるにも関わらず、プログラム実行時に表示されるウィンドウには上の画像のように、

No USB devices or running emulators detected

Connected Devices
<none>

接続されたデバイスがありません、と表示されてしまいました。

うまくいく対処法がなかなか見つからず、ここでかなりの時間を消費してしまいました。

試行錯誤の末にようやく解決したので、備忘録を残します。

作業環境

PC側の環境:Windows10 / Android Studio 3.1.4 / JDK 8
スマホ側の環境: Android8.0 / Huawei Nova2

Android Studioで実機が認識されないときの対処法

「USB使用」を「写真を転送」または「ファイルを転送」に変える

USBを用いてスマホをPCに接続するときには、次の5つの接続方法があるようです。

「写真を転送」
「ファイルを転送」
「充電のみ」
「給電」
「MIDI」

この設定は、スマホ側から

設定 > デバイス接続 > USB

で確認することができます。

この設定が、デフォルトでは「充電のみ」となっていました。 これが実機が認識されない原因のひとつでした。

「写真を転送」はPTP(Photo Transfer Protocol)、「ファイルを転送」はMTP(Media Transfer Protocol)と呼ばれる接続形式で、実際にPCとデータのやり取りをするための接続方式なのでしょう。 このどちらかに設定することで、Android Studioが実機を認識するようになりました。

Fig. 2 「USB使用」を「写真へ転送」としたところ、実機が認識された


さて、私の場合は上記の設定変更が決定打となりましたが、これ以外にも前提として変更を行った箇所があります。 もしかすると必要でない操作があったのかもしれませんが、以下記録します。

「USBデバッグ」をONにする

スマホ側の設定で「USBデバッグ」をONにするのは、必要な作業です。

手順は、次のようになります。

  1. 設定 > システム > 端末情報 > ビルド番号を連続タップし「デベロッパーになりました」の表示が出る

  2. 設定 > システム > 開発者向けオプションから、「開発者向けオプション」をONにする

  3. 同じく開発者向けオプションから、「USBデバッグ」ONにする


注意したいのは、この「USBデバッグ」は、他の設定を変更した際にOFFに戻ることがあることです。 結局そのタイミング・原因はわかりませんでしたが、私は何かを変更したときはこの「USBデバッグ」がONになっていることを定期的に確認していました。


Android SDK Managerから該当Androidバージョンをインストールする

Android StudioのSDK Managerから、実機Android OSの該当バージョンをインストールしました。

SDK ManagerでサポートされているAndroid OSバージョンは、


Android Studioツールバー内「Tools」 > SDK Manager


から確認することができます。

自身のスマホAndroidバージョンの「Status」が「Not installed」である場合は、インストールする必要があります。 インストールするには、チェックボタンをチェックし、左のインストールボタンを押します。

「Google USB Driver」をインストールする

先ほどと同じくAndroid StudioのSDK Managerから、「Google USB Driver」をインストールしました。


Android Studioツールバー内「Tools」 > SDK Manager > SDK Toolsタブ


ここから、「Google USB Driver」の欄を確認します。 これもまた「Status」が「Not installed」である場合は、インストールする必要があります。 チェックボタンをチェック、インストールボタンを押すことで、インストールができました。

おわりに

今回は、Android Studioでプログラムの実行時に実機が認識されないときの対処法を書き残しました。

最終的に解決したはいいのですが、よく考えると自分がスマホの仕組みをよく知らないことに驚きました。

例えば、今回の私の場合、スマホとPCの接続方法の設定が肝となっていました。 USBを介した接続がどのような仕組みで行われているのか、どのような種類があるのか、よく知りません。 あるいはもっと言えば、スマホがハードウェアとしてどのような構造なのか、どう情報をやり取りしているのかも大して知りません。

日常的に使っているのに全然中身を知らないというのは、なかなか面白いことです。 このあたりの仕組みを調べてみるのも面白そうですね。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

参考

Developer Guides  |  Android Developers