Skip to content

Commit 7e6c468

Browse files
committed
Merge pull request godotengine#101427 from Lazy-Rabbit-2001/camera_2d_draggable
Improve usability of `Camera2D`
2 parents 2f5f3c9 + 5ca70d8 commit 7e6c468

File tree

6 files changed

+378
-5
lines changed

6 files changed

+378
-5
lines changed

doc/classes/Camera2D.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@
142142
<member name="limit_bottom" type="int" setter="set_limit" getter="get_limit" default="10000000">
143143
Bottom scroll limit in pixels. The camera stops moving when reaching this value, but [member offset] can push the view past the limit.
144144
</member>
145+
<member name="limit_enabled" type="bool" setter="set_limit_enabled" getter="is_limit_enabled" default="true">
146+
If [code]true[/code], the limits will be enabled. Disabling this will allow the camera to focus anywhere, when the four [code]limit_*[/code] properties will not work.
147+
</member>
145148
<member name="limit_left" type="int" setter="set_limit" getter="get_limit" default="-10000000">
146149
Left scroll limit in pixels. The camera stops moving when reaching this value, but [member offset] can push the view past the limit.
147150
</member>
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/**************************************************************************/
2+
/* camera_2d_editor_plugin.cpp */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#include "camera_2d_editor_plugin.h"
32+
33+
#include "canvas_item_editor_plugin.h"
34+
#include "core/config/project_settings.h"
35+
#include "editor/editor_node.h"
36+
#include "editor/editor_undo_redo_manager.h"
37+
#include "editor/themes/editor_scale.h"
38+
#include "scene/2d/camera_2d.h"
39+
#include "scene/gui/label.h"
40+
#include "scene/gui/menu_button.h"
41+
42+
void Camera2DEditor::edit(Camera2D *p_camera) {
43+
if (p_camera == selected_camera) {
44+
return;
45+
}
46+
selected_camera = p_camera;
47+
}
48+
49+
void Camera2DEditor::_menu_option(int p_option) {
50+
switch (p_option) {
51+
case MENU_SNAP_LIMITS_TO_VIEWPORT: {
52+
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
53+
Rect2 prev_rect = selected_camera->get_limit_rect();
54+
ur->create_action(TTR("Snap the Limits to the Viewport"), UndoRedo::MERGE_DISABLE, selected_camera);
55+
ur->add_do_method(this, "_snap_limits_to_viewport");
56+
ur->add_do_reference(selected_camera);
57+
ur->add_undo_method(this, "_undo_snap_limits_to_viewport", prev_rect);
58+
ur->commit_action();
59+
} break;
60+
}
61+
}
62+
63+
void Camera2DEditor::_snap_limits_to_viewport() {
64+
selected_camera->set_limit(SIDE_LEFT, 0);
65+
selected_camera->set_limit(SIDE_TOP, 0);
66+
selected_camera->set_limit(SIDE_RIGHT, GLOBAL_GET("display/window/size/viewport_width"));
67+
selected_camera->set_limit(SIDE_BOTTOM, GLOBAL_GET("display/window/size/viewport_height"));
68+
}
69+
70+
void Camera2DEditor::_undo_snap_limits_to_viewport(const Rect2 &p_prev_rect) {
71+
Point2 end = p_prev_rect.get_end();
72+
selected_camera->set_limit(SIDE_LEFT, p_prev_rect.position.x);
73+
selected_camera->set_limit(SIDE_TOP, p_prev_rect.position.y);
74+
selected_camera->set_limit(SIDE_RIGHT, end.x);
75+
selected_camera->set_limit(SIDE_BOTTOM, end.y);
76+
}
77+
78+
void Camera2DEditor::_notification(int p_what) {
79+
switch (p_what) {
80+
case NOTIFICATION_THEME_CHANGED: {
81+
options->set_button_icon(get_editor_theme_icon(SNAME("Camera2D")));
82+
} break;
83+
}
84+
}
85+
86+
void Camera2DEditor::_bind_methods() {
87+
ClassDB::bind_method(D_METHOD("_snap_limits_to_viewport"), &Camera2DEditor::_snap_limits_to_viewport);
88+
ClassDB::bind_method(D_METHOD("_undo_snap_limits_to_viewport", "prev_rect"), &Camera2DEditor::_undo_snap_limits_to_viewport);
89+
}
90+
91+
Camera2DEditor::Camera2DEditor() {
92+
options = memnew(MenuButton);
93+
94+
CanvasItemEditor::get_singleton()->add_control_to_menu_panel(options);
95+
96+
options->set_text(TTRC("Camera2D"));
97+
98+
options->get_popup()->add_item(TTRC("Snap the Limits to the Viewport"), MENU_SNAP_LIMITS_TO_VIEWPORT);
99+
options->set_switch_on_hover(true);
100+
101+
options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &Camera2DEditor::_menu_option));
102+
103+
#ifdef TOOLS_ENABLED
104+
add_user_signal(MethodInfo("_editor_theme_changed"));
105+
#endif
106+
}
107+
108+
void Camera2DEditorPlugin::_update_approach_text_visibility() {
109+
if (camera_2d_editor->selected_camera == nullptr) {
110+
return;
111+
}
112+
approach_to_move_rect->set_visible(camera_2d_editor->selected_camera->is_limit_enabled());
113+
}
114+
115+
void Camera2DEditorPlugin::_editor_theme_changed() {
116+
approach_to_move_rect->remove_theme_color_override(SceneStringName(font_color));
117+
approach_to_move_rect->add_theme_color_override(SceneStringName(font_color), Color(0.6f, 0.6f, 0.6f, 1));
118+
approach_to_move_rect->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1));
119+
approach_to_move_rect->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE);
120+
approach_to_move_rect->add_theme_constant_override("line_spacing", 0);
121+
}
122+
123+
void Camera2DEditorPlugin::edit(Object *p_object) {
124+
Callable update_text = callable_mp(this, &Camera2DEditorPlugin::_update_approach_text_visibility);
125+
StringName update_signal = SNAME("_camera_limit_enabled_updated");
126+
127+
Camera2D *prev_cam = camera_2d_editor->selected_camera;
128+
if (prev_cam != nullptr && prev_cam->is_connected(update_signal, update_text)) {
129+
prev_cam->disconnect(update_signal, update_text);
130+
}
131+
Camera2D *cam = Object::cast_to<Camera2D>(p_object);
132+
if (cam != nullptr) {
133+
camera_2d_editor->edit(cam);
134+
_update_approach_text_visibility();
135+
if (!cam->is_connected(update_signal, update_text)) {
136+
cam->connect(update_signal, update_text);
137+
}
138+
}
139+
}
140+
141+
bool Camera2DEditorPlugin::handles(Object *p_object) const {
142+
return p_object->is_class("Camera2D");
143+
}
144+
145+
void Camera2DEditorPlugin::make_visible(bool p_visible) {
146+
if (p_visible) {
147+
camera_2d_editor->options->show();
148+
approach_to_move_rect->show();
149+
} else {
150+
camera_2d_editor->options->hide();
151+
approach_to_move_rect->hide();
152+
}
153+
}
154+
155+
Camera2DEditorPlugin::Camera2DEditorPlugin() {
156+
camera_2d_editor = memnew(Camera2DEditor);
157+
EditorNode::get_singleton()->get_gui_base()->add_child(camera_2d_editor);
158+
camera_2d_editor->connect(SNAME("_editor_theme_changed"), callable_mp(this, &Camera2DEditorPlugin::_editor_theme_changed));
159+
160+
approach_to_move_rect = memnew(Label);
161+
approach_to_move_rect->set_text(TTRC("In Move Mode: \nHold Ctrl + left mouse button to move the limit rectangle.\nHold left mouse button to move the camera only."));
162+
approach_to_move_rect->hide();
163+
_editor_theme_changed();
164+
CanvasItemEditor::get_singleton()->get_controls_container()->add_child(approach_to_move_rect);
165+
166+
make_visible(false);
167+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**************************************************************************/
2+
/* camera_2d_editor_plugin.h */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#pragma once
32+
33+
#include "editor/plugins/editor_plugin.h"
34+
35+
class Camera2D;
36+
class Label;
37+
class MenuButton;
38+
39+
class Camera2DEditor : public Control {
40+
GDCLASS(Camera2DEditor, Control);
41+
42+
enum Menu {
43+
MENU_SNAP_LIMITS_TO_VIEWPORT,
44+
};
45+
46+
Camera2D *selected_camera = nullptr;
47+
48+
friend class Camera2DEditorPlugin;
49+
MenuButton *options = nullptr;
50+
51+
void _menu_option(int p_option);
52+
void _snap_limits_to_viewport();
53+
void _undo_snap_limits_to_viewport(const Rect2 &p_prev_rect);
54+
55+
protected:
56+
static void _bind_methods();
57+
void _notification(int p_what);
58+
59+
public:
60+
void edit(Camera2D *p_camera);
61+
Camera2DEditor();
62+
};
63+
64+
class Camera2DEditorPlugin : public EditorPlugin {
65+
GDCLASS(Camera2DEditorPlugin, EditorPlugin);
66+
67+
Camera2DEditor *camera_2d_editor = nullptr;
68+
69+
Label *approach_to_move_rect = nullptr;
70+
71+
void _editor_theme_changed();
72+
void _update_approach_text_visibility();
73+
74+
public:
75+
virtual void edit(Object *p_object) override;
76+
virtual bool handles(Object *p_object) const override;
77+
virtual void make_visible(bool p_visible) override;
78+
79+
Camera2DEditorPlugin();
80+
};

editor/register_editor_types.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
#include "editor/plugins/audio_stream_randomizer_editor_plugin.h"
7474
#include "editor/plugins/bit_map_editor_plugin.h"
7575
#include "editor/plugins/bone_map_editor_plugin.h"
76+
#include "editor/plugins/camera_2d_editor_plugin.h"
7677
#include "editor/plugins/camera_3d_editor_plugin.h"
7778
#include "editor/plugins/cast_2d_editor_plugin.h"
7879
#include "editor/plugins/collision_polygon_2d_editor_plugin.h"
@@ -252,6 +253,7 @@ void register_editor_types() {
252253
EditorPlugins::add_by_type<VoxelGIEditorPlugin>();
253254

254255
// 2D
256+
EditorPlugins::add_by_type<Camera2DEditorPlugin>();
255257
EditorPlugins::add_by_type<CollisionPolygon2DEditorPlugin>();
256258
EditorPlugins::add_by_type<CollisionShape2DEditorPlugin>();
257259
EditorPlugins::add_by_type<CPUParticles2DEditorPlugin>();

0 commit comments

Comments
 (0)