I created a class for handling sprites the purpose is to choose symbols from a menu and drag them to positions on the screen. But it seems to not work all the time, or theres got to be a better way to do this.
here is the touch part of the class.
ScaledSprite = class()
function ScaledSprite:init(mySprite,Ssize,x,y)
self.pos = vec2(x,y)
self.mySprite = mySprite
self.Ssize = Ssize
self.Sw,self.Sh = spriteSize(self.mySprite)
self.action = nil
self.selected = false
end
function ScaledSprite:draw()
-- Codea does not automatically call this method
factor = self.Ssize / 100
sprite(self.mySprite,self.pos.x,self.pos.y,self.Sw * factor,self.Sh * factor)
end
function ScaledSprite:touched(touch)
-- Codea does not automatically call this method
if touch.state == MOVING then
if (math.abs(self.pos.x - touch.x) <= (self.Sw/2)
and math.abs(self.pos.y - touch.y) <= (self.Sh/2)) then
if flying ~= "none" then
self.selected = true
else
self.selected = false
end
elseif touch.state == ENDED then
if self.selected == true and self.action then
self.selected = false
self.action()
end
end
end
As I explained sometimes it gets the ENDED condition but sometimes it doesn’t.
From Main this were I called the class action: (Fliying is a control variable to indicate that I hit symbol from the menu)
if (flying == "P1") then
if CurrentTouch.y > 680 then
fixedy = 680
elseif CurrentTouch.y < 100 then
fixedy = 100
else
fixedy = CurrentTouch.y
end
ssP1 = ScaledSprite("Dropbox:symbol-P1",symbSize * vsmFactor,CurrentTouch.x,fixedy)
ssP1.action = function() btnSymbPRO1pressed() end
ssP1:draw()
dragging = true
end
Action function that’s is called after the touch ENDED is detected
Perhaps related to the other touch problem thread.
Can you check if you get any touch event at all by simply printing t.state? Especially look out for the undocumented state CANCELLED (which equals to 3 on Codea 1.5) and verrrrry unlikely STATIONARY (4 on Codea 1.5).
I don’t fully understand your question (I am new working with objects and classes) but here is where I call the class
if (flying == "P1") then
if CurrentTouch.y > 680 then
fixedy = 680
elseif CurrentTouch.y < 100 then
fixedy = 100
else
fixedy = CurrentTouch.y
end
ssP1 = ScaledSprite("Dropbox:symbol-P1",symbSize * vsmFactor,CurrentTouch.x,fixedy)
ssP1.action = function() btnSymbPRO1pressed() end
ssP1:draw()
dragging = true
end
And I use the currentTouch property for dragging the sprite on the screen and when I release the touch it suppose to save the position in a table it sometimes does it but sometimes don’t
CurrentTouch is a strange beast : it works as long as you never plan to do more than a single touch and you can depend on that. Otherwise, CurrentTouch gets the last touch, which in a multitouch scenario would be bad for your code; you might not get the ended state if there’s a new or different touch id involved.
Nonetheless, I don’t see anywhere you call ssP1:touched(touch), and use the touch.state property in your sprite class, but based on your previous commentary, you must call it at so e point.
btnHELP:touched(touch)
if (location == "new" or location == "edit") then
btnPROCESSsymbols:touched(touch)
btnMATERIALsymbols:touched(touch)
btnINFORMATIONsymbols:touched(touch)
btnGENERALsymbols:touched(touch)
btnCONNECTORSsymbols:touched(touch)
if(menustatus =="steady") then
btnSymbPRO1:touched(touch)
end
ssP1:touched(touch)
end
end
Here is the state property being used inside the sprite class
function ScaledSprite:touched(touch)
-- Codea does not automatically call this method
if touch.state == MOVING then
if (math.abs(self.pos.x - touch.x) <= (self.Sw/2)
and math.abs(self.pos.y - touch.y) <= (self.Sh/2)) then
if flying ~= "none" then
self.selected = true
else
self.selected = false
end
end
elseif touch.state == ENDED or (touch.state == MOVING and
(math.abs(math.abs(touch.deltaX) + math.abs(touch.deltaY)) < 2.6)) then
if self.selected == true and self.action then
flying = "none"
self.selected = false
self.action()
end
end
end
This is driving me nuts, because it works a 50% of the time, but I cannot move forward with this app until I find a workaround which I think could be a timing issue of the execution.
I’ve read your post too hastily the first time, let’s go on with a more profound analysis that tries to unravel your wrongdoing since I won’t let you go with a comment like “Codea doesn’t handle well the touch.state triggering during runtime” (except for an edge case that I look at a moment before).
Like aciolino mentioned you should avoid the CurrentTouch variable or at least make sure with a simple test program that it fulfills your needs. What we’re not really seeing is the full program flow, starting with the global functions draw() and touched().
Look at this part of the code:
if (flying == "P1") then
if CurrentTouch.y > 680 then
fixedy = 680
elseif CurrentTouch.y < 100 then
fixedy = 100
else
fixedy = CurrentTouch.y
end
ssP1 = ScaledSprite("Dropbox:symbol-P1",symbSize * vsmFactor,CurrentTouch.x,fixedy)
ssP1.action = function() btnSymbPRO1pressed() end
ssP1:draw()
dragging = true
end
Where do you execute this? When? I hope not when flying == “P1”, in this case you would call this very often. Or do you set flying to a different value later on? Is it necessary to draw ssP1 after creation? There should be a separate code section concerned with drawing the sprite that is independent of the code section where it is created.
Your work around operates diffently from your original intention.
Original (abbreviated):
function ScaledSprite:touched(touch)
-- Codea does not automatically call this method
if touch.state == MOVING then
-- self selected can be set here
elseif touch.state == ENDED then
if self.selected == true and self.action then
self.selected = false
self.action()
end
end
end
You original solution requires you to move your finger and not just touch the sprite to execute the action.
Your work around:
if touch.state == ENDED and flying == "P1" then
btnSymbPRO1pressed()
end
You’re calling btnSymbPRO1pressed (why not the associated sprite action?) now when the touch ended which includes tapping without dragging. I thought this was somewhat essential.
I assume you’ve got a wrong event flow in mind, so please provide more context so we have a chance to repair it.
Codeslinger thanks for your response; I agree with your statement that this could be generated by a wrong event flow made by me.
But let me try to explain what I am trying to do. The app has a menu with different symbols (a total of 9) each symbol is a Class treated as a Button, my intention is to select each sprite by dragging them out of the menu, then you move around the screen to select a position. When you release your finger (touch.state == ENDED) condition stores the position and id of each symbol on a table.
So my issue was that when I released the symbol sometimes the class action was executed and sometimes didn’t.
Answering your questions…
flying == “P1”, is part of the Global Draw function, flying is just a control var to enable the drawing of the dragged symbol. Fixedy is just a modification to avoid drawing the symbol over the menu bars.
btnSymbPRO1pressed() is the function that is called with the action associated to the Class action I just added as a Plan B in case that the function was not triggered by the touch state condition.
You say when the touch.state == ENDED, you save the position and ID. Is the ID you’re saving the touch.id . Once the touch state ends, the id isn’t valid for anything anymore. Another touch can use the same id as a previous one that’s ended. Even if you touch the same button, a new id or sometimes the same id will be used. The touch.id is valid only as long as the touch is in progress. I’m not sure if that might be your problem, but keep that in mind when using touch.id.
--# Circle
Circle = class()
function Circle:init(n, x, y)
-- you can accept and set parameters here
self.n = n
self.x = x
self.y = y
self.lifted = false
end
function Circle:draw()
fill(127, 127, 127, 255)
ellipse(self.x, self.y, 50)
fill(0, 0, 0, 255)
text(self.n, self.x, self.y)
end
function Circle:touched(touch)
if touch.state == BEGAN then
if math.abs(touch.x - self.x) < 30 and
math.abs(touch.y - self.y) < 30 then
self.lifted = true
end
end
if touch.state == MOVING and self.lifted then
self.x = touch.x
self.y = touch.y
end
if touch.state == ENDED and self.lifted then
self.lifted = false
end
end
--# Main
-- Ttest
displayMode(FULLSCREEN)
function setup()
print("Hello World!")
circles = {}
for i = 1, 7 do circles[i] = Circle(i, i * 100, 100) end
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
-- This sets the line thickness
for i = 1, 7 do circles[i]:draw() end
-- Do your drawing here
end
function touched(touch)
for i = 1, 7 do circles[i]:touched(touch) end
end