Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/config/project_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1852,6 +1852,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "input_devices/pointing/android/rotary_input_scroll_axis", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1);
GLOBAL_DEF("input_devices/pointing/android/override_volume_buttons", false);
GLOBAL_DEF_BASIC("input_devices/pointing/android/disable_scroll_deadzone", false);
GLOBAL_DEF_BASIC("input_devices/virtual_controller/enable_controller", false);

// These properties will not show up in the dialog. If you want to exclude whole groups, use add_hidden_prefix().
GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray());
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1716,6 +1716,9 @@
<member name="input_devices/sensors/enable_magnetometer" type="bool" setter="" getter="" default="false">
If [code]true[/code], the magnetometer sensor is enabled and [method Input.get_magnetometer] returns valid data.
</member>
<member name="input_devices/virtual_controller/enable_controller" type="bool" setter="" getter="" default="false">
If [code]true[/code], the virtual controller is enabled and will be created in the scene.
</member>
<member name="internationalization/locale/fallback" type="String" setter="" getter="" default="&quot;en&quot;">
The locale to fall back to if a translation isn't available in a given language. If left empty, [code]en[/code] (English) will be used.
[b]Note:[/b] Not to be confused with [TextServerFallback].
Expand Down
6 changes: 6 additions & 0 deletions doc/classes/VirtualJoystick.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@
Emitted when the tip moved outside the deadzone and the joystick is released. The [param input_vector] contains the last input direction and strength before release. Its length is between [code]0.0[/code] and [code]1.0[/code].
</description>
</signal>
<signal name="input_changed">
<param index="0" name="input_vector" type="Vector2" />
<description>
Emitted when the input vector changes.
</description>
</signal>
<signal name="pressed">
<description>
Emitted when the joystick is pressed.
Expand Down
587 changes: 587 additions & 0 deletions scene/gui/virtual_controller.cpp

Large diffs are not rendered by default.

