Merge pull request #21245 from RandomShaper/fix-physics-canvas-xform

Take CanvasLayer transform into account for 2D physics
This commit is contained in:
Rémi Verschelde 2018-08-21 21:46:04 +02:00 committed by GitHub
commit ed10ff65fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 43 additions and 46 deletions

View File

@ -349,23 +349,12 @@ void CanvasItem::_update_callback() {
Transform2D CanvasItem::get_global_transform_with_canvas() const { Transform2D CanvasItem::get_global_transform_with_canvas() const {
const CanvasItem *ci = this; if (canvas_layer)
Transform2D xform; return canvas_layer->get_transform() * get_global_transform();
const CanvasItem *last_valid = NULL;
while (ci) {
last_valid = ci;
xform = ci->get_transform() * xform;
ci = ci->get_parent_item();
}
if (last_valid->canvas_layer)
return last_valid->canvas_layer->get_transform() * xform;
else if (is_inside_tree()) else if (is_inside_tree())
return get_viewport()->get_canvas_transform() * xform; return get_viewport()->get_canvas_transform() * get_global_transform();
else
return xform; return get_global_transform();
} }
Transform2D CanvasItem::get_global_transform() const { Transform2D CanvasItem::get_global_transform() const {

View File

@ -139,6 +139,8 @@ class CanvasItem : public Node {
GDCLASS(CanvasItem, Node); GDCLASS(CanvasItem, Node);
friend class CanvasLayer;
public: public:
enum BlendMode { enum BlendMode {

View File

@ -38,7 +38,7 @@ void CollisionObject2D::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: { case NOTIFICATION_ENTER_TREE: {
Transform2D global_transform = get_global_transform(); Transform2D global_transform = get_global_transform_with_canvas();
if (area) if (area)
Physics2DServer::get_singleton()->area_set_transform(rid, global_transform); Physics2DServer::get_singleton()->area_set_transform(rid, global_transform);
@ -64,7 +64,7 @@ void CollisionObject2D::_notification(int p_what) {
} break; } break;
case NOTIFICATION_TRANSFORM_CHANGED: { case NOTIFICATION_TRANSFORM_CHANGED: {
Transform2D global_transform = get_global_transform(); Transform2D global_transform = get_global_transform_with_canvas();
if (only_update_transform_changes && global_transform == last_transform) { if (only_update_transform_changes && global_transform == last_transform) {
return; return;

View File

@ -35,19 +35,6 @@
#include "engine.h" #include "engine.h"
#include "math_funcs.h" #include "math_funcs.h"
#include "scene/scene_string_names.h" #include "scene/scene_string_names.h"
void PhysicsBody2D::_notification(int p_what) {
/*
switch(p_what) {
case NOTIFICATION_TRANSFORM_CHANGED: {
Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_TRANSFORM,get_global_transform());
} break;
}
*/
}
void PhysicsBody2D::_set_layers(uint32_t p_mask) { void PhysicsBody2D::_set_layers(uint32_t p_mask) {
@ -436,7 +423,7 @@ bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia,
Physics2DServer::MotionResult *r = NULL; Physics2DServer::MotionResult *r = NULL;
if (p_result.is_valid()) if (p_result.is_valid())
r = p_result->get_result_ptr(); r = p_result->get_result_ptr();
return Physics2DServer::get_singleton()->body_test_motion(get_rid(), get_global_transform(), p_motion, p_infinite_inertia, p_margin, r); return Physics2DServer::get_singleton()->body_test_motion(get_rid(), get_global_transform_with_canvas(), p_motion, p_infinite_inertia, p_margin, r);
} }
void RigidBody2D::_direct_state_changed(Object *p_state) { void RigidBody2D::_direct_state_changed(Object *p_state) {
@ -449,7 +436,7 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
set_block_transform_notify(true); // don't want notify (would feedback loop) set_block_transform_notify(true); // don't want notify (would feedback loop)
if (mode != MODE_KINEMATIC) if (mode != MODE_KINEMATIC)
set_global_transform(state->get_transform()); set_global_transform(get_canvas_transform().affine_inverse() * state->get_transform());
linear_velocity = state->get_linear_velocity(); linear_velocity = state->get_linear_velocity();
angular_velocity = state->get_angular_velocity(); angular_velocity = state->get_angular_velocity();
if (sleeping != state->is_sleeping()) { if (sleeping != state->is_sleeping()) {
@ -1144,7 +1131,7 @@ bool KinematicBody2D::separate_raycast_shapes(bool p_infinite_inertia, Collision
Physics2DServer::SeparationResult sep_res[8]; //max 8 rays Physics2DServer::SeparationResult sep_res[8]; //max 8 rays
Transform2D gt = get_global_transform(); Transform2D gt = get_global_transform_with_canvas();
Vector2 recover; Vector2 recover;
int hits = Physics2DServer::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin); int hits = Physics2DServer::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin);
@ -1158,7 +1145,7 @@ bool KinematicBody2D::separate_raycast_shapes(bool p_infinite_inertia, Collision
} }
gt.elements[2] += recover; gt.elements[2] += recover;
set_global_transform(gt); set_global_transform(get_canvas_transform().affine_inverse() * gt);
if (deepest != -1) { if (deepest != -1) {
r_collision.collider = sep_res[deepest].collider_id; r_collision.collider = sep_res[deepest].collider_id;
@ -1179,7 +1166,7 @@ bool KinematicBody2D::separate_raycast_shapes(bool p_infinite_inertia, Collision
bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) { bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) {
Transform2D gt = get_global_transform(); Transform2D gt = get_global_transform_with_canvas();
Physics2DServer::MotionResult result; Physics2DServer::MotionResult result;
bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result, p_exclude_raycast_shapes); bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result, p_exclude_raycast_shapes);
@ -1198,7 +1185,7 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_
if (!p_test_only) { if (!p_test_only) {
gt.elements[2] += result.motion; gt.elements[2] += result.motion;
set_global_transform(gt); set_global_transform(get_canvas_transform().affine_inverse() * gt);
} }
return colliding; return colliding;
@ -1272,9 +1259,9 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
if (p_stop_on_slope) { if (p_stop_on_slope) {
if (Vector2() == lv_n + p_floor_direction) { if (Vector2() == lv_n + p_floor_direction) {
Transform2D gt = get_global_transform(); Transform2D gt = get_global_transform_with_canvas();
gt.elements[2] -= collision.travel; gt.elements[2] -= collision.travel;
set_global_transform(gt); set_global_transform(get_canvas_transform().affine_inverse() * gt);
return Vector2(); return Vector2();
} }
} }
@ -1323,7 +1310,7 @@ Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_veloci
} }
Collision col; Collision col;
Transform2D gt = get_global_transform(); Transform2D gt = get_global_transform_with_canvas();
if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) { if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) {
gt.elements[2] += col.travel; gt.elements[2] += col.travel;
@ -1332,7 +1319,7 @@ Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_veloci
on_floor_body = col.collider_rid; on_floor_body = col.collider_rid;
floor_velocity = col.collider_vel; floor_velocity = col.collider_vel;
} }
set_global_transform(gt); set_global_transform(get_canvas_transform().affine_inverse() * gt);
} }
return ret; return ret;
@ -1429,22 +1416,22 @@ void KinematicBody2D::_direct_state_changed(Object *p_state) {
last_valid_transform = state->get_transform(); last_valid_transform = state->get_transform();
set_notify_local_transform(false); set_notify_local_transform(false);
set_global_transform(last_valid_transform); set_global_transform(get_canvas_transform().affine_inverse() * last_valid_transform);
set_notify_local_transform(true); set_notify_local_transform(true);
} }
void KinematicBody2D::_notification(int p_what) { void KinematicBody2D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) { if (p_what == NOTIFICATION_ENTER_TREE) {
last_valid_transform = get_global_transform(); last_valid_transform = get_global_transform_with_canvas();
} }
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
//used by sync to physics, send the new transform to the physics //used by sync to physics, send the new transform to the physics
Transform2D new_transform = get_global_transform(); Transform2D new_transform = get_global_transform_with_canvas();
Physics2DServer::get_singleton()->body_set_state(get_rid(), Physics2DServer::BODY_STATE_TRANSFORM, new_transform); Physics2DServer::get_singleton()->body_set_state(get_rid(), Physics2DServer::BODY_STATE_TRANSFORM, new_transform);
//but then revert changes //but then revert changes
set_notify_local_transform(false); set_notify_local_transform(false);
set_global_transform(last_valid_transform); set_global_transform(get_canvas_transform().affine_inverse() * last_valid_transform);
set_notify_local_transform(true); set_notify_local_transform(true);
} }
} }

View File

@ -49,7 +49,6 @@ class PhysicsBody2D : public CollisionObject2D {
uint32_t _get_layers() const; uint32_t _get_layers() const;
protected: protected:
void _notification(int p_what);
PhysicsBody2D(Physics2DServer::BodyMode p_mode); PhysicsBody2D(Physics2DServer::BodyMode p_mode);
static void _bind_methods(); static void _bind_methods();

View File

@ -29,6 +29,7 @@
/*************************************************************************/ /*************************************************************************/
#include "canvas_layer.h" #include "canvas_layer.h"
#include "scene/2d/canvas_item.h"
#include "viewport.h" #include "viewport.h"
void CanvasLayer::set_layer(int p_xform) { void CanvasLayer::set_layer(int p_xform) {
@ -62,6 +63,24 @@ void CanvasLayer::_update_xform() {
transform.set_origin(ofs); transform.set_origin(ofs);
if (viewport.is_valid()) if (viewport.is_valid())
VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform); VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
if (!is_inside_tree())
return;
_notify_xform(this);
}
void CanvasLayer::_notify_xform(Node *p_node) {
for (int i = 0; i < p_node->get_child_count(); i++) {
CanvasItem *ci = Object::cast_to<CanvasItem>(p_node->get_child(i));
if (ci) {
ci->_notify_transform(ci);
} else {
_notify_xform(p_node->get_child(i));
}
}
} }
void CanvasLayer::_update_locrotscale() { void CanvasLayer::_update_locrotscale() {

View File

@ -56,6 +56,7 @@ class CanvasLayer : public Node {
int sort_index; int sort_index;
void _update_xform(); void _update_xform();
void _notify_xform(Node *p_node);
void _update_locrotscale(); void _update_locrotscale();
protected: protected: