0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Godotで複数指が触っている物体の検出をする

Posted at

最初に

あまりにもGodotのスクリーンタッチに関する情報が少なくて苦戦したので、これが助けになるかはわかりませんが記事を書こうと思いました。

環境

  • Godot 4.2.1
  • Windows 11

経緯

GarageBandのピアノや、音ゲーのようなものを作りたいと思いGodotを勉強していました。しかし、マウスがそのオブジェクトを触っている状態かどうかという情報を入手する簡単な関数がないので、「鍵盤が押されている」「レーンを触っている」状態を入手することが非常に困難でした。
その状態を入手する方法を頑張って作ったので記していきます。

実際に作ったもの

動画の載せ方を知らないのでツイッターからになってしまいますが、このようなデモを作ってみました。

GitHubにもデモを載せておきました。初めてGitHub使ったので間違っているかもしれません。

作成

設定変更

コードに移る前にセッティングやノードなどを配置していきます。
まずProject Settings >> Input Devicesに行き、
Emulate Mouse From Touchを無効にします。
image.png

タッチ判定ノードを作成

タッチ判定で色が変わるノードを作成していきます。
ノード構成はこのようになっています。形は好きな形で大丈夫です。
image.png

MeshInstance3Dについては、色を変えないといけないので以下のようにSurface Material OverrideStandard Material 3Dを追加します。
image.png

ここで注意なのですが、Standard Material 3DResourceLocal to SceneをONにしないとCollideObjectの色が連動して変わってしまいます。
image.png

外観はこのようになりました。
image.png
白い[]はtouchingIndicesLabelです。

メインノードを作成

ノード構成はこのようになっています。

image.png
上で作ったタッチ判定ノードのCollideObjectCollideObjectsというNode3Dでひとまとめにします。
CollideObjectが一つ外にあるのは、最終的にCollideObjects子ノードでないと判定されないかどうかを確認するためです。

配置はこのようにしました。
image.png

スクリプトをアタッチ

CollideObjectに以下のスクリプトをアタッチします。

collide_object.gd
extends StaticBody3D

@onready var mesh_instance_3d = $MeshInstance3D
@onready var touching_indices_label = $touchingIndicesLabel
@onready var material = mesh_instance_3d.get_surface_override_material(0)

const OFF_COLOR = Color(0, 0, 0)
const ON_COLOR = Color(255, 255, 255)

var touchingIndices = {}
var was_touching = false

func _ready():
	changeColor(OFF_COLOR)
	
func changeColor(color):
	material.albedo_color = color
	mesh_instance_3d.set_surface_override_material(0, material)

func screenTouchUpdate(event, colliding:bool):
	var val = event.index
	
	if colliding:
		touchingIndices[val] = event.position
	else:
		touchingIndices.erase(val)
		
	var is_touching = not touchingIndices.is_empty()
	if was_touching != is_touching:
		if is_touching:#just pressed / entered
			changeColor(ON_COLOR)
		else:#just released / left
			changeColor(OFF_COLOR)
			
	was_touching = is_touching
	touching_indices_label.text = str(touchingIndices.keys())

メインノードのCollideObjectsに以下のスクリプトをアタッチします。

CollideObjects.gd
extends Node3D

@onready var main_camera = $"../MainCamera"


func getIntersect(pos):
   var worldspace = get_world_3d().direct_space_state
   var start = main_camera.project_ray_origin(pos)
   var end = main_camera.project_position(pos, 1000)
   var parameters = PhysicsRayQueryParameters3D.create(start, end)
   var result = worldspace.intersect_ray(parameters)
   
   return result
   
func _input(event):
   #mouse debug
   if event is InputEventMouse:
   	if event.is_pressed():
   		print(getIntersect(event.position))
   
   elif event is InputEventScreenTouch or event is InputEventScreenDrag:
   	get_viewport().set_input_as_handled()
   	var collider = null
   	if event is InputEventScreenTouch and event.is_released():#touch released
   		collider = null
   	else:#touch pressed / entered
   		var intersect = getIntersect(event.position)
   		if not intersect.is_empty():
   			collider = intersect["collider"]
   			
   		
   	for collideObject in get_children():
   		var colliding = collider == collideObject
   		collideObject.screenTouchUpdate(event, colliding)

これで完成です。

参考にした情報

上記のgetIntersect関数に関してはこの動画を参考にしました。

複数指のトラッキングについてはこのサイトを参考にしました。

その他

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?