128 changes: 128 additions & 0 deletions scene/gui/virtual_controller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**************************************************************************/
/* virtual_controller.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/

#pragma once

#include "scene/gui/control.h"

class Button;
class VirtualJoystick;

class VirtualController : public Control {
GDCLASS(VirtualController, Control);

private:
int device_id = -1;

struct ThemeCache {
Ref<StyleBox> button_normal;
Ref<StyleBox> button_pressed;
Ref<StyleBox> left_normal_joystick;
Ref<StyleBox> left_normal_tip;
Ref<StyleBox> left_pressed_joystick;
Ref<StyleBox> left_pressed_tip;
Ref<StyleBox> right_normal_joystick;
Ref<StyleBox> right_normal_tip;
Ref<StyleBox> right_pressed_joystick;
Ref<StyleBox> right_pressed_tip;
} theme_cache;

VirtualJoystick *left_joystick = nullptr;
VirtualJoystick *right_joystick = nullptr;
Button *left_joystick_button = nullptr;
Button *right_joystick_button = nullptr;
Button *dpad_up = nullptr;
Button *dpad_down = nullptr;
Button *dpad_left = nullptr;
Button *dpad_right = nullptr;
Button *button_a = nullptr;
Button *button_b = nullptr;
Button *button_x = nullptr;
Button *button_y = nullptr;
Button *left_shoulder = nullptr;
Button *right_shoulder = nullptr;
Button *left_trigger = nullptr;
Button *right_trigger = nullptr;
Button *start_button = nullptr;
Button *back_button = nullptr;
Button *guide_button = nullptr;

void _setup_controls();

void _create_button_event(JoyButton p_button, bool p_pressed);
void _create_motion_event(JoyAxis p_axis, float p_value);
void _update_left_joystick_style(VirtualJoystick *p_joystick);
void _update_right_joystick_style(VirtualJoystick *p_joystick);
void _update_button_style(Button *p_button);

void _on_left_joystick_motion(Vector2 p_value);
void _on_right_joystick_motion(Vector2 p_value);
void _on_left_joystick_pressed();
void _on_left_joystick_released();
void _on_right_joystick_pressed();
void _on_right_joystick_released();
void _on_dpad_up_pressed();
void _on_dpad_up_released();
void _on_dpad_down_pressed();
void _on_dpad_down_released();
void _on_dpad_left_pressed();
void _on_dpad_left_released();
void _on_dpad_right_pressed();
void _on_dpad_right_released();
void _on_button_a_pressed();
void _on_button_a_released();
void _on_button_b_pressed();
void _on_button_b_released();
void _on_button_x_pressed();
void _on_button_x_released();
void _on_button_y_pressed();
void _on_button_y_released();
void _on_left_shoulder_pressed();
void _on_left_shoulder_released();
void _on_right_shoulder_pressed();
void _on_right_shoulder_released();
void _on_left_trigger_pressed();
void _on_left_trigger_released();
void _on_right_trigger_pressed();
void _on_right_trigger_released();
void _on_start_button_pressed();
void _on_start_button_released();
void _on_back_button_pressed();
void _on_back_button_released();
void _on_guide_button_pressed();
void _on_guide_button_released();

protected:
static void _bind_methods();
void _notification(int p_what);

public:
VirtualController();
};
4 changes: 4 additions & 0 deletions scene/gui/virtual_joystick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ void VirtualJoystick::gui_input(const Ref<InputEvent> &p_event) {
} else if (touch->get_index() == touch_index) {
is_pressed = false;
emit_signal(SNAME("released"), input_vector);
emit_signal(SNAME("input_changed"), Vector2());

if (!is_flick_canceled && !has_moved) {
emit_signal(SNAME("tapped"));
Expand Down Expand Up @@ -127,6 +128,8 @@ void VirtualJoystick::_update_joystick(const Vector2 &p_pos) {
input_vector = Vector2();
}

emit_signal(SNAME("input_changed"), input_vector);

if (!is_flick_canceled && was_pressed && !has_input) {
is_flick_canceled = true;
emit_signal(SNAME("flick_canceled"));
Expand Down Expand Up @@ -247,6 +250,7 @@ void VirtualJoystick::_bind_methods() {
ADD_SIGNAL(MethodInfo("released", PropertyInfo(Variant::VECTOR2, "input_vector")));
ADD_SIGNAL(MethodInfo("flicked", PropertyInfo(Variant::VECTOR2, "input_vector")));
ADD_SIGNAL(MethodInfo("flick_canceled"));
ADD_SIGNAL(MethodInfo("input_changed", PropertyInfo(Variant::VECTOR2, "input_vector")));

BIND_ENUM_CONSTANT(JOYSTICK_FIXED);
BIND_ENUM_CONSTANT(JOYSTICK_DYNAMIC);
Expand Down
41 changes: 41 additions & 0 deletions scene/main/scene_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ STATIC_ASSERT_INCOMPLETE_TYPE(class, RenderingServer);
#include "scene/animation/tween.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/gui/control.h"
#include "scene/gui/virtual_controller.h"
#include "scene/main/canvas_layer.h"
#include "scene/main/multiplayer_api.h"
#include "scene/main/node.h"
#include "scene/main/viewport.h"
Expand Down Expand Up @@ -1887,6 +1889,43 @@ bool SceneTree::is_multiplayer_poll_enabled() const {
return multiplayer_poll;
}

void SceneTree::set_virtual_controller_visible(bool p_visible) {
if (p_visible) {
if (virtual_controller_canvas_layer == nullptr) {
virtual_controller_canvas_layer = memnew(CanvasLayer);
// Begin name with an underscore to avoid conflict with project nodes.
virtual_controller_canvas_layer->set_name("_VirtualControllerCanvasLayer");
get_root()->add_child(virtual_controller_canvas_layer, false, Node::INTERNAL_MODE_BACK);

virtual_controller = memnew(VirtualController);
virtual_controller->set_name("_VirtualController");
virtual_controller_canvas_layer->add_child(virtual_controller, false, Node::INTERNAL_MODE_BACK);
} else {
ERR_PRINT("Virtual controller already exists.");
}
} else {
if (virtual_controller_canvas_layer != nullptr) {
// Free when closing to avoid reserving memory during the project's run duration.
virtual_controller_canvas_layer->queue_free();
virtual_controller_canvas_layer = nullptr;
virtual_controller = nullptr;
}
}
}

bool SceneTree::is_virtual_controller_visible() const {
if (virtual_controller_canvas_layer) {
return virtual_controller_canvas_layer->is_visible();
}

// Licenses dialog isn't created yet. Therefore, it's not visible.
return false;
}

void SceneTree::_project_settings_changed() {
set_virtual_controller_visible(ProjectSettings::get_singleton()->get("input_devices/virtual_controller/enable_controller"));
}

void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_root"), &SceneTree::get_root);
ClassDB::bind_method(D_METHOD("has_group", "name"), &SceneTree::has_group);
Expand Down Expand Up @@ -2178,6 +2217,8 @@ SceneTree::SceneTree() {
Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/2d/sdf/scale", PROPERTY_HINT_ENUM, "100%,50%,25%"), 1)));
root->set_sdf_scale(sdf_scale);

ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &SceneTree::_project_settings_changed));

#ifndef _3D_DISABLED
{ // Load default fallback environment.
// Get possible extensions.
Expand Down
10 changes: 10 additions & 0 deletions scene/main/scene_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@
#include <cstdlib>

class ArrayMesh;
class CanvasLayer;
class InputEvent;
class Material;
class MultiplayerAPI;
class Node;
class PackedScene;
class Tween;
class Viewport;
class VirtualController;
class Window;

#ifndef _3D_DISABLED
Expand Down Expand Up @@ -204,6 +206,9 @@ class SceneTree : public MainLoop {
ObjectID prev_scene_id;
ObjectID pending_new_scene_id;

CanvasLayer *virtual_controller_canvas_layer = nullptr;
VirtualController *virtual_controller = nullptr;

Color debug_collisions_color;
Color debug_collision_contact_color;
Color debug_paths_color;
Expand Down Expand Up @@ -283,6 +288,8 @@ class SceneTree : public MainLoop {
//used by viewport
void _call_input_pause(const StringName &p_group, CallInputType p_call_type, const Ref<InputEvent> &p_input, Viewport *p_viewport);

void _project_settings_changed();

protected:
void _notification(int p_notification);
static void _bind_methods();
Expand Down Expand Up @@ -451,6 +458,9 @@ class SceneTree : public MainLoop {
void set_multiplayer_poll_enabled(bool p_enabled);
bool is_multiplayer_poll_enabled() const;

void set_virtual_controller_visible(bool p_visible);
bool is_virtual_controller_visible() const;

static void add_idle_callback(IdleCallback p_callback);

void set_disable_node_threading(bool p_disable);
Expand Down
19 changes: 19 additions & 0 deletions scene/theme/default_theme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,25 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("pressed_joystick", "VirtualJoystick", style_joystick);
theme->set_stylebox("pressed_tip", "VirtualJoystick", style_joystick_tip);

// Virtual Controller

Ref<StyleBoxFlat> style_virtual_controller_button = make_flat_stylebox(style_normal_color, 0, 0, 0, 0, 10000, false, 4 * scale);
style_virtual_controller_button->set_corner_detail(24 * scale);

Ref<StyleBoxFlat> style_virtual_controller_button_pressed = make_flat_stylebox(style_pressed_color, 0, 0, 0, 0, 10000, true, 4 * scale);
style_virtual_controller_button_pressed->set_corner_detail(24 * scale);

theme->set_stylebox("button_normal", "VirtualController", style_virtual_controller_button);
theme->set_stylebox("button_pressed", "VirtualController", style_virtual_controller_button_pressed);
theme->set_stylebox("left_normal_joystick", "VirtualController", style_joystick);
theme->set_stylebox("left_normal_tip", "VirtualController", style_joystick_tip);
theme->set_stylebox("left_pressed_joystick", "VirtualController", style_joystick);
theme->set_stylebox("left_pressed_tip", "VirtualController", style_joystick_tip);
theme->set_stylebox("right_normal_joystick", "VirtualController", style_joystick);
theme->set_stylebox("right_normal_tip", "VirtualController", style_joystick_tip);
theme->set_stylebox("right_pressed_joystick", "VirtualController", style_joystick);
theme->set_stylebox("right_pressed_tip", "VirtualController", style_joystick_tip);

// Window

theme->set_stylebox("embedded_border", "Window", sb_expand(make_flat_stylebox(style_popup_color, 10, 28, 10, 8), 8, 32, 8, 6));
Expand Down
Loading