• 2D
  • move and click in the same time on touch screens

Hello :) I made a small game for testing in IOS. I need to move a gun left and right with one finger. The moving part was made by using the x mouse position when pressed and also the simulate mouse to touchscreen setting. So when I move one finger the gun slides with it. In the same time, I want use a second finger to touch the screen repeatedly to fire bullets. How could I achieve this?

You will probably need to use InputEventScreenTouch (documentation) and InputEventScreenDrag (documentation). You can track which touch is which using the provided index provided by both input events.

I made a tutorial on how to make a touchscreen joystick, which might help. It is probably a bit more complicated than necessary if the second finger/touch only fires bullets, but hopefully it can server as a reference on how to use InputEventScreenTouch and InputEventScreenDrag.

Hopefully this helps!

You dont need to do anything fancy to achieve this. First, you're using process to handle input. why not use _input? Second, how do you recognize the gestures? How do you know when the user swipe from when they double tap? You can with Input Events like mentioned above.

I'll throw in a Third just for the hell of it, This is bad game design. You're going to destroy someone's device if you force them to keep tapping to shoot. Why not just check for a hold instead of a tap? Its easier and its better.

@canvasbushi said: ... I'll throw in a Third just for the hell of it, This is bad game design. You're going to destroy someone's device if you force them to keep tapping to shoot. Why not just check for a hold instead of a tap? Its easier and its better.

I have played several games that require the user to tap rapidly/continuously, sometimes it is a fun addition and sometimes it isn't.

While tapping on a device may damage the device if the user is tapping really hard, it is unlikely to damage the device if the user is tapping normally. While I agree that adding the ability to hold instead of tap might make the game easier to play and would reduce the number of taps needed, for some games it might be better to tap. For example, a good reason to use a tap based system is if the projectile is different and/or is angled based on where you tap. While you could achieve this with a hold as well, the game might play better using taps instead.

Regardless, I don't think it is necessarily bad game design by default. I think for certain games either method, or even a completely different control scheme, would work just fine. :smile:

I can only give advice, its up to you if you want it or not. I'm not forcing you to buy it. I'll explain a little further altho i'm sure you'll still hold firm on your opinion. These tap games you're talking about are either outdated games or games that are primarily based on just randomly tapping.

From his description, its clearly a space shooter type game where the player would have to coordinate eye-hand frequently, tapping everytime u need to act would not only be tiring(and boring) but also an outdated design pattern for the genre.

TLDR; Tapping is for outdated games, newer titles use hold and players will come to expect this feature. I'm not forcing u to accept this, you can do whatever you want. Its just advice.

PS: Some developers have even gone as far as to make shooting automatic for a much more enjoyable experience and less intensive decision making on the player's side.

Hello, i will go to my pc in around 6 hours.

I have tryed the InputEventScreenTouch and InputEventScreenDrag methods, but only the drag one makes the action. The ScreenTouch one only teleport for a fraction of second the gun in the other position.

Maybe i have to dezactivate emulate mouse clicks? Didn’t tried that.

I inserted a “print drag” and “print touch” + event.index in bouth functions to see the indexes of two functions. The indexes grow fast and I don’t know how to handle them yet. Anyway, I repeat, the ScreenTouch even if it prints the test text it doesn’t fire the bullets. Also is there a just touch function? I mean like “just” click :) I have to code it, I think :)

Also the screentouch one is hard to acomplish because a small move of your tap will register as a drag one. The tests were made on a win10 touchscreen laptop.

I’m a newbe in godot and in coding in general, I thought that was a easy thing :) I will study the tutorial to understand how to finetune the thing for my needs.

Canvasbushi, I understand the ideea, but this game will not evolve yet in a real product :) I just want to learn technically if what I asked is possible just to understand the input tricks. I can see a situation where some kind of ammo is limited so the tap could be also an option in some moments :) But only for learning godot was the question :)

gaby424 you can set how long you want the swipe gesture. This is untested so... but it should give you an idea of how simple this is to do.

var swipe_start = null
var swipe_end = null

    func _input(event):
    	if event is InputEventMouseButton:
    		if event.pressed:
    			swipe_start = get_global_mouse_position()
    			print("down")
    		else:
    			swipe_end = get_global_mouse_position()
    			print("up")
    		if swipe_end.x - swipe_start.x > 100:
    			print("swipe right")
    		elif swipe_end.x - swipe_start.x < -100:
    			print("swipe left")
    		elif swipe_end.y - swipe_start.y > 100:
    			print("swipe down")
    		elif swipe_end.y - swipe_start.y < -100:
    			print("swipe up")
    		else:
    			print("tap")

