Display objects with custom-sized touch handlers

@AnscaTeam and whoever else may know…

Case:
I have a display object (sprite, image, primitive shape… can be whatever).

Goal:
I want to register a “touch” listener that will be of different shape/size than that of the display object. In my game I am going to have some small display objects, which I want the user to be able to touch without problems.

Approach1:
I can make a function that takes the object, makes a group and a primitive (transparent) shape and then inserts the object and the shape into the group. So, I can register the listener to the shape (of custom size, according to the Goal) and when something is listened I can act on the object itself, inside the event handler. However, instead of the object I should now transform the group to have the listening shape “follow” the object.

Problem:
That solution works, but I don’t like it! It is not flexible, as I have to know which object has a listener and which hasn’t, to call the group or the object itself when transforming.

Thoughts:
If only objects could have “children” by themselves (if they inherited from an abstract container class and not the opposite -as groups do inheritting from display objects) Corona would be more powerful!

Approach2:
I can write an object builder, which would make a group (as my major object), put the desired display object and the helper shape inside and then return the group (so I always transform the group itself and not the object-or-group like in Approach1). The listeners can be registered for the helper shape which will always follow the group. I just have to deep-call the display object for handling things like playing sprite’s animations etc. Things like location, alpha etc are directly mofied on the parent-group.
QUESTION:
Can you think of any other approach to implement custom-sized sensors for touch-handling?
How do you find Approach2? Is it somewhat bloated from the start? [import]uid: 7356 topic_id: 3691 reply_id: 303691[/import]

Any advice on this? (aka …bump)

Thanks [import]uid: 7356 topic_id: 3691 reply_id: 11270[/import]

Uhmm… I haven’t tested it… especially if it’s operating on the right “self”, but give it a try! It’s just for giving a “method”.

[lua]local function customTouch(self,event)
if event.phase == “ended” then
local ctouch = self.ctouch

if event.x >= ctouch.x[1] and event.x <= ctouch.x[2] then
if event.y >= ctouch.y[1] and event.y <= ctouch.y[2] then
self:onTouch()
end
end
end

return true
end

local function addMyTouch(obj,xsize,ysize,ontouch)

obj.ctouch = {x={},y={}}

obj.ctouch.hw = xsize*0.5 – half width
obj.ctouch.hh = ysize*0.5 – half height

function obj:__makeCorners()
self.ctouch.x[1] = self.x - self.ctouch.hw – computes corners based on centered reference point
self.ctouch.x[2] = self.x + self.ctouch.hw
self.ctouch.y[1] = self.y - self.ctouch.hh
self.ctouch.y[2] = self.y + self.ctouch.hh
end

–[[
---- Must implement custom transformation for custom touch area!

obj.__translate = obj.translate

function obj:translate(dx,dy)
self:__translate(dx,dy)
self:__makeCorners()
end
]]

obj:__makeCorners() – computes corners
if ontouch then obj.onTouch = ontouch end

obj.touch = customTouch
obj:addEventListener(“touch”,obj)
end

— USAGE:

local myObj = display.newImage(“myImage.png”)

addMyTouch(myObj,myObj.width*2,myObj.height*0.5,function (self) print(“Current Position:”,self.x,self.y) end)[/lua]

Translation is commented… you might check if it works already like that, but not really needed if we’re talking static objects.
Just beware, needs to be re-tought if you also want to scale it. You need to save the xsize and ysize in the object as well.

I hope you get the idea tho. :wink: [import]uid: 5750 topic_id: 3691 reply_id: 11507[/import]

@erpy

Nice idea! Thanks for the code and your time.

However, there are some problems with this kind of approach, too:

The touch event is only “listened” by the object when the event.x/y are inside the object’s bounding box! So, it works nicely when you specify areas smaller than that of the original object’s but fails to catch the tap on any extending area outside the object.

One solution could be to handle every touch event from within the stage group and inside there to check every object’s area and trigger the right object’s handler manually. But this loop-check can be really slow for a stage with a dozen of objects when dragging one with the finger. At least I suppose so…

***

Approach 2 from my previous post is also not viable, as it forbids usage of physics (physics objects cannot be placed within different groups, because they must share the same coordinates system).

I wonder why the Ansca engineers didn’t make display objects to inherit from an abstract container (like the “group”), instead of the opposite (groups inherit from display object). If only we could “addChildren” to an object, such problems wouldn’t exist. We would simply take a sprite and attach a custom shape for touch handling, a custom shape for physics, a textfield for conversations and whatever else one could imagine… [import]uid: 7356 topic_id: 3691 reply_id: 11576[/import]

@Magenda

I haven’t tested it extensively, but in the example I wrote “xsize” is set to “myObj.width*2”… that is twice the width of the original object.

Please, have a go with actual test graphics (like a simple rectangle) and see if you can touch it outside its bounds. [import]uid: 5750 topic_id: 3691 reply_id: 11580[/import]

@erpy

I tested your example with an actual image object before writing the previous post. It works nicely for y (0.5) but not for x (2). The touch event is fired by SDK after it is checked that the tap falls inside the object’s original bounds.

This is an expected behavior. Otherwise, every touch event would be fired for all objects in the stage. Of course, as I said above, you can stop this behavior with many ways -e.g. with setting the focus to each single object, checking if it falls inside the custom shape and if not continue with passing the focus to the next object. However, this loop can get very slow if it is performed at each frame (e.g. when dragging an object).

[import]uid: 7356 topic_id: 3691 reply_id: 11595[/import]

@Magenda

I see. I’d try registering using Runtime then, something like:

[lua]Runitme:addEventListener(“touch”,obj)[/lua]

You are correct, most probably when registering through an object (as with “obj:addEventListener()”) the underlying engine checks for objects bounds.

[import]uid: 5750 topic_id: 3691 reply_id: 11603[/import]