Browse Source

Examples about (multi)touch events

Pedro J. Estébanez 7 years ago
parent
commit
b6db599fa1

+ 151 - 0
misc/multitouch_cubes/CubeScene.tscn

@@ -0,0 +1,151 @@
+[gd_scene load_steps=3 format=1]
+
+[sub_resource type="FixedMaterial" id=1]
+
+flags/visible = true
+flags/double_sided = false
+flags/invert_faces = false
+flags/unshaded = false
+flags/on_top = false
+flags/lightmap_on_uv2 = true
+flags/colarray_is_srgb = true
+params/blend_mode = 0
+params/depth_draw = 1
+params/line_width = 0.0
+fixed_flags/use_alpha = false
+fixed_flags/use_color_array = false
+fixed_flags/use_point_size = false
+fixed_flags/discard_alpha = false
+fixed_flags/use_xy_normalmap = false
+params/diffuse = Color( 0.259476, 0.699219, 0.379718, 1 )
+params/specular = Color( 1, 1, 1, 1 )
+params/emission = Color( 0, 0, 0, 1 )
+params/specular_exp = 40
+params/detail_mix = 1.0
+params/normal_depth = 1
+params/shader = 0
+params/shader_param = 0.5
+params/glow = 0
+params/point_size = 1.0
+uv_xform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )
+textures/diffuse_tc = 0
+textures/detail_tc = 0
+textures/specular_tc = 0
+textures/emission_tc = 0
+textures/specular_exp_tc = 0
+textures/glow_tc = 0
+textures/normal_tc = 0
+textures/shade_param_tc = 0
+
+[sub_resource type="Environment" id=2]
+
+ambient_light/enabled = true
+ambient_light/color = Color( 0.601563, 0.696429, 1, 1 )
+ambient_light/energy = 0.5
+fxaa/enabled = true
+background/mode = 1
+background/color = Color( 0, 0, 0, 1 )
+background/energy = 1.0
+background/scale = 1.0
+background/glow = 0.0
+background/canvas_max_layer = null
+glow/enabled = false
+glow/blur_passes = 1
+glow/blur_scale = 1
+glow/blur_strength = 1
+glow/blur_blend_mode = null
+glow/bloom = 0.0
+glow/bloom_treshold = 0.5
+dof_blur/enabled = false
+dof_blur/blur_passes = 1
+dof_blur/begin = 100.0
+dof_blur/range = 10.0
+hdr/enabled = false
+hdr/tonemapper = 0
+hdr/exposure = 0.4
+hdr/white = 1.0
+hdr/glow_treshold = 0.95
+hdr/glow_scale = 0.2
+hdr/min_luminance = 0.4
+hdr/max_luminance = 8.0
+hdr/exposure_adj_speed = 0.5
+fog/enabled = false
+fog/begin = 100.0
+fog/begin_color = Color( 0, 0, 0, 1 )
+fog/end_color = Color( 0, 0, 0, 1 )
+fog/attenuation = 1.0
+fog/bg = true
+bcs/enabled = false
+bcs/brightness = 1.0
+bcs/contrast = 1.0
+bcs/saturation = 1.0
+srgb/enabled = false
+
+[node name="Spatial" type="Spatial"]
+
+_import_transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )
+
+[node name="TestCube" type="TestCube" parent="."]
+
+_import_transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )
+transform/local = Transform( 0.707107, 0, -0.707107, -0.353553, 0.866025, -0.353553, 0.612372, 0.5, 0.612372, 0, 0, 0 )
+layers = 1
+geometry/visible = true
+geometry/material_override = SubResource( 1 )
+geometry/cast_shadow = 1
+geometry/receive_shadows = true
+geometry/range_begin = 0.0
+geometry/range_end = 0.0
+geometry/extra_cull_margin = 0.0
+geometry/billboard = false
+geometry/billboard_y = false
+geometry/depth_scale = false
+geometry/visible_in_all_rooms = false
+geometry/use_baked_light = false
+geometry/baked_light_tex_id = 0
+
+[node name="Camera" type="Camera" parent="."]
+
+_import_transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )
+transform/local = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 7.09558 )
+projection = 0
+fov = 50.0
+near = 0.1
+far = 100.0
+keep_aspect = 1
+current = false
+visible_layers = 1048575
+environment = null
+h_offset = 0.0
+v_offset = 0.0
+
+[node name="DirectionalLight" type="DirectionalLight" parent="."]
+
+_import_transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )
+transform/local = Transform( 0.926535, 0.11439, -0.358396, 0.199614, 0.658013, 0.726067, 0.318884, -0.744267, 0.586839, 0, 4.14991, 0 )
+layers = 1
+params/enabled = true
+params/editor_only = false
+params/bake_mode = 0
+params/energy = 1.0
+colors/diffuse = Color( 1, 1, 1, 1 )
+colors/specular = Color( 1, 1, 1, 1 )
+shadow/shadow = false
+shadow/darkening = 0.0
+shadow/z_offset = 0.05
+shadow/z_slope_scale = 0.0
+shadow/esm_multiplier = 60.0
+shadow/blur_passes = 1.0
+projector = null
+operator = 0
+shadow/mode = 0
+shadow/max_distance = 0.0
+shadow/split_weight = 0.5
+shadow/zoffset_scale = 2.0
+
+[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
+
+_import_transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )
+environment = SubResource( 2 )
+
+

