VisualServer 使用 Physics2DServer 主体进行变换和塑形
VisualServer transform & shape with Physics2DServer body
我正在尝试仅使用 Physics2DServer
和 VisualServer
创建像 Item 这样的刚体
像这样:
extends Node2D
var _body:RID
var canvasItem:RID
func _enter_tree():
_body=Physics2DServer.body_create();
Physics2DServer.body_set_space(_body, get_world_2d().space);
var shape= RectangleShape2D.new();
shape.extents=Vector2(30,30);
var ci_rid = VisualServer.canvas_item_create() # ci= Canvas Item
VisualServer.canvas_item_set_parent(ci_rid, get_canvas_item())
Physics2DServer.body_add_shape(_body, shape.get_rid(), self.global_transform, false);
Physics2DServer.body_set_force_integration_callback(_body, self, "_body_moved",ci_rid);
var image=Image.new();
image.load("res://icon.png")
var texture_rid := VisualServer.texture_create_from_image(image)
VisualServer.texture_set_flags (texture_rid,VisualServer.TEXTURE_FLAG_ANISOTROPIC_FILTER)
VisualServer.canvas_item_set_parent(ci_rid, get_canvas_item())
VisualServer.canvas_item_add_texture_rect(ci_rid, Rect2(image.get_size() * -0.5, image.get_size()), texture_rid);
VisualServer.canvas_item_set_transform(ci_rid, self.transform)
func _body_moved(state:Physics2DDirectBodyState,ci_rid):
VisualServer.canvas_item_set_transform(ci_rid,state.transform)
但由于某些原因,碰撞不起作用
编辑:
我认为主要问题是 var shape= RectangleShape2D.new();
因为当我添加一个 export(Shape2D) var shape;
并手动添加一个 RectangleShape2D
时,碰撞工作正常
编辑基于变换的问题:
extends Node2D
var _body:RID
var _shape:RID
var canvasItem:RID
func _enter_tree():
_body=Physics2DServer.body_create();
Physics2DServer.body_set_space(_body, get_world_2d().space);
var ci_rid = VisualServer.canvas_item_create() # ci= Canvas Item
VisualServer.canvas_item_set_parent(ci_rid, get_canvas_item())
_shape = Physics2DServer.rectangle_shape_create()
Physics2DServer.shape_set_data(_shape, Vector2(30,30))
Physics2DServer.body_add_shape(_body,_shape);
Physics2DServer.body_set_force_integration_callback(_body, self, "_body_moved",ci_rid);
var texture:Texture = load("res://icon.png")
var image:Image = texture.get_data()
var texture_rid := VisualServer.texture_create_from_image(image)
VisualServer.texture_set_flags(texture_rid,VisualServer.TEXTURE_FLAG_ANISOTROPIC_FILTER)
VisualServer.canvas_item_set_parent(ci_rid, get_canvas_item())
VisualServer.canvas_item_add_texture_rect(ci_rid, Rect2(image.get_size() * -0.5, image.get_size()), texture_rid);
VisualServer.canvas_item_set_transform(ci_rid, Transform2D.IDENTITY)
set_notify_transform(true)
func _exit_tree():
if(_body.get_id()!=0):
Physics2DServer.free_rid(_body)
if(_shape.get_id()!=0):
Physics2DServer.free_rid(_shape)
func _body_moved(state:Physics2DDirectBodyState,ci_rid):
VisualServer.canvas_item_set_transform(ci_rid,state.transform)
func _notification(what: int) -> void:
if what == NOTIFICATION_TRANSFORM_CHANGED:
if _body.get_id() != 0:
Physics2DServer.body_set_state(_body, Physics2DServer.BODY_STATE_TRANSFORM, transform)
缺少形状
形状的问题在于它正在释放。
如果您使用脚本顶部的形状声明一个字段,然后对其进行初始化 _enter_tree
,它会正常工作。但是在 _enter_tree
内部声明它会一直存在到方法结束时超出范围。
教训是 RID
不是引用。
另一种方法是使用 Physics2DServer
:
创建形状和纹理
var shape_rid := Physics2DServer.rectangle_shape_create()
Physics2DServer.shape_set_data(shape_rid, Vector2(30,30))
并且由于这是使用 Physics2DServer
创建的 RID
,您可以通过调用 Physics2DServer
的 free_rid
方法来释放它。
顺便说一句,我收到了有关纹理的警告。您可以将其加载为 Texture
而不是:
var texture:Texture = load("res://icon.png")
var image:Image = texture.get_data()
哪个警告会消失。
然后我们很想这样做:
var texture_rid := texture.get_rid()
但是我们得到了错误……问题是一样的,纹理在方法结束时被释放,因为变量是唯一的引用并且它超出了范围。在文件顶部声明纹理可修复垃圾邮件错误。
而且,是的,我们可以使用 VisualServer
创建纹理。但是因为你是从资源中加载它,所以不实用。
转换
首先,canvas项相对于代码所在的节点定位运行:
VisualServer.canvas_item_set_parent(ci_rid, get_canvas_item())
VisualServer.canvas_item_set_transform(ci_rid, Transform2D.IDENTITY)
其次,body放在全局坐标中。所以我们应该这样做:
Physics2DServer.body_set_state(_body, Physics2DServer.BODY_STATE_TRANSFORM, global_transform)
注意 global_transform
而不是 transform
。
这让我们想到了这一点:
state.transform
为全局坐标。
canvas_item_set_transform
想要相对于 parent(代码为 运行 的节点)的坐标。
这是一种处理方式:
VisualServer.canvas_item_set_transform(ci_rid, global_transform.inverse() * state.transform)
或者,您可以移动节点以跟随 body:
func _body_moved(state:Physics2DDirectBodyState, _user_data) -> void:
global_transform = state.transform
这也会移动 canvas 项,因为请记住它是 parented(canvas_item_set_parent
)。
由于您在节点移动时移动 body(在 _notification
中),我相信移动节点以跟随 body 是正确的解决方案。这样,他们就一直保持同步。
关于形状:它是相对于body放置的。形状和 body 都可以移动。物理引擎将移动 body(并且形状跟随,因为它是相对于 body 定位的),但物理引擎不会直接移动形状。但是,您可以根据需要直接移动形状。这与 RigidBody2D
及其 CollisionShape2D
的关系相同。
我正在尝试仅使用 Physics2DServer
和 VisualServer
创建像 Item 这样的刚体
像这样:
extends Node2D
var _body:RID
var canvasItem:RID
func _enter_tree():
_body=Physics2DServer.body_create();
Physics2DServer.body_set_space(_body, get_world_2d().space);
var shape= RectangleShape2D.new();
shape.extents=Vector2(30,30);
var ci_rid = VisualServer.canvas_item_create() # ci= Canvas Item
VisualServer.canvas_item_set_parent(ci_rid, get_canvas_item())
Physics2DServer.body_add_shape(_body, shape.get_rid(), self.global_transform, false);
Physics2DServer.body_set_force_integration_callback(_body, self, "_body_moved",ci_rid);
var image=Image.new();
image.load("res://icon.png")
var texture_rid := VisualServer.texture_create_from_image(image)
VisualServer.texture_set_flags (texture_rid,VisualServer.TEXTURE_FLAG_ANISOTROPIC_FILTER)
VisualServer.canvas_item_set_parent(ci_rid, get_canvas_item())
VisualServer.canvas_item_add_texture_rect(ci_rid, Rect2(image.get_size() * -0.5, image.get_size()), texture_rid);
VisualServer.canvas_item_set_transform(ci_rid, self.transform)
func _body_moved(state:Physics2DDirectBodyState,ci_rid):
VisualServer.canvas_item_set_transform(ci_rid,state.transform)
但由于某些原因,碰撞不起作用
编辑:
我认为主要问题是 var shape= RectangleShape2D.new();
因为当我添加一个 export(Shape2D) var shape;
并手动添加一个 RectangleShape2D
时,碰撞工作正常
编辑基于变换的问题:
extends Node2D
var _body:RID
var _shape:RID
var canvasItem:RID
func _enter_tree():
_body=Physics2DServer.body_create();
Physics2DServer.body_set_space(_body, get_world_2d().space);
var ci_rid = VisualServer.canvas_item_create() # ci= Canvas Item
VisualServer.canvas_item_set_parent(ci_rid, get_canvas_item())
_shape = Physics2DServer.rectangle_shape_create()
Physics2DServer.shape_set_data(_shape, Vector2(30,30))
Physics2DServer.body_add_shape(_body,_shape);
Physics2DServer.body_set_force_integration_callback(_body, self, "_body_moved",ci_rid);
var texture:Texture = load("res://icon.png")
var image:Image = texture.get_data()
var texture_rid := VisualServer.texture_create_from_image(image)
VisualServer.texture_set_flags(texture_rid,VisualServer.TEXTURE_FLAG_ANISOTROPIC_FILTER)
VisualServer.canvas_item_set_parent(ci_rid, get_canvas_item())
VisualServer.canvas_item_add_texture_rect(ci_rid, Rect2(image.get_size() * -0.5, image.get_size()), texture_rid);
VisualServer.canvas_item_set_transform(ci_rid, Transform2D.IDENTITY)
set_notify_transform(true)
func _exit_tree():
if(_body.get_id()!=0):
Physics2DServer.free_rid(_body)
if(_shape.get_id()!=0):
Physics2DServer.free_rid(_shape)
func _body_moved(state:Physics2DDirectBodyState,ci_rid):
VisualServer.canvas_item_set_transform(ci_rid,state.transform)
func _notification(what: int) -> void:
if what == NOTIFICATION_TRANSFORM_CHANGED:
if _body.get_id() != 0:
Physics2DServer.body_set_state(_body, Physics2DServer.BODY_STATE_TRANSFORM, transform)
缺少形状
形状的问题在于它正在释放。
如果您使用脚本顶部的形状声明一个字段,然后对其进行初始化 _enter_tree
,它会正常工作。但是在 _enter_tree
内部声明它会一直存在到方法结束时超出范围。
教训是 RID
不是引用。
另一种方法是使用 Physics2DServer
:
var shape_rid := Physics2DServer.rectangle_shape_create()
Physics2DServer.shape_set_data(shape_rid, Vector2(30,30))
并且由于这是使用 Physics2DServer
创建的 RID
,您可以通过调用 Physics2DServer
的 free_rid
方法来释放它。
顺便说一句,我收到了有关纹理的警告。您可以将其加载为 Texture
而不是:
var texture:Texture = load("res://icon.png")
var image:Image = texture.get_data()
哪个警告会消失。
然后我们很想这样做:
var texture_rid := texture.get_rid()
但是我们得到了错误……问题是一样的,纹理在方法结束时被释放,因为变量是唯一的引用并且它超出了范围。在文件顶部声明纹理可修复垃圾邮件错误。
而且,是的,我们可以使用 VisualServer
创建纹理。但是因为你是从资源中加载它,所以不实用。
转换
首先,canvas项相对于代码所在的节点定位运行:
VisualServer.canvas_item_set_parent(ci_rid, get_canvas_item())
VisualServer.canvas_item_set_transform(ci_rid, Transform2D.IDENTITY)
其次,body放在全局坐标中。所以我们应该这样做:
Physics2DServer.body_set_state(_body, Physics2DServer.BODY_STATE_TRANSFORM, global_transform)
注意 global_transform
而不是 transform
。
这让我们想到了这一点:
state.transform
为全局坐标。canvas_item_set_transform
想要相对于 parent(代码为 运行 的节点)的坐标。
这是一种处理方式:
VisualServer.canvas_item_set_transform(ci_rid, global_transform.inverse() * state.transform)
或者,您可以移动节点以跟随 body:
func _body_moved(state:Physics2DDirectBodyState, _user_data) -> void:
global_transform = state.transform
这也会移动 canvas 项,因为请记住它是 parented(canvas_item_set_parent
)。
由于您在节点移动时移动 body(在 _notification
中),我相信移动节点以跟随 body 是正确的解决方案。这样,他们就一直保持同步。
关于形状:它是相对于body放置的。形状和 body 都可以移动。物理引擎将移动 body(并且形状跟随,因为它是相对于 body 定位的),但物理引擎不会直接移动形状。但是,您可以根据需要直接移动形状。这与 RigidBody2D
及其 CollisionShape2D
的关系相同。