slide over the keys

How to implement a slide over the keys?

For example on the piano keys.

That is, you need to catch the event of a group of objects even if event.began on other groups.

I think you may be able to use multi touch.

this should be done with one finger and continuously.

In a controlled situation (like on a piano keyboard) it’s pretty simple.

You have to create a single button button overlaying all the keys.

When the button is touched or moved you check for the touch position and estimate over which key that was.

You also should keep trackof the last pressed key, so you can deactivate it.

Try something like this (simplified pseudo code):

local keyWidth = 20 local keys = { {name = "c", graphic = keyGraphic, sound = "cSound"}, {name = "d", graphic = keyGraphic, sound = "dSound"}, {name = "e", graphic = keyGraphic, sound = "eSound"}, } local activeKey local button = display.newButton(0, 0, #keys\*keyWidth, 100) button.x, button.y = button.width\*0.5, button.height\*0.5 local function stopKey(key) if activeKey then --do whatever you have to stop active key playing activeKey = nil end end local function playKey(key) if activeKey ~= key then --check if key is already playing stopKey() activeKey = key --do whatever you have to when a key is played end end local function buttonTouch(event) local phase = event.phase if phase == "began" then local playedKeyNum = math.ceil(event.x / keyWidth) local playedKey = key[playedKeyNum] if playedKey then --check if key exists playKey(playedKey) end elseif phase == "moved" then local playedKeyNum = math.ceil(event.x / keyWidth) local playedKey = key[playedKeyNum] if playedKey then --check if key exists playKey(playedKey) end else stopKey() end end button:addEventListener("touch", buttonTouch)

How it can catch touch on the black keys which located above the white keys?

Then you might try something like this:

local whiteKeyWidth = 20 local whiteKeyHeight = 100 local blackKeyWidth = 10 local blackKeyHeight = 80 local whiteKeys = { [1] = {name = "c", graphic = keyGraphic, sound = "cSound"}, [2] = {name = "d", graphic = keyGraphic, sound = "dSound"}, [3] = {name = "e", graphic = keyGraphic, sound = "eSound"}, [4] = {name = "f", graphic = keyGraphic, sound = "dSound"}, [5] = {name = "g", graphic = keyGraphic, sound = "eSound"}, } local blackKeys = { [1] = {name = "c#", graphic = keyGraphic, sound = "c#Sound"}, [2] = {name = "d#", graphic = keyGraphic, sound = "d#Sound"}, --third key does not exists, as there is no black key between e and f [4] = {name = "f#", graphic = keyGraphic, sound = "c#Sound"}, } local activeKey local button = display.newButton(0, 0, #keys\*whiteKeyWidth, whiteKeyHeight) button.x, button.y = button.width\*0.5, button.height\*0.5 local function stopKey(key) if activeKey then --do whatever you have to stop active key playing activeKey = nil end end local function playKey(key) if activeKey ~= key then --check if key is already playing stopKey() activeKey = key --do whatever you have to when a key is played end end local function buttonTouch(event) local phase = event.phase local eventX = event.x local eventY = event.y local playedKey if eventY \<= blackKeyHeight then --check for black key first local shiftedX = eventX - blackKeyWidth\*0.5 --shift position so we could check easier afterwards local moduloShiftedX = shiftedX%whiteKeyWidth local shiftedBlackKeyArea = whiteKeyWidth - blackKeyWidth if moduloShiftedX \>= shiftedBlackKeyArea or moduloShiftedX == 0 then local playedKeyNum = math.ceil(shiftedX / keyWidth) playedKey = blackKeys[playedKeyNum] end end if not playedKey then --if no black key has been played, maybe there is a white one instead playedKeyNum = math.ceil(eventX / whiteKeyWidth) playedKey = whiteKeys[playedKeyNum] end if phase == "began" then if playedKey then --check if key exists playKey(playedKey) end elseif phase == "moved" then if playedKey then --check if key exists playKey(playedKey) end else stopKey() end end button:addEventListener("touch", buttonTouch)

Will this work fast? Similar logic is in applications like fill-the-words when the selection of multiple letters is possible with a single flick of a finger.

I see no reason why it shouldn’t be fast.

There are only simple math and some if cases involved.

You could even Brute Force the key by checking every possible key and would still be fast as it’s only a tiny bit of code.

This version uses simplified spacial hashing to get the right key in no time.

Or what is your concern?

this code does not provide for the distance between the white keys

Why hould there be any distance between the white keys?

On the pianos I know they are right next to each other.

Anyways, maybe you could use what I posted as a startingpoint and develop it further to your needs?

Or if there’s some fundamental misunderstanding you explain a bit further.

I think you may be able to use multi touch.

this should be done with one finger and continuously.

In a controlled situation (like on a piano keyboard) it’s pretty simple.

You have to create a single button button overlaying all the keys.

When the button is touched or moved you check for the touch position and estimate over which key that was.

You also should keep trackof the last pressed key, so you can deactivate it.

Try something like this (simplified pseudo code):

local keyWidth = 20 local keys = { {name = "c", graphic = keyGraphic, sound = "cSound"}, {name = "d", graphic = keyGraphic, sound = "dSound"}, {name = "e", graphic = keyGraphic, sound = "eSound"}, } local activeKey local button = display.newButton(0, 0, #keys\*keyWidth, 100) button.x, button.y = button.width\*0.5, button.height\*0.5 local function stopKey(key) if activeKey then --do whatever you have to stop active key playing activeKey = nil end end local function playKey(key) if activeKey ~= key then --check if key is already playing stopKey() activeKey = key --do whatever you have to when a key is played end end local function buttonTouch(event) local phase = event.phase if phase == "began" then local playedKeyNum = math.ceil(event.x / keyWidth) local playedKey = key[playedKeyNum] if playedKey then --check if key exists playKey(playedKey) end elseif phase == "moved" then local playedKeyNum = math.ceil(event.x / keyWidth) local playedKey = key[playedKeyNum] if playedKey then --check if key exists playKey(playedKey) end else stopKey() end end button:addEventListener("touch", buttonTouch)

How it can catch touch on the black keys which located above the white keys?

Then you might try something like this:

local whiteKeyWidth = 20 local whiteKeyHeight = 100 local blackKeyWidth = 10 local blackKeyHeight = 80 local whiteKeys = { [1] = {name = "c", graphic = keyGraphic, sound = "cSound"}, [2] = {name = "d", graphic = keyGraphic, sound = "dSound"}, [3] = {name = "e", graphic = keyGraphic, sound = "eSound"}, [4] = {name = "f", graphic = keyGraphic, sound = "dSound"}, [5] = {name = "g", graphic = keyGraphic, sound = "eSound"}, } local blackKeys = { [1] = {name = "c#", graphic = keyGraphic, sound = "c#Sound"}, [2] = {name = "d#", graphic = keyGraphic, sound = "d#Sound"}, --third key does not exists, as there is no black key between e and f [4] = {name = "f#", graphic = keyGraphic, sound = "c#Sound"}, } local activeKey local button = display.newButton(0, 0, #keys\*whiteKeyWidth, whiteKeyHeight) button.x, button.y = button.width\*0.5, button.height\*0.5 local function stopKey(key) if activeKey then --do whatever you have to stop active key playing activeKey = nil end end local function playKey(key) if activeKey ~= key then --check if key is already playing stopKey() activeKey = key --do whatever you have to when a key is played end end local function buttonTouch(event) local phase = event.phase local eventX = event.x local eventY = event.y local playedKey if eventY \<= blackKeyHeight then --check for black key first local shiftedX = eventX - blackKeyWidth\*0.5 --shift position so we could check easier afterwards local moduloShiftedX = shiftedX%whiteKeyWidth local shiftedBlackKeyArea = whiteKeyWidth - blackKeyWidth if moduloShiftedX \>= shiftedBlackKeyArea or moduloShiftedX == 0 then local playedKeyNum = math.ceil(shiftedX / keyWidth) playedKey = blackKeys[playedKeyNum] end end if not playedKey then --if no black key has been played, maybe there is a white one instead playedKeyNum = math.ceil(eventX / whiteKeyWidth) playedKey = whiteKeys[playedKeyNum] end if phase == "began" then if playedKey then --check if key exists playKey(playedKey) end elseif phase == "moved" then if playedKey then --check if key exists playKey(playedKey) end else stopKey() end end button:addEventListener("touch", buttonTouch)

Will this work fast? Similar logic is in applications like fill-the-words when the selection of multiple letters is possible with a single flick of a finger.

I see no reason why it shouldn’t be fast.

There are only simple math and some if cases involved.

You could even Brute Force the key by checking every possible key and would still be fast as it’s only a tiny bit of code.

This version uses simplified spacial hashing to get the right key in no time.

Or what is your concern?

this code does not provide for the distance between the white keys

Why hould there be any distance between the white keys?

On the pianos I know they are right next to each other.

Anyways, maybe you could use what I posted as a startingpoint and develop it further to your needs?

Or if there’s some fundamental misunderstanding you explain a bit further.