Android Tutorial Tick-Tack-Toe: working with arrays of views

Erel

Administrator
Staff member
Licensed User
This is an example of a Tick-Tack-Toe game.
This game demonstrates two concepts. The first is an example of working with multiple views without duplicating code. In this case it is 9 buttons, however similar code can easily handle any number of views.
The second concept is the handling of Activity_Pause and Activity_Resume events to keep the game state during the activity life cycle.

The test it you just need to rotate the device. During the orientation change the activity is paused, created again and eventually resumed.
The game should continue from the previous state.



The following code creates the 9 buttons, puts each button in the correct place and stores a reference to this button in the Buttons array (two dimensions array):
B4X:
    For x = 0 To 2
        For y = 0 To 2
            Dim b As Button
            b.Initialize("button") 'All buttons share the same event sub
            b.TextSize = 30
            Activity.AddView(b,offsetX + x * (width + 10dip), offsetY + y * (width + 10dip), width, width)
            Buttons(x, y) = b 'store a reference to this view
        Next
    Next
Later in Sub Button2_Click we find the button that raised the event with the help of Sender keyword:
B4X:
Sub Button_Click
    'Using Sender we find the button that raised this event
    Dim b As Button
    b = Sender
    If b.Text <> "" Then Return 'Already used button
    ...
Saving the game state is done by using a process global variable. Unlike regular global variables, these variables are kept even when the activity is recreated.
B4X:
Sub Activity_Resume
    'restore the previous state when the activity resumes
    For x = 0 To 2
        For y = 0 To 2
            Buttons(x, y).Text = ButtonsText(x, y)
        Next
    Next
End Sub
Sub Activity_Pause (UserClosed As Boolean)
    If UserClosed Then
        'If the user pressed on the back key we cancel the current game
        NewGame
    End If
    'save the current state when the activity is paused.
    For x = 0 To 2
        For y = 0 To 2
            ButtonsText(x, y) = Buttons(x, y).Text
        Next
    Next
End Sub
Note that the Buttons array cannot be declared as a process global variable. Only non-UI objects can be declared in Sub Process_Globals.

The code is available here: http://www.basic4ppc.com/android/files/tutorials/TickTackToe.zip
 

myriaddev

Active Member
Licensed User
Who was pushed from an array stand point ?

Who was pushed from an array stand point ? I love
the generic approach using "b = Sender", but how
do you translate that info to which item in the array
was pushed ? Could you use "b.Tag" to store array
index info and how ?
Thanks, Jerry
 

Erel

Administrator
Staff member
Licensed User
You have two options. You can iterate over the array and check for equality.
Or you can use the Tag property to store the array index.
In this case there are two values so you need to declare your own type:
B4X:
Sub Globals
 Type indices(x as int, y as int)
End  Sub
...
For y = 0 To 2
            Dim b As Button
            b.Initialize("button") 'All buttons share the same event sub
            b.TextSize = 30
            Activity.AddView(b,offsetX + x * (width + 10dip), offsetY + y * (width + 10dip), width, width)
            Buttons(x, y) = b 'store a reference to this view
            Dim i as indices
            i.initialize 'Not really necessary in this case
            i.x = x
            i.y = y
            b.Tag = i
        Next
...
Sub Button_Click
    'Using Sender we find the button that raised this event
    Dim b As Button
    b = Sender
   Dim i as indices
    i = b.Tag
 

nfordbscndrd

Well-Known Member
Licensed User
...
B4X:
Sub Activity_Resume
    'restore the previous state when the activity resumes
    For x = 0 To 2
        For y = 0 To 2
            Buttons(x, y).Text = ButtonsText(x, y)
        Next
    Next
End Sub
I just came across this thread while searching for something else.
I believe that the above code should be in Activity_Create, not Activity_Resume.

As you noted in this post:

Loading the state from a file should be done in Activity_Create.
If FirstTime = False you can optimize your application and load the state
from a process global variable instead of a file.
And that Activity_Resume should [only] be used for...

resuming elements like timers, animations, GPS, camera and so on
[which presumably were turned off in Activity_Pause]...
...since code in Activity_Resume is run every time the app is started, even if the
device was just turned on, and every time you leave the app and come back
even if Android didn't kill the app and its data/states are still in memory.
 

Erel

Administrator
Staff member
Licensed User
You are correct. Putting the code in Activity_Resume is correct but less optimized.
 

Peter Simpson

Expert
Licensed User
Thank you for this code

Hello Erel,
Thank you for putting this code in the forum.

I'm already writing an app but I've just started writing another app that uses MySQL DB with dynamically generated buttons.

This code hit the sweet spot :)
 

ukimiku

Active Member
Licensed User
Erel,

thanks for the code that shows how to programmatically add views. It (as many other things) now is very easy, esprecially when compared to other development environments. I think you are very good at making things simple (yet flexible) without oversimplifying.

Regards,
 

LouFromDetroit

Member
Licensed User
Nice Demo - I made update if anyone interested

Hi All,

I am new to the B4A forum but I like what I see so far. I started with this demo to test out my system. I added a feature so you can play the computer /android option. If anyone is intersted I can post. I can't promise excellent code writing, but it works.

Thanks to Erel for the demo.
 

paolofi

Member
Licensed User
I tried to use Panels array to create panels grid but I receive an error when try to retrieve the tag id:

java.lang.RuntimeException: Object should first be initialized (Panel).

B4X:
Sub Globals
    Dim ImgPanel(12) As Panel
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Dim r As Int
    Dim c As Int
    Dim sx As Int
    Dim sxInc As Int
    Dim a As Int
    Dim aInc As Int
    r=0
    c=0
  
    For i = 0 To ImgPanel.Length - 1
        Dim p As Panel
        p.Initialize("ImgPanel")
        Activity.AddView(p, sx+(c*sxInc), a+(r*aInc), 130dip, 130dip) 'add the panel to the layout
  
        p.Tag=i
      
        ImgPanel(i)=p
      
        c=c+1
  
        If c>3 Then
            r=r+1
            c=0
        End If
    Next
End Sub

Sub ImgPanel_Click
    'Using Sender we find the panel that raised this event
    Dim p As Panel
    Dim Id As Int
  
    p = Sender
    Id=p.Tag '**** HERE I RECEIVE THE ERROR: java.lang.RuntimeException: Object should first be initialized (Panel).
  
End Sub
Some suggest?

Thanks in advance

Lenny
 
Top