Quick Links: Download Gideros Studio | Gideros Documentation | Gideros Development Center | Gideros community chat | DONATE
Clicking a shape returns false for hitTestPoint. — Gideros Forum

Clicking a shape returns false for hitTestPoint.

I can’t figure out why clicking a shape is returning false for hitTestPoint.

I have a Button class which defines a click method. I use this method in my splashScene for a button to start the game and it works fine.

In the splashScene (and it will eventually be added to all other scenes) I’ve added a button for raising and lowering the volume of the background music. The code for this is below.

There is a group for the button. Added to this group is an image of text as a label for the button and the image of the button itself.

Added to the button is a shape overlaying the top half of the button, the area with the “up” arrow. Once I get this working, the opacity of this shape will be set to 0 and another shape will be added overlaying the bottom half of the button, the area with the down area, to lower the volume.

The shape has a click event listener which uses the same button class click method I used for the start button, which works fine. But when I click the shape, the hitTestPoint returns false and so, of course, nothing happens. I can’t figure out why it doesn’t return true.

CODE BELOW:
--add music volume button group
local musicVolumeButtonGroup = Sprite.new()
musicVolumeButtonGroup:setAnchorPoint( 0 , 0 )
musicVolumeButtonGroup:setPosition( conf.gameWidth * 0.87, conf.gameHeight * 0.6 )
self:addChildAt(musicVolumeButtonGroup, 3)

--add text image to button group
local musicVolumeText = Bitmap.new(Texture.new("images/musicVolumeText.png", true))
musicVolumeText:setAnchorPoint( 0 , 0 )
musicVolumeText:setPosition( 0 , 0 )
musicVolumeButtonGroup:addChildAt( musicVolumeText , 1 )

--add button image to button group
local musicVolumeButton = Bitmap.new(Texture.new("images/musicVolumeButton.png", true))
musicVolumeButton:setAnchorPoint( 0 , 0 )
musicVolumeButton:setPosition( 0 , musicVolumeText:getHeight() * 1.1 )
musicVolumeButtonGroup:addChildAt( musicVolumeButton , 1 )

--add volume up shape to button
local volumeUpButton = Shape.new()
volumeUpButton:setLineStyle( 2, color.yellow, 1 )
volumeUpButton:setFillStyle( Shape.SOLID, color.blue, 0.8 )
local volumeUpButtonX = musicVolumeButton:getWidth()
local volumeUpButtonY = musicVolumeButton:getHeight() / 2
volumeUpButton:beginPath()
volumeUpButton:moveTo( 0 , volumeUpButtonY )
volumeUpButton:lineTo( volumeUpButtonX , volumeUpButtonY )
volumeUpButton:lineTo( volumeUpButtonX , 0 )
volumeUpButton:lineTo( 0 , 0 )
volumeUpButton:closePath()
volumeUpButton:endPath()
volumeUpButton:setAnchorPoint( 0 , 0 )
volumeUpButton:setPosition( 0, 0 )
volumeUpButton:addEventListener("click", function()
if backgroundMusicVolume < 1 then backgroundMusicVolume = backgroundMusicVolume + 0.1 end
end)
musicVolumeButton:addChildAt ( volumeUpButton , 1 )

Comments

  • keszeghkeszegh Member
    edited January 2018
    you might need to call hittestpoint for shape:globalToLocal(x,y) instead of for x,y.
  • Thanks, keszegh, but I don't know how to implement what you suggested.

    Below is the code for the Button class, which includes the "click" event which is called in the event listener. (Note: The print statement in the button class code is how I know hitTestPoint is returning false.)

    BUTTON CLASS CODE:
    Button = Core.class(Sprite)

    function Button:init(sprite)
    self:addChild(sprite)
    self:addEventListener(Event.MOUSE_UP, self.onMouseUp, self)
    end

    -- This function does 3 things
    -- 1. Checks if click point is in object.
    -- 2. Stops propagation of this event.
    -- 3. MOST IMPORTANT-Tells program to do task specific to the button which called this function.
    function Button:onMouseUp(event)
    print("self:hitTestPoint(event.x, event.y)= ", self:hitTestPoint(event.x, event.y))
    if self:hitTestPoint(event.x, event.y) then
    event:stopPropagation()
    local clickEvent = Event.new("click")
    self:dispatchEvent(clickEvent)
    end
    end
  • i don't have time to look into it now, why don't you use the 'standard' button class:
    https://github.com/gideros/Button
    or at least have a look how that works.
  • Thanks, keszegh.

    I well understand that you and others are volunteers and I never expect "immediate responses" and I'm grateful for the time you put into helping neophytes like me.

    Regarding "why don't you use the 'standard' button class", frankly I wasn't aware there is one and I will certanly take a look at it.

    I have been following pretty closely ar2rsawseen's book and my button class is pretty much taken from there. But again, I'll look at using the standard one you referenced. Thanks again.
  • at first look your code seems to be fine, event.x,y are given in global coord system according to http://docs.giderosmobile.com/reference/gideros/Sprite/hitTestPoint so there should be no need to use globalToLocal (contrary to what i suggested).
  • @rpallen
    The standard button class is in the examples that go with Gideros Studio

    Also see my class buttons - In my class, you can press several buttons simultaneously
    http://giderosmobile.com/forum/discussion/7200/button-class-is-multitouch#latest

    Likes: keszegh, antix

    my games:
    https://play.google.com/store/apps/developer?id=razorback456
    мій блог по гідерос https://simartinfo.blogspot.com
    Слава Україні!
    +1 -1 (+2 / -0 )Share on Facebook
  • Thanks, Oleg. For now, I'll concentrate on the standard button class. If I ever progress to doing something with multitouch, I'll look at you advanced version.

    keszegh, I'll chang to the standard button class in my program and see what happens.
  • @rpallen

    my class also knows how to work without a multitouch =)
    my games:
    https://play.google.com/store/apps/developer?id=razorback456
    мій блог по гідерос https://simartinfo.blogspot.com
    Слава Україні!
  • Well, I've got a problem with using the standard button class.

    I changed thebutton class file to the one in the examples folder of Gideros. In my splashScene there's a button to start the game. In the code for this button, I changed from a single local variable for the image for the button to 2 local variables, "up" and "down" for the images and then changed the Button.new() to include the two images.

    Here is the code (I don't have specific up and down buttons yet, so I just used images of 2 different buttons I already have. I'll change them when this works.):

    local up = Bitmap.new(Texture.new("images/restartButton.png", true))
    local down = Bitmap.new(Texture.new("images/quitButton.png", true))
    local startButton = Button.new( up, down )

    When I run the project, at first, it performs as expected - displaying the button. I expected that when I clicked the botton, the button image would change to the other image and change back when released and it would perform the "click" function, which in this case is change to the playScene. However, when I click the button, it just changes the image and stops and produces the output below in the console.

    classes/button.lua:98: bad argument #1 to 'contains' (Sprite expected, got nil)
    stack traceback:
    classes/button.lua:98: in function 'updateVisualState'
    classes/button.lua:17: in function 'init'
    [string "property.lua"]:52: in function '__new'
    [string "property.lua"]:59: in function 'new'
    scenes/PlayScene.lua:94: in function 'init'
    [string "property.lua"]:52: in function '__new'
    [string "property.lua"]:59: in function 'new'
    classes/scenemanager.lua:287: in function 'changeScene'

    Here are lines 98, 99 and 100 of button.lua
    if self:contains(self.downState) then
    self:removeChild(self.downState)
    end

    I wondered if there was a problem with the function in the event listener. Below is the code. You'll see that I commented out the sceneManager line and added a print statement. When I did this I got the expected results: on clicking, the button image changed, the print statement printed and the button image changed back.

    So why does the sceneManager line "break" this? It worked fine with my simpler Button class.

    startButton:addEventListener("click", function()
    print("start button clicked")
    --sceneManager:changeScene("play", conf.transitionTime, conf.transition, conf.easing)
    end)

  • rpallenrpallen Member
    edited January 2018
    A side note:
    While I'm waiting for a solution for my last comment, I decided to try something UNRELATED. I decided I don't necessarily want to have an up state and a down state and therefore have to create 2 images. Of course, I could just put the same variable for both images in the function call, i.r., local startButton = Button.new( buttonImage , buttonImage ).

    But I decided if I'm only using one image, I'd rather only put one image in the function call, so in the init function I replaced
    self.downState = downState

    with

    if not downState then
    print("Did you intend not to add an image for the down state?")
    self.downState = upState
    else
    self.downState = downState
    end

    So now, I can enter 2 images if I want to or, if I enter just one image, it will use the same image for both states (and give me a warning in the console).

    Is there any reason I shouldn't do this?
  • olegoleg Member
    edited January 2018
    I just change the button image when she is pressed


    self:setColorTransform(2, 2, 2, 1)


    **ps


    self.downState = upState --

    it makes no sense to do so!!!
    -- if state is true show downState else show upState
    function Button:updateVisualState(state)
    	if state then
     
    			--self:setAlpha(0.5)
     
    				self:setColorTransform(2, 2, 2, 1)
     
     
    	else
     
    			--self:setAlpha(1)
     
    				self:setColorTransform(1, 1, 1, 1)
     
     
    	end
    end
    my games:
    https://play.google.com/store/apps/developer?id=razorback456
    мій блог по гідерос https://simartinfo.blogspot.com
    Слава Україні!
  • keszeghkeszegh Member
    edited January 2018
    the error is not with the button you pressed but with a button which is created when entering the new scene (i think so because the error is happening in the 'init' function of the button class). there must be a button for which the 'downState' image is non-existent for some reason. if you would send the whole project in pm or something i guess the error would be apparent.
  • btw i also sometimes use the same image for down and upstate, you can simply just init the button with the same image like this:
    b=Button.new(buttonBmp,buttonBmp)
  • rpallenrpallen Member
    edited January 2018
    Oleg, I think we are not understanding each other. You said, "I just change the button image when she is pressed". I don't want to change the button image - EVER. Why? I have many buttons and all have 3 images (image.png, image@med.png and image@big.png). If I'm going to change the image for each, I'll then have 6 images for each button. This takes time to make all of those buttons, but more importantly, it doubles the storage for each button to have twice as many files per button.
  • olegoleg Member
    edited January 2018
    function Button:updateVisualState(state)
    	if state then
     
    if self.downState then
     
                    if self:contains(self.upState) then
    			self:removeChild(self.upState)
    		end
     
    		if not self:contains(self.downState) then
    			self:addChild(self.downState)
    		end
    else
       self:setColorTransform(2, 2, 2, 1)
     
    end
     
    else
    ......
    my games:
    https://play.google.com/store/apps/developer?id=razorback456
    мій блог по гідерос https://simartinfo.blogspot.com
    Слава Україні!
  • GOOD CALL, KESZEGH!

    "the error is not with the button you pressed but with a button which is created when entering the new scene" is the problem. I went to playScene (the new scene being entered) and commented out all of the listeners. When I clicked the start button, it went to the playScene, no problem.

    Now I just have to make changes throughout the project based on the new Button class.

    Thanks again, keszegh!

    And I still have to see if the new Button class solves the original problem with the hitTestPoint.
  • Well, the class had nothing to do with the hitTestPoint problem. The problem was that even though I created the shapes to overlay the buttons, and they appeared on the screen, I hadn't made them into buttons at all! I never did the call to Button.new for the shapes. I've now done that and hitTestPoint is now returning true.

    Likes: keszegh, antix

    +1 -1 (+2 / -0 )Share on Facebook
Sign In or Register to comment.