Path: blob/master/modules/godot_physics_2d/godot_area_2d.cpp
10278 views
/**************************************************************************/1/* godot_area_2d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "godot_area_2d.h"31#include "godot_body_2d.h"32#include "godot_space_2d.h"3334GodotArea2D::BodyKey::BodyKey(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {35rid = p_body->get_self();36instance_id = p_body->get_instance_id();37body_shape = p_body_shape;38area_shape = p_area_shape;39}4041GodotArea2D::BodyKey::BodyKey(GodotArea2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {42rid = p_body->get_self();43instance_id = p_body->get_instance_id();44body_shape = p_body_shape;45area_shape = p_area_shape;46}4748void GodotArea2D::_shapes_changed() {49if (!moved_list.in_list() && get_space()) {50get_space()->area_add_to_moved_list(&moved_list);51}52}5354void GodotArea2D::set_transform(const Transform2D &p_transform) {55if (!moved_list.in_list() && get_space()) {56get_space()->area_add_to_moved_list(&moved_list);57}5859_set_transform(p_transform);60_set_inv_transform(p_transform.affine_inverse());61}6263void GodotArea2D::set_space(GodotSpace2D *p_space) {64if (get_space()) {65if (monitor_query_list.in_list()) {66get_space()->area_remove_from_monitor_query_list(&monitor_query_list);67}68if (moved_list.in_list()) {69get_space()->area_remove_from_moved_list(&moved_list);70}71}7273monitored_bodies.clear();74monitored_areas.clear();7576_set_space(p_space);77}7879void GodotArea2D::set_monitor_callback(const Callable &p_callback) {80_unregister_shapes();8182monitor_callback = p_callback;8384monitored_bodies.clear();85monitored_areas.clear();8687_shape_changed();8889if (!moved_list.in_list() && get_space()) {90get_space()->area_add_to_moved_list(&moved_list);91}92}9394void GodotArea2D::set_area_monitor_callback(const Callable &p_callback) {95_unregister_shapes();9697area_monitor_callback = p_callback;9899monitored_bodies.clear();100monitored_areas.clear();101102_shape_changed();103104if (!moved_list.in_list() && get_space()) {105get_space()->area_add_to_moved_list(&moved_list);106}107}108109void GodotArea2D::_set_space_override_mode(PhysicsServer2D::AreaSpaceOverrideMode &r_mode, PhysicsServer2D::AreaSpaceOverrideMode p_new_mode) {110bool do_override = p_new_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED;111if (do_override == (r_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED)) {112return;113}114_unregister_shapes();115r_mode = p_new_mode;116_shape_changed();117}118119void GodotArea2D::set_param(PhysicsServer2D::AreaParameter p_param, const Variant &p_value) {120switch (p_param) {121case PhysicsServer2D::AREA_PARAM_GRAVITY_OVERRIDE_MODE:122_set_space_override_mode(gravity_override_mode, (PhysicsServer2D::AreaSpaceOverrideMode)(int)p_value);123break;124case PhysicsServer2D::AREA_PARAM_GRAVITY:125gravity = p_value;126break;127case PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR:128gravity_vector = p_value;129break;130case PhysicsServer2D::AREA_PARAM_GRAVITY_IS_POINT:131gravity_is_point = p_value;132break;133case PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE:134gravity_point_unit_distance = p_value;135break;136case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE:137_set_space_override_mode(linear_damping_override_mode, (PhysicsServer2D::AreaSpaceOverrideMode)(int)p_value);138break;139case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP:140linear_damp = p_value;141break;142case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE:143_set_space_override_mode(angular_damping_override_mode, (PhysicsServer2D::AreaSpaceOverrideMode)(int)p_value);144break;145case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP:146angular_damp = p_value;147break;148case PhysicsServer2D::AREA_PARAM_PRIORITY:149priority = p_value;150break;151}152}153154Variant GodotArea2D::get_param(PhysicsServer2D::AreaParameter p_param) const {155switch (p_param) {156case PhysicsServer2D::AREA_PARAM_GRAVITY_OVERRIDE_MODE:157return gravity_override_mode;158case PhysicsServer2D::AREA_PARAM_GRAVITY:159return gravity;160case PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR:161return gravity_vector;162case PhysicsServer2D::AREA_PARAM_GRAVITY_IS_POINT:163return gravity_is_point;164case PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE:165return gravity_point_unit_distance;166case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE:167return linear_damping_override_mode;168case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP:169return linear_damp;170case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE:171return angular_damping_override_mode;172case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP:173return angular_damp;174case PhysicsServer2D::AREA_PARAM_PRIORITY:175return priority;176}177178return Variant();179}180181void GodotArea2D::_queue_monitor_update() {182ERR_FAIL_NULL(get_space());183184if (!monitor_query_list.in_list()) {185get_space()->area_add_to_monitor_query_list(&monitor_query_list);186}187}188189void GodotArea2D::set_monitorable(bool p_monitorable) {190if (monitorable == p_monitorable) {191return;192}193194monitorable = p_monitorable;195_set_static(!monitorable);196_shapes_changed();197}198199void GodotArea2D::call_queries() {200if (!monitor_callback.is_null() && !monitored_bodies.is_empty()) {201if (monitor_callback.is_valid()) {202Variant res[5];203Variant *resptr[5];204for (int i = 0; i < 5; i++) {205resptr[i] = &res[i];206}207208for (HashMap<BodyKey, BodyState, BodyKey>::Iterator E = monitored_bodies.begin(); E;) {209if (E->value.state == 0) { // Nothing happened210HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;211++next;212monitored_bodies.remove(E);213E = next;214continue;215}216217res[0] = E->value.state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED;218res[1] = E->key.rid;219res[2] = E->key.instance_id;220res[3] = E->key.body_shape;221res[4] = E->key.area_shape;222223HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;224++next;225monitored_bodies.remove(E);226E = next;227228Callable::CallError ce;229Variant ret;230monitor_callback.callp((const Variant **)resptr, 5, ret, ce);231232if (ce.error != Callable::CallError::CALL_OK) {233ERR_PRINT_ONCE("Error calling event callback method " + Variant::get_callable_error_text(monitor_callback, (const Variant **)resptr, 5, ce));234}235}236} else {237monitored_bodies.clear();238monitor_callback = Callable();239}240}241242if (!area_monitor_callback.is_null() && !monitored_areas.is_empty()) {243if (area_monitor_callback.is_valid()) {244Variant res[5];245Variant *resptr[5];246for (int i = 0; i < 5; i++) {247resptr[i] = &res[i];248}249250for (HashMap<BodyKey, BodyState, BodyKey>::Iterator E = monitored_areas.begin(); E;) {251if (E->value.state == 0) { // Nothing happened252HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;253++next;254monitored_areas.remove(E);255E = next;256continue;257}258259res[0] = E->value.state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED;260res[1] = E->key.rid;261res[2] = E->key.instance_id;262res[3] = E->key.body_shape;263res[4] = E->key.area_shape;264265HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;266++next;267monitored_areas.remove(E);268E = next;269270Callable::CallError ce;271Variant ret;272area_monitor_callback.callp((const Variant **)resptr, 5, ret, ce);273274if (ce.error != Callable::CallError::CALL_OK) {275ERR_PRINT_ONCE("Error calling event callback method " + Variant::get_callable_error_text(area_monitor_callback, (const Variant **)resptr, 5, ce));276}277}278} else {279monitored_areas.clear();280area_monitor_callback = Callable();281}282}283}284285void GodotArea2D::compute_gravity(const Vector2 &p_position, Vector2 &r_gravity) const {286if (is_gravity_point()) {287const real_t gr_unit_dist = get_gravity_point_unit_distance();288Vector2 v = get_transform().xform(get_gravity_vector()) - p_position;289if (gr_unit_dist > 0) {290const real_t v_length_sq = v.length_squared();291if (v_length_sq > 0) {292const real_t gravity_strength = get_gravity() * gr_unit_dist * gr_unit_dist / v_length_sq;293r_gravity = v.normalized() * gravity_strength;294} else {295r_gravity = Vector2();296}297} else {298r_gravity = v.normalized() * get_gravity();299}300} else {301r_gravity = get_gravity_vector() * get_gravity();302}303}304305GodotArea2D::GodotArea2D() :306GodotCollisionObject2D(TYPE_AREA),307monitor_query_list(this),308moved_list(this) {309_set_static(true); //areas are not active by default310}311312GodotArea2D::~GodotArea2D() {313}314315316