+ 133 - 0
misc/multitouch_cubes/GestureArea.gd

@@ -0,0 +1,133 @@
+extends Control
+
+export(NodePath) var target
+export var min_scale = 0.1
+export var max_scale = 3.0
+export var one_finger_rot_x = true
+export var one_finger_rot_y = true
+export var two_fingers_rot_z = true
+export var two_fingers_zoom = true
+
+var base_state
+var curr_state
+
+var target_node
+
+# We keep here a copy of the state before the number of fingers changed to avoid accumulation errors
+var base_xform
+
+func _ready():
+	base_state = {}
+	curr_state = {}
+	target_node = get_node(target)
+	set_process_unhandled_input(true)
+
+# Using unhandled input since it's the method that has empirically proven to work the best
+func _unhandled_input(event):
+	# We must start touching inside, but we can drag or unpress outside
+	if !(event.type == InputEvent.SCREEN_DRAG ||
+		(event.type == InputEvent.SCREEN_TOUCH && (!event.pressed || get_global_rect().has_point(Vector2(event.x, event.y))))):
+		return
+
+	var finger_count_changed = false
+	var finger_count = base_state.size()
+
+	if finger_count == 0:
+		# No fingers => Accept press
+
+		if event.type == InputEvent.SCREEN_TOUCH:
+			if event.pressed:
+				# A finger started touching
+
+				base_state = {
+					event.index: Vector2(event.x, event.y),
+				}
+
+	elif finger_count == 1:
+		# One finger => For rotating around X and Y
+		# Accept one more press, unpress or drag
+
+		if event.type == InputEvent.SCREEN_TOUCH:
+			if event.pressed:
+				# One more finger started touching
+
+				# Reset the base state to the only current and the new fingers
+				base_state = {
+					curr_state.keys()[0]: curr_state.values()[0],
+					event.index: Vector2(event.x, event.y),
+				}
+			else:
+				if base_state.has(event.index):
+					# Only touching finger released
+
+					base_state.clear()
+
+		elif event.type == InputEvent.SCREEN_DRAG:
+			if curr_state.has(event.index):
+				# Touching finger dragged
+
+				var unit_drag = _px2unit(base_state[base_state.keys()[0]] - Vector2(event.x, event.y))
+				if one_finger_rot_x:
+					target_node.global_rotate(Vector3(0, 1, 0), deg2rad(180.0 * unit_drag.x))
+				if one_finger_rot_y:
+					target_node.global_rotate(Vector3(1, 0, 0), deg2rad(180.0 * unit_drag.y))
+				# Since rotating around two axes, we have to reset the base constantly
+				curr_state[event.index] = Vector2(event.x, event.y)
+				base_state[event.index] = Vector2(event.x, event.y)
+				base_xform = target_node.get_transform()
+
+	elif finger_count == 2:
+		# Two fingers => To pinch-zoom and rotate around Z
+		# Accept unpress or drag
+
+		if event.type == InputEvent.SCREEN_TOUCH:
+			if !event.pressed && base_state.has(event.index):
+				# Some known touching finger released
+
+				# Remove released finger from the base state
+				base_state.erase(event.index)
+				# Reset the base state to the now only toyching finger
+				base_state = {
+					curr_state.keys()[0]: curr_state.values()[0],
+				}
+
+		elif event.type == InputEvent.SCREEN_DRAG:
+			if curr_state.has(event.index):
+				# Some known touching finger dragged
+
+				# Update
+				curr_state[event.index] = Vector2(event.x, event.y)
+
+				# Compute base and current inter-finger vectors
+				var base_segment = base_state[base_state.keys()[0]] - base_state[base_state.keys()[1]]
+				var new_segment = curr_state[curr_state.keys()[0]] - curr_state[curr_state.keys()[1]]
+
+				# Get the base scale from the base matrix
+				var base_scale = Vector3(base_xform.basis.x.x, base_xform.basis.y.y, base_xform.basis.z.z).length()
+
+				if two_fingers_zoom:
+					# Compute the new scale limiting it and taking into account the base scale
+					var new_scale = clamp(base_scale * (new_segment.length() / base_segment.length()), min_scale, max_scale) / base_scale
+					target_node.set_transform(base_xform.scaled(new_scale * Vector3(1, 1, 1)))
+				else:
+					target_node.set_transform(base_xform)
+
+				if two_fingers_rot_z:
+					# Apply rotation between base inter-finger vector and the current one
+					var rot = new_segment.angle_to(base_segment)
+					target_node.global_rotate(Vector3(0, 0, 1), rot)
+
+	# Finger count changed?
+	if base_state.size() != finger_count:
+		# Copy new base state to the current state
+		curr_state = {}
+		for idx in base_state.keys():
+			curr_state[idx] = base_state[idx]
+		# Remember the base transform
+		base_xform = target_node.get_transform()
+
+# Converts a vector in pixels to a unitary magnitude,
+# considering the number of pixels of the shorter axis is the unit
+func _px2unit(v):
+	var shortest = min(get_size().x, get_size().y)
+	return v * (1.0 / shortest)

