mirror of https://github.com/godotengine/godot
Adds VirtualJoystick
This commit is contained in:
parent
5ad8b27d8d
commit
fa2d63e3fe
|
|
@ -0,0 +1,119 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="VirtualJoystick" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
A virtual joystick control for touchscreen devices.
|
||||
</brief_description>
|
||||
<description>
|
||||
A customizable on-screen joystick control designed for touchscreen devices. It allows users to provide directional input by dragging a virtual tip within a defined circular area.
|
||||
This control can simulate directional actions (see [member action_up], [member action_down], [member action_left], and [member action_right]), which are triggered when the joystick is moved in the corresponding directions.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="action_down" type="StringName" setter="set_action_down" getter="get_action_down" default="&"ui_down"">
|
||||
The action to trigger when the joystick is moved down.
|
||||
</member>
|
||||
<member name="action_left" type="StringName" setter="set_action_left" getter="get_action_left" default="&"ui_left"">
|
||||
The action to trigger when the joystick is moved left.
|
||||
</member>
|
||||
<member name="action_right" type="StringName" setter="set_action_right" getter="get_action_right" default="&"ui_right"">
|
||||
The action to trigger when the joystick is moved right.
|
||||
</member>
|
||||
<member name="action_up" type="StringName" setter="set_action_up" getter="get_action_up" default="&"ui_up"">
|
||||
The action to trigger when the joystick is moved up.
|
||||
</member>
|
||||
<member name="clampzone_ratio" type="float" setter="set_clampzone_ratio" getter="get_clampzone_ratio" default="1.0">
|
||||
The multiplier applied to the joystick's radius that defines the clamp zone.
|
||||
This zone limits how far the joystick tip can move from its center before being clamped.
|
||||
A value of [code]1.0[/code] means the tip can move up to the edge of the joystick's visual size.
|
||||
In [constant JOYSTICK_FOLLOWING] mode, this radius also determines how far the finger can move before the joystick base starts following the touch input.
|
||||
</member>
|
||||
<member name="deadzone_ratio" type="float" setter="set_deadzone_ratio" getter="get_deadzone_ratio" default="0.0">
|
||||
The ratio of the joystick size that defines the joystick deadzone. The joystick tip must move beyond this ratio before being considered active.
|
||||
This deadzone is applied before triggering input actions and affects the joystick's input vector and all related signals.
|
||||
Note that input actions may also define their own deadzones in the InputMap. If both are set, the joystick deadzone is applied first, followed by the action's deadzone.
|
||||
By default, this value is [code]0.0[/code], meaning the joystick does not apply its own deadzone and relies entirely on the InputMap action deadzones.
|
||||
</member>
|
||||
<member name="initial_offset_ratio" type="Vector2" setter="set_initial_offset_ratio" getter="get_initial_offset_ratio" default="Vector2(0.5, 0.5)">
|
||||
The initial position of the joystick as a ratio of the control's size. [code](0, 0)[/code] is top-left and [code](1, 1)[/code] is bottom-right.
|
||||
</member>
|
||||
<member name="joystick_mode" type="int" setter="set_joystick_mode" getter="get_joystick_mode" enum="VirtualJoystick.JoystickMode" default="0">
|
||||
The joystick mode to use.
|
||||
</member>
|
||||
<member name="joystick_size" type="float" setter="set_joystick_size" getter="get_joystick_size" default="100.0">
|
||||
The size of the joystick in pixels.
|
||||
</member>
|
||||
<member name="joystick_texture" type="Texture2D" setter="set_joystick_texture" getter="get_joystick_texture">
|
||||
The texture to use for the joystick base. When [code]null[/code], a ring is drawn using the [theme_item ring_normal_color] and [theme_item ring_pressed_color].
|
||||
</member>
|
||||
<member name="tip_size" type="float" setter="set_tip_size" getter="get_tip_size" default="50.0">
|
||||
The size of the joystick tip in pixels.
|
||||
</member>
|
||||
<member name="tip_texture" type="Texture2D" setter="set_tip_texture" getter="get_tip_texture">
|
||||
The texture to use for the joystick tip. When [code]null[/code], a circle is drawn using the [theme_item tip_normal_color] and [theme_item tip_pressed_color].
|
||||
</member>
|
||||
<member name="visibility_mode" type="int" setter="set_visibility_mode" getter="get_visibility_mode" enum="VirtualJoystick.VisibilityMode" default="0">
|
||||
The visibility mode to use.
|
||||
</member>
|
||||
</members>
|
||||
<signals>
|
||||
<signal name="flick_canceled">
|
||||
<description>
|
||||
Emitted when the tip enters the deadzone after being outside of it.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="flicked">
|
||||
<param index="0" name="input_vector" type="Vector2" />
|
||||
<description>
|
||||
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="pressed">
|
||||
<description>
|
||||
Emitted when the joystick is pressed.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="released">
|
||||
<param index="0" name="input_vector" type="Vector2" />
|
||||
<description>
|
||||
Emitted when the joystick is released. The [param input_vector] is the final input direction and strength, with a length between [code]0.0[/code] and [code]1.0[/code].
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="tapped">
|
||||
<description>
|
||||
Emitted when the joystick is released without moving the tip.
|
||||
</description>
|
||||
</signal>
|
||||
</signals>
|
||||
<constants>
|
||||
<constant name="JOYSTICK_FIXED" value="0" enum="JoystickMode">
|
||||
The joystick doesn't move.
|
||||
</constant>
|
||||
<constant name="JOYSTICK_DYNAMIC" value="1" enum="JoystickMode">
|
||||
The joystick is moved to the initial touch position as long as it's within the joystick's bounds. It moves back to its original position when released.
|
||||
</constant>
|
||||
<constant name="JOYSTICK_FOLLOWING" value="2" enum="JoystickMode">
|
||||
The joystick is moved to the initial touch position as long as it's within the joystick's bounds. It will follow the touch input if it goes outside the joystick's range. It moves back to its original position when released.
|
||||
</constant>
|
||||
<constant name="VISIBILITY_ALWAYS" value="0" enum="VisibilityMode">
|
||||
The joystick is always visible.
|
||||
</constant>
|
||||
<constant name="VISIBILITY_WHEN_TOUCHED" value="1" enum="VisibilityMode">
|
||||
The joystick is only visible when being touched.
|
||||
</constant>
|
||||
</constants>
|
||||
<theme_items>
|
||||
<theme_item name="ring_normal_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)">
|
||||
Default ring joystick [Color].
|
||||
</theme_item>
|
||||
<theme_item name="ring_pressed_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)">
|
||||
Ring joystick [Color] when pressed.
|
||||
</theme_item>
|
||||
<theme_item name="tip_normal_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)">
|
||||
Default Tip joystick [Color].
|
||||
</theme_item>
|
||||
<theme_item name="tip_pressed_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)">
|
||||
Tip joystick [Color] when pressed.
|
||||
</theme_item>
|
||||
</theme_items>
|
||||
</class>
|
||||
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#8eef97" d="m8 14A1 1 0 008 2 1 1 0 008 14M8 3A1 1 0 118 13 1 1 0 118 3M8 6A1 1 0 008 10 1 1 0 008 6"/></svg>
|
||||
|
After Width: | Height: | Size: 185 B |
|
|
@ -109,6 +109,7 @@
|
|||
#include "editor/scene/gui/margin_container_editor_plugin.h"
|
||||
#include "editor/scene/gui/style_box_editor_plugin.h"
|
||||
#include "editor/scene/gui/theme_editor_plugin.h"
|
||||
#include "editor/scene/gui/virtual_joystick_editor_plugin.h"
|
||||
#include "editor/scene/material_editor_plugin.h"
|
||||
#include "editor/scene/packed_scene_editor_plugin.h"
|
||||
#include "editor/scene/resource_preloader_editor_plugin.h"
|
||||
|
|
@ -256,6 +257,7 @@ void register_editor_types() {
|
|||
EditorPlugins::add_by_type<TextureRegionEditorPlugin>();
|
||||
EditorPlugins::add_by_type<ThemeEditorPlugin>();
|
||||
EditorPlugins::add_by_type<ToolButtonEditorPlugin>();
|
||||
EditorPlugins::add_by_type<VirtualJoystickEditorPlugin>();
|
||||
EditorPlugins::add_by_type<VoxelGIEditorPlugin>();
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
EditorPlugins::add_by_type<SkeletonIK3DEditorPlugin>();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
/**************************************************************************/
|
||||
/* virtual_joystick_editor_plugin.cpp */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "virtual_joystick_editor_plugin.h"
|
||||
|
||||
#include "editor/scene/canvas_item_editor_plugin.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
#include "scene/gui/virtual_joystick.h"
|
||||
|
||||
void VirtualJoystickEditorPlugin::edit(Object *p_object) {
|
||||
if (virtual_joystick) {
|
||||
virtual_joystick->disconnect(SceneStringName(draw), callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
|
||||
}
|
||||
|
||||
virtual_joystick = Object::cast_to<VirtualJoystick>(p_object);
|
||||
|
||||
if (virtual_joystick) {
|
||||
virtual_joystick->connect(SceneStringName(draw), callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
|
||||
}
|
||||
CanvasItemEditor::get_singleton()->update_viewport();
|
||||
}
|
||||
|
||||
bool VirtualJoystickEditorPlugin::handles(Object *p_object) const {
|
||||
return Object::cast_to<VirtualJoystick>(p_object) != nullptr;
|
||||
}
|
||||
|
||||
void VirtualJoystickEditorPlugin::forward_canvas_draw_over_viewport(Control *p_viewport_control) {
|
||||
if (!virtual_joystick || !virtual_joystick->is_visible_in_tree()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * virtual_joystick->get_screen_transform();
|
||||
|
||||
Vector2 center = virtual_joystick->get_joystick_position();
|
||||
float base_radius = virtual_joystick->get_joystick_size() * 0.5f;
|
||||
|
||||
float clampzone_radius = base_radius * virtual_joystick->get_clampzone_ratio();
|
||||
float deadzone_radius = clampzone_radius * virtual_joystick->get_deadzone_ratio();
|
||||
|
||||
// NOTE: This color is copied from Camera2DEditor::forward_canvas_draw_over_viewport.
|
||||
// We may want to unify them somehow in the future.
|
||||
Color clampzone_color = Color(1, 1, 0.25, 0.63);
|
||||
Color deadzone_color = Color(1, 1, 0.25, 0.63);
|
||||
|
||||
int width = Math::round(1 * EDSCALE);
|
||||
|
||||
p_viewport_control->draw_circle(xform.xform(center), clampzone_radius * xform.get_scale().x, clampzone_color, false, width);
|
||||
|
||||
p_viewport_control->draw_circle(xform.xform(center), deadzone_radius * xform.get_scale().x, deadzone_color, false, width);
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/**************************************************************************/
|
||||
/* virtual_joystick_editor_plugin.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 "editor/plugins/editor_plugin.h"
|
||||
|
||||
class CanvasItemEditor;
|
||||
class VirtualJoystick;
|
||||
|
||||
class VirtualJoystickEditorPlugin : public EditorPlugin {
|
||||
GDCLASS(VirtualJoystickEditorPlugin, EditorPlugin);
|
||||
|
||||
VirtualJoystick *virtual_joystick = nullptr;
|
||||
|
||||
public:
|
||||
void forward_canvas_draw_over_viewport(Control *p_viewport_control) override;
|
||||
|
||||
virtual void edit(Object *p_object) override;
|
||||
virtual bool handles(Object *p_object) const override;
|
||||
};
|
||||
|
|
@ -0,0 +1,405 @@
|
|||
/**************************************************************************/
|
||||
/* virtual_joystick.cpp */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "virtual_joystick.h"
|
||||
|
||||
#include "core/input/input.h"
|
||||
#include "core/input/input_map.h"
|
||||
#include "scene/theme/theme_db.h"
|
||||
|
||||
void VirtualJoystick::gui_input(const Ref<InputEvent> &p_event) {
|
||||
Ref<InputEventScreenTouch> touch = p_event;
|
||||
if (touch.is_valid()) {
|
||||
if (touch->is_pressed()) {
|
||||
if (touch_index == -1 && has_point(touch->get_position())) {
|
||||
Rect2 base_rect = Rect2(joystick_pos - Vector2(0.5, 0.5) * joystick_size, Vector2(joystick_size, joystick_size));
|
||||
if (joystick_mode == JOYSTICK_DYNAMIC || joystick_mode == JOYSTICK_FOLLOWING || (base_rect.has_point(touch->get_position()) && joystick_mode == JOYSTICK_FIXED)) {
|
||||
if (joystick_mode == JOYSTICK_DYNAMIC || joystick_mode == JOYSTICK_FOLLOWING) {
|
||||
joystick_pos = touch->get_position();
|
||||
}
|
||||
|
||||
emit_signal(SceneStringName(pressed));
|
||||
|
||||
is_pressed = true;
|
||||
touch_index = touch->get_index();
|
||||
_update_joystick(touch->get_position());
|
||||
}
|
||||
}
|
||||
} else if (touch->get_index() == touch_index) {
|
||||
is_pressed = false;
|
||||
emit_signal(SNAME("released"), input_vector);
|
||||
|
||||
if (!is_flick_canceled && !has_moved) {
|
||||
emit_signal(SNAME("tapped"));
|
||||
} else if (has_input && has_moved) {
|
||||
emit_signal(SNAME("flicked"), input_vector);
|
||||
}
|
||||
_reset();
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventScreenDrag> drag = p_event;
|
||||
if (drag.is_valid() && drag->get_index() == touch_index) {
|
||||
has_moved = true;
|
||||
_update_joystick(drag->get_position());
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualJoystick::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_DRAW: {
|
||||
if (!Engine::get_singleton()->is_editor_hint() && visibility == VISIBILITY_WHEN_TOUCHED && !is_pressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (joystick_texture.is_valid()) {
|
||||
Rect2 rect = Rect2(joystick_pos - Vector2(0.5, 0.5) * joystick_size, Vector2(joystick_size, joystick_size));
|
||||
draw_texture_rect(joystick_texture, rect);
|
||||
} else {
|
||||
draw_circle(joystick_pos, joystick_size * 0.5, is_pressed ? theme_cache.ring_pressed_color : theme_cache.ring_normal_color, false, joystick_size * 0.05, true);
|
||||
}
|
||||
|
||||
if (tip_texture.is_valid()) {
|
||||
Rect2 rect = Rect2(tip_pos - Vector2(0.5, 0.5) * tip_size, Vector2(tip_size, tip_size));
|
||||
draw_texture_rect(tip_texture, rect);
|
||||
} else {
|
||||
draw_circle(tip_pos, tip_size * 0.5, is_pressed ? theme_cache.tip_pressed_color : theme_cache.tip_normal_color, true, -1, true);
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
joystick_pos = get_size() * initial_offset_ratio;
|
||||
tip_pos = joystick_pos;
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_RESIZED: {
|
||||
_reset();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualJoystick::_update_joystick(const Vector2 &p_pos) {
|
||||
Vector2 offset = p_pos - joystick_pos;
|
||||
float length = offset.length();
|
||||
Vector2 direction = offset.normalized();
|
||||
|
||||
float clampzone_radius = joystick_size * 0.5f * clampzone_ratio;
|
||||
|
||||
if (joystick_mode == JOYSTICK_FOLLOWING && length > clampzone_radius && has_point(p_pos)) {
|
||||
joystick_pos = p_pos - direction * clampzone_radius;
|
||||
}
|
||||
|
||||
if (length > clampzone_radius) {
|
||||
length = clampzone_radius;
|
||||
offset = direction * length;
|
||||
}
|
||||
|
||||
tip_pos = joystick_pos + offset;
|
||||
|
||||
bool was_pressed = has_input;
|
||||
raw_input_vector = offset / clampzone_radius;
|
||||
if (length > deadzone_ratio * clampzone_radius) {
|
||||
has_input = true;
|
||||
float scaled = Math::inverse_lerp(deadzone_ratio * clampzone_radius, clampzone_radius, length);
|
||||
input_vector = direction * scaled;
|
||||
} else {
|
||||
has_input = false;
|
||||
input_vector = Vector2();
|
||||
}
|
||||
|
||||
if (!is_flick_canceled && was_pressed && !has_input) {
|
||||
is_flick_canceled = true;
|
||||
emit_signal(SNAME("flick_canceled"));
|
||||
} else if (is_flick_canceled && !was_pressed && has_input) {
|
||||
is_flick_canceled = false;
|
||||
}
|
||||
|
||||
_handle_input_actions();
|
||||
|
||||
queue_redraw();
|
||||
}
|
||||
|
||||
void VirtualJoystick::_handle_input_actions() {
|
||||
Input *input = Input::get_singleton();
|
||||
|
||||
if (input_vector.x >= 0.0f && input->is_action_pressed(action_left)) {
|
||||
input->action_release(action_left);
|
||||
}
|
||||
if (input_vector.x <= 0.0f && input->is_action_pressed(action_right)) {
|
||||
input->action_release(action_right);
|
||||
}
|
||||
if (input_vector.y >= 0.0f && input->is_action_pressed(action_up)) {
|
||||
input->action_release(action_up);
|
||||
}
|
||||
if (input_vector.y <= 0.0f && input->is_action_pressed(action_down)) {
|
||||
input->action_release(action_down);
|
||||
}
|
||||
|
||||
if (input_vector.x < 0.0f) {
|
||||
input->action_press(action_left, -input_vector.x);
|
||||
} else if (input_vector.x > 0.0f) {
|
||||
input->action_press(action_right, input_vector.x);
|
||||
}
|
||||
if (input_vector.y < 0.0f) {
|
||||
input->action_press(action_up, -input_vector.y);
|
||||
} else if (input_vector.y > 0.0f) {
|
||||
input->action_press(action_down, input_vector.y);
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualJoystick::_reset() {
|
||||
is_pressed = false;
|
||||
has_input = false;
|
||||
has_moved = false;
|
||||
raw_input_vector = Vector2();
|
||||
input_vector = Vector2();
|
||||
is_flick_canceled = false;
|
||||
touch_index = -1;
|
||||
joystick_pos = get_size() * initial_offset_ratio;
|
||||
tip_pos = joystick_pos;
|
||||
|
||||
Input *input = Input::get_singleton();
|
||||
for (const StringName &action : { action_left, action_right, action_down, action_up }) {
|
||||
if (input->is_action_pressed(action)) {
|
||||
input->action_release(action);
|
||||
}
|
||||
}
|
||||
|
||||
queue_redraw();
|
||||
}
|
||||
|
||||
void VirtualJoystick::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_joystick_mode", "mode"), &VirtualJoystick::set_joystick_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_joystick_mode"), &VirtualJoystick::get_joystick_mode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_joystick_size", "size"), &VirtualJoystick::set_joystick_size);
|
||||
ClassDB::bind_method(D_METHOD("get_joystick_size"), &VirtualJoystick::get_joystick_size);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_tip_size", "size"), &VirtualJoystick::set_tip_size);
|
||||
ClassDB::bind_method(D_METHOD("get_tip_size"), &VirtualJoystick::get_tip_size);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_deadzone_ratio", "ratio"), &VirtualJoystick::set_deadzone_ratio);
|
||||
ClassDB::bind_method(D_METHOD("get_deadzone_ratio"), &VirtualJoystick::get_deadzone_ratio);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_clampzone_ratio", "ratio"), &VirtualJoystick::set_clampzone_ratio);
|
||||
ClassDB::bind_method(D_METHOD("get_clampzone_ratio"), &VirtualJoystick::get_clampzone_ratio);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_initial_offset_ratio", "ratio"), &VirtualJoystick::set_initial_offset_ratio);
|
||||
ClassDB::bind_method(D_METHOD("get_initial_offset_ratio"), &VirtualJoystick::get_initial_offset_ratio);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_action_left", "action"), &VirtualJoystick::set_action_left);
|
||||
ClassDB::bind_method(D_METHOD("get_action_left"), &VirtualJoystick::get_action_left);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_action_right", "action"), &VirtualJoystick::set_action_right);
|
||||
ClassDB::bind_method(D_METHOD("get_action_right"), &VirtualJoystick::get_action_right);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_action_up", "action"), &VirtualJoystick::set_action_up);
|
||||
ClassDB::bind_method(D_METHOD("get_action_up"), &VirtualJoystick::get_action_up);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_action_down", "action"), &VirtualJoystick::set_action_down);
|
||||
ClassDB::bind_method(D_METHOD("get_action_down"), &VirtualJoystick::get_action_down);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_visibility_mode", "mode"), &VirtualJoystick::set_visibility_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_visibility_mode"), &VirtualJoystick::get_visibility_mode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_joystick_texture", "texture"), &VirtualJoystick::set_joystick_texture);
|
||||
ClassDB::bind_method(D_METHOD("get_joystick_texture"), &VirtualJoystick::get_joystick_texture);
|
||||
ClassDB::bind_method(D_METHOD("set_tip_texture", "texture"), &VirtualJoystick::set_tip_texture);
|
||||
ClassDB::bind_method(D_METHOD("get_tip_texture"), &VirtualJoystick::get_tip_texture);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "joystick_mode", PROPERTY_HINT_ENUM, "Fixed,Dynamic,Following"), "set_joystick_mode", "get_joystick_mode");
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "joystick_size", PROPERTY_HINT_RANGE, "10,500,1"), "set_joystick_size", "get_joystick_size");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tip_size", PROPERTY_HINT_RANGE, "5,250,1"), "set_tip_size", "get_tip_size");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "deadzone_ratio", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_deadzone_ratio", "get_deadzone_ratio");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "clampzone_ratio", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_clampzone_ratio", "get_clampzone_ratio");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "initial_offset_ratio", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_initial_offset_ratio", "get_initial_offset_ratio");
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "action_left", PROPERTY_HINT_INPUT_NAME, "show_builtin,loose_mode"), "set_action_left", "get_action_left");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "action_right", PROPERTY_HINT_INPUT_NAME, "show_builtin,loose_mode"), "set_action_right", "get_action_right");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "action_up", PROPERTY_HINT_INPUT_NAME, "show_builtin,loose_mode"), "set_action_up", "get_action_up");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "action_down", PROPERTY_HINT_INPUT_NAME, "show_builtin,loose_mode"), "set_action_down", "get_action_down");
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "visibility_mode", PROPERTY_HINT_ENUM, "Always,When Touched"), "set_visibility_mode", "get_visibility_mode");
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "joystick_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_joystick_texture", "get_joystick_texture");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tip_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_tip_texture", "get_tip_texture");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("pressed"));
|
||||
ADD_SIGNAL(MethodInfo("tapped"));
|
||||
ADD_SIGNAL(MethodInfo("released", PropertyInfo(Variant::VECTOR2, "input_vector")));
|
||||
ADD_SIGNAL(MethodInfo("flicked", PropertyInfo(Variant::VECTOR2, "input_vector")));
|
||||
ADD_SIGNAL(MethodInfo("flick_canceled"));
|
||||
|
||||
BIND_ENUM_CONSTANT(JOYSTICK_FIXED);
|
||||
BIND_ENUM_CONSTANT(JOYSTICK_DYNAMIC);
|
||||
BIND_ENUM_CONSTANT(JOYSTICK_FOLLOWING);
|
||||
BIND_ENUM_CONSTANT(VISIBILITY_ALWAYS);
|
||||
BIND_ENUM_CONSTANT(VISIBILITY_WHEN_TOUCHED);
|
||||
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, VirtualJoystick, ring_normal_color);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, VirtualJoystick, tip_normal_color);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, VirtualJoystick, ring_pressed_color);
|
||||
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, VirtualJoystick, tip_pressed_color);
|
||||
}
|
||||
|
||||
Vector2 VirtualJoystick::get_joystick_position() const {
|
||||
return joystick_pos;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_joystick_size(float p_size) {
|
||||
if (joystick_size == p_size) {
|
||||
return;
|
||||
}
|
||||
joystick_size = p_size;
|
||||
_reset();
|
||||
}
|
||||
|
||||
float VirtualJoystick::get_joystick_size() const {
|
||||
return joystick_size;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_tip_size(float p_size) {
|
||||
if (tip_size == p_size) {
|
||||
return;
|
||||
}
|
||||
tip_size = p_size;
|
||||
_reset();
|
||||
}
|
||||
|
||||
float VirtualJoystick::get_tip_size() const {
|
||||
return tip_size;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_deadzone_ratio(float p_ratio) {
|
||||
deadzone_ratio = p_ratio;
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
queue_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
float VirtualJoystick::get_deadzone_ratio() const {
|
||||
return deadzone_ratio;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_clampzone_ratio(float p_ratio) {
|
||||
clampzone_ratio = p_ratio;
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
queue_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
float VirtualJoystick::get_clampzone_ratio() const {
|
||||
return clampzone_ratio;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_initial_offset_ratio(const Vector2 &p_ratio) {
|
||||
if (initial_offset_ratio == p_ratio) {
|
||||
return;
|
||||
}
|
||||
initial_offset_ratio = p_ratio;
|
||||
_reset();
|
||||
}
|
||||
|
||||
Vector2 VirtualJoystick::get_initial_offset_ratio() const {
|
||||
return initial_offset_ratio;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_joystick_mode(JoystickMode p_mode) {
|
||||
joystick_mode = p_mode;
|
||||
}
|
||||
|
||||
VirtualJoystick::JoystickMode VirtualJoystick::get_joystick_mode() const {
|
||||
return joystick_mode;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_action_left(const StringName &p_action) {
|
||||
action_left = p_action;
|
||||
}
|
||||
|
||||
StringName VirtualJoystick::get_action_left() const {
|
||||
return action_left;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_action_right(const StringName &p_action) {
|
||||
action_right = p_action;
|
||||
}
|
||||
|
||||
StringName VirtualJoystick::get_action_right() const {
|
||||
return action_right;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_action_up(const StringName &p_action) {
|
||||
action_up = p_action;
|
||||
}
|
||||
|
||||
StringName VirtualJoystick::get_action_up() const {
|
||||
return action_up;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_action_down(const StringName &p_action) {
|
||||
action_down = p_action;
|
||||
}
|
||||
|
||||
StringName VirtualJoystick::get_action_down() const {
|
||||
return action_down;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_visibility_mode(VisibilityMode p_mode) {
|
||||
visibility = p_mode;
|
||||
}
|
||||
|
||||
VirtualJoystick::VisibilityMode VirtualJoystick::get_visibility_mode() const {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_joystick_texture(const Ref<Texture2D> &p_texture) {
|
||||
if (joystick_texture == p_texture) {
|
||||
return;
|
||||
}
|
||||
joystick_texture = p_texture;
|
||||
queue_redraw();
|
||||
}
|
||||
|
||||
Ref<Texture2D> VirtualJoystick::get_joystick_texture() const {
|
||||
return joystick_texture;
|
||||
}
|
||||
|
||||
void VirtualJoystick::set_tip_texture(const Ref<Texture2D> &p_texture) {
|
||||
if (tip_texture == p_texture) {
|
||||
return;
|
||||
}
|
||||
tip_texture = p_texture;
|
||||
queue_redraw();
|
||||
}
|
||||
|
||||
Ref<Texture2D> VirtualJoystick::get_tip_texture() const {
|
||||
return tip_texture;
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/**************************************************************************/
|
||||
/* virtual_joystick.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 VirtualJoystick : public Control {
|
||||
GDCLASS(VirtualJoystick, Control);
|
||||
|
||||
public:
|
||||
enum JoystickMode {
|
||||
JOYSTICK_FIXED,
|
||||
JOYSTICK_DYNAMIC,
|
||||
JOYSTICK_FOLLOWING,
|
||||
};
|
||||
|
||||
enum VisibilityMode {
|
||||
VISIBILITY_ALWAYS,
|
||||
VISIBILITY_WHEN_TOUCHED,
|
||||
};
|
||||
|
||||
private:
|
||||
JoystickMode joystick_mode = JOYSTICK_FIXED;
|
||||
float joystick_size = 100.0f;
|
||||
float tip_size = 50.0f;
|
||||
float deadzone_ratio = 0.0f;
|
||||
float clampzone_ratio = 1.0f;
|
||||
Vector2 initial_offset_ratio = Vector2(0.5, 0.5);
|
||||
StringName action_left = "ui_left";
|
||||
StringName action_right = "ui_right";
|
||||
StringName action_up = "ui_up";
|
||||
StringName action_down = "ui_down";
|
||||
VisibilityMode visibility = VISIBILITY_ALWAYS;
|
||||
|
||||
struct ThemeCache {
|
||||
Color ring_normal_color;
|
||||
Color tip_normal_color;
|
||||
Color ring_pressed_color;
|
||||
Color tip_pressed_color;
|
||||
} theme_cache;
|
||||
|
||||
bool is_pressed = false;
|
||||
bool has_input = false;
|
||||
bool has_moved = false;
|
||||
Vector2 raw_input_vector;
|
||||
Vector2 input_vector;
|
||||
bool is_flick_canceled = false;
|
||||
int touch_index = -1;
|
||||
|
||||
Vector2 joystick_pos;
|
||||
Vector2 tip_pos;
|
||||
|
||||
Ref<Texture2D> joystick_texture;
|
||||
Ref<Texture2D> tip_texture;
|
||||
|
||||
void _update_joystick(const Vector2 &p_pos);
|
||||
void _handle_input_actions();
|
||||
void _reset();
|
||||
|
||||
protected:
|
||||
virtual void gui_input(const Ref<InputEvent> &p_event) override;
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
Vector2 get_joystick_position() const;
|
||||
|
||||
void set_joystick_mode(JoystickMode p_mode);
|
||||
JoystickMode get_joystick_mode() const;
|
||||
|
||||
void set_joystick_size(float p_size);
|
||||
float get_joystick_size() const;
|
||||
|
||||
void set_tip_size(float p_size);
|
||||
float get_tip_size() const;
|
||||
|
||||
void set_deadzone_ratio(float p_ratio);
|
||||
float get_deadzone_ratio() const;
|
||||
|
||||
void set_clampzone_ratio(float p_ratio);
|
||||
float get_clampzone_ratio() const;
|
||||
|
||||
void set_initial_offset_ratio(const Vector2 &p_ratio);
|
||||
Vector2 get_initial_offset_ratio() const;
|
||||
|
||||
void set_action_left(const StringName &p_action);
|
||||
StringName get_action_left() const;
|
||||
void set_action_right(const StringName &p_action);
|
||||
StringName get_action_right() const;
|
||||
void set_action_up(const StringName &p_action);
|
||||
StringName get_action_up() const;
|
||||
void set_action_down(const StringName &p_action);
|
||||
StringName get_action_down() const;
|
||||
|
||||
void set_visibility_mode(VisibilityMode p_mode);
|
||||
VisibilityMode get_visibility_mode() const;
|
||||
|
||||
void set_joystick_texture(const Ref<Texture2D> &p_texture);
|
||||
Ref<Texture2D> get_joystick_texture() const;
|
||||
void set_tip_texture(const Ref<Texture2D> &p_texture);
|
||||
Ref<Texture2D> get_tip_texture() const;
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(VirtualJoystick::JoystickMode);
|
||||
VARIANT_ENUM_CAST(VirtualJoystick::VisibilityMode);
|
||||
|
|
@ -94,6 +94,7 @@
|
|||
#include "scene/gui/texture_rect.h"
|
||||
#include "scene/gui/tree.h"
|
||||
#include "scene/gui/video_stream_player.h"
|
||||
#include "scene/gui/virtual_joystick.h"
|
||||
#include "scene/main/canvas_item.h"
|
||||
#include "scene/main/canvas_layer.h"
|
||||
#include "scene/main/http_request.h"
|
||||
|
|
@ -556,6 +557,8 @@ void register_scene_types() {
|
|||
GDREGISTER_CLASS(FoldableGroup);
|
||||
GDREGISTER_CLASS(FoldableContainer);
|
||||
|
||||
GDREGISTER_CLASS(VirtualJoystick);
|
||||
|
||||
OS::get_singleton()->yield(); // may take time to init
|
||||
|
||||
int swap_cancel_ok = GLOBAL_DEF(PropertyInfo(Variant::INT, "gui/common/swap_cancel_ok", PROPERTY_HINT_ENUM, "Auto,Cancel First,OK First"), 0);
|
||||
|
|
|
|||
Loading…
Reference in New Issue