From 32628cd59611b227f590f1afcb4ec45f8a023109 Mon Sep 17 00:00:00 2001 From: jiepengtan Date: Fri, 18 Oct 2024 09:29:31 +0800 Subject: [PATCH] Support boundary checking --- core/extension/gdextension_spx_ext.cpp | 12 ++++ core/extension/gdextension_spx_ext.h | 3 + core/extension/spx_physic_mgr.cpp | 85 +++++++++++++++++++++++--- core/extension/spx_physic_mgr.h | 2 + core/extension/spx_sprite.cpp | 6 ++ core/extension/spx_sprite.h | 6 +- platform/web/godot_js_spx.cpp | 12 ++++ platform/web/js/engine/gdspx.js | 32 ++++++++++ 8 files changed, 150 insertions(+), 8 deletions(-) diff --git a/core/extension/gdextension_spx_ext.cpp b/core/extension/gdextension_spx_ext.cpp index af72084474a6..ae620406c8c6 100644 --- a/core/extension/gdextension_spx_ext.cpp +++ b/core/extension/gdextension_spx_ext.cpp @@ -146,6 +146,9 @@ static void gdextension_spx_physic_raycast(GdVec2 from,GdVec2 to,GdInt collision static void gdextension_spx_physic_check_collision(GdVec2 from,GdVec2 to,GdInt collision_mask,GdBool collide_with_areas,GdBool collide_with_bodies,GdBool* ret_val) { *ret_val = physicMgr->check_collision(from, to, collision_mask, collide_with_areas, collide_with_bodies); } +static void gdextension_spx_physic_check_touched_camera_boundary(GdObj obj,GdInt board_type,GdBool* ret_val) { + *ret_val = physicMgr->check_touched_camera_boundary(obj, board_type); +} static void gdextension_spx_platform_set_window_size(GdInt width,GdInt height) { platformMgr->set_window_size(width, height); } @@ -248,6 +251,12 @@ static void gdextension_spx_sprite_set_scale(GdObj obj,GdVec2 scale) { static void gdextension_spx_sprite_get_scale(GdObj obj,GdVec2* ret_val) { *ret_val = spriteMgr->get_scale(obj); } +static void gdextension_spx_sprite_set_render_scale(GdObj obj,GdVec2 scale) { + spriteMgr->set_render_scale(obj, scale); +} +static void gdextension_spx_sprite_get_render_scale(GdObj obj,GdVec2* ret_val) { + *ret_val = spriteMgr->get_render_scale(obj); +} static void gdextension_spx_sprite_set_color(GdObj obj,GdColor color) { spriteMgr->set_color(obj, color); } @@ -610,6 +619,7 @@ void gdextension_spx_setup_interface() { REGISTER_SPX_INTERFACE_FUNC(spx_input_is_action_just_released); REGISTER_SPX_INTERFACE_FUNC(spx_physic_raycast); REGISTER_SPX_INTERFACE_FUNC(spx_physic_check_collision); + REGISTER_SPX_INTERFACE_FUNC(spx_physic_check_touched_camera_boundary); REGISTER_SPX_INTERFACE_FUNC(spx_platform_set_window_size); REGISTER_SPX_INTERFACE_FUNC(spx_platform_get_window_size); REGISTER_SPX_INTERFACE_FUNC(spx_platform_set_window_title); @@ -644,6 +654,8 @@ void gdextension_spx_setup_interface() { REGISTER_SPX_INTERFACE_FUNC(spx_sprite_get_rotation); REGISTER_SPX_INTERFACE_FUNC(spx_sprite_set_scale); REGISTER_SPX_INTERFACE_FUNC(spx_sprite_get_scale); + REGISTER_SPX_INTERFACE_FUNC(spx_sprite_set_render_scale); + REGISTER_SPX_INTERFACE_FUNC(spx_sprite_get_render_scale); REGISTER_SPX_INTERFACE_FUNC(spx_sprite_set_color); REGISTER_SPX_INTERFACE_FUNC(spx_sprite_get_color); REGISTER_SPX_INTERFACE_FUNC(spx_sprite_set_texture_altas); diff --git a/core/extension/gdextension_spx_ext.h b/core/extension/gdextension_spx_ext.h index 458ee8451e87..054372fbf423 100644 --- a/core/extension/gdextension_spx_ext.h +++ b/core/extension/gdextension_spx_ext.h @@ -228,6 +228,7 @@ typedef void (*GDExtensionSpxInputIsActionJustReleased)(GdString action, GdBool* // SpxPhysic typedef void (*GDExtensionSpxPhysicRaycast)(GdVec2 from, GdVec2 to, GdInt collision_mask, GdObj* ret_value); typedef void (*GDExtensionSpxPhysicCheckCollision)(GdVec2 from, GdVec2 to, GdInt collision_mask, GdBool collide_with_areas, GdBool collide_with_bodies, GdBool* ret_value); +typedef void (*GDExtensionSpxPhysicCheckTouchedCameraBoundary)(GdObj obj,GdInt board_type, GdBool* ret_value); // SpxPlatform typedef void (*GDExtensionSpxPlatformSetWindowSize)(GdInt width, GdInt height); typedef void (*GDExtensionSpxPlatformGetWindowSize)(GdVec2* ret_value); @@ -266,6 +267,8 @@ typedef void (*GDExtensionSpxSpriteSetRotation)(GdObj obj, GdFloat rot); typedef void (*GDExtensionSpxSpriteGetRotation)(GdObj obj, GdFloat* ret_value); typedef void (*GDExtensionSpxSpriteSetScale)(GdObj obj, GdVec2 scale); typedef void (*GDExtensionSpxSpriteGetScale)(GdObj obj, GdVec2* ret_value); +typedef void (*GDExtensionSpxSpriteSetRenderScale)(GdObj obj, GdVec2 scale); +typedef void (*GDExtensionSpxSpriteGetRenderScale)(GdObj obj, GdVec2* ret_value); typedef void (*GDExtensionSpxSpriteSetColor)(GdObj obj, GdColor color); typedef void (*GDExtensionSpxSpriteGetColor)(GdObj obj, GdColor* ret_value); typedef void (*GDExtensionSpxSpriteSetTextureAltas)(GdObj obj, GdString path, GdRect2 rect2); diff --git a/core/extension/spx_physic_mgr.cpp b/core/extension/spx_physic_mgr.cpp index 730a3e22bdb5..59d33dc6f21b 100644 --- a/core/extension/spx_physic_mgr.cpp +++ b/core/extension/spx_physic_mgr.cpp @@ -30,11 +30,20 @@ #include "spx_physic_mgr.h" -#include "spx_sprite.h" -#include "scene/resources/circle_shape_2d.h" #include "scene/resources/world_2d.h" #include "servers/physics_server_2d.h" #include "servers/physics_server_3d.h" +#include "spx_sprite.h" +#include "spx_sprite_mgr.h" + +#include "scene/2d/camera_2d.h" +#include "scene/2d/collision_shape_2d.h" +#include "scene/main/window.h" +#include "scene/resources/rectangle_shape_2d.h" +#include "spx_engine.h" +#include "spx_sprite_mgr.h" + +#define spriteMgr SpxEngine::get_singleton()->get_sprite() GdObj SpxPhysicMgr::raycast(GdVec2 from, GdVec2 to, GdInt collision_mask) { auto node = (Node2D *)get_root(); @@ -43,15 +52,15 @@ GdObj SpxPhysicMgr::raycast(GdVec2 from, GdVec2 to, GdInt collision_mask) { PhysicsDirectSpaceState2D::RayResult result; PhysicsDirectSpaceState2D::RayParameters params; // flip y axis - from = GdVec2{ from.x, -from.y }; - to = GdVec2{ to.x, -to.y }; + from = GdVec2{ from.x, -from.y }; + to = GdVec2{ to.x, -to.y }; params.from = from; params.to = to; params.collision_mask = (uint32_t)collision_mask; bool hit = space_state->intersect_ray(params, result); if (hit) { SpxSprite *collider = dynamic_cast(result.collider); - if(collider != nullptr) { + if (collider != nullptr) { return collider->get_gid(); } } @@ -65,8 +74,8 @@ GdBool SpxPhysicMgr::check_collision(GdVec2 from, GdVec2 to, GdInt collision_mas PhysicsDirectSpaceState2D::RayParameters params; // flip y axis - from = GdVec2{ from.x, -from.y }; - to = GdVec2{ to.x, -to.y }; + from = GdVec2{ from.x, -from.y }; + to = GdVec2{ to.x, -to.y }; params.from = from; params.to = to; params.collision_mask = (uint32_t)collision_mask; @@ -75,3 +84,65 @@ GdBool SpxPhysicMgr::check_collision(GdVec2 from, GdVec2 to, GdInt collision_mas bool hit = space_state->intersect_ray(params, result); return hit; } +const GdInt BOUND_CAM_LEFT = 1 << 0; +const GdInt BOUND_CAM_TOP = 1 << 1; +const GdInt BOUND_CAM_RIGHT = 1 << 2; +const GdInt BOUND_CAM_BOTTOM = 1 << 3; +const GdInt BOUND_CAM_ALL = BOUND_CAM_LEFT | BOUND_CAM_TOP | BOUND_CAM_TOP | BOUND_CAM_BOTTOM; + +GdInt SpxPhysicMgr::check_touched_camera_boundaries(GdObj obj) { + auto sprite = spriteMgr->get_sprite(obj); + if (sprite == nullptr) { + print_error("try to get property of a null sprite gid=" + itos(obj)); + return false; + } + Transform2D sprite_transform = sprite->get_global_transform(); + + CollisionShape2D *collision_shape = sprite->get_trigger(); + if (!collision_shape) { + return false; + } + Ref sprite_shape = collision_shape->get_shape(); + if (sprite_shape.is_null()) { + return false; + } + + Camera2D *camera = get_tree()->get_root()->get_camera_2d(); + if (!camera) { + return false; + } + Transform2D camera_transform = camera->get_global_transform(); + + Vector2 viewport_size = camera->get_viewport_rect().size; + Vector2 zoom = camera->get_zoom(); + Vector2 half_size = (viewport_size * zoom) * 0.5; + Vector2 camera_position = camera_transform.get_origin(); + + Ref vertical_edge_shape; + vertical_edge_shape.instantiate(); + vertical_edge_shape->set_size(Vector2(1, half_size.y)); + + Ref horizontal_edge_shape; + horizontal_edge_shape.instantiate(); + horizontal_edge_shape->set_size(Vector2(half_size.x, 1)); + + Transform2D left_edge_transform(0, camera_position + Vector2(-half_size.x, 0)); + Transform2D right_edge_transform(0, camera_position + Vector2(half_size.x, 0)); + Transform2D top_edge_transform(0, camera_position + Vector2(0, -half_size.y)); + Transform2D bottom_edge_transform(0, camera_position + Vector2(0, half_size.y)); + + bool is_colliding_left = sprite_shape->collide(sprite_transform, vertical_edge_shape, left_edge_transform); + bool is_colliding_right = sprite_shape->collide(sprite_transform, vertical_edge_shape, right_edge_transform); + bool is_colliding_top = sprite_shape->collide(sprite_transform, horizontal_edge_shape, top_edge_transform); + bool is_colliding_bottom = sprite_shape->collide(sprite_transform, horizontal_edge_shape, bottom_edge_transform); + GdInt result = 0; + result += is_colliding_top ? 1 << BOUND_CAM_TOP : 0; + result += is_colliding_right ? 1 << BOUND_CAM_RIGHT : 0; + result += is_colliding_bottom ? 1 << BOUND_CAM_BOTTOM : 0; + result += is_colliding_left ? 1 << BOUND_CAM_LEFT : 0; + return is_colliding_left || is_colliding_right || is_colliding_top || is_colliding_bottom; +} +GdBool SpxPhysicMgr::check_touched_camera_boundary(GdObj obj, GdInt board_type) { + auto result = check_touched_camera_boundaries(obj); + return (result & board_type) != 0; +} diff --git a/core/extension/spx_physic_mgr.h b/core/extension/spx_physic_mgr.h index a14820c9dbbf..0adfd56c5f3c 100644 --- a/core/extension/spx_physic_mgr.h +++ b/core/extension/spx_physic_mgr.h @@ -40,6 +40,8 @@ class SpxPhysicMgr : SpxBaseMgr { public: GdObj raycast(GdVec2 from, GdVec2 to, GdInt collision_mask); GdBool check_collision(GdVec2 from, GdVec2 to, GdInt collision_mask, GdBool collide_with_areas, GdBool collide_with_bodies); + GdInt check_touched_camera_boundaries(GdObj obj) ; + GdBool check_touched_camera_boundary(GdObj obj,GdInt board_type); }; #endif // SPX_PHYSIC_MGR_H diff --git a/core/extension/spx_sprite.cpp b/core/extension/spx_sprite.cpp index 8f34f74b9af9..429e50978fee 100644 --- a/core/extension/spx_sprite.cpp +++ b/core/extension/spx_sprite.cpp @@ -481,3 +481,9 @@ GdBool SpxSprite::check_collision_with_point(GdVec2 point, GdBool is_trigger) { } return this_shape->get_shape()->_edit_is_selected_on_click(point, 0); } +void SpxSprite::set_render_scale(GdVec2 scale) { + anim2d->set_scale(scale); +} +GdVec2 SpxSprite::get_render_scale() { + return anim2d->get_scale(); +} diff --git a/core/extension/spx_sprite.h b/core/extension/spx_sprite.h index a7d3f8f33c27..7512188059b8 100644 --- a/core/extension/spx_sprite.h +++ b/core/extension/spx_sprite.h @@ -59,7 +59,8 @@ class SpxSprite : public CharacterBody2D { CollisionShape2D *trigger2d; CollisionShape2D *collider2d; VisibleOnScreenNotifier2D *visible_notifier; - +public: + CollisionShape2D * get_trigger(){ return trigger2d;} public: template T *get_component(GdBool recursive = false); @@ -155,6 +156,9 @@ class SpxSprite : public CharacterBody2D { CollisionShape2D* get_collider(bool is_trigger = false); GdBool check_collision(SpxSprite *other, GdBool is_src_trigger = true,GdBool is_dst_trigger = true); GdBool check_collision_with_point(GdVec2 point, GdBool is_trigger = true); + + void set_render_scale(GdVec2 scale); + GdVec2 get_render_scale(); }; template T *SpxSprite::get_component(Node *node, GdBool recursive) { diff --git a/platform/web/godot_js_spx.cpp b/platform/web/godot_js_spx.cpp index a02f930c7a1e..914f00b89737 100644 --- a/platform/web/godot_js_spx.cpp +++ b/platform/web/godot_js_spx.cpp @@ -175,6 +175,10 @@ void gdspx_physic_check_collision(GdVec2* from,GdVec2* to,GdInt* collision_mask, *ret_val = physicMgr->check_collision(*from, *to, *collision_mask, *collide_with_areas, *collide_with_bodies); } EMSCRIPTEN_KEEPALIVE +void gdspx_physic_check_touched_camera_boundary(GdObj* obj,GdInt* board_type,GdBool* ret_val) { + *ret_val = physicMgr->check_touched_camera_boundary(*obj, *board_type); +} +EMSCRIPTEN_KEEPALIVE void gdspx_platform_set_window_size(GdInt* width,GdInt* height) { platformMgr->set_window_size(*width, *height); } @@ -311,6 +315,14 @@ void gdspx_sprite_get_scale(GdObj* obj,GdVec2* ret_val) { *ret_val = spriteMgr->get_scale(*obj); } EMSCRIPTEN_KEEPALIVE +void gdspx_sprite_set_render_scale(GdObj* obj,GdVec2* scale) { + spriteMgr->set_render_scale(*obj, *scale); +} +EMSCRIPTEN_KEEPALIVE +void gdspx_sprite_get_render_scale(GdObj* obj,GdVec2* ret_val) { + *ret_val = spriteMgr->get_render_scale(*obj); +} +EMSCRIPTEN_KEEPALIVE void gdspx_sprite_set_color(GdObj* obj,GdColor* color) { spriteMgr->set_color(*obj, *color); } diff --git a/platform/web/js/engine/gdspx.js b/platform/web/js/engine/gdspx.js index 6d035505e008..e1c8a68a72fc 100644 --- a/platform/web/js/engine/gdspx.js +++ b/platform/web/js/engine/gdspx.js @@ -267,6 +267,18 @@ function gdspx_physic_check_collision(from,to,collision_mask,collide_with_areas, FreeGdBool(_retValue); return _finalRetValue } +function gdspx_physic_check_touched_camera_boundary(obj,board_type) { + _gdFuncPtr = GodotEngine.rtenv['_gdspx_physic_check_touched_camera_boundary']; + _retValue = AllocGdBool(); + _arg0 = ToGdObj(obj); + _arg1 = ToGdInt(board_type); + _gdFuncPtr(_arg0, _arg1, _retValue); + FreeGdObj(_arg0); + FreeGdInt(_arg1); + _finalRetValue = ToJsBool(_retValue); + FreeGdBool(_retValue); + return _finalRetValue +} function gdspx_platform_set_window_size(width,height) { _gdFuncPtr = GodotEngine.rtenv['_gdspx_platform_set_window_size']; @@ -605,6 +617,26 @@ function gdspx_sprite_get_scale(obj) { FreeGdVec2(_retValue); return _finalRetValue } +function gdspx_sprite_set_render_scale(obj,scale) { + _gdFuncPtr = GodotEngine.rtenv['_gdspx_sprite_set_render_scale']; + + _arg0 = ToGdObj(obj); + _arg1 = ToGdVec2(scale); + _gdFuncPtr(_arg0, _arg1); + FreeGdObj(_arg0); + FreeGdVec2(_arg1); + +} +function gdspx_sprite_get_render_scale(obj) { + _gdFuncPtr = GodotEngine.rtenv['_gdspx_sprite_get_render_scale']; + _retValue = AllocGdVec2(); + _arg0 = ToGdObj(obj); + _gdFuncPtr(_arg0, _retValue); + FreeGdObj(_arg0); + _finalRetValue = ToJsVec2(_retValue); + FreeGdVec2(_retValue); + return _finalRetValue +} function gdspx_sprite_set_color(obj,color) { _gdFuncPtr = GodotEngine.rtenv['_gdspx_sprite_set_color'];