summaryrefslogtreecommitdiff
path: root/scene/2d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/2d')
-rw-r--r--scene/2d/line_2d.cpp3
-rw-r--r--scene/2d/line_2d.h4
-rw-r--r--scene/2d/line_builder.cpp13
-rw-r--r--scene/2d/physics_body_2d.cpp147
-rw-r--r--scene/2d/physics_body_2d.h8
5 files changed, 130 insertions, 45 deletions
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 3e61dd05f4..e9e895b5bb 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -349,7 +349,7 @@ void Line2D::_bind_methods() {
ADD_GROUP("Fill", "");
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "None,Tile"), "set_texture_mode", "get_texture_mode");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "None,Tile,Stretch"), "set_texture_mode", "get_texture_mode");
ADD_GROUP("Capping", "");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "joint_mode", PROPERTY_HINT_ENUM, "Sharp,Bevel,Round"), "set_joint_mode", "get_joint_mode");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "begin_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_begin_cap_mode", "get_begin_cap_mode");
@@ -368,6 +368,7 @@ void Line2D::_bind_methods() {
BIND_ENUM_CONSTANT(LINE_TEXTURE_NONE);
BIND_ENUM_CONSTANT(LINE_TEXTURE_TILE);
+ BIND_ENUM_CONSTANT(LINE_TEXTURE_STRETCH);
ClassDB::bind_method(D_METHOD("_gradient_changed"), &Line2D::_gradient_changed);
}
diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h
index 24c48982cd..6918018c12 100644
--- a/scene/2d/line_2d.h
+++ b/scene/2d/line_2d.h
@@ -52,8 +52,8 @@ public:
enum LineTextureMode {
LINE_TEXTURE_NONE = 0,
- LINE_TEXTURE_TILE
- // TODO STRETCH mode
+ LINE_TEXTURE_TILE,
+ LINE_TEXTURE_STRETCH
};
Line2D();
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index 845788bada..74ad3e79d0 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -146,7 +146,9 @@ void LineBuilder::build() {
float current_distance1 = 0.f;
float total_distance = 0.f;
_interpolate_color = gradient != NULL;
- bool distance_required = _interpolate_color || texture_mode == Line2D::LINE_TEXTURE_TILE;
+ bool distance_required = _interpolate_color ||
+ texture_mode == Line2D::LINE_TEXTURE_TILE ||
+ texture_mode == Line2D::LINE_TEXTURE_STRETCH;
if (distance_required)
total_distance = calculate_total_distance(points);
if (_interpolate_color)
@@ -170,7 +172,7 @@ void LineBuilder::build() {
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
uvx0 = 0.5f / tile_aspect;
}
- new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, 1.f, 1.f));
+ new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, fmin(uvx0 * 2, 1.f), 1.f));
total_distance += width;
current_distance0 += hw;
current_distance1 = current_distance0;
@@ -292,6 +294,9 @@ void LineBuilder::build() {
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
uvx0 = current_distance0 / (width * tile_aspect);
uvx1 = current_distance1 / (width * tile_aspect);
+ } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) {
+ uvx0 = current_distance0 / total_distance;
+ uvx1 = current_distance1 / total_distance;
}
strip_add_quad(pos_up1, pos_down1, color1, uvx1);
@@ -378,6 +383,8 @@ void LineBuilder::build() {
}
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
uvx1 = current_distance1 / (width * tile_aspect);
+ } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) {
+ uvx1 = current_distance1 / total_distance;
}
strip_add_quad(pos_up1, pos_down1, color1, uvx1);
@@ -386,7 +393,7 @@ void LineBuilder::build() {
if (end_cap_mode == Line2D::LINE_CAP_ROUND) {
// Note: color is not used in case we don't interpolate...
Color color = _interpolate_color ? gradient->get_color(gradient->get_points_count() - 1) : Color(0, 0, 0);
- new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f, 0.f, 1.f, 1.f));
+ new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f / tile_aspect, 0.f, 1.0f / tile_aspect, 1.f));
}
}
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index feb11089d0..713d1daeef 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -32,8 +32,8 @@
#include "core/method_bind_ext.gen.inc"
#include "engine.h"
+#include "math_funcs.h"
#include "scene/scene_string_names.h"
-
void PhysicsBody2D::_notification(int p_what) {
/*
@@ -971,11 +971,11 @@ RigidBody2D::~RigidBody2D() {
//////////////////////////
-Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia) {
+Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes) {
Collision col;
- if (move_and_collide(p_motion, p_infinite_inertia, col)) {
+ if (move_and_collide(p_motion, p_infinite_inertia, col, p_exclude_raycast_shapes)) {
if (motion_cache.is_null()) {
motion_cache.instance();
motion_cache->owner = this;
@@ -989,11 +989,48 @@ Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p
return Ref<KinematicCollision2D>();
}
-bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision) {
+bool KinematicBody2D::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) {
+
+ Physics2DServer::SeparationResult sep_res[8]; //max 8 rays
+
+ Transform2D gt = get_global_transform();
+
+ Vector2 recover;
+ int hits = Physics2DServer::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin);
+ int deepest = -1;
+ float deepest_depth;
+ for (int i = 0; i < hits; i++) {
+ if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) {
+ deepest = i;
+ deepest_depth = sep_res[i].collision_depth;
+ }
+ }
+
+ gt.elements[2] += recover;
+ set_global_transform(gt);
+
+ if (deepest != -1) {
+ r_collision.collider = sep_res[deepest].collider_id;
+ r_collision.collider_metadata = sep_res[deepest].collider_metadata;
+ r_collision.collider_shape = sep_res[deepest].collider_shape;
+ r_collision.collider_vel = sep_res[deepest].collider_velocity;
+ r_collision.collision = sep_res[deepest].collision_point;
+ r_collision.normal = sep_res[deepest].collision_normal;
+ r_collision.local_shape = sep_res[deepest].collision_local_shape;
+ r_collision.travel = recover;
+ r_collision.remainder = Vector2();
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes) {
Transform2D gt = get_global_transform();
Physics2DServer::MotionResult result;
- bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result);
+ bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result, p_exclude_raycast_shapes);
if (colliding) {
r_collision.collider_metadata = result.collider_metadata;
@@ -1027,48 +1064,67 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
while (p_max_slides) {
Collision collision;
+ bool found_collision = false;
+
+ for (int i = 0; i < 2; i++) {
+ bool collided;
+ if (i == 0) { //collide
+ collided = move_and_collide(motion, p_infinite_inertia, collision);
+ if (!collided) {
+ motion = Vector2(); //clear because no collision happened and motion completed
+ }
+ } else { //separate raycasts (if any)
+ collided = separate_raycast_shapes(p_infinite_inertia, collision);
+ if (collided) {
+ collision.remainder = motion; //keep
+ collision.travel = Vector2();
+ }
+ }
- bool collided = move_and_collide(motion, p_infinite_inertia, collision);
-
- if (collided) {
-
- motion = collision.remainder;
-
- if (p_floor_direction == Vector2()) {
- //all is a wall
- on_wall = true;
- } else {
- if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor
+ if (collided) {
+ found_collision = true;
+ }
- on_floor = true;
- floor_velocity = collision.collider_vel;
+ if (collided) {
- Vector2 rel_v = lv - floor_velocity;
- Vector2 hv = rel_v - p_floor_direction * p_floor_direction.dot(rel_v);
+ motion = collision.remainder;
- if (collision.travel.length() < 1 && hv.length() < p_slope_stop_min_velocity) {
- Transform2D gt = get_global_transform();
- gt.elements[2] -= collision.travel;
- set_global_transform(gt);
- return Vector2();
- }
- } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling
- on_ceiling = true;
- } else {
+ if (p_floor_direction == Vector2()) {
+ //all is a wall
on_wall = true;
+ } else {
+ if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor
+
+ on_floor = true;
+ floor_velocity = collision.collider_vel;
+
+ Vector2 rel_v = lv - floor_velocity;
+ Vector2 hv = rel_v - p_floor_direction * p_floor_direction.dot(rel_v);
+
+ if (collision.travel.length() < 1 && hv.length() < p_slope_stop_min_velocity) {
+ Transform2D gt = get_global_transform();
+ gt.elements[2] -= collision.travel;
+ set_global_transform(gt);
+ return Vector2();
+ }
+ } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling
+ on_ceiling = true;
+ } else {
+ on_wall = true;
+ }
}
- }
- Vector2 n = collision.normal;
- motion = motion.slide(n);
- lv = lv.slide(n);
+ Vector2 n = collision.normal;
+ motion = motion.slide(n);
+ lv = lv.slide(n);
- colliders.push_back(collision);
+ colliders.push_back(collision);
+ }
+ }
- } else {
+ if (!found_collision) {
break;
}
-
p_max_slides--;
if (motion == Vector2())
break;
@@ -1077,6 +1133,22 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
return lv;
}
+bool KinematicBody2D::snap_to_floor(const Vector2 &p_direction, float p_floor_max_angle) {
+
+ Transform2D gt = get_global_transform();
+ Physics2DServer::MotionResult result;
+ bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_direction, false, margin, &result, false);
+ if (colliding) {
+ gt.elements[2] += result.motion;
+ if (Math::acos(p_direction.normalized().dot(-result.collision_normal)) < p_floor_max_angle) {
+ on_floor = true;
+ }
+ set_global_transform(gt);
+ }
+
+ return colliding;
+}
+
bool KinematicBody2D::is_on_floor() const {
return on_floor;
@@ -1140,8 +1212,9 @@ Ref<KinematicCollision2D> KinematicBody2D::_get_slide_collision(int p_bounce) {
void KinematicBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia"), &KinematicBody2D::_move, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes"), &KinematicBody2D::_move, DEFVAL(true), DEFVAL(true));
ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "infinite_inertia", "slope_stop_min_velocity", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(true), DEFVAL(5), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
+ ClassDB::bind_method(D_METHOD("snap_to_floor", "motion", "max_floor_angle"), &KinematicBody2D::snap_to_floor, DEFVAL(Math::deg2rad(45.0)));
ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody2D::test_move);
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 0fda3c5c05..1873c977a9 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -290,22 +290,26 @@ private:
bool on_floor;
bool on_ceiling;
bool on_wall;
+
Vector<Collision> colliders;
Vector<Ref<KinematicCollision2D> > slide_colliders;
Ref<KinematicCollision2D> motion_cache;
_FORCE_INLINE_ bool _ignores_mode(Physics2DServer::BodyMode) const;
- Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true);
+ Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true);
Ref<KinematicCollision2D> _get_slide_collision(int p_bounce);
protected:
static void _bind_methods();
public:
- bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision);
+ bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true);
+ bool snap_to_floor(const Vector2 &p_direction, float p_floor_max_angle = Math::deg2rad((float)45));
bool test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia);
+ bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision);
+
void set_safe_margin(float p_margin);
float get_safe_margin() const;