Virtual Pad Example

Virtual Pad Example for Defold

This project demonstrates how to use universal virtual pad in Defold games. The main folder hosts a minimal scene: the player listens to move messages, while controls.gui_script captures input and forwards it to gui/virtual_pad.lua.

PLAY

Hooking It Up

local VirtualPad = require "gui.virtual_pad"

function init(self)
    msg.post(".", "acquire_input_focus")
    self.pad = VirtualPad.new("virtual_pad")
    self.pad.fixed_position = false
    self.pad.always_visible = false
end

function on_input(self, action_id, action)
    if action_id == hash("touch") then
        self.touch = action
    elseif action_id == hash("touch_multi") then
        self.touch_multi = action
    end
end

function update(self, dt)
    self.pad:on_input(self.touch, self.touch_multi)
    self.pad:update(dt)

    local x, y = self.pad:get_data()
    msg.post("player", "move", { released = (x == 0 and y == 0), x = x, y = y })
end

Virtual Pad Features (gui/virtual_pad.lua)

  • Dynamic or fixed placement: fixed_position lets you anchor the pad or spawn it under the finger on first touch.
  • Flexible visibility: make the pad always visible, show it only before the first touch (always_visible_before_first_input), or hide it immediately on release.
  • Two activation zones: set_borders and set_borders_2 constrain the screen regions that accept touches—ideal when you need to keep one half of the screen for buttons.
  • Full multitouch support: the module consumes both touch and touch_multi, remembers the active finger, and can ignore individual ids via set_blocked_touch.
  • Normalized output and a safe zone: get_data() returns values in the [-1; 1] range, while is_safe() / is_in_safe_area() tell you when the stick snaps back to the center.
  • Screen adaptation: on_resize() recalculates GUI node positions so the pad stays correct across orientations and aspect ratios.
  • State control: set_enabled() / is_enabled(), automatic reset(), and the safe_zone_time timer make it easy to fade the pad out during cutscenes or tutorials.

Project Layout

  • gui/virtual_pad.gui and gui/virtual_pad.lua — the visual part and the logic of the stick.
  • main/controls.gui + main/controls.gui_script — a sample UI screen that shows how the pad is initialized.
  • main/player.script — a simple game object that reacts to move messages and moves around.

Use this sample as a starting point and tune the visuals or sensitivity for your game

9 Likes

Thank you for these wonderful gifts. They are amazing☺️

2 Likes

I think your pad works very neat! :fireworks:

I don’t know if I get this right, but if multitouch is consumed by the module, does it mean that we cannot use other buttons (like for shooting) with it together?

2 Likes

It depends in how you worked with multi touch.

I have 2 cases.

  1. If you use 2 fingers. Left side to pad, right side for camera control
  • You can set blocked area.
  • Then
VirtualPad:set_blocked_touch(touch_camera_id)

2)If you have buttons. You can check virtual pad in on_input. Only if buttons not consumed input before

self.views.virtual_pad:set_blocked_touch(self.views.btn_build.clickable.touch_id
		or self.views.btn_remove.clickable.touch_id or
		self.views.btn_rebirth.clickable.touch_id or self.views.btn_pets.clickable.touch_id or
		self.views.btn_islands.clickable.touch_id)
	if consumed then return true end

	if action_id == HASH.INPUT.TOUCH or action_id == HASH.INPUT.TOUCH_MULTI then
		if self.views.virtual_pad:on_input() then return true end
	end
3 Likes

Cool! Thanks for the reply :+1: