Displaying the Board
With make_board() producing the data and GridLayout able to hold an 8×8 grid of buttons, this lesson connects the two: turning the plain Python board into actual colored gems on screen.
Mapping colors to RGBA
GEM_RGBA = {
'red': (0.9, 0.2, 0.2, 1),
'blue': (0.2, 0.4, 0.9, 1),
'green': (0.2, 0.8, 0.3, 1),
'yellow': (0.95, 0.85, 0.2, 1),
'purple': (0.6, 0.2, 0.8, 1),
}
Every gem color string from board needs a matching entry here, this dictionary is the only place that translates the game's data (plain strings) into something Kivy can actually render.
Building the grid of buttons
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
class Match3App(App):
def build(self):
self.board = make_board()
self.grid = GridLayout(cols=BOARD_SIZE)
self.buttons = {} # (row, col) -> Button, so taps can be mapped back to a position
for row in range(BOARD_SIZE):
for col in range(BOARD_SIZE):
gem = Button(text='', background_normal='')
self.buttons[(row, col)] = gem
self.grid.add_widget(gem)
self.render_board()
return self.grid
def render_board(self):
for row in range(BOARD_SIZE):
for col in range(BOARD_SIZE):
color = self.board[row][col]
self.buttons[(row, col)].background_color = GEM_RGBA[color]
if __name__ == '__main__':
Match3App().run()
A few things worth noticing:
self.buttonsis a dictionary keyed by(row, col), created once inbuild(). Every later lesson looks up "which button is at this position?" through this dictionary rather than re-creating widgets, Kivy widgets are relatively expensive to create, so the board reuses the same 64 buttons for the entire game.render_board()is deliberately a separate method frombuild(): it only readsself.boardand updates colors, it never creates new widgets. That means any later change toself.board(a swap, a match being cleared, gems falling) can be shown on screen just by callingself.render_board()again.- Note the important order: rows are added top to bottom, and within each row, columns left to right, matching
GridLayout(cols=BOARD_SIZE)'s own top-to-bottom, left-to-right fill order, soself.buttons[(row, col)]really does end up in the right visual position.
TIP
Separating "update the data" from "redraw from the data" (the same idea as Pygame's update/draw split) is what makes the rest of this game's logic straightforward: every lesson from here on just changes self.board and then calls self.render_board().