YouTube/Twitchのコメントを物理演算で降らせて遊ぶ!Godot 4 × Python 連携ハンズオン
あなたは
「推しの配信を見ている時、このコメントの奔流が物理的な物体として降ってきたら面白いのに」 と思ったことはありませんか?
今回は、軽量で扱いやすいゲームエンジン Godot Engine 4 と、豊富なライブラリを持つ Python を連携させて、「YouTubeのコメントアイコンをリアルタイム(またはアーカイブ)で物理演算オブジェクトとして降らせる」 実装を紹介します。
完成すれば、配信画面を見ながら手元のサブモニタで「コメントが物理的に積み重なるカオス」を楽しめるようになります。
🛠 技術構成とアーキテクチャ
今回は以下の構成で実装します。
-
Python:
pytchatライブラリでYouTubeのチャットを取得し、必要なデータ(名前、アイコンURL)を抽出。 - UDP通信: PythonからGodotへデータを「投げっぱなし」にします。
-
Godot 4: UDPサーバーとして待機し、データを受信したら
RigidBody2D(物理ボール)を生成。アイコン画像を動的にロードしてテクスチャとして貼り付けます。
なぜUDPなのか?
TCPではなくUDPを採用する理由は 「リアルタイム性」と「実装のシンプルさ」 です。
コメントが大量に流れる状況では、1つや2つのパケットロス(コメントの欠落)よりも、遅延なく次々と降ってくるスピード感の方が重要だからです。
Step 1: Python側(コメント取得と送信)
まずは「送信機」となるPythonスクリプトを作成します。
ライブラリは pytchat を使用します。インストールしていない場合は pip install pytchat を実行してください。
ここでは複雑なロジックは排除し、「チャットを取得してJSONで投げる」ことに特化したコードにします。
import pytchat
import json
import socket
import time
VIDEO_ID = "YOUR_VIDEO_ID_HERE"
HOST = "127.0.0.1"
PORT = 4242
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
chat = pytchat.create(video_id=VIDEO_ID)
print("Connected. Listening for chats...")
while chat.is_alive():
for c in chat.get().sync_items():
data = {
"name": c.author.name,
"message": c.message,
"icon_url": c.author.imageUrl
}
json_data = json.dumps(data)
sock.sendto(json_data.encode('utf-8'), (HOST, PORT))
time.sleep(0.1)
except KeyboardInterrupt:
print("Stopped.")
if __name__ == "__main__":
main()
Point:
VIDEO_ID には、テストしたいYouTube動画(ライブまたはアーカイブ)のID文字列を入れてください(URLの v= の後ろの部分)。
Twitchの場合も socket ライブラリでIRCチャットに接続すれば、同じ sock.sendto の仕組みでGodotにデータを送れます。
Step 2: Godot側(受信サーバーと生成)
次にGodot側を作ります。
シーンのセットアップ
Main.tscn を作成し、以下のようなノード構成にします。
Node2D (Main) <-- スクリプトをアタッチ
└─ StaticBody2D (Floor)
└─ CollisionShape2D (床のあたり判定)
ルートノードにアタッチするスクリプトは以下の通りです。 _process 内で常にパケットを監視し、データが来たらボールを生成します。
extends Node2D
var server := UDPServer.new()
var ball_scene = preload("res://Ball.tscn")
const PORT = 4242
func _ready():
server.listen(PORT)
func _process(_delta):
server.poll()
if server.is_connection_available():
var peer = server.take_connection()
var packet = peer.get_packet()
var json_str = packet.get_string_from_utf8()
var json = JSON.new()
if json.parse(json_str) == OK:
spawn_ball(json.data)
func spawn_ball(data):
var new_ball = ball_scene.instantiate()
var screen_width = get_viewport_rect().size.x
new_ball.position = Vector2(randf_range(50, screen_width - 50), -50)
new_ball.icon_url = data.get("icon_url", "")
add_child(new_ball)
Step 3: 動的なアイコン画像のロード(最重要)
ここが今回のキモです。 Pythonから送られてくるのは画像のURL文字列だけです。Godot側でこれをダウンロードし、テクスチャとしてスプライトに適用する必要があります。
Ballシーンのセットアップ
Ball.tscn を作成し、以下のような構成にします。CollisionShape2Dを忘れると床をすり抜けるので注意してください。
RigidBody2D (Ball) <-- スクリプトをアタッチ
├─ Sprite2D (アイコン表示用)
└─ CollisionShape2D (円形のあたり判定)
extends RigidBody2D
var icon_url = ""
func _ready():
if icon_url != "":
var http = HTTPRequest.new()
add_child(http)
http.request_completed.connect(_on_request_completed)
http.request(icon_url)
func _on_request_completed(_result, response_code, _headers, body):
if response_code == 200:
var image = Image.new()
var error = image.load_jpg_from_buffer(body)
if error != OK:
error = image.load_png_from_buffer(body)
if error == OK:
var texture = ImageTexture.create_from_image(image)
var sprite = $Sprite2D
sprite.texture = texture
var target_size = 64.0
var s = target_size / max(texture.get_width(), texture.get_height())
sprite.scale = Vector2(s, s)
Step 4: 遊んでみる
準備ができたら実行してみましょう。
- Godot でプロジェクトを実行(F5)。何もない画面(床だけ)が表示されます。
- Python スクリプトの
VIDEO_IDに、コメントの流れが速い人気配信者のアーカイブIDを入力して実行。
Godotの画面に、配信のコメントに合わせてアイコンがボトボトと降ってくれば成功です!
加藤純一さんやぺこらさんなど、コメント流量が「滝」のような配信で試すと、物理演算が悲鳴を上げるカオスな光景が見られて非常に楽しいです。
おわりに
このシステムを応用すれば、特定のキーワード(例:「草」「w」)が流れた時だけ爆発エフェクトを出したり、スパチャの金額に応じてボールのサイズを変えたりといった「視聴者参加型ゲーム」のベースを作ることができます。
GodotはPythonとの相性が良く(GDScriptの文法が似ていることもあり)、非同期処理や通信周りも手軽に書けるので、ぜひオリジナルの配信演出ツールを作ってみてください。
今回の記事ではコア機能のみを解説しましたが、さらに 「同じ人のアイコンがくっつくと進化するスイカゲーム風ロジック」や「配信連動ボム機能」 などを実装した完全版のプロジェクトファイルについては、販売中の本のほうをご覧ください。
Discussion