Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added spring arm node #18822

Merged
merged 1 commit into from
Aug 20, 2018
Merged

Added spring arm node #18822

merged 1 commit into from
Aug 20, 2018

Conversation

QbieShay
Copy link
Contributor

@QbieShay QbieShay commented May 12, 2018

Thanks to @AndreaCatania, Godot now can have a Spring Arm node!
Closes #16508.

The spring arm node is a node that pushes all its children back on his local z considering collision with the environment. If there is a collision, the spring arm will reduce its length.
The spring arm only moves its immediate children, and only the location( rotation control it's left in the hands of the developer ). It supports collision masks and specific body exclusion. It has a shape as property which is the shape that will be cast to do collision avoidance. Multiple shapes are not supported.

This type of node comes in handy when making 3rd person cameras, but it's not bound to that.

Example usage:

A classic responsive 3rd person camera can be achieved by simply adding the spring node as a child of the character, regulating its orientation to match the desired angle, and adding a camera as a child of the spring arm node. This implementation can be modified in various ways, for example, moving the spring arm on the shoulder of the character will achieve a shoulder camera with minimal effort.

The spring arm itself does not move on his own, so it is possible to control its motion , for example, for a racing game it's useful to have damping on the camera movement, and this can be easily achieved by scripting the spring arm node.

@@ -0,0 +1,141 @@
/*************************************************************************/
/* spring_arm.h */
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be .cpp

@QbieShay
Copy link
Contributor Author

corrected the license, also added a method to get the current spring length.

build.bat Outdated
@@ -0,0 +1,3 @@
@echo off
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64
scons p=windows
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was added by mistake.

@QbieShay
Copy link
Contributor Author

@vnen, yeah, sorry. Fixed

@AndreaCatania
Copy link
Contributor

I think that is better if you initialize current_spring_length to 0 and mask to 1 ( that is the same value of all other physics body)
This line is not required : excluded_objects = Set<RID>();
In the header you have to reorder correctly "set" and "get" functions

@QbieShay QbieShay force-pushed the master branch 2 times, most recently from 3ea6202 to 292e489 Compare May 13, 2018 21:25
@karroffel karroffel added this to the 3.1 milestone May 14, 2018
@QbieShay
Copy link
Contributor Author

Done :)

@reduz
Copy link
Member

reduz commented May 27, 2018

This looks nice, but I'm not sure this should be core, it does not seem like something you will use very often and could be very well provided by a script in the asset library

@Zireael07
Copy link
Contributor

Most 3D games will probably use this, @reduz

@QbieShay
Copy link
Contributor Author

@reduz i think it would be nice to have, i felt the need for this and i think also the people in #16508 did :)
With @AndreaCatania modifications, this code is simple, lightweight, and very general purpose anyway.

@silverweed
Copy link

I agree with @Zireael07 and @QbieShay, imho it'd be more convenient to have it core rather than having to import it every time. Moreover, for something as performance-intensive as a spring arm, to me C++ appears as a better choice than gdscript.

@AndreaCatania
Copy link
Contributor

@reduz is saying correctly, but I think that it will make life easier for all the people that want to avoid camera overlapping with environment. Is not a lot of code and i think worth it

@ghost
Copy link

ghost commented May 28, 2018

This is useful unless the game is in first person or camera movement is deterministic. I don't think I can make unobscured third person view without implementing something similar to this, and doing so takes a considerable amount of time and coding skill. I think it is justified according to this.

@fire
Copy link
Member

fire commented Jul 24, 2018

Is anyone interested in adding enabling camera lag for location and rotation?

There's camera lag speed, camera rotation lag speed variables and a max camera lag distance.

Bonus points for adding arm debugging helpers.

The reason is that the arm motion is abrupt.

@QbieShay
Copy link
Contributor Author

Hey @fire, achieving camera lag shouldn't bee to complicated: you place a dummy object under the spring arm node and you make your camera follow it with the lag you prefer. I believe you can also use an interpolated camera and have it out of the box

@fire
Copy link
Member

fire commented Jul 24, 2018

It's working.

I placed a dummy CameraTarget as a child of the spring arm node, then put the interpolated camera somewhere not as a child of the spring arm node. (its location should be close to the controlled mesh, this defines the minimum camera distance.) and set the interpolated camera's target to be CameraTarget.

@reduz
Copy link
Member

reduz commented Jul 24, 2018

@QbieShay A lot of users really insisted about this feature, so in the latest PR meeting review we have decided to merge it, as such, I will review it for inclusion.

set_process_internal(false);
}
break;
case NOTIFICATION_INTERNAL_PROCESS:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be INTERNAL_PHYSICS_PROCESS, because then you make sure that physics world is available for raycasting (as in, may happen that thread physics is enabled and you will get an error). You also need to use set_physics_process_internal()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If physic process is used and the spring arm is used for a camera, the difference between physic process and regular process is visible to the user and annoying. See here you can try out a spring arm that uses physic process

public:
void set_spring_length(float p_length);
float get_spring_length() const;
void set_shape(Ref<Shape> p_shape);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is setting a shape worth it? I would honestly just use a raycast with a margin, this covers pretty much any case I can think of.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked in the physics server but I don't see a way to set a margin for a raycast

bool remove_excluded_object(RID p_rid);
void clear_excluded_objects();
float get_current_spring_length();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also set a node via NodePath that you want to automatically make the SpringArm change position to on every frame (usually a camera). Could be a function like

set_target_node(const NodePath&)
NodePath get_target_node() const

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The movement of the spring arm node is intentionally left to the user. In order to achieve what you mention, it is enough to put the spring arm node as a child of a remote transform or the object itself. Leaving the movement to the user also allows for adding manual lag - damping - ecc.

@@ -390,6 +391,8 @@ void register_scene_types() {
ClassDB::register_class<RigidBody>();
ClassDB::register_class<KinematicCollision>();
ClassDB::register_class<KinematicBody>();
ClassDB::register_class<SpringArm>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should probably add a gizmo to this, where you can edit the length (and optionally the margin if you use that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you point me to an example of where this is done? I have no idea on how to implement that. Probably also @groud can help me?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check the ray shape gizmo, I think that you can copy most part of code from there

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AndreaCatania I'm not sure the ray shape gizmo is that good, I opened an issue on that here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be improved, but the basic code is almost the same

void add_excluded_object(RID p_rid);
bool remove_excluded_object(RID p_rid);
void clear_excluded_objects();
float get_current_spring_length();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use a get_hit_length() function or similar, instead of get_current_sprint_length(), to make it less confusing

@reduz
Copy link
Member

reduz commented Aug 10, 2018

Gizmos changed recently due to @JFonS , so this will need re-adapting to the new way gizmos are done.
Once conflicts are fixed, I will merge it. I will also probably test it well on a few scenarios and existing demo scenes and possibly do small changes, but I think as is this is good.

@JFonS
Copy link
Contributor

JFonS commented Aug 10, 2018

@QbieShay you can take the new RayCastSpatialGizmoPlugin as an example on how to convert your gizmo, and ask away if you have any doubts.

@reduz reduz merged commit c1bd768 into godotengine:master Aug 20, 2018
@aaronfranke
Copy link
Member

This Node is lacking an icon.

@yushgh
Copy link

yushgh commented Jul 22, 2019

This Node is lacking an icon.

I made one by modifying <damped spring joint 2d> and just leave it here.
preview_spring_arm

icon_spring_arm.zip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Spring Arm Node