Work in progress
The content of this page was not yet updated for Godot
4.3
and may be outdated. If you know how to improve this page or you can confirm
that it's up to date, feel free to open a pull request.
サーバーを使用した最適化
Godotのようなエンジンは、高レベルの構造と機能により、使いやすさが向上しています。それらのほとんどは、Scene System を介してアクセスおよび使用されます。ノードとリソースを使用すると、複雑なゲームのプロジェクト編成と資産管理が簡素化されます。
もちろん、常に欠点もあります:
複雑さがさらに増します。
単純な API を直接使用するよりもパフォーマンスが低下します。
複数のスレッドを使用してそれらを制御することはできません。
より多くのメモリが必要になります。
多くの場合、これは実際には問題ではありません(Godotは非常に最適化されており、ほとんどの操作はシグナルで処理されるため、ポーリングは不要です)。それでも、時にはそれが必要です。たとえば、フレームごとに処理する必要がある何かのインスタンスを数万件処理することがボトルネックになる可能性があります。
このような状況では、プログラマはゲームエンジンを使用していることを後悔し、より手作りの低レベルのゲームコード実装に戻ることを望みます。
それでも、Godotはこの問題を回避するように設計されています。
参考
Bullet Shower デモ プロジェクト <https://github.com/godotengine/godot-demo-projects/tree/master/2d/bullet_shower> を使用して、低レベル サーバーが実際にどのように機能するかを確認できます
サーバー
Godotの最も興味深い設計上の決定の1つは、シーンシステム全体が オプション であるという事実です。現時点ではこれをコンパイルすることはできませんが、完全にバイパスすることは可能です。
コアでは、Godotはサーバーの概念を使用します。サーバーはレンダリング、物理演算、サウンドなどを制御するための非常に低レベルのAPIです。シーンシステムはそれらの上に構築され、それらを直接使用します。最も一般的なサーバーは次のとおりです:
RenderingServer: グラフィックに関連するすべてを処理します。
PhysicsServer3D: 3D物理演算に関連するすべてを処理します。
PhysicsServer2D: 2D物理演算に関連するすべてを処理します。
AudioServer: オーディオに関連するすべてを処理します。
それらの APIを調べるだけで、提供されるすべての機能がGodotで実行可能なすべての低レベル実装であることに気付くでしょう。
RIDs
サーバーを使用する鍵は、リソースID(RID)オブジェクトを理解することです。これらは、サーバー実装への不透明なハンドルです。それらは手動で割り当てられ、解放されます。サーバーのほぼすべての機能には、実際のリソースにアクセスするためのRIDが必要です。
Most Godot nodes and resources contain these RIDs from the servers internally, and they can be obtained with different functions. In fact, anything that inherits Resource can be directly casted to an RID. Not all resources contain an RID, though: in such cases, the RID will be empty. The resource can then be passed to server APIs as an RID.
警告
Resources are reference-counted (see RefCounted), and references to a resource's RID are not counted when determining whether the resource is still in use. Make sure to keep a reference to the resource outside the server, or else both it and its RID will be erased.
ノードには、次の多くの機能が用意されています:
CanvasItemの場合、CanvasItem.get_canvas_item() メソッドは、サーバー内のキャンバスアイテムRIDを返します。
CanvasLayerの場合、CanvasLayer.get_canvas() メソッドはサーバーのキャンバスRIDを返します。
ビューポートの場合、Viewport.get_viewport_rid() メソッドはサーバーのビューポートRIDを返します。
For 3D, the World3D resource (obtainable in the Viewport and Node3D nodes) contains functions to get the RenderingServer Scenario, and the PhysicsServer Space. This allows creating 3D objects directly with the server API and using them.
For 2D, the World2D resource (obtainable in the Viewport and CanvasItem nodes) contains functions to get the RenderingServer Canvas, and the Physics2DServer Space. This allows creating 2D objects directly with the server API and using them.
The VisualInstance3D class, allows getting the scenario instance and instance base via the VisualInstance3D.get_instance() and VisualInstance3D.get_base() respectively.
Try exploring the nodes and resources you are familiar with and find the functions to obtain the server RIDs.
すでにノードが関連付けられているオブジェクトからRIDを制御することはお勧めしません。代わりに、サーバー関数を常に使用して、新しい関数を作成および制御し、既存の関数と対話する必要があります。
スプライトの作成
This is an example of how to create a sprite from code and move it using the low-level CanvasItem API.
extends Node2D
# RenderingServer expects references to be kept around.
var texture
func _ready():
# Create a canvas item, child of this node.
var ci_rid = RenderingServer.canvas_item_create()
# Make this node the parent.
RenderingServer.canvas_item_set_parent(ci_rid, get_canvas_item())
# Draw a texture on it.
# Remember, keep this reference.
texture = load("res://my_texture.png")
# Add it, centered.
RenderingServer.canvas_item_add_texture_rect(ci_rid, Rect2(-texture.get_size() / 2, texture.get_size()), texture)
# Add the item, rotated 45 degrees and translated.
var xform = Transform2D().rotated(deg_to_rad(45)).translated(Vector2(20, 30))
RenderingServer.canvas_item_set_transform(ci_rid, xform)
public partial class MyNode2D : Node2D
{
// RenderingServer expects references to be kept around.
private Texture2D _texture;
public override void _Ready()
{
// Create a canvas item, child of this node.
Rid ciRid = RenderingServer.CanvasItemCreate();
// Make this node the parent.
RenderingServer.CanvasItemSetParent(ciRid, GetCanvasItem());
// Draw a texture on it.
// Remember, keep this reference.
_texture = ResourceLoader.Load<Texture2D>("res://MyTexture.png");
// Add it, centered.
RenderingServer.CanvasItemAddTextureRect(ciRid, new Rect2(-_texture.GetSize() / 2, _texture.GetSize()), _texture.GetRid());
// Add the item, rotated 45 degrees and translated.
Transform2D xform = Transform2D.Identity.Rotated(Mathf.DegToRad(45)).Translated(new Vector2(20, 30));
RenderingServer.CanvasItemSetTransform(ciRid, xform);
}
}
サーバーのCanvas Item APIを使用すると、描画プリミティブを追加できます。追加した後は変更できません。アイテムをクリアし、プリミティブを再度追加する必要があります(これは、幾何学変換を設定する場合には当てはまりません。これは、必要な回数だけ実行できます)。
プリミティブは次の方法でクリアされます:
RenderingServer.canvas_item_clear(ci_rid)
RenderingServer.CanvasItemClear(ciRid);
メッシュを3D空間にインスタンス化する
The 3D APIs are different from the 2D ones, so the instantiation API must be used.
extends Node3D
# RenderingServer expects references to be kept around.
var mesh
func _ready():
# Create a visual instance (for 3D).
var instance = RenderingServer.instance_create()
# Set the scenario from the world, this ensures it
# appears with the same objects as the scene.
var scenario = get_world_3d().scenario
RenderingServer.instance_set_scenario(instance, scenario)
# Add a mesh to it.
# Remember, keep the reference.
mesh = load("res://mymesh.obj")
RenderingServer.instance_set_base(instance, mesh)
# Move the mesh around.
var xform = Transform3D(Basis(), Vector3(20, 100, 0))
RenderingServer.instance_set_transform(instance, xform)
public partial class MyNode3D : Node3D
{
// RenderingServer expects references to be kept around.
private Mesh _mesh;
public override void _Ready()
{
// Create a visual instance (for 3D).
Rid instance = RenderingServer.InstanceCreate();
// Set the scenario from the world, this ensures it
// appears with the same objects as the scene.
Rid scenario = GetWorld3D().Scenario;
RenderingServer.InstanceSetScenario(instance, scenario);
// Add a mesh to it.
// Remember, keep the reference.
_mesh = ResourceLoader.Load<Mesh>("res://MyMesh.obj");
RenderingServer.InstanceSetBase(instance, _mesh.GetRid());
// Move the mesh around.
Transform3D xform = new Transform3D(Basis.Identity, new Vector3(20, 100, 0));
RenderingServer.InstanceSetTransform(instance, xform);
}
}
2D RigidBodyの作成とスプライトの移動
This creates a RigidBody2D using the PhysicsServer2D API, and moves a CanvasItem when the body moves.
# Physics2DServer expects references to be kept around.
var body
var shape
func _body_moved(state, index):
# Created your own canvas item, use it here.
RenderingServer.canvas_item_set_transform(canvas_item, state.transform)
func _ready():
# Create the body.
body = Physics2DServer.body_create()
Physics2DServer.body_set_mode(body, Physics2DServer.BODY_MODE_RIGID)
# Add a shape.
shape = Physics2DServer.rectangle_shape_create()
# Set rectangle extents.
Physics2DServer.shape_set_data(shape, Vector2(10, 10))
# Make sure to keep the shape reference!
Physics2DServer.body_add_shape(body, shape)
# Set space, so it collides in the same space as current scene.
Physics2DServer.body_set_space(body, get_world_2d().space)
# Move initial position.
Physics2DServer.body_set_state(body, Physics2DServer.BODY_STATE_TRANSFORM, Transform2D(0, Vector2(10, 20)))
# Add the transform callback, when body moves
# The last parameter is optional, can be used as index
# if you have many bodies and a single callback.
Physics2DServer.body_set_force_integration_callback(body, self, "_body_moved", 0)
The 3D version should be very similar, as 2D and 3D physics servers are identical (using RigidBody3D and PhysicsServer3D respectively).
サーバーからデータを取得する
Try to never request any information from RenderingServer, PhysicsServer2D or PhysicsServer3D
by calling functions unless you know what you are doing. These servers will often run asynchronously
for performance and calling any function that returns a value will stall them and force them to process
anything pending until the function is actually called. This will severely decrease performance if you
call them every frame (and it won't be obvious why).
このため、このようなサーバーのほとんどのAPIは、保存可能な実際のデータができるまで、情報を要求することさえできないように設計されています。