How to get specific part of object when calling touch listener on Corona - listener

I have a group which presents a character. It contains head, arms and other parts of body.
I want to set touch Listener to that group so when I touch the head, arms and body will do some movements.
I don't want to set touch listener to head only, but the whole group.
I set name to head, and hope event.other can work(like collision), but it's not.
Do you have any solution?
My code below
local touchListener= function( event )
if (event.phase=="began") then
local group = event.target
local head= group[1]
local arms= group[2]
local body= group[3]
if( event.other.name == "head" ) then
// do something here
end
end
return true
end

You should first create those spesific parts of the body. And then you should add touch listeners to everyone of them. For example, you have objects named "head", "arms" and "body"
head.id = "head"
arms.id = "arms"
body.id = "body"
head:addEventListener( "touch", touchHandler )
arms:addEventListener( "touch", touchHandler )
body:addEventListener( "touch", touchHandler )
-- Touch function here
local function touchHandler( event )
if event.phase == "began" then
display.getCurrentStage():setFocus( event.target )
event.target.isFocus = true
elseif event.target.isFocus then
if event.phase == "moved" and not ( inBounds( event ) ) then
display.getCurrentStage():setFocus( nil )
event.target.isFocus = false
elseif event.phase == "ended" then
if event.id == "head" then
-- Do stuff for head
elseif event.id == "arms" then
-- Do stuff for arms
elseif event.id == "body" then
-- Do stuff for body
end
display.getCurrentStage():setFocus( nil )
event.target.isFocus = false
end
end
return true
end
function inBounds( event )
local bounds = event.target.contentBounds
if event.x > bounds.xMin and event.x < bounds.xMax and event.y > bounds.yMin and event.y < bounds.yMax then
return true
else
return false
end
end
This code will also look for boundries of an object. For example, if user touchs the screen and then moves his/her finger to outside of the object, the object will no longer be focused.
Cheers ^^

Related

Substituting multiple inputs for a function with one function?

I am trying to see if I can simplify input by using a function that produces more than one output for use with another function. Is there any way I can do this? Do I HAVE to make a function to return single variables for each input?
--here is a snippet of what im trying to do (for a game)
--Result is the same for game environment and lua demo.
en = {
box ={x=1,y=2,w=3}
}
sw = {
box = {x=1,y=2,w=3}
}
function en.getbox()
return en.box.x,en.box.y,en.box.w,en.box.w
end
function sw.getbox()
return sw.box.x,sw.box.y,sw.box.w,sw.box.w
end
function sw.getvis()
return true
end
function CheckCollision(x1,y1,w1,h1, x2,y2,w2,h2)
return x1 < x2+w2 and
x2 < x1+w1 and
y1 < y2+h2 and
y2 < y1+h1
end
if CheckCollision(en.getbox(),sw.getbox()) == true then
if sw.getvis() == true then
en.alive = false
end
end
print(tostring(en.alive))
I am expecting the enemy (en) to die (en.alive = false) but I am getting the error: input:25: attempt to perform arithmetic on a nil value (local 'w2')
You can find an explaination for the issue you are seeing here: Programming in Lua: 5.1 – Multiple Results
I suggest you read the whole page but here is a relevant section
A function call that is not the last element in the list always produces one result:
x,y = foo2(), 20 -- x='a', y=20
x,y = foo0(), 20, 30 -- x=nil, y=20, 30 is discarded
I suggest the following changes to get your code working. wrap your output from getbox into a table with clear keys that make it easy to understand.
function en.getbox()
return {
x = en.box.x,
y = en.box.y,
w = en.box.w,
h = en.box.w
}
end
function sw.getbox()
return {
x = sw.box.x,
y = sw.box.y,
w = sw.box.w,
h = sw.box.w
}
end
function CheckCollision(o1, o2)
return o1.x < o2.x + o2.w and
o2.x < o1.x + o1.w and
o1.y < o2.y + o2.h and
o2.y < o1.y + o1.h
end
Alternatively you can wrap the output of getbox "on the fly" like:
function CheckCollision(o1, o2)
return o1[1] < o2[1] + o2[3] and
o2[1] < o1[1] + o1[3] and
o1[2] < o2[2] + o2[4] and
o2[2] < o1[2] + o1[4]
end
if CheckCollision({en.getbox()}, {sw.getbox()}) == true then
if sw.getvis() == true then
en.alive = false
end
end
I do strongly encourage the first option over the last. The last option leads to code that is harder to follow and should be accompanied by clear comments explaining it.

uiresume (gcbf) worked in the function, but failed when the function being called

I want to let the user select multiple ROI's on a picture. I used a while loop. I paused and let the user select an ROI. After that the while loop would continue unless the user clicked another button on the toolbar to terminate the while loop. The code worked on single pictures. I made the code a function. When I looped and called the function in another script, it failed to proceed. I pressed Ctrl + C and it showed that "Operation terminated by user during uiwait". Apparently the uiresume didn't work.
Please let me know where the problems are. Thanks! My code:
% Below was basically a copy of the example given in R2014a.
% It created an interactive toolbar with 2 pushbuttons.
fh = figure('ToolBar', 'none'); hold on;
h_im = imshow(rgb2gray (I));
tbh = uitoolbar(fh);
[X_OK, map_OK] = imread(fullfile(matlabroot,...
'toolbox','matlab','icons','greenarrowicon.gif'));
[X_rect, map_rect] = imread(fullfile(matlabroot,...
'toolbox','matlab','icons','tool_rectangle.gif'));
% Convert indexed image and colormap to truecolor
icon_OK = ind2rgb(X_OK, map_OK);
icon_rect = ind2rgb(X_rect, map_rect);
% Create 2 uipushtools in the toolbar
% I introduced 2 variables, leave and draw, to facilitate the control of the
% later while-loop.
pth_OK = uipushtool(tbh, 'CData',icon_OK,...
'TooltipString','Toolbar push button',...
'ClickedCallback',...
'leave = 1; uiresume (gcbf)');
pth_rect = uipushtool(tbh, 'CData',icon_rect, 'Separator','on',...
'TooltipString','Toolbar push button',...
'ClickedCallback',...
'draw = 1; uiresume (gcbf)');
% The loop for ROI selection.
ii = 1;
% Maximum the use can select 30 ROI's.
while ii < 31;
draw = 0;
uiwait;
if leave == 1;
% If the user pressed "OK" button, leave will be 1.
break;
end;
if draw == 1;
% If the user pressed the "rect" button, draw will be 1.
h = imrect;
wait (h);
gui_Mask = createMask(h, h_im);
greyImg (~gui_Mask) = 255;
ii = ii + 1;
continue;
end;
end;
I saw someone used set/waitfor instead.
I tried to change to set/waitfor. Now it works both in the function and when the function being called.
But I still want to know why uiresume didn't work.

Lua callback "attemp to index global"

function AnotherSCT:OnNormalColorFontClick( wndHandler, wndControl, eMouseButton )
local color = Color.new(0.5, 1, 0.5, 1)
ColorGetter.GetColor(color, false, ColorCallBack, color)
end
function ColorCallBack(color)
if color == nil then
Print("nil")
else
wndMain:FindChild("NormalFontTypeTestText"):SetTextColor(color)
end
end
The line:
wndMain:FindChild <--- generates "Attempt to index global 'wndMain'
How can i access wndMain in my callback function?
Do you have access to wndMain in OnNormalColorFontClick? If so then you could either pass it to your callback as an argument, or define the callback locally within OnNormalColorFontClick, making it a closure that captures wndMain.
Edit: here is the "closure" solution.
function AnotherSCT:OnNormalColorFontClick( wndHandler, wndControl, eMouseButton )
local color = Color.new(0.5, 1, 0.5, 1)
local function ColorCallBack(color)
if color == nil then
print("nil")
else
wndMain:FindChild("NormalFontTypeTestText"):SetTextColor(color)
end
end
ColorGetter.GetColor(color, false, ColorCallBack, color)
end

Detect how many object user touches in one touch? Corona

Can you tell me how to make a function that would detect how many objects one touch intercepts/touches using Corona SDK?
The way I would do to solve this is to create a counter for the current number of touches:
local counter = 0
and a function to handle the touches and updates the counter accordingly:
local function touchHandler( event )
if event.phase == "began" then
counter = counter + 1
elseif event.phase == "ended" then
counter = counter - 1
end
end
Then you just add a touch listener to all the objects:
object:addEventListener("touch", touchHandler)

Make two objects touchable which were created with a function (LUA, Corona)

I gues this is a real newbie question,
but I have the following code:
local function createCircle()
[...]
circle = display.newCircle( positionX, positionY, circleRadius )
[...]
end
function circle:touch( event )
if event.phase == "ended" then
scaleCircle(self,scaleUp)
end
return true;
end
circle:addEventListener("touch", circle)
I cleaned it up a bit, to concentrate on the important things.
My problem right now is: I can touch one circle and scale it. But this works only for one of the circles (I want to create like 3 or 4 of them). And I guess it only works for the last circle which was created.
I guess the main problem here is, that all circles I create with "createCircle()" are named "circle". So the evenListener only works for the "circle" I created.
Any ideas how I can select the other circles I created?
thank you :)
You MUST use tables. For eg.:
circles = {}
local function createCircle()
--[[ MORE CODE ]]--
table.insert( circles, display.newCircle( positionX, positionY, circleRadius ) )
--[[ MORE CODE ]]--
end
function circle:touch( event )
if event.phase == "ended" then
scaleCircle(self,scaleUp)
end
return true;
end
for _, circle in ipairs( circles ) do
circle:addEventListener("touch", circle)
end
This is how I solved it:
local function createCircle()
--[[ MORE CODE ]]--
table.insert(circleTable, display.newCircle( positionX, positionY, circleRadius ) )
--[[ MORE CODE ]]--
end
function onObjectTouch(event)
local self = event.target
if event.phase == "ended" then
--[[ MORE CODE ]]--
end
return true;
end
local function addTouchListeners()
for _, circle in ipairs(circleTable) do
circle:addEventListener("touch", onObjectTouch)
end
end
createCircle()
addTouchListeners()
I guess Dream Eaters solution should work as well. But I had another mistake in calling my createCircle() function. I solved this with creating a function for the TouchListeners and call it AFTER the createCircle() function.
Hope this helps other people with similar problems.