How can I define platformer controls for mobile: move with touch without ui buttons (left, right, up)

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By anssiko

Hi,

I’m trying to create simple 2d platformer touch screen controls without ui buttons. Basically what I’m trying to archieve is: touch and hold on either side of player to make her move towards that x direction, and to touch or swipe above the player to make her jump or climb.

Note that I’m a complete beginner with code.

I think I need to write something like:

var player position
var touch position (hold)
if touch position x > player position x
move +x (=left)
if touch position x < player position x
move -x (=right)
if touch position y < player position y
jump (or climb if ladder etc.)

I have no idea of the feasibility of this. Atleast jumping/climbing would probably would need some margins between player position and the touch position x/y, so that you need to touch/swipe pretty directy above the character, and similarly touch+hold x direction far enough from the character.

I’m grateful for any feedback, ideas and especially examples with code of how to write this.

(I’ll add my best try to comments.)

:bust_in_silhouette: Reply From: njamster
func _input(event):
	if event is InputEventMouseButton:
		if event.pressed:
			var local_event = make_input_local(event)

			if local_event.position.x > 100:
				print("move right")
			elif local_event.position.x < -100:
				print("move left")
			elif local_event.position.y in range(-100, -50):
				print("climb")

This will print “move right” if you click a position at least 100 pixels to the right from the node the script is attached to, “move left” if you click a position at least 100 pixels to the left of it or “climb” if both of these conditions are false and you click in a region in the area between 50 and 100 pixels above the node. Adjust the values to your liking.

Thank you. I managed to create a simple set distance movement to those directions with a click on either side. Next I need to figure out how to create continuous movement with a held touch.

anssiko | 2020-02-21 16:19

enum STATES {
  MoveRight,
  MoveLeft,
  Climb,
  Idle
}

onready var state = STATES.Idle

func _input(event):
	if event is InputEventMouseButton and event.button_index == BUTTON_LEFT:
		if event.pressed:
			var local_event = make_input_local(event)

			if local_event.position.x > 100:
				state = STATES.MoveRight
			elif local_event.position.x < -100:
				state = STATES.MoveLeft
			elif round(local_event.position.y) in range(-100, -50):
				state = STATES.Climb
		else:
			state = STATES.Idle

func _physics_process(delta):
	match state:
		STATES.MoveRight:
			print("Move Right")
		STATES.MoveLeft:
			print("Move Left")
		STATES.Climb:
			print("Climb")

Replace the print-statements with your movement-code and the player character will move as long as you hold down the mouse-button / finger.

Note that I fixed two smaller issues in my code along the way:

  1. I now ensure that event.button_index == BUTTON_LEFT
  2. I round the y-position to an integer in order for the clim-condition to work

njamster | 2020-02-22 13:28

Thank you so much. I tried to do something similar with var and constants, but I didn’t think of to use match state as a link between the input event and movement.

Now the basic movement works, and I understand how to try and tweak it further.

I’ll add my code below.

:slight_smile:

anssiko | 2020-02-22 19:22

extends KinematicBody2D

const ACCELERATION = 20
const GRAVITY = 20

const MAX_SPEED = 200
const JUMP_HEIGHT = -500
const UP = Vector2(0,-1)

var motion = Vector2() 

enum STATES {
	MoveRight,
	MoveLeft,
	Jump
	Idle
}

onready var state = STATES.Idle

func _input(event):
    if event is InputEventMouseButton and event.button_index == BUTTON_LEFT:
        if event.pressed:
            var local_event = make_input_local(event)
			
            if local_event.position.x > 20: #and local_event.position.y > -50:
                state = STATES.MoveRight
            elif local_event.position.x < -20: #and local_event.position.y > -50:
                state = STATES.MoveLeft
            elif round(local_event.position.y) in range(-400, -20):
                state = STATES.Jump
        else:
            state = STATES.Idle

func _physics_process(delta):
	motion.y += GRAVITY
	var friction = false
	match state:
		STATES.MoveRight:
			motion.x = min(motion.x+ACCELERATION, MAX_SPEED)
			$Sprite.flip_h = false
			$Sprite.play("Run")
		STATES.MoveLeft:
			motion.x = max(motion.x-ACCELERATION, -MAX_SPEED)
			$Sprite.flip_h = true
			$Sprite.play("Run")
		STATES.Idle:
			$Sprite.play("Idle")
			friction = true
		STATES.Jump:
			if is_on_floor(): 
				motion.y = JUMP_HEIGHT	
				if friction == true:
					motion.x = lerp(motion.x, 0, 0.2)
			if motion.y < 0:
				$Sprite.play("Jump")
			else:
				$Sprite.play("Fall")
	if friction == true:
		motion.x = lerp(motion.x, 0, 0.1)
		
		
	motion = move_and_slide(motion, UP)
	pass

(I don't know why it formats this so badly)

anssiko | 2020-02-22 19:22

In order for code to be formatted correctly here, it needs to be indented by at least one level. Just select all of your code in the editor and click the button with the curly brackets “{ }” and it will be formatted automagically for you. :wink:

njamster | 2020-02-24 13:27

Magic, thanks!

anssiko | 2020-02-24 13:34