+ 256 - 0
misc/multitouch_cubes/Main.tscn

@@ -0,0 +1,256 @@
+[gd_scene load_steps=3 format=1]
+
+[ext_resource path="res://GestureArea.gd" type="Script" id=1]
+[ext_resource path="res://CubeScene.tscn" type="PackedScene" id=2]
+
+[node name="VBoxContainer" type="VBoxContainer"]
+
+anchor/right = 1
+anchor/bottom = 1
+focus/ignore_mouse = false
+focus/stop_mouse = false
+size_flags/horizontal = 2
+size_flags/vertical = 2
+margin/left = 0.0
+margin/top = 0.0
+margin/right = 0.0
+margin/bottom = 0.0
+alignment = 0
+
+[node name="HBoxContainer" type="HBoxContainer" parent="."]
+
+focus/ignore_mouse = false
+focus/stop_mouse = false
+size_flags/horizontal = 3
+size_flags/vertical = 3
+margin/left = 0.0
+margin/top = 0.0
+margin/right = 512.0
+margin/bottom = 254.0
+alignment = 0
+
+[node name="GestureArea" type="Control" parent="HBoxContainer"]
+
+focus/ignore_mouse = false
+focus/stop_mouse = true
+size_flags/horizontal = 3
+size_flags/vertical = 3
+margin/left = 0.0
+margin/top = 0.0
+margin/right = 254.0
+margin/bottom = 254.0
+script/script = ExtResource( 1 )
+target = NodePath("Viewport/Spatial/TestCube")
+min_scale = 0.1
+max_scale = 3.0
+one_finger_rot_x = true
+one_finger_rot_y = false
+two_fingers_rot_z = false
+two_fingers_zoom = false
+
+[node name="Viewport" type="Viewport" parent="HBoxContainer/GestureArea"]
+
+rect = Rect2( 0, 0, 254, 254 )
+own_world = true
+world = null
+transparent_bg = false
+render_target/enabled = false
+render_target/v_flip = false
+render_target/clear_on_new_frame = true
+render_target/filter = false
+render_target/gen_mipmaps = false
+render_target/update_mode = 2
+audio_listener/enable_2d = false
+audio_listener/enable_3d = false
+physics/object_picking = false
+gui/disable_input = false
+
+[node name="Spatial" parent="HBoxContainer/GestureArea/Viewport" instance=ExtResource( 2 )]
+
+[node name="Label" type="Label" parent="HBoxContainer/GestureArea"]
+
+focus/ignore_mouse = true
+focus/stop_mouse = true
+size_flags/horizontal = 2
+size_flags/vertical = 0
+margin/left = 7.0
+margin/top = 6.0
+margin/right = 157.0
+margin/bottom = 20.0
+text = "One-finger rot around X"
+percent_visible = 1.0
+lines_skipped = 0
+max_lines_visible = -1
+
+[node name="GestureArea_1" type="Control" parent="HBoxContainer"]
+
+focus/ignore_mouse = false
+focus/stop_mouse = true
+size_flags/horizontal = 3
+size_flags/vertical = 3
+margin/left = 258.0
+margin/top = 0.0
+margin/right = 512.0
+margin/bottom = 254.0
+script/script = ExtResource( 1 )
+target = NodePath("Viewport/Spatial/TestCube")
+min_scale = 0.1
+max_scale = 3.0
+one_finger_rot_x = true
+one_finger_rot_y = true
+two_fingers_rot_z = false
+two_fingers_zoom = false
+
+[node name="Viewport" type="Viewport" parent="HBoxContainer/GestureArea_1"]
+
+rect = Rect2( 0, 0, 254, 254 )
+own_world = true
+world = null
+transparent_bg = false
+render_target/enabled = false
+render_target/v_flip = false
+render_target/clear_on_new_frame = true
+render_target/filter = false
+render_target/gen_mipmaps = false
+render_target/update_mode = 2
+audio_listener/enable_2d = false
+audio_listener/enable_3d = false
+physics/object_picking = false
+gui/disable_input = false
+
+[node name="Spatial" parent="HBoxContainer/GestureArea_1/Viewport" instance=ExtResource( 2 )]
+
+[node name="Label2" type="Label" parent="HBoxContainer/GestureArea_1"]
+
+focus/ignore_mouse = true
+focus/stop_mouse = true
+size_flags/horizontal = 2
+size_flags/vertical = 0
+margin/left = 15.0
+margin/top = 6.0
+margin/right = 55.0
+margin/bottom = 20.0
+text = "One-finger rot around X and Y"
+percent_visible = 1.0
+lines_skipped = 0
+max_lines_visible = -1
+
+[node name="HBoxContainer_1" type="HBoxContainer" parent="."]
+
+focus/ignore_mouse = false
+focus/stop_mouse = false
+size_flags/horizontal = 3
+size_flags/vertical = 3
+margin/left = 0.0
+margin/top = 258.0
+margin/right = 512.0
+margin/bottom = 512.0
+alignment = 0
+
+[node name="GestureArea" type="Control" parent="HBoxContainer_1"]
+
+focus/ignore_mouse = false
+focus/stop_mouse = true
+size_flags/horizontal = 3
+size_flags/vertical = 3
+margin/left = 0.0
+margin/top = 0.0
+margin/right = 254.0
+margin/bottom = 254.0
+script/script = ExtResource( 1 )
+target = NodePath("Viewport/Spatial/TestCube")
+min_scale = 0.1
+max_scale = 3.0
+one_finger_rot_x = true
+one_finger_rot_y = true
+two_fingers_rot_z = true
+two_fingers_zoom = false
+
+[node name="Viewport" type="Viewport" parent="HBoxContainer_1/GestureArea"]
+
+rect = Rect2( 0, 0, 254, 254 )
+own_world = true
+world = null
+transparent_bg = false
+render_target/enabled = false
+render_target/v_flip = false
+render_target/clear_on_new_frame = true
+render_target/filter = false
+render_target/gen_mipmaps = false
+render_target/update_mode = 2
+audio_listener/enable_2d = false
+audio_listener/enable_3d = false
+physics/object_picking = false
+gui/disable_input = false
+
+[node name="Spatial" parent="HBoxContainer_1/GestureArea/Viewport" instance=ExtResource( 2 )]
+
+[node name="Label2" type="Label" parent="HBoxContainer_1/GestureArea"]
+
+focus/ignore_mouse = true
+focus/stop_mouse = true
+size_flags/horizontal = 2
+size_flags/vertical = 0
+margin/left = 7.0
+margin/top = 12.0
+margin/right = 47.0
+margin/bottom = 26.0
+text = "One-finger X/Y rot + two-finger Z rot"
+percent_visible = 1.0
+lines_skipped = 0
+max_lines_visible = -1
+
+[node name="GestureArea_1" type="Control" parent="HBoxContainer_1"]
+
+focus/ignore_mouse = false
+focus/stop_mouse = true
+size_flags/horizontal = 3
+size_flags/vertical = 3
+margin/left = 258.0
+margin/top = 0.0
+margin/right = 512.0
+margin/bottom = 254.0
+script/script = ExtResource( 1 )
+target = NodePath("Viewport/Spatial/TestCube")
+min_scale = 0.1
+max_scale = 3.0
+one_finger_rot_x = true
+one_finger_rot_y = true
+two_fingers_rot_z = true
+two_fingers_zoom = true
+
+[node name="Viewport" type="Viewport" parent="HBoxContainer_1/GestureArea_1"]
+
+rect = Rect2( 0, 0, 254, 254 )
+own_world = true
+world = null
+transparent_bg = false
+render_target/enabled = false
+render_target/v_flip = false
+render_target/clear_on_new_frame = true
+render_target/filter = false
+render_target/gen_mipmaps = false
+render_target/update_mode = 2
+audio_listener/enable_2d = false
+audio_listener/enable_3d = false
+physics/object_picking = false
+gui/disable_input = false
+
+[node name="Spatial" parent="HBoxContainer_1/GestureArea_1/Viewport" instance=ExtResource( 2 )]
+
+[node name="Label3" type="Label" parent="HBoxContainer_1/GestureArea_1"]
+
+focus/ignore_mouse = true
+focus/stop_mouse = true
+size_flags/horizontal = 2
+size_flags/vertical = 0
+margin/left = 15.0
+margin/top = 12.0
+margin/right = 55.0
+margin/bottom = 26.0
+text = "One-finger X/Y, two-finger Z + pinch"
+percent_visible = 1.0
+lines_skipped = 0
+max_lines_visible = -1
+
+

+ 18 - 0
misc/multitouch_cubes/engine.cfg

@@ -0,0 +1,18 @@
+[application]
+
+name="InteractiveCubes"
+main_scene="res://Main.tscn"
+icon="res://icon.png"
+
+[display]
+
+width=512
+height=512
+
+[physics_2d]
+
+motion_fix_enabled=true
+
+[render]
+
+default_clear_color=#ff1d2232

BIN
misc/multitouch_cubes/icon.png


+ 1 - 0
misc/multitouch_cubes/icon.png.flags

@@ -0,0 +1 @@
+gen_mipmaps=false

+ 23 - 0
misc/multitouch_view/Main.gd

@@ -0,0 +1,23 @@
+extends Node2D
+
+func _ready():
+	set_process(true)
+
+func _process(delta):
+	# To keep redrawing on every frame
+	update()
+
+func _draw():
+	# Get the touch helper singleton
+	var touch_helper = get_node("/root/TouchHelper")
+	# Draw every pointer as a circle
+	for ptr_id in touch_helper.state.keys():
+		var pos = touch_helper.state[ptr_id]
+		var color = _get_color_for_ptr_id(ptr_id)
+		color.a = 0.75
+		draw_circle(pos, 40.0, color)
+
+# Just a way of getting different colors
+func _get_color_for_ptr_id(id):
+	var x = (id % 7) + 1
+	return Color(float(bool(x & 1)), float(bool(x & 2)), float(bool(x & 4)))

+ 10 - 0
misc/multitouch_view/Main.tscn

@@ -0,0 +1,10 @@
+[gd_scene load_steps=2 format=1]
+
+[ext_resource path="res://Main.gd" type="Script" id=1]
+
+[node name="Main" type="Node2D"]
+
+visibility/blend_mode = 1
+script/script = ExtResource( 1 )
+
+

+ 45 - 0
misc/multitouch_view/TouchHelper.gd

@@ -0,0 +1,45 @@
+# This will track the position of every pointer in its public `state` property, which is a
+# Dictionary, in which each key is a pointer id (integer) and each value its position (Vector2).
+# It works by listening to input events not handled by other means.
+# It also remaps the pointer indices coming from the OS to the lowest available to be friendlier.
+# It can be conveniently setup as a singleton.
+
+extends Node
+
+var state = {}
+var _os2own = {}
+
+func _ready():
+	set_process_unhandled_input(true)
+
+func _unhandled_input(event):
+	if event.type == InputEvent.SCREEN_TOUCH:
+		if event.pressed:
+			# Down
+			if !_os2own.has(event.index): # Defensively discard index if already known
+				var ptr_id = _find_free_pointer_id()
+				state[ptr_id] = Vector2(event.x, event.y)
+				_os2own[event.index] = ptr_id
+		else:
+			# Up
+			if _os2own.has(event.index): # Defensively discard index if not known
+				var ptr_id = _os2own[event.index]
+				state.erase(ptr_id)
+				_os2own.erase(event.index)
+		return true
+
+	elif event.type == InputEvent.SCREEN_DRAG:
+		# Move
+		if _os2own.has(event.index): # Defensively discard index if not known
+			var ptr_id = _os2own[event.index]
+			state[ptr_id] = Vector2(event.x, event.y)
+		return true
+
+	return false
+
+func _find_free_pointer_id():
+	var used = state.keys()
+	var i = 0
+	while i in used:
+		i += 1
+	return i

+ 17 - 0
misc/multitouch_view/engine.cfg

@@ -0,0 +1,17 @@
+[application]
+
+name="TouchesView"
+main_scene="res://Main.tscn"
+icon="res://icon.png"
+
+[autoload]
+
+TouchHelper="*res://TouchHelper.gd"
+
+[physics_2d]
+
+motion_fix_enabled=true
+
+[render]
+
+default_clear_color=#ff1d2232

BIN
misc/multitouch_view/icon.png


+ 1 - 0
misc/multitouch_view/icon.png.flags

@@ -0,0 +1 @@
+gen_mipmaps=false