@gaby424 said: Hello, i will go to my pc in around 6 hours.

I have tryed the InputEventScreenTouch and InputEventScreenDrag methods, but only the drag one makes the action. The ScreenTouch one only teleport for a fraction of second the gun in the other position.

Maybe i have to dezactivate emulate mouse clicks? Didn’t tried that.

Deactivating mouse clicks might help.

Are you trying to replicate the movement code above in mouse_position_handler? If so, the reason InputEventScreenTouch isn't working is because InputEventScreenTouch is only called on the initial touch, and only when the touch happens.

is_mouse_button_pressed returns true when the mouse button is just pressed, or held down. InputEventScreenTouch is only passed in _input when the touch/tap just happened. To make code like mouse_position_handler, you'll need to do something like this (untested):

# We need to track the index of the touch.
var first_touch_index = -1;

func _input(event):
	if (event is InputEventScreenTouch):
		# Do we already have a single touch?
		if (first_touch_index != -1):
			if (event.index == first_touch_index and event.pressed = false):
				# Touch released!
				first_touch_index = -1;
		else:
			# If we are not tracking a touch already, then start tracking this touch!
			# NOTE: This will not work for multiple touches. See next code example!
			first_touch_down = true;
			first_touch_index = event.index;
			
			# Move gun_x into position
			gun_x = event.position.x; # Might need to offset for size of gun
	
	elif (event is InputEventScreenDrag):
		# Is this event the touch we are following?
		if (event.index == first_touch_index):
			# Move gun_x into position
			gun_x = event.position.x; # Might need to offset for size of gun

I inserted a “print drag” and “print touch” + event.index in bouth functions to see the indexes of two functions. The indexes grow fast and I don’t know how to handle them yet. Anyway, I repeat, the ScreenTouch even if it prints the test text it doesn’t fire the bullets. Also is there a just touch function? I mean like “just” click :) I have to code it, I think :)

Also the screentouch one is hard to acomplish because a small move of your tap will register as a drag one. The tests were made on a win10 touchscreen laptop.

I’m a newbe in godot and in coding in general, I thought that was a easy thing :) I will study the tutorial to understand how to finetune the thing for my needs.

Hopefully the tutorial will help. Working with touchscreens can be complicated, especially depending on what you need to track and what you need it for.

I think, and granted I have not tested, but this code should work :smile:

extends Area2D

# Add other class variables (like bullet_class for example) here!

# We need to track the index of the touches.
var first_touch_index = -1;
var second_touch_index = -1;

func _ready():
	position.x = screensize_w/2;
	position.y=screensize_h - gunsize_h/2;

func _process(delta):
	keyboard_position_handler();

func keyboard_position_handler():
	if Input.is_key_pressed(KEY_LEFT):
		if gun__x > gunsize_h / 2:
			gun_x -= 5;
		else:
			gun_x = gunsize_w/2;
	if Input.is_key_pressed(KEY_RIGHT):
		if gun_x < screensize_w - gunsize_w / 2:
			gun_x += 5
		else:
			gun_x = screensize_w-gunsize_w/2

func fire_bullet():
	var bullet = bullet_class.instance();
	get_parent().add_child(bullet);

func _input(event):
	if (event is InputEventScreenTouch):
		# Is this event a press or a release?
		if (event.pressed == true):
			# If the event is a press, assign to either first_touch_index or second_touch_index
			if (first_touch_index == -1):
				first_touch_index = event.index;
				# Move the gun into position!
				gun_x = event.position.x;
			elif (second_touch_index == -1):
				second_touch_index = event.index;
				# Fire a bullet!
				fire_bullet();
			else:
				pass; # Already have two touches, no need to track more!
		else:
			# The touch is a release. Stop tracking the touch (if we are tracking it)
			if (event.index == first_touch_index):
				first_touch_index = -1;
			elif (event.index == second_touch_index):
				second_touch_index = -1;
			else:
				pass; # Not a touch we are tracking

		# Do we already have a single touch?
		if (first_touch_index != -1):
			if (event.index == first_touch_index and event.pressed = false):
				# Touch released!
				first_touch_index = -1;
		else:
			# If we are not tracking a touch already, then start tracking this touch!
			# NOTE: This will not work for multiple touches. See next code example!
			first_touch_down = true;
			first_touch_index = event.index;
			
			# Move gun_x into position
			gun_x = event.position.x; # Might need to offset for size of gun
	
	elif (event is InputEventScreenDrag):
		# Check if the drag event is the first touch
		if (event.index == first_touch_index):
			# If it is, then move gun_x into position!
			gun_x = event.position.x;

I'm not sure if the code will work, but hopefully that gives you an idea on how to go about it :smile:


@canvasbushi said: I can only give advice, its up to you if you want it or not. I'm not forcing you to buy it. I'll explain a little further altho i'm sure you'll still hold firm on your opinion.

Fair enough. I just don't think we should call someone's mechanic "bad game design", especially without knowing more about the project and/or when they are not asking for that type of feedback. Not to mention whether the mechanic is bad/good/whatever is unrelated to the question in this topic.

Side note: For the record, I agree with you that in many games, having a hold to shoot mechanic is better than having to tap, however as I mentioned, there are times it might be good design. I would say if very much depends on the project.

@TT What do you mean by "#This will not work for multiple touches. See next code example!" 1. not more than 2 fingers in the same time? 2. or if i make a drag and some tapstaps, than release the drag and start the drag again with another taps will not work?

what did you mean on line 64? first_touch_down = true;

first_touch_down is not defined yet. I commented that line. It is working ok if I start to drag with the first finger. Than start to tap multiple times with second finger. But if I release the drag finger and try again to start to drag, the gun doesn't follow the event position. I think it is because the condition from line 72 if (event.index == first_touch_index): if I remove condition it works with the following part but than the tap doesn't work anymore.

I think this is because I have tore reset var first_touch_index and var second_touch_index to -1 when my hands are not on the screen(like i make a pause). I will test more tomorow.

Also @canvasbushi i will mix some logic of your code(checking for delta position in any direction if is smaller than a given amount) in the TT code to try to identify a double drag (like a short one) and make it action like a tap. I mean, if with first finger i make the drag and with the second I need to do a tap but by mistake I make a small drag, than the small drag to make the action of the tap(to fire).

Thank you guys :)

Here is a printscreen with the TT implmented but still under review to make it work.

Also I adapted this basic code and it also seems to work. But with the same problem, that I have to make small drags made by mistake to act like a tap.

@gaby424 said: @TT What do you mean by "#This will not work for multiple touches. See next code example!" 1. not more than 2 fingers in the same time? 2. or if i make a drag and some tapstaps, than release the drag and start the drag again with another taps will not work?

I was just meaning that the first example will only track a single touch/finger. You could use more than one tap/finger at the same time, but the code will only respond to the first touch/finger.

what did you mean on line 64? first_touch_down = true;

first_touch_down is not defined yet. I commented that line.

Whoops, that was a leftover variable. Initially I was using first_touch_down to detect whether a touch is down instead of checking first_touch_index != -1. That line should be removed, since it doesn't do anything.

It is working ok if I start to drag with the first finger. Than start to tap multiple times with second finger. But if I release the drag finger and try again to start to drag, the gun doesn't follow the event position. I think it is because the condition from line 72 if (event.index == first_touch_index): if I remove condition it works with the following part but than the tap doesn't work anymore.

I think this is because I have tore reset var first_touch_index and var second_touch_index to -1 when my hands are not on the screen(like i make a pause). I will test more tomorow.

I'm not sure why it is not working when you release. Resetting the variables manually should help though. I also realized that I made a few mistakes in the example code I posted, which might be contributing/causing the problem.

Here is a printscreen with the TT implmented but still under review to make it work.

Looking at the code again that I posted, and looking at the image, I realized I made a few mistakes. Theoretically, a few changes should help and maybe fix the drag issue.

First, lines 76 to 87 need to be deleted. They are messing up the first touch. I accidentally forgot to remove them when I copy-pasted the code from the first example to use as a base.

Lines 94 and 95 should be removed if you want only the first finger to be able to move the gun. If you want any/all fingers to move the gun, then lines 94 and 95 should work fine.

(NOTE: I have not tested the code, I am just going off what I know about Godot and GDScript. I don't have a device I can test with handy, so unfortunately I cannot test the code to know whether it works)

Also I adapted this basic code and it also seems to work. But with the same problem, that I have to make small drags made by mistake to act like a tap.

I'm not sure how to fix the small drag acting a like a tap problem, unfortunately. It might be because, as far as I can tell, looking at the code it seems that every touch/tap will fire a bullet, and every drag will move the gun. I don't know if this is what you are intending or not.

One thing you could try is checking the speed property of the InputEventScreenDrag, and if it is lower than a certain value, then ignore the event. Something like this:

if (event.speed.length() < 16):
	return; 
else:
	# Do whatever is needed with the drag here

Thank you guys :)

Happy to help! Hopefully this helps. :smile:

Thank you guys!! You made me to start thinking more deeply to solve my problem.

2 days after :) First of all wanted to understand when you make a drag gesture(swipe like) what type of events are involved. I was surprised to realize that both the InputEventScreenTouch and InputEventScreenDrag are involved in, in one after another mode. First InputEventScreenTouch, than InputEventScreenDrag, than InputEventScreenTouch again. So i made a small helper script to print a "tap" when InputEventScreenTouch is working and a "drag" when InputEventScreenDrag is working. Also print some other additional parameters to see what I can use from there.

Unfortunatelly the speed and relative parameters of drag event don't tell me something relevant.(anyway doesn't matter now)

Here is the result in one picture, what Godot do when you make a swipe(drag) gesture.

Than with this info in mind, I did everything again. Here is what I wanted the script to do.

The objective:

We have space for two fingers to act in the same time.

One to "drag" the gun (horizontally only) and one to "tap" to fire bullets

Doesn't matter which is first

If one finger is already in a "drag" action, the other finger

is not allowed to move the gun, even if it is also doing a drag.

It will only fire on release.

Also, if one finger is down and it wasn't "dragging" enough

pixels (a minim value), the drag will not register(not moving the gun), so the

action will act like a tap/fire on release. This is to

prevent accidental small drags when tapping.

You can put both fingers to act repeatedly in any order,

in the same times or not, the script will figure out

what yours intentions are, doesn't matter the location on the screen

I don't know how to format code here so I put the pictures:

So happy now. Thank you

Sorry for the delay, I meant to get back sooner but forgot. Yesterday was busy and by the time I remembered, it was late at night.

@gaby424 said: Unfortunatelly the speed and relative parameters of drag event don't tell me something relevant.(anyway doesn't matter now) Here is the result in one picture, what Godot do when you make a swipe(drag) gesture.

Hmm, that is strange that speed and relative are not being updated.

However, since you have the positions between each drag event, in theory you can calculate the speed yourself by getting the delta between positions. Looking at how minor the movements are between drag events, you might want to add the deltas together and then on a timer reset the calculated velocity to zero.

That is what I would do to calculate the velocity of the drag, but I haven't tested so I don't know if it would work.

I don't know how to format code here so I put the pictures:

You can format the code by indenting it with a single tab if the code is over more than one line. For single lines of code, you can just add the Tilda (`) key around the code you want to format.


Is the code you posted working? I took a quick look through it, and it seems like it should work.

Or you can just paste the code in, select it all then click on the code option under the paragraph(¶) menu in editor header.

@TT the speed was not used, I did it with the a minimum amount of pixels like abs(endposition-startposition) to remove the unrelevant drags.. But I understand the idea :) About your question, yes the code is working :)

Thx guys, here is the code.

#define the minimum amount of pixels for the drag action to execute
var min_drag=10
var event_index=null
var start_position=null
var end_position=null
var real_drag=false
var event_index2=null
var start_position2=null
var end_position2=null
var real_drag2=false

func _input(event):
	# We have space for two fingers to act in the same time. 
	# One to "drag" the gun and one to "tap" to fire bullets
	# Doesn't matter which is first
	# If one finger is already in a "drag" action, the other finger
	# is not allowed to move the gun, even if it is also doing a drag. 
	# It will only fire on release.
	# Also, if one finger is down and it wasn't "dragging" enough
	# pixels (a minim value), the drag will not register, so the 
	# action will act like a tap/fire on release. This is to
	# prevent accidental small drags when tapping.
	# You can put both fingers to act repeatedly in any order,
	# in the same times or not, the script will figure it out,
	# what you are intentions, doesn't matter the location on the screen
			
	# we have to virtual slots for fingers to process in the same time.
	# they are empty in the beginning (see above):
	# event_index =null
	# event_index2 =null
	
	if (event is InputEventScreenTouch):
		#on press 
		if event.pressed:
			#check if slot 1 is empty to make space for the first finger touch
			if event_index==null and event.index!=event_index2:
				#print ("Allocate event_index=",event.index)
				event_index=event.index
				start_position=event.position
			
			#check if slot 2 is empty to make space for the second finger touch
			if event_index2==null and event.index!=event_index:
				#print("Allocate event_index2=",event.index)
				event_index2=event.index
				start_position2=event.position

		#on release (we have to do actions like fire or not(if it is a drag) and clear the slots)
		elif not event.pressed:

			#check if the release is made on slot 1
			if event.index==event_index:
				end_position=event.position
				
				#check if the release position is very near the press position
				#so we can translate accidental drag gestures, that in fact were ment 
				#to be a taps, so in this case we do a tap action/fire
				if abs(start_position.x-end_position.x)<min_drag:
					fire_bullet()
				
				#reset the drag flag here on release when a real drag ends
				else:
					#this is a drag flag that was activated in another part of 
					#the script (in the drag part) and here on release we reset it
					real_drag=false
					
				#reset the release position (we clear the slot 1)
				end_position=null 
				
				#print ("1111 RELEASE ", "event_index before=",event_index)
				event_index=null #(we clear the slot 1)
				#print ("event_index after=",event_index)
			
			#check if the release is made on slot 2
			elif event.index==event_index2:
				end_position2=event.position
				
				#check if the release position is very near the press position
				#so we can translate accidental drag gestures, that in fact were ment 
				#to be a taps, so in this case we do a tap action/fire
				if abs(start_position2.x-end_position2.x)<min_drag:
					fire_bullet()
					
				#reset the drag flag here on release when a real drag ends
				else:
					#this is a drag flag that was activated in another part of 
					#the script (in the drag part) and here on release we reset it
					real_drag2=false
					
				#reset the release position (we clear the slot 2)
				end_position2=null
				
				#print ("2222 RELEASE ", "event_index2 before=",event_index2)
				event_index2=null #(we clear the slot 2)
				#print ("event_index2 after=",event_index2)
				
				
				
	#when you are in the process of dragging here is the action
	elif event is InputEventScreenDrag:
		
		#check if the drag is made in the slot 1
		if event.index==event_index:
			
			#check if in the slot 1 you are allowed to drag
			#by checking if in slot 2 you are not already dragging
			if real_drag2==false:
				
				#check if the instant position is very near the start position
				#so we can translate accidental drag gestures, that in fact were ment 
				#to be a taps, so we are not moving the gun in this case
				if abs(event.position.x-start_position.x)<min_drag:
					
					#also we check the drag flag because we need to
					#check the possibility that the drag move has come 
					#back after a long ride near the starting point so we use the status of the
					#drag flag to see if we can move the gun in that small pixels interval
					#so you don`t feel a snap in a long drag move when you are again
					#near stating point.
					if real_drag==true:
						gun_x=event.position.x
						
				#here we are dragging away from the starting point so it is safe to mark
				#drag flag as true and move the gun
				else:
					real_drag=true
					gun_x=event.position.x
					
		#check if the drag is made in the slot 2
		elif event.index==event_index2:
			
			#check if in the slot 2 you are allowed to drag
			#by checking if in slot 1 you are not already dragging
			if real_drag==false:
				
				#check if the instant position is very near the start position
				#so we can translate accidental drag gestures, that in fact were ment 
				#to be a taps, so we are not moving the gun in this case
				if abs(event.position.x-start_position2.x)<min_drag:
					
					#also we check the drag flag because we need to
					#check the possibility that the drag move has come 
					#back after a long ride near the starting point so we use the status of the
					#drag flag to see if we can move the gun in that small pixels interval
					#so you don`t feel a snap in a long drag move when you are again
					#near stating point.
					if real_drag2==true:
						gun_x=event.position.x
		
				#here we are dragging away from the starting point so it is safe to mark
				#drag flag as true and move the gun
				else:
					real_drag2=true
					gun_x=event.position.x