Upgrade to Pro — share decks privately, control downloads, hide ads and more …

こわくない!! たのしい!! GDExtension

ueshita
October 25, 2023

こわくない!! たのしい!! GDExtension

第1回 Godot勉強会のLTスライドです。

ueshita

October 25, 2023
Tweet

More Decks by ueshita

Other Decks in Programming

Transcript

  1. ターゲット固有機能の使用 • ターゲット固有機能 – OSサービスの使用 (ex.課金APIなど) – 特殊なデバイスの使用 (ex.USB機器など) •

    もしかしたら、既に存在しているかも? – エンジンの機能? → 公式ドキュメントで探す – OSSで存在? → AssetLibraryやGitHubで探す
  2. GDExtensionで使用できる言語 • 公式のサポート – C++: https://github.com/godotengine/godot-cpp • コミュニティベースのサポート (下記は一例) –

    Rust: https://github.com/godot-rust/gdext – Go: https://github.com/godot-go/godot-go – D: https://github.com/godot-d/godot-d
  3. ターゲットごとにビルドが必要 • Windows → dll • macOS → dylib •

    Linux → so • iOS → dylib • Android → so • Web → wasm GDExtensionはつらい!? 用途を絞って使いましょう
  4. 基本のスクリプト • 画面端でバウンドするだけ func _process(delta: float) -> void: position +=

    velocity * delta if position.x < 0.0: velocity.x = -velocity.x elif position.x > 1280.0: velocity.x = -velocity.x if position.y < 0.0: velocity.y = -velocity.y elif position.y > 720.0: velocity.y = -velocity.y
  5. _processをC++化してみた GDScript C++ func _process(delta: float) -> void: position +=

    velocity * delta if position.x < 0.0: velocity.x = -velocity.x elif position.x > 1280.0: velocity.x = -velocity.x if position.y < 0.0: velocity.y = -velocity.y elif position.y > 720.0: velocity.y = -velocity.y void SpriteCpp::_process(float delta) { Vector2 position = get_position(); position += velocity * delta; set_position(position); if (position.x < 0.0) { velocity.x = -velocity.x; } else if (position.x > 1280.0) { velocity.x = -velocity.x; } if (position.y < 0.0) { velocity.y = -velocity.y; } else if (position.y > 720.0) { velocity.y = -velocity.y; } }
  6. パフォーマンス比較 スプライト数 GDScript C++ 10000 63 fps 124 fps 20000

    33 fps 62 fps 30000 21 fps 44 fps • FPS計測結果 (高いほど速い) ※ instanciate(ノード生成)負荷は除外 (実際はFPSは半分くらいになる)
  7. RenderingServerで2Dスプライトを表示 extends Node2D var texture: Texture var rid: RID func

    _ready(): # CanvasItem(2Dの描画インスタンス)を作成 (RIDが返ってくる。free_ridで解放する必要あり) rid = RenderingServer.canvas_item_create() # 親インスタンスを設定 (自分は2Dノードである必要がある ) RenderingServer.canvas_item_set_parent(rid, get_canvas_item()) # テクスチャをロード(参照は維持しておく必要がある) texture = load("res://my_texture.png") # テクスチャ描画を追加 (原点に中心が来るようにする ) var rect = Rect2(texture.get_size() / -2, textexture.get_size()) RenderingServer.canvas_item_add_texture_rect(sprite.rid, rect, texture.get_rid()) # 45度回転させて(200,300)に移動するトランスフォームをセットする var xform = Transform2D().rotated(deg_to_rad(45)).translated(Vector2(200, 300)) RenderingServer.canvas_item_set_transform(rid, xform)
  8. サーバーAPIを活用してみた GDScript C++ func _process(delta: float) -> void: if spawn:

    # Spawn phase for i in range(10): var sprite = ServerSpriteGD.new() sprite.rid = RenderingServer.canvas_item_create() RenderingServer.canvas_item_set_parent(sprite.rid, get_canvas_item()) RenderingServer.canvas_item_set_draw_index(sprite.rid, len(sprites)) var rect = Rect2(0, 0, texture.get_width(), texture.get_height()) RenderingServer.canvas_item_add_texture_rect(sprite.rid, rect, texture.get_rid()) var speed = 200 var direction = angle + i * (deg_to_rad(360)) / 10 sprite.position = Vector2(640, 360) sprite.velocity = Vector2(cos(direction), sin(direction)) * speed sprites.append(sprite) angle += deg_to_rad(2) # Update phase for sprite in sprites: sprite.position += sprite.velocity * delta if sprite.position.x < 0.0: sprite.velocity.x = -sprite.velocity.x elif sprite.position.x > 1280.0: sprite.velocity.x = -sprite.velocity.x if sprite.position.y < 0.0: sprite.velocity.y = -sprite.velocity.y elif sprite.position.y > 720.0: sprite.velocity.y = -sprite.velocity.y var sprite_transform = Transform2D(0.0, Vector2(0.25, 0.25), 0.0, sprite.position) RenderingServer.canvas_item_set_transform(sprite.rid, sprite_transform) void SpriteServerCpp::_process(float delta) { auto rs = RenderingServer::get_singleton(); if (spawn) { // Spawn phase for (int i = 0; i < 10; i++) { auto sprite = ServerSpriteCpp(); sprite.rid = rs->canvas_item_create(); rs->canvas_item_set_parent(sprite.rid, get_canvas_item()); rs->canvas_item_set_draw_index(sprite.rid, (int)sprites.size()); Rect2 rect = Rect2(0, 0, texture->get_width(), texture->get_height()); rs->canvas_item_add_texture_rect(sprite.rid, rect, texture->get_rid()); float speed = 200.0f; float direction = angle + i * (UtilityFunctions::deg_to_rad(360.0f)) / 10.0f; sprite.position = Vector2(640, 360); sprite.velocity = Vector2(cos(direction), sin(direction)) * speed; sprites.emplace_back(sprite); } angle += UtilityFunctions::deg_to_rad(2); } // Update phase for (auto& sprite : sprites) { sprite.position += sprite.velocity * delta; if (sprite.position.x < 0.0) { sprite.velocity.x = -sprite.velocity.x; } else if (sprite.position.x > 1280.0) { sprite.velocity.x = -sprite.velocity.x; } if (sprite.position.y < 0.0) { sprite.velocity.y = -sprite.velocity.y; } else if (sprite.position.y > 720.0) { sprite.velocity.y = -sprite.velocity.y; } Transform2D sprite_transform = Transform2D(0.0, Vector2(0.25, 0.25), 0.0, sprite.position); rs->canvas_item_set_transform(sprite.rid, sprite_transform); } }
  9. まとめ • GDExtension – エンジンに足りない機能を追加できる – 言語はRust,Go,Dなど色々選択できる • パフォーマンス改善について –

    重い処理をC++で実装して高速化できる – 更にパフォーマンスを上げたい時はサーバーAPIを使う
  10. 参考リンク • Godot公式リンク – GDExtensionの解説とチュートリアル – サーバーを使用した最適化 • 自分関係のリポジトリ –

    今回のデモ: パフォーマンス改善のコード一式 – EffekseerForGodot4: エフェクトエンジンのGodotプラグイン – ADXLE-GodotPlugin: サウンドミドルウェアのGodotプラグイン