Detect touches on objects

Hi all,

Loving Codea, seeing this as a good entry level to iOS after trying (and failing!) to learn Obj-C and then Cocos2D. I’m not a coding newbie as such as my day-to-day job is PHP coding, plus i used to code in BASIC and have dabbled with various languages.

Anyways, been tinkering today with Codea and wondered how to ‘detect’ a touch on a shape/sprite.

For example, I’m creating a UI test and have made simple “left”, “right” and “fire” buttons for a mock Space Invaders type game.

I can get touch co-ordinates I guess, but I’m assuming there is a better solution to this?

Also I’ve added a class called “Buttons” but not sure if this is the right way to create the UI? Guess I’d have to create the buttons something like;

leftButton = Button(color, xco-ord, yco-ord) …?

Would that work? If so, I guess the answer I’m looking for would be

leftButton.touch ?

Thanks for any help.

Paul

I’ve dealt with this by creating a simple class called “Frame” to hold rectangular boundaries. Then I use frame to define buttons, text boxes, and other control area.


Frame = class()

-- Frame 
-- ver. 1.0
-- a simple rectangle for holding controls.
-- ====================

function Frame:init(left, bottom, right, top)
    self.left = left
    self.right = right
    self.bottom = bottom
    self.top = top
end

function Frame:inset(dx, dy)
    self.left = self.left + dx
    self.right = self.right - dx
    self.bottom = self.bottom + dy
    self.top = self.top - dy
end

function Frame:offset(dx, dy)
    self.left = self.left + dx
    self.right = self.right + dx
    self.bottom = self.bottom + dy
    self.top = self.top + dy
end
    
function Frame:draw()
    pushStyle()
    rectMode(CORNERS)
    rect(self.left, self.bottom, self.right, self.top)
    popStyle()
end

function Frame:touched(touch)
    if touch.x >= self.left and touch.x <= self.right then
        if touch.y >= self.bottom and touch.y <= self.top then
            return true
        end
    end
    return false
end

function Frame:ptIn(x, y)
    if x >= self.left and x <= self.right then
        if y >= self.bottom and y <= self.top then
            return true
        end
    end
    return false
end

function Frame:overlaps(f)
    if self.left > f.right or self.right < f.left or
    self.bottom > f.top or self.top < f.bottom then
        return false
    else
        return true
    end
end

function Frame:width()
    return self.right - self.left
end

function Frame:height()
    return self.top - self.bottom
end

function Frame:midX()
    return (self.left + self.right) / 2
end
    
function Frame:midY()
    return (self.bottom + self.top) / 2
end

Thanks Mark, its kinda what I thought, but seems awfully long-winded (no offence!) to do something fairly straight forward?

Hmmm… ok I’ll have a play with this, appreciate the help :slight_smile:

How do you use Frame to define buttons? Could you, if you have the time, create an example project? for example, something super simple with one button that when pushed changes the background, or something of that nature

Well, you clearly don’t need all of that class just to test for touches. My frame class reflects various needs that have come up in projects. You could trim it to something like this if you just want a dedicated button class. This example doesn’t include the fill / font settings. You define those in the class or before you call draw()

SimpleBtn = class()

function SimpleBtn:init(text, left, bottom, right, top)
    self.text = text
    self.left = left
    self.right = right
    self.bottom = bottom
    self.top = top
end
    
function SimpleBtn:draw()
    pushStyle()
    rectMode(CORNERS)
    textMode(CORNERS)
    rect(self.left, self.bottom, self.right, self.top)
    fill(0, 0, 0, 255)
    text(self.text, self.left + 30, self.bottom + 20)
    popStyle()
end

function SimpleBtn:touched(touch)
    if touch.x >= self.left and touch.x <= self.right then
        if touch.y >= self.bottom and touch.y <= self.top then
            return true
        end
    end
    return false
end


what does it do if it returns true?

It does nothing. True just means that the touch you tested was in the bounds of the button.

If you want it to do something like change color when touched, you could add that to the button class. But if what you want is some other action (like move my character left) your better off not embedding that in the control.

So I could do,

SimpleBtn = class()

function SimpleBtn:init(text, left, bottom, right, top)
    self.text = text
    self.left = left
    self.right = right
    self.bottom = bottom
    self.top = top
end
    
function SimpleBtn:draw()
    pushStyle()
    rectMode(CORNERS)
    tectMode(CORNERS)
    rect(self.left, self.bottom, self.right, self.top)
    text(self.text, self.left + 10, self.bottom + 10)
    popStyle()
end

function SimpleBtn:touched(touch)
    if touch.x >= self.left and touch.x <= self.right then
        if touch.y >= self.bottom and touch.y <= self.top then
            return true
function draw() 
Background(0,0,0,0)
        end
    end
    return false
end

And it would make a black screen If I pushed the button?

Try something more like this…

Start a new project. In that project, create a new class called SimpleBtn. Now select all the code in that class and replace it with the sample code above.

Now, in your main file, go into the init function and add a couple of lines:

myBtn = SimpleBtn("Test", 100, 100, 200, 150)
showMsg = false

Then go down to the draw() function in main, and add this:

myBtn:draw()
if showMsg then
    text("Message On!", 100, 300)
end

If you run the program now, you should see a button on the screen. It will be ugly, but you can pretty it up by adding the right fill(), stroke(), and font() statements to get the look you want.

Now, at the bottom of your draw() routine, you’ll need to call the touched routine. Just adding:

touched(CurrentTouch)

should do it.

Finally, go to the touched function and add this

if myBtn:touched(touch) then
    showMsg = not showMsg
end

So, you’ve now created a button, drawn it on the screen, used it to control a value, and used that value to display a message.

Make sense?

This is all great, thanks guys!

The last couple of bits of code are confusing Mark?

I get an error on the touched(CurrentTouch) line and you say add the last bit of code to the touch function which isn’t defined anywhere?

Any tips please?

Thanks :slight_smile:

@Bieber208 I embedded your code inside a ~~~ block to make it more readable.

@John Thanks. However, i can’t get this code to work… is there another way? I’m using a class that draws a sprite i created in spritely. i want it to do playing = false when i touch it. This possible?

@pbb76 Same here. this is why i can’t get it to work…

@John Thanks. However, i can’t get this code to work… is there another way? I’m using a class that draws a sprite i created in spritely. i want it to do playing = false when i touch it. This possible?

@pbb76 Same here. this is why i can’t get it to work…

@pbb76 Same here. this is why i can’t get it to work…

Here’s the Main with everything in place as noted above.


function setup()
    myBtn = SimpleBtn("Test", 100, 100, 200, 150)
    showMsg = false
end

function draw()
    background(40, 40, 50)
    strokeWidth(5)
    myBtn:draw()
    if showMsg then
        text("Message On!", 100, 300)
    end
    touched(CurrentTouch)
end

function touched(touch)
    if myBtn:touched(touch) and touch.state == BEGAN then
        showMsg = not showMsg
    end
end

@Mark I do not understand how your example works? Could you possibly alter your example so that it creates a button that when touched switches to a different screen? P.S.I am still on v. 1.2.5 so text does not work.

I’m afraid there is no “go to a different screen.”. If you want the screen to be different, just draw something different.

Using the same code above, you could put any amount of drawing you want inside the “if showMsg” segment.