Making png as buttons

Yoel12

New Member
Joined
Mar 9, 2019
Hey, I’m fairly new to cx and coding in general and I was wondering if you can make a png image as a button so when it is clicked with the mouse it changes the game state
 

magic

Active Member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Code need image.png ad button:
Import mojo
Function Main();New MyApp;end   
Class MyApp Extends App
    Field but:Image
    Field but_state:Int=0
    Method OnCreate()
        but=LoadImage("image.png")
    End
    Method OnUpdate()
        If MouseX<but.Width() And MouseY<but.Height()
            but_state=1
            If MouseHit() Then but_state=2;Print "Do Something!"   
        Else
            but_state=0
        Endif
    End
    Method OnRender()
        Cls()
        Select but_state
            Case 0 ; SetAlpha(0.8)
            Case 1 ; SetAlpha(1)
            Case 2 ; SetColor(255,0,0);DrawRect(0,0,1000,1000)
        End
        DrawImage(but,0,0)
    End
End
The above code need a data folder and put image.png in it.
If you a beginner, you can just download this zip file.
 

Attachments

Paul59

Active Member
CX Code Contributor
Joined
Dec 13, 2018
Location
UK
Hey, I’m fairly new to cx and coding in general and I was wondering if you can make a png image as a button so when it is clicked with the mouse it changes the game state
Break the problem down.

First you need to know whether the x,y co-ords of the mouse are 'over' or 'within' the button. @magic shows you how to do it for a button at top left of screen. Draw a rectangle or use an image and get your program to print a message (or something) whenever the mouse is over the button. (Clue; if (mouse x > button x) and (mouse x < button x + button width) and (same for y) then mouse is over button. Draw it on a piece of paper if you can't get your head round it.

Once you've got that sorted you can check for clicks and change the game state or whatever.
 

dawlane

Active Member
CX Code Contributor
Joined
Jun 21, 2017
Hey, I’m fairly new to cx and coding in general and I was wondering if you can make a png image as a button so when it is clicked with the mouse it changes the game state
Yes you can, but you will have to know a few programming concepts first to do the job, or programming in general.
I don't know your level of knowledge of computers and how they work, so I will start with the basics.

Under stand how computers store information.​
Computers are basically transistor calculators that have large memory storage. If you have ever studied electronics at school, you will know that a transistor will only allow an electric current to flow through it if an electric current is applied to only that transistors designated connection that makes it operate in that fashion. You can therefore say when an electric current is applied to that connection, the transistor is turned on. So a transistor can be only in a binary state, either on or off. As memory is also constructed of transistors, and organised in such a way that it lends it's self to fit neatly with the modern binary number system. From here on I will call one of these transistors a bit, which is a short form for binary digit.​
Now humans have used eight fingers and two thumbs for counting, so it's logically easy for us to use a power of 10 counting system (e.g. Thousands(1000-9000), Hundreds(100-900), Tens (10-90), Units (1-9)). When we have counted past 9 Units, we would add 1 to the Tens, then start again from Unit 0. When Tens goes past 9, then add 1 to the Hundreds and so on.​
Now computer memory is organised into groups of eight bits know as a byte. And as binary numbers are a power of 2 counting system and following the same process as for power of 10 counting above, the Units would be in the range of 0-255. When the Unit passed 255 you add one to the next memory byte along. Now it gets complicated, mostly because for the development of computers and compilers over the last several decades. You will hear the term WORD used from time to time. For the explanation of how memory is organised I will stick to the data type defined in most compilers for Intel x86 CPU.​
BYTE = 8 BITS number range 0-256​
WORD = 2 BYTES (16 BITS) number range 0-65535​
DWORD = 4 BYTES (32 BITS) number range 0-4294967295​
QWORD = 8 BYTES (64 BITS) number range 0-18446744073709551615​
Now the CPU in a computer can also determine how those bytes are arranged in memory.​
There are two ways and known as Endiannes:​
Numbers are stored from the lowest byte (aka least significant) to the highest byte (aka most significant). e.g. Units, Tens, Hundreds, Thousands.​
Numbers are stored from the highest (aka most significant) to lowest (aka least significant). e.g. Thousands, Hundreds, Tens, Units.​
Integer numbers (aka Int data type) in Cerberus are signed 32 bit (DWORD) values in the range of -2,147,483,648 to 2,147,483,647. There are a number of ways to signify a negative number with the most dominate today being 'Two's Compliment'.​
Floating point numbers (aka Float data type) in Cerberus and depending on the target, use a single precision 32 bit encoded representation. Some targets can support double precision.​
In general, everything is stored as binary data either as is, or encoded.​
Note that the Hexadecimal number system also fits very well to power of 2 system. A single hex digit (0-9-A-F=0-15) can represent four bits (also known as a nibble). So a value of 255 can be written as FF (16*(F=15)+(F=15)).​
Bit-wise operators allow you to manipulate the individual bits of memory, or in the case of Cerberus variable of type Int and Float.​
These are useful for setting, shifting and testing the on/off state of a bit. If you wanted to support multiple controllers and didn't want to re-invent the wheel having to write test code for each to move the same game sprite, then you would create a custom data type to encapsulate the functions to read the device and set individual bit of a integer data type that can be read by just one bit of code to move the game sprite.​
Cerberus supports a form of oop, which can be use to create a custom data type to represent anything you can imagine. For something like a button you need to handle input devices, generate events created by the input device and the actual button it's self. If there is to be more than one button, then you need a way to store buttons and retrieve that button when required. One way is to store a button by giving it an id code and storing it in a collection container type such as a Map.​
Now for a demonstration of a simple button system that shows some of the concepts outlined. You may not understand the code as it's a bit on the advanced side, but after you have read and gone through the on-line tutorials and the language reference you should have a better understanding. It's broken up into individual source files that you must create and name accordingly, so create a new folder to hold them together. You would do this to make source code more manageable.

To use images instead of coloured rectangles, you can create what is known as an texture atlas that contains all the images for the GUI buttons. You would then store the position and dimensions for each GUI button in the image atlas as an array and use the DrawImageRect function to copy the that part of the texture atlas to screen.

Note due to the amount of text allowed in a post I have not been able to add many comments to explain in detail what is happening in the code and how it works.

The main file:
demo.cxs:
Strict

Import mojo
Import common
Import input
Import button

Class CGame Extends App
    Method OnCreate:Int()
        SetUpdateRate(60)
        CreateButton(GUI_BUTTON_HELLO, 100, 200, 100, 25, " HELLO ")
        CreateButton(GUI_BUTTON_GOODBYE, 205, 200, 100, 25, " GOODBYE ")
        Return 0
    End Method

    Method OnUpdate:Int()
        Local buttonID:Int
        PollInput()
        buttonID = PollButtons()

        Select buttonID
            Case GUI_BUTTON_HELLO
                Print "HELLO"
            Case GUI_BUTTON_GOODBYE
                Print "GOOD BYE"
        End Select
        Return 0
    End Method

    Method OnRender:Int()
        Cls
        RenderButtons()
        DrawText("X:"+DevicePointerX()+", Y:"+DevicePointerY(), DevicePointerX()+10, DevicePointerY() )
        Return 0
    End Method
End Class

Function Main:Int()
    New CGame()
    Return 0
End Function
The Input device file.
input.cxs:
Strict

Import mojo
Import common

' Read the device controls and set the device button status flag
Function PollInput:Void()
    CInputDevice.device.status = 0

    CInputDevice.device.pointer.XPos = MouseX()
    CInputDevice.device.pointer.YPos = MouseY()

    ' Map a mouse button to a bit in the button status flag. Using bitwise OR(|) sets a bit in the button status flag.
    If MouseDown(MOUSE_LEFT) CInputDevice.device.status |= CTL_BUTTON_ONE
    If MouseDown(MOUSE_RIGHT) CInputDevice.device.status |= CTL_BUTTON_TWO
    If MouseDown(MOUSE_MIDDLE) CInputDevice.device.status |= CTL_BUTTON_THREE

End Function

Function CheckInput:Bool(buttons:Int=CTL_BUTTON_NONE)
    ' Using the button mask passed bitwise AND(&) it to the device button status flag
    ' If the corresponding bit in the button mask is turned on in the device button status flag, then return a boolean value of true
    If CInputDevice.device.status & buttons Return True
    Return False
End Function

Function DevicePointer:CPoint()
    Return CInputDevice.device.pointer
End Function

Function DevicePointerX:Float()
    Return CInputDevice.device.PointerX()
End Function

Function DevicePointerY:Float()
    Return CInputDevice.device.PointerY()
End Function

' Simple wrapper class to encapsulate a control device status.
Class CInputDevice

    Method Clear:Void()
        status = 0
    End Method

    Method PointerX:Float()
        Return pointer.XPos()
    End Method

    Method PointerY:Float()
        Return pointer.YPos()
    End Method

    Private
        Global device:= New CInputDevice()

        Field status:Int
        Field pointer:= New CPoint(DeviceWidth()/2, DeviceHeight()/2)
End Class
The button code.
button.cxs:
Strict

Import mojo
Import common
Import input

' Create a button and add it to the collection container so that it can be drawn or polled with the next two function below.
Function CreateButton:CButton(id:Int, x:Float, y:Float, w:Int=100, h:Int=25, text:String="Button")
    Local b:= New CButton(id, x, y, w, h, text)
    CButton.buttons.Add(id, b)
    Return b
End Function

Function RenderButtons:Void()
    For Local i:=Eachin CButton.buttons
        ' We have to get the value of an item in the container first before you can call the items Draw method.
        i.Value().Draw()
    Next
End Function

Function PollButtons:Int()
    For Local i:=Eachin CButton.buttons
        If i.Value().ButtonCheck() Return i.Value().ButtonID()
    Next
    Return GUI_BUTTON_NONE
End Function

Class CButton

    Method New(id:Int, x:Float=0, y:Float=0, w:Int=1, h:Int=1, text:String="Button")
        Self.pos.XPos = x
        Self.pos.YPos = y
        Self.w = w
        Self.h = h
        Self.state = BTNSTAT_NORMAL
        Self.id = id
        Self.text = text
    End Method

    Method ButtonCheck:Bool()
        state=BTNSTAT_NORMAL

        ' Note to test for multiple button inputs you can chain the constants together using the bitwise OR(|) operator.
        ' CTL_BUTTON_ONE|CTL_BUTTON_TWO
        Local input:= CheckInput(CTL_BUTTON_ONE)

        If Point2RectBounds(DevicePointerX(), DevicePointerY(), pos.XPos, pos.YPos, pos.XPos+w, pos.YPos+h)
            ' Any non zero value retrieved will equate to a boolean true value
            If input
                ' Set the GUI buttons state to pressed and save this state
                state = BTNSTAT_DOWN
                lastState = state
            Else
                ' If the last state was the GUI button pressed and there was no input, then set the button to it's non pressed state and
                ' trigger that the button was pressed by returning a boolean true value.
                If lastState = BTNSTAT_DOWN And input = 0
                    lastState = BTNSTAT_NORMAL
                    state = lastState
                    Return True
                End
                ' If there in no input state and the device cursor is over a button, the highlight the button.
                state = BTNSTAT_HOVER
                lastState = state
            Endif
        Else

            state = BTNSTAT_NONE
            lastState = state
        Endif
        Return False
    End Method

    Method Draw:Void()
        Select state
            Case BTNSTAT_DOWN
                SetColor(100, 100, 100)
            Case BTNSTAT_HOVER
                SetColor(255, 255, 255)
            Default
                SetColor(175, 175, 175)
        End Select

        DrawRect(pos.XPos, pos.YPos, w, h)
        DrawText(text, pos.XPos+(w/2), pos.YPos+(h/2), 0.5, 0.5)
    End Method

    ' Returns the button id that was set when creating the button.
    Method ButtonID:Int()
        Return id
    End Method

    Private
        Const BTNSTAT_NONE:=-1
        Const BTNSTAT_NORMAL:=0
        Const BTNSTAT_DOWN:=1
        Const BTNSTAT_HOVER:=2

        Global buttons:= New IntMap<CButton>()
        Field pos:=New CPoint()
        Field w:Int
        Field h:Int
        Field state:Int
        Field lastState:Int
        Field id:Int
        Field text:String
End Class
Code that is used by a number of other files.
common.cxs:
Strict

' Button masks to trap a bit in the device button status flag.
Const CTL_BUTTON_NONE:=0
Const CTL_BUTTON_ONE:=$01
Const CTL_BUTTON_TWO:=$02
Const CTL_BUTTON_THREE:=$04

' Consts for the button id's
Const GUI_BUTTON_NONE:=0
Const GUI_BUTTON_HELLO:=1
Const GUI_BUTTON_GOODBYE:=2

' This is a custom data type the represents s point in 2D (screen) space.
Class CPoint

    Method New(x:Float, y:Float)
        Self.x = x
        Self.y = y
    End Method

    Method XPos:Void(x:Float) Property
        Self.x = x
    End Method

    Method XPos:Float() Property
        Return x
    End Method

    Method YPos:Void(y:Float) Property
        Self.y = y
    End Method

    Method YPos:Float() Property
        Return y
    End Method

    Method GetPoint:CPont()
        Return Self
    End Method

    Private
        Field x:Float
        Field y:Float
End Class

#Rem    This is a general purpose function to check if a point is within a rectangle.
        x and y is the position of the point in 2D space
        x1 and y1 is the top left corner of the rectangle.
#End    x2 and y2 is the bottom right of the rectangle and would be the rectangles x positon + width and the rectangles y position + height
Function Point2RectBounds:Bool(x:Float, y:Float, x1:Float, y1:Float, x2:Float, y2:Float)
    If x > x1 And x < x2 And y > y1 And y < y2 Then Return True
    Return False
End Function
 
Last edited:

Holzchopf

Moderator
Joined
Jul 31, 2017
Location
Bern, Switzerland
Sorry @dawlane but I think for a beginner your answer is waaaaaaaay to detailed. It should be sufficient to mention how to
retrieve the mouse coordinates, to know how to check whether there inside a rectangular bound (hint: use >= and <) and how to change a state. Judging from the fact @Yoel12 said he's fairly new, I'd say his "state" is either just a variable telling which state is active or plainly non-present (in that case: use a variable that tells which state is active)
 
Last edited:
Top Bottom