How to create a game for wxPython - Part 4 (Phoenix)
Keywords : Break-wall, Othello, Chess, Snake.
Contents
Demonstrating :
Tested py3.x, wx4.x and Win10.
Are you ready to use some samples ?
Test, modify, correct, complete, improve and share your discoveries !
Break-wall
1 # break-wall.py
2
3 """
4
5 File : break-wall.py
6 Author : Masaharu Kanda - @kanlkan
7 Link : https://qiita.com/kanlkan/items/5b8d2c5b567a8d5ae6bf
8 Link : https://github.com/kanlkan/break-wall
9 Tested : LinuxMint 17.3 (python 2.7.6 + wxpython 3.0.3) (Classic)
10 Tested : Windows 10 (python 2.7.11 + wxpython 3.0.2 (Classic)
11 Tested : Windows 10 (python 3.8.5 + wxpython 4.1.1 (Phoenix))
12
13 """
14
15 import wx
16 import random
17 import math
18
19 #---------------------------------------------------------------------------
20
21 gVersion = "v0.8.0"
22 gGameState = ("INIT", "PLAYING", "END")
23 gTimerInterval = 5 # [msec]
24 gFieldWidth = 652
25 gFieldHeight = 720
26 gFieldColor = (230, 230, 160)
27 gBarIniPos = (300, 640)
28 gBarSize = (120, 20)
29 gBarColor = (90, 170, 90)
30 gBarSpeed = 60
31 gBallRadius = 8
32 gBallColor = (0, 0, 255)
33 gIniBallSpeed = 5
34 gBlkTop = 120
35 gBlkVCnt = 8
36 gBlkHCnt = 3
37 gBlkSize = (80, 40)
38 gBlkColor = ((255 ,0, 0),(0, 255 ,0),(0, 0, 255))
39
40 #---------------------------------------------------------------------------
41
42 # class MyFrame
43 # class MyFieldPanel
44 # class MyBar
45 # class MyBall
46 # class MyBlock
47
48 #---------------------------------------------------------------------------
49
50 class MyFrame(wx.Frame):
51 def __init__(self):
52 wx.Frame.__init__(self, None, wx.ID_ANY, "Break wall " + gVersion,
53 size=(gFieldWidth + 4, gFieldHeight + 4),
54 style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER |
55 wx.MAXIMIZE_BOX))
56
57 self.SetIcon(wx.Icon('./icons/wxwin.ico', wx.BITMAP_TYPE_ICO))
58
59 #------------
60
61 self.main_field = MyFieldPanel(self)
62
63 self.Bind(wx.EVT_CLOSE, self.onClose)
64 self.Bind(wx.EVT_TIMER, self.onTimer)
65
66 self.timer = wx.Timer(self)
67 self.timer.Start(gTimerInterval)
68
69 #-----------------------------------------------------------------------
70
71 def onClose(self, event):
72 self.timer.Stop()
73 self.Destroy()
74
75
76 def onTimer(self, event):
77 self.main_field.update()
78
79 #---------------------------------------------------------------------------
80
81 class MyFieldPanel(wx.Panel):
82 def __init__(self, parent, pos=(2, 2), size=(gFieldWidth, gFieldHeight)):
83 wx.Panel.__init__(self, parent, pos=pos, size=size)
84
85 self.pos = pos
86 self.size = size
87
88 self.SetBackgroundColour(gFieldColor)
89 self.SetBackgroundStyle(wx.BG_STYLE_PAINT)
90
91 self.bar = MyBar(self, gBarIniPos[0], gBarIniPos[1])
92 self.ball = MyBall(self, gBarIniPos[0], (gBarIniPos[1] - gBallRadius))
93 self.blocks = [[MyBlock(i*gBlkSize[0], gBlkTop+j*gBlkSize[1], \
94 gBlkColor[(gBlkVCnt*j+i)%gBlkHCnt]) \
95 for i in range(gBlkVCnt)] for j in range(gBlkHCnt)]
96 self.block_exist = [[1 for i in range(gBlkVCnt)] for j in range(gBlkHCnt)]
97 self.state = gGameState[0]
98
99 self.Bind(wx.EVT_PAINT, self.onPaint)
100 self.Bind(wx.EVT_KEY_DOWN, self.onKey)
101
102 #-----------------------------------------------------------------------
103
104 def update(self):
105 self.ball.move()
106 self.Refresh()
107
108
109 def onPaint(self, event):
110 # wx.AutoBufferedPaintDC.
111 pdc = wx.AutoBufferedPaintDCFactory(self)
112 pdc.Clear()
113 dc = wx.GCDC(pdc)
114
115 # Paint Bar.
116 dc.SetPen(wx.Pen(self.bar.color))
117 dc.SetBrush(wx.Brush(self.bar.color))
118 dc.DrawRectangle(self.bar.x, self.bar.y, self.bar.size[0], self.bar.size[1])
119
120 # Paint Ball.
121 dc.SetPen(wx.Pen(self.ball.color))
122 dc.SetBrush(wx.Brush(self.ball.color))
123 dc.DrawCircle(int(self.ball.x), int(self.ball.y), self.ball.radius)
124
125 # Paint Blocks.
126 for (i, b_list) in enumerate(self.blocks):
127 for (j, b) in enumerate(b_list):
128 if self.block_exist[i][j] == 1:
129 dc.SetPen(wx.Pen(b.color,1))
130 dc.SetBrush(wx.Brush(b.color))
131 dc.DrawRectangle(b.x, b.y, b.size[0], b.size[1])
132
133
134 def onKey(self, event):
135 keycode = event.GetKeyCode()
136 if keycode == wx.WXK_SPACE:
137 if self.state == "INIT":
138 self.ball.shoot()
139 self.state = gGameState[1]
140 elif self.state == "END":
141 self.initialize()
142 self.state = gGameState[0]
143 elif (keycode == wx.WXK_LEFT or keycode == ord('Q')) and self.state != "END":
144 self.bar.move(-1)
145 elif (keycode == wx.WXK_RIGHT or keycode == ord('D')) and self.state != "END":
146 self.bar.move(1)
147
148
149 def initialize(self):
150 self.bar.x = gBarIniPos[0]
151 self.bar.y = gBarIniPos[1]
152 self.ball.x = self.bar.x
153 self.ball.y = self.bar.y - self.ball.radius
154 self.ball.vec = [0, 0]
155 self.block_exist = [[1 for i in range(gBlkVCnt)] for j in range(gBlkHCnt)]
156
157 #---------------------------------------------------------------------------
158
159 class MyBar(object):
160 def __init__(self, parent, x, y, size=gBarSize, color=gBarColor, speed=gBarSpeed):
161
162 self.parent = parent
163 self.x = x
164 self.y = y
165 self.size = size
166 self.color = color
167 self.speed = speed
168
169 #-----------------------------------------------------------------------
170
171 def move(self, direction):
172 if direction >= 0:
173 self.x += self.speed
174 elif direction < 0:
175 self.x -= self.speed
176
177 if self.x < self.parent.pos[0]:
178 self.x = self.parent.pos[0]
179 elif self.x > (self.parent.pos[0] + self.parent.size[0] - self.size[0]):
180 self.x = self.parent.pos[0] + self.parent.size[0] - self.size[0]
181
182 #---------------------------------------------------------------------------
183
184 class MyBall(object):
185 def __init__(self, parent, x, y, radius=gBallRadius, vec=[0.0,0.0],
186 color=gBallColor, speed=gIniBallSpeed):
187
188 self.parent = parent
189 self.x = x
190 self.y = y
191 self.radius = radius
192 self.vec = vec
193 self.color = color
194 self.speed = speed
195
196 #-----------------------------------------------------------------------
197
198 def shoot(self):
199 self.parent.state = gGameState[1]
200 rand_x = random.randrange(1000, 5000)
201 rand_y = random.randrange(2000, 5000)
202 self.vec = (-1.0 * float(rand_x)/1000.0, -1.0 * float(rand_y)/1000.0)
203 pass
204
205
206 def move(self):
207 if self.parent.state == "INIT":
208 self.x = self.parent.bar.x
209 self.y = self.parent.bar.y - self.radius
210 elif self.parent.state == "END":
211 pass
212 else:
213 unit = self.speed / math.sqrt(pow(self.vec[0],2) + pow(self.vec[1],2))
214 self.x += (self.vec[0] * unit)
215 self.y += (self.vec[1] * unit)
216 self.collision()
217
218
219 def collision(self):
220 # Game over.
221 if (self.y + self.radius) >= self.parent.size[1]:
222 self.parent.state = gGameState[2]
223 return
224
225 # Bound at bar.
226 if self.x >= self.parent.bar.x and \
227 self.x <= (self.parent.bar.x + self.parent.bar.size[0]) and \
228 self.y >= (self.parent.bar.y - self.radius) and \
229 self.y < (self.parent.bar.y + self.radius) and \
230 self.vec[1] > 0:
231
232 self.vec = [self.vec[0], -1*self.vec[1]]
233 return
234
235 # Bound at frame.
236 #### Left.
237 if self.vec[0] < 0 and \
238 self.x <= (self.parent.pos[0] + self.radius):
239 self.vec = [-1*self.vec[0], self.vec[1]]
240 return
241
242 #### Right.
243 if self.vec[0] > 0 and \
244 self.x >= (self.parent.pos[0] + self.parent.size[0] - self.radius):
245 self.vec = [-1*self.vec[0], self.vec[1]]
246 return
247
248 #### Ceiling.
249 if self.y <= (self.parent.pos[1] + self.radius):
250 self.vec = [self.vec[0], -1*self.vec[1]]
251 return
252
253 # Bound at Blocks.
254 no_block = 1
255 for (i, b_exist_list) in enumerate(self.parent.block_exist):
256 for (j, b_exist) in enumerate(b_exist_list):
257 if b_exist == 1:
258 no_block = 0
259 tgt_block = self.parent.blocks[i][j]
260
261 # Ball cross the block edge.
262 if self.x > (tgt_block.x - self.radius) and \
263 self.x < (tgt_block.x + tgt_block.size[0] + self.radius) and \
264 self.y > (tgt_block.y - self.radius) and \
265 self.y < (tgt_block.y + tgt_block.size[1] + self.radius):
266
267 self.parent.block_exist[i][j] = 0
268 # Update vec.
269 x0 = tgt_block.x + tgt_block.size[0] / 2
270 y0 = tgt_block.y + tgt_block.size[1] / 2
271 k = float(tgt_block.size[1]) / float(tgt_block.size[0])
272 #### Top.
273 if (self.vec[1] > 0) and \
274 (self.x < x0 and \
275 self.y < (k * (self.x - x0) + y0 - self.radius)) or \
276 (self.x > x0 and \
277 self.y < (-1 * k * (self.x - x0) + y0 - self.radius)):
278
279 self.vec = [self.vec[0], -1*self.vec[1]]
280 #### Bottom.
281 elif (self.vec[1] < 0) and \
282 (self.x < x0 and \
283 self.y > (-1 * k * (self.x - x0) + y0 + self.radius)) or \
284 (self.x > x0 and \
285 self.y > (k * (self.x - x0) + y0 + self.radius)):
286
287 self.vec = [self.vec[0], -1*self.vec[1]]
288 #### Left.
289 elif (self.vec[0] > 0) and (self.x < x0):
290 self.vec = [-1*self.vec[0], self.vec[1]]
291 ### Right.
292 elif (self.vec[0] < 0) and (self.x > x0):
293 self.vec = [-1*self.vec[0], self.vec[1]]
294
295 return
296
297 if no_block == 1:
298 # Game clear.
299 self.parent.state = gGameState[2]
300
301 #---------------------------------------------------------------------------
302
303 class MyBlock(object):
304 def __init__(self, x, y, color, size=gBlkSize):
305
306 self.x = x
307 self.y = y
308 self.color = color
309 self.size = size
310
311 #---------------------------------------------------------------------------
312
313 def main():
314 app = wx.App()
315 frame = MyFrame()
316 frame.Show(True)
317 app.MainLoop()
318
319 #---------------------------------------------------------------------------
320
321 if __name__ == '__main__':
322 main()
Othello
1 # othello.py
2
3 """
4
5 File : othello.py
6 Author : Keames
7 Link : https://python-forum.io/Thread-WxPython-Polishing-an-Othello-game-I-wrote-in-wx
8
9 """
10
11 import wx
12 import os
13
14 #---------------------------------------------------------------------------
15
16 # The wxPython implementation of an Othello game I wrote for my mother.
17 # These are displayed in help windows when an item from the help menu is selected :
18
19 gameRules = """Game Rules
20
21 Othello is a game played on a board with an 8x8 grid on it. There are 2 players and 64 gamepieces, enough to fill the entire gameboard. Each piece has a black side and a white side and each player plays as either black or white. The goal is when either the board is filled or their is no valid move available to either player for the majority of the pieces on the board to have your color upturned.
22
23 The application will automatically assess whether an attempted move is valid but to alleviate the frustration of guessing where one can place a gamepiece, here is a brief explanation:
24
25 If a space is already occupied, the move is invalid.
26
27 If there are no adjacent pieces, the move is invalid.
28
29 When there are adjacent pieces, their must be at least one vertical, horizontal or diagonal row of your opponents pieces with another of your pieces on the other end.
30
31 When you place a gamepiece, all adjacent vertical, horizontal or diagonal rows of your opponents pieces with another of your pieces at the other end will be flipped.
32
33 You may occaisionally find yourself in a situation in which there is no valid move available to you but your opponent has a valid move. You can give your opponent your move by clicking their player button. The text in their button will turn red, indicating that it is their turn. If there are no valid moves available to you, it will say so in the status bar.
34 """
35
36 applicationHelp = """Application Help
37
38 Options Menu:
39
40 The options menu provides options for starting a new game,
41 saving a game, opening an existing game, saving and quitting and
42 quit without saving. A single player gamemode is also listed in
43 this menu, but it is not yet implemented.
44
45 Give Move to Opponent:
46
47 There are situations in which the current player has no valid
48 move, but their opponent does. In this situation, you give your
49 move to your opponent by clicking their player button (one of the
50 large buttons at the top or bottom of the window.) The text in
51 their button will turn red indicating that it's their move.
52
53 Options Menu Items:
54
55 New Game -- Start a new game.
56
57 New Single Player Game -- coming soon
58
59 Save Game -- Displays a file navigator to locate and select a save
60 file to save the current game. The destination file must be a
61 text file (*.txt). The application will remember the path of a
62 current saved game until it is closed, so you won't be prompted
63 for a save file if you have specified one already. When 'new
64 game' is clicked, the path of any previously specified save file is
65 forgotten to avoid overwriting a pre-existing saved game.
66
67 Save Game As -- Allows you to save a previously saved game
68 under a different name. This feature can be used for among
69 other things, creating back-ups of your saves.
70
71 Open Game -- Displays a file navigator to locate the a save file
72 (*.txt) to open a pre-existing game. The filepath of the
73 selected game is remembered until the application is closed,
74 so you won't be prompted to re-select the file when saving.
75
76 Save and Quit -- Automatically saves the game before exiting. If
77 no file has been previously specified, the user will be prompted
78 for a save file.
79
80 Quit Without Saving -- Quits the game without saving.
81 """
82
83 # class OthelloGameFrame
84 # class HelpWindow
85
86 #---------------------------------------------------------------------------
87
88 # The program itself is implemented inside a class for encapsulation and to allow import,
89 # ease of implementation, and readability.
90
91 class OthelloGameFrame(wx.Frame):
92 """
93 The Othello game proper. Almost all of the code that makes this app work is in here.
94 It uses a pretty standard constructor for a class inheriting from Frame:
95
96 __init__(self, *args, **kwArgs) Passing in the size parameter is recommended.
97 """
98
99 # I know it is not recommended to create custom IDs but I didn't find wx IDs which
100 # corresponded to the actions of these four menu items.
101 ID_NEW_SINGLE_PLAYER = wx.NewIdRef(1)
102 ID_SAVE_AND_QUIT = wx.NewIdRef(1)
103 ID_GAMERULES = wx.NewIdRef(1)
104 ID_QUIT_WITHOUT_SAVING = wx.NewIdRef(1)
105
106 # Constants for buttons:
107 PLAYER1BUTT = wx.NewIdRef(1)
108 PLAYER2BUTT = wx.NewIdRef(1)
109
110 # I couldn't use wx.NewIDRef here because it is important that these numerical IDs be 64
111 # sequential integers.
112 GAMEBOARDBUTTS_LOWER = 5929 # GAMEBOARDBUTTS_UPPER - 64
113 GAMEBOARDBUTTS_UPPER = 5993
114
115 # Color Constants:
116 bgAndBoardColor = wx.Colour(0x41, 0xA1, 0x23)
117 player1Color = wx.Colour(0x00, 0x00, 0x00)
118 player2Color = wx.Colour(0xFF, 0xFF, 0xFF)
119
120 def __init__(self, *args, **kwArgs):
121 wx.Frame.__init__(self, *args, **kwArgs)
122 """
123 OthelloGameFrame.__init__(self, *args, *kwArgs)
124 Returns an object representing the main window of the Othello game app.
125 Specifying the size parameter in the arg list is recommended. Otherwise, it
126 works just like a normal wx.Frame.
127 """
128
129 self.SetIcon(wx.Icon('./icons/wxwin.ico', wx.BITMAP_TYPE_ICO))
130
131 #------------
132
133 # non-GUI related instance variables:
134 self.saveFile = ""
135 self.firstPlayersMove = True
136 self.gameAltered = False
137
138 self.SetBackgroundColour(wx.Colour(0x30, 0x30, 0x30))
139 self.CreateStatusBar()
140
141 # Creating an options menu with all the non-gameplay related options
142 # I want to make available to the user.
143 self.optionsMenu = wx.Menu()
144 menuNewGame = self.optionsMenu.Append(wx.ID_NEW, "&New Game", "Start a new game.")
145 menuNewSinglePlayer = self.optionsMenu.Append(self.ID_NEW_SINGLE_PLAYER, "New Single &Player Game (Not yet implemented)", "Start a game against the AI. This feature is currently unavailable.")
146 self.optionsMenu.AppendSeparator()
147 menuSaveGame = self.optionsMenu.Append(wx.ID_SAVE, "&Save Game", "Save the current game and remember the filename for future saves.")
148 menuSaveAs = self.optionsMenu.Append(wx.ID_SAVEAS, "Save Game &As...", "Save a previously save game under a new name.")
149 menuOpenGame = self.optionsMenu.Append(wx.ID_OPEN, "&Open Game", "Open a previously saved game.")
150 menuSaveAndQuit = self.optionsMenu.Append(self.ID_SAVE_AND_QUIT, "Sa&ve and Quit", "Save the game and quit.")
151 menuQuitWithoutSaving = self.optionsMenu.Append(self.ID_QUIT_WITHOUT_SAVING, "Quit &Without Saving", "Close the application without saving the game.")
152
153 # The help menu will display instances of HelpWindow containing a helptext
154 # appropriate to the menu item selected.
155 self.helpMenu = wx.Menu()
156 menuShowGamerules = self.helpMenu.Append(self.ID_GAMERULES, "Game&rules", "Explains Othello game rules.")
157 menuShowAppHelp = self.helpMenu.Append(wx.ID_HELP, "Application &Help", "How to use this software")
158
159 # Create the toolbar.
160 self.toolbar = wx.MenuBar()
161 self.toolbar.Append(self.optionsMenu, "&Options")
162 self.toolbar.Append(self.helpMenu, "&Help")
163 self.SetMenuBar(self.toolbar)
164
165 # Add Widgets
166 player1ButtonFont = wx.Font(30, wx.ROMAN, wx.NORMAL, wx.NORMAL)
167 player2ButtonFont = wx.Font(30, wx.ROMAN, wx.NORMAL, wx.NORMAL)
168 gameboardButtonFont = wx.Font(12, wx.ROMAN, wx.NORMAL, wx.NORMAL)
169 # The gameboard buttons are added iteratively. (There are 64 of them. If anybody
170 # knows a better way to do this, I'm all ears. This code is rather messy.)
171 throwaway = []
172 for i in range(64):
173 # That's a tuple being appended to the list. I know a tuple literal as the
174 # single argument to a function is a little unreadable.
175 gameboardButton = wx.Button(self, self.GAMEBOARDBUTTS_UPPER - i, "", style = wx.NO_BORDER)
176 gameboardButton.SetFont(gameboardButtonFont)
177 gameboardButton.SetBackgroundColour(self.bgAndBoardColor)
178 gameboardButton.SetForegroundColour(wx.Colour(0xFF, 0x00, 0x00))
179 throwaway.append( (gameboardButton, 0, wx.EXPAND) )
180
181 buttonGrid = wx.GridSizer(8, 8, 0, 0)
182 buttonGrid.SetHGap(2)
183 buttonGrid.SetVGap(2)
184 buttonGrid.AddMany(throwaway)
185 self.gameboard = [[]]
186 thrIndex = 0
187 for row in range(8):
188 for col in range(8):
189 self.gameboard[-1].append(throwaway[thrIndex][0])
190 thrIndex += 1
191 self.gameboard.append([])
192 del self.gameboard[-1]
193
194 # Creating the layout:
195 self.player1Butt = wx.Button(self, self.PLAYER1BUTT, "Player 1", style = wx.NO_BORDER)
196 self.player1Butt.SetFont(player1ButtonFont)
197 self.player1Butt.SetBackgroundColour(self.player1Color)
198 self.player1Butt.SetForegroundColour(wx.Colour(0xFF, 0x00, 0x00))
199 self.player2Butt = wx.Button(self, self.PLAYER2BUTT, "Player 2", style = wx.NO_BORDER)
200 self.player2Butt.SetFont(player2ButtonFont)
201 self.player2Butt.SetBackgroundColour(self.player2Color)
202 self.layout = wx.BoxSizer(wx.VERTICAL)
203 self.layout.Add(self.player1Butt, 1, wx.EXPAND)
204 self.layout.Add(buttonGrid, 8, wx.CENTRE)
205 self.layout.Add(self.player2Butt, 1, wx.EXPAND)
206
207 self.SetSizer(self.layout)
208
209 # Bind the menu events to their respective callbacks.
210 self.Bind(wx.EVT_MENU, self.newGame, menuNewGame)
211 self.Bind(wx.EVT_MENU, self.newSinglePlayer, menuNewSinglePlayer)
212
213 self.Bind(wx.EVT_MENU, self.saveGame, menuSaveGame)
214 self.Bind(wx.EVT_MENU, self.saveAs, menuSaveAs)
215 self.Bind(wx.EVT_MENU, self.openGame, menuOpenGame)
216 self.Bind(wx.EVT_MENU, self.saveAndQuit, menuSaveAndQuit)
217 self.Bind(wx.EVT_MENU, self.quitWithoutSaving, menuQuitWithoutSaving)
218
219 self.Bind(wx.EVT_MENU, self.showGameRules, menuShowGamerules)
220 self.Bind(wx.EVT_MENU, self.showAppHelp, menuShowAppHelp)
221
222 # Bind the player buttons to callbacks
223 self.Bind(wx.EVT_BUTTON, self.player1ButtonClicked, id = self.PLAYER1BUTT)
224 self.Bind(wx.EVT_BUTTON, self.player2ButtonClicked, id = self.PLAYER2BUTT)
225
226 # Bind all close events to self.quitWithoutSaving to ensure the user is always
227 # asked whether they're sure they want to quit without saving their game.
228 self.Bind(wx.EVT_CLOSE, self.quitWithoutSaving)
229
230 # Bind the gameboard button events to lambdas which pass row and col values to
231 # self.gameboardButtonClicked appropriate to their position on the board.
232 for row in range(8):
233 for col in range(8):
234 callbackLambda = eval(
235 "lambda evt: self.gameboardButtonClicked(evt, {}, {})".format(row, col),
236 {"self": self})
237 self.Bind(wx.EVT_BUTTON, callbackLambda, self.gameboard[row][col])
238
239 self.Show(True)
240 self.newGame()
241
242 #-----------------------------------------------------------------------
243
244 def newGame(self, event=None):
245 """
246 OthelloGameFrame.newGame(self, event = None)
247 Resets the gameboard and resets the saveFile field to prevent
248 an existing game from being overwritten.
249 """
250
251 self.saveFile = ""
252 self.gameAltered = False
253 for row in range(8):
254 for col in range(8):
255 self.gameboard[row][col].SetBackgroundColour(self.bgAndBoardColor)
256
257 self.gameboard[3][3].SetBackgroundColour(self.player2Color)
258 self.gameboard[3][4].SetBackgroundColour(self.player1Color)
259 self.gameboard[4][3].SetBackgroundColour(self.player1Color)
260 self.gameboard[4][4].SetBackgroundColour(self.player2Color)
261
262 # For testing purposes:
263 #self.gameboard[2][2].SetBackgroundColour(self.player2Color)
264 #self.gameboard[2][5].SetBackgroundColour(self.player1Color)
265 self.firstPlayersMove = True
266 self.player1Butt.SetForegroundColour("RED")
267 self.player2Butt.SetForegroundColour("BLACK")
268
269
270 def newSinglePlayer(self, event=None):
271 """
272 OthelloGameFrame.newSinglePlayer(self, event = None)
273 This feature is not yet implemented.
274 """
275
276 print("I am a computer. A smart, handsome programmer has to teach me Othello.")
277
278
279 def saveGame(self, event=None):
280 """
281 OthelloGameFrame.saveGame(self, event = None)
282 Prompt the user for a file in which to save the game if none has been selected yet
283 and save the game
284 """
285
286 saveList = [[]]
287 for row in range(8):
288 for col in range(8):
289 # Map each gameboard color to a number: 0 for empty space, 1 for player 1 (black), and 2 for player 2.
290 saveList[-1].append(
291 {str(self.bgAndBoardColor): 0, str(self.player1Color): 1, str(self.player2Color):2}[str(self.gameboard[row][col].GetBackgroundColour())])
292 if row != 7: saveList.append([])
293
294 saveDict = {"saveList": saveList, "firstPlayersMove": self.firstPlayersMove} # Save everything in a dictionary.
295
296 # If no file has been previously selected, use a wx.FileDialog to get the
297 # path of the file in which the user wants to save their game.
298 if self.saveFile == "":
299
300 fd = wx.FileDialog(self, "Select a file", os.getcwd(), "", "*.txt", wx.FD_OPEN)
301 if fd.ShowModal() == wx.ID_OK:
302 self.saveFile = fd.GetPath()
303 else:
304 fd.Destroy()
305 return
306 fd.Destroy()
307
308 # Save the game as a string representation of saveDict.
309 with open(self.saveFile, "w") as f:
310 try:
311 f.write(repr(saveDict))
312 except FileNotFoundError:
313 mdlg = wx.MessageDialog(self, "The currently selected file could not be accessed at this time. Please try again.", "wxOthello", wx.OK)
314 mdlg.ShowModal()
315 mdlg.Destroy()
316 self.saveFile = ""
317 self.gameAltered = False
318
319
320 def saveAs(self, event=None):
321 """
322 OthelloGameFrame.saveAs(self, event = None)
323 Save a previously saved game under a different filename.
324 """
325
326 self.saveFile = ""
327 self.saveGame()
328
329
330 def openGame(self, event=None):
331 """
332 OthelloGameFrame.openGame(self, event = None)
333 Open a previously saved game stored in the format described in the saveGame method
334 {"saveList": [Nested lists containing integers mapped to gameboard colors], "firstPlayersMove": True/False}
335 """
336
337 # Use wx.FileDialog to get the save file to open.
338 fd = wx.FileDialog(self, "Select a file", os.getcwd(), "", "*.txt", wx.FD_OPEN)
339 if fd.ShowModal() == wx.ID_OK:
340 self.saveFile = fd.GetPath()
341 else:
342 fd.Destroy()
343 return
344 fd.Destroy()
345
346 # Open the save file and convert its contents into a dictionary.
347 with open(self.saveFile, "r") as f:
348 try:
349 saveDict = eval(f.read())
350 except FileNotFoundError:
351 mdlg = wx.MessageDialog(self, "The currently selected file could not be accessed at this time. Please try again.", "wxOthello", wx.OK)
352 mdlg.ShowModal()
353 mdlg.Destroy()
354 self.saveFile = ""
355 return
356 # If the files contents are incompatible with the attempted parse into a dictionary, inform the user.
357 except SyntaxError:
358 mdlg = wx.MessageDialog(self, "The currently selected file is either corrupted or its contents incompatible with opening in this game.", "wxOthello", wx.OK)
359 mdlg.ShowModal()
360 mdlg.Destroy()
361 self.saveFile = ""
362 return
363
364 # Load the dictionarys data into the relevant instance variables. When single player mode is implemented,
365 # a check for the key "isSinglePlayer" will also need to be added here.
366 self.firstPlayersMove = saveDict["firstPlayersMove"]
367 for row in range(8):
368 for col in range(8):
369 self.gameboard[row][col].SetBackgroundColour([self.bgAndBoardColor, self.player1Color, self.player2Color][saveDict["saveList"][row][col]])
370 self.Refresh()
371 self.gameAltered = False
372
373
374 def saveAndQuit(self, event=None):
375 """
376 OthelloGameFrame.saveAndQuit(self, event = None)
377 Saves the game and quits.
378 """
379
380 self.saveGame()
381 self.Destroy()
382 exit()
383
384
385 def quitWithoutSaving(self, event=None):
386 """
387 OthelloGameFrame.quitWithoutSaving(self, event = None)
388 If the game has been altered since last save, this function
389 asks the user via messageBox whether they are sure they don't
390 want to save. It exits the game if they answer yes, calls
391 saveGame if they answer no and returns if they click cancel.
392 """
393
394 if self.gameAltered:
395 usersFinalDecision = wx.MessageBox("All progress you've made in this game will be lost. Are you sure you want to quit without saving? Answering 'no' will open a save dialog if no file was selected previously then exit the game.",
396 "wxOthello", wx.YES_NO | wx.CANCEL, self)
397 if usersFinalDecision == wx.YES:
398 self.Destroy()
399 exit()
400 elif usersFinalDecision == wx.NO:
401 self.saveGame()
402 elif usersFinalDecision == wx.CANCEL:
403 return
404 else:
405 self.Destroy()
406 exit()
407
408
409 def showGameRules(self, event=None):
410 """
411 OthelloGameFrame.showGameRules(self, event = None)
412 This callback displays an instance of HelpWindow that
413 displays the rules of Othello as its help text with
414 a call to showHelp.
415 """
416
417 global gameRules
418 self.showHelp(gameRules)
419
420
421 def showAppHelp(self, event=None):
422 """
423 OthelloGameFrame.showAppHelp(self, event = None)
424 This callback displays an instance of HelpWindow that
425 displays help information for this application with
426 a call to showHelp.
427 """
428
429 global applicationHelp
430 self.showHelp(applicationHelp)
431
432
433 def showHelp(self, helpText):
434 """
435 OthelloGameFrame.showHelp(self, helpText)
436 Displays an instance of HelpWindow displaying
437 the value of helpText.
438 """
439
440 with HelpWindow(self, helpText) as hdlg:
441 hdlg.ShowModal()
442
443
444 def player1ButtonClicked(self, event=None):
445 """
446 OthelloGameFrame.player1ButtonClicked(self, event = None)
447 Gives the next move to player 1. This feature is
448 intended for use when it is player 2s turn and there are
449 no moves available to player 2.
450 """
451
452 self.firstPlayersMove = True
453 self.player1Butt.SetForegroundColour("RED")
454 self.player2Butt.SetForegroundColour("BLACK")
455
456
457 def player2ButtonClicked(self, event=None):
458 """
459 OthelloGameFrame.player2ButtonClicked(self, event = None)
460 Gives the next move to player 2. This feature is
461 intended for use when it is player 1s turn and there are
462 no moves available to player 1.
463 """
464
465 self.firstPlayersMove = False
466 self.player1Butt.SetForegroundColour("WHITE")
467 self.player2Butt.SetForegroundColour("RED")
468
469
470 def gameboardButtonClicked(self, event=None, row = 0, col = 0):
471 """
472 OthelloGameFrame.gameboardButtonClicked(self, event = None, row = 0, col = 0)
473 This method is called through lambdas bound to the gameboard buttons generated
474 in __init__. It displays an error message in the space where the move is
475 attempted and returns if a move is invalid. Otherwise, it executes the move,
476 checks whether somebody has won, gives the next move to the other player, and
477 informs the next player if there is no move available to them in the status bar.
478 """
479
480 # self,firstPlayersMove is a boolean indicating whether it's player 1s turn.
481 if self.firstPlayersMove:
482 me = self.player1Color
483 opponent = self.player2Color
484
485 else:
486 me = self.player2Color
487 opponent = self.player1Color
488
489 # Detect invalid move attempts, inform the user if their move is invalid and
490 # the reason their move is invalid and return from the function.
491 moveIsValid, message = self.isValidMove(row, col, me, opponent)
492 if not moveIsValid:
493 self.gameboard[row][col].SetLabel(message)
494 wx.MilliSleep(1000)
495 self.gameboard[row][col].SetLabel("")
496 return
497
498 # Make the move selected by the player.
499 self.makeMove(row, col, me, opponent)
500 self.gameAltered = True
501
502 # The method detectWin returns a tuple with a boolean indicating whether there
503 # are no valid moves available to either player and a message string appropriate to
504 # the situation of 1: A player 1 victory, 2: A draw, or 3: A player 2 victory.
505 winDetected, message = self.detectWin()
506 if winDetected:
507 m = wx.MessageDialog(self, message, "wxOthello")
508 m.ShowModal()
509 m.Destroy()
510
511 # Invert the value of the self.firstPlayersMove flag and change the color of the
512 # text in the player 1 and player 2 buttons in a manner according to whose turn it
513 # is.
514 self.firstPlayersMove = not self.firstPlayersMove
515
516 if self.firstPlayersMove:
517 self.player1Butt.SetForegroundColour("RED")
518 self.player2Butt.SetForegroundColour("BLACK")
519 else:
520 self.player1Butt.SetForegroundColour("WHITE")
521 self.player2Butt.SetForegroundColour("RED")
522
523 # Inform the next player if there is no valid move available to them.
524 if not self.moveAvailableToPlayer(opponent, me):
525
526 if opponent == self.player1Color:
527 self.SetStatusText("No move available to player 1.")
528 else:
529 self.SetStatusText("No move available to player 2.")
530 else:
531 self.SetStatusText("")
532
533
534 def moveAvailableToPlayer(self, me, opponent):
535 for row in range(8):
536 for col in range(8):
537 if self.isValidMove(row, col, me, opponent)[0]: return True
538 return False
539
540
541 def isValidMove(self, row, col, me, opponent):
542 """
543 OthelloGameFrame.isValidMove(self, row, col, me, opponent)
544 This method returns the tuple (isValidMove, messaage). It tests
545 whether a move at a specified position on the gameboard is valid
546 for a specific player and if the move is invalid, returns a
547 message explaining why the move is invalid.
548 """
549
550 # Check whether the grid space is empty
551 if self.gameboard[row][col].GetBackgroundColour() != self.bgAndBoardColor:
552 return False, "This Space\nIs Occupied!"
553
554 # A series of scanning vectors for the 8 scanning directions: up, down, left, right and the four diagonal directions
555 scanningDirections = ((-1, 0), (0, 1), (1, 0), (0, -1),
556 (-1, -1), (-1, 1), (1, 1), (1, -1))
557
558 # Iterate over the diffetent scanning directions, return True if the move is valid and set message to a message string
559 # that explains why the move is invalid, if the move is invalid.
560 message = "No Adjacent\nGamepieces!"
561 for SDRow, SDCol in scanningDirections:
562 currentRow = row + SDRow
563 currentCol = col + SDCol
564 sawOpponent = False
565 while currentRow in range(0, 8) and currentCol in range(0, 8):
566 if self.gameboard[currentRow][currentCol].GetBackgroundColour() == self.bgAndBoardColor:
567 break
568 else:
569 message = "No Pieces\nTo Flip!"
570 if self.gameboard[currentRow][currentCol].GetBackgroundColour() == opponent: sawOpponent = True
571 if self.gameboard[currentRow][currentCol].GetBackgroundColour() == me and sawOpponent:
572 return True, "You won't see this message!"
573 if self.gameboard[currentRow][currentCol].GetBackgroundColour() == me and not sawOpponent: break
574
575 currentRow += SDRow
576 currentCol += SDCol
577
578 return False, message
579
580
581 def makeMove(self, row, col, me, opponent):
582 """
583 OthelloGameFrame.makeMove(self, row, col, me, opponent)
584 Performs a move for a specified player at a specified position.
585 """
586
587 # Put down the players gamepiece
588 self.gameboard[row][col].SetBackgroundColour(me)
589
590 # A series of scanning vectors for the 8 scanning directions: up, down, left, right and the four diagonal directions
591 scanningDirections = ((-1, 0), (0, 1), (1, 0), (0, -1),
592 (-1, -1), (-1, 1), (1, 1), (1, -1))
593
594 # Iterate over the scanning vectors.
595 for SDRow, SDCol in scanningDirections:
596 currentRow = row + SDRow
597 currentCol = col + SDCol
598 sawOpponent = False
599 canFlipPieces = False
600 # Check whether gamepieces can be flipped in the current scanning direction.
601 while currentRow in range(0, 8) and currentCol in range(0, 8):
602 if self.gameboard[currentRow][currentCol].GetBackgroundColour() == self.bgAndBoardColor: break
603 if self.gameboard[currentRow][currentCol].GetBackgroundColour() == opponent: sawOpponent = True
604 if self.gameboard[currentRow][currentCol].GetBackgroundColour() == me and sawOpponent:
605 canFlipPieces = True
606 break
607 if self.gameboard[currentRow][currentCol].GetBackgroundColour() == me and not sawOpponent: break
608 currentRow += SDRow
609 currentCol += SDCol
610
611 # If gamepieces can be flipped in the current scanning direction, flip the pieces.
612 currentRow = row + SDRow
613 currentCol = col + SDCol
614 while canFlipPieces and currentRow in range(0, 8) and currentCol in range(0, 8):
615 if self.gameboard[currentRow][currentCol].GetBackgroundColour() == opponent:
616 self.gameboard[currentRow][currentCol].SetBackgroundColour(me)
617 elif self.gameboard[currentRow][currentCol].GetBackgroundColour() == me:
618 break
619 else:
620 print("Kyle, you have some debugging to do! This else clause is never supposed to execute. Something has gone horribly wrong!")
621 currentRow += SDRow
622 currentCol += SDCol
623
624
625 def detectWin(self):
626 """
627 OthelloGameFrame.detectWin(self)
628 This method returns a the tuple (noValidMoves, message), where noValidMoves is a boolean indicating whether there are no more valid moves
629 available to either player and message is one of the the strings "The winner is player 1!", if the majority of the pieces on the board are
630 black, "This game is a draw!" if player 1 and player 2 have equal numbers of pieces on the board, or "The winner is player 2!" if the
631 majority of the pieces on the board are white.
632 """
633
634 noValidMoves = True # We begin by assuming that neither player has a valid move available to them.
635 player1Count = 0 # Counters for the number of spaces each player has captured.
636 player2Count = 0
637 # Iterate over the gameboard. Check whether there is a valid move available to either player and
638 # count the number of spaces captured by each player.
639 for row in range(8):
640 for col in range(8):
641 if self.isValidMove(row, col, self.player1Color, self.player2Color)[0] or self.isValidMove(row, col, self.player2Color, self.player1Color)[0]: noValidMoves = False
642 if self.gameboard[row][col].GetBackgroundColour() == self.player1Color: player1Count += 1
643 if self.gameboard[row][col].GetBackgroundColour() == self.player2Color: player2Count += 1
644
645 if noValidMoves:
646 # Return True and a message indicating who won
647 if player1Count > player2Count:
648 return True, "The winner is player 1!"
649 elif player1Count == player2Count:
650 return True, "This game is a draw!"
651 elif player1Count < player2Count:
652 return True, "The winner is player 2!"
653
654 else:
655 return False, "You're not supposed to see this message."
656
657 #---------------------------------------------------------------------------
658
659 class HelpWindow(wx.Dialog):
660 """
661 A simple dialog class for displaying help information to the user.
662 """
663 def __init__ (self, parent, helpText):
664 wx.Dialog.__init__(self, parent, -1, helpText.split("\n")[0])
665
666 self.SetMinSize(wx.Size(400, 400))
667 self.topExitButton = wx.Button(self, wx.ID_CLOSE, "Close Help")
668 self.helpDisplay = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = helpText,
669 style = wx.TE_MULTILINE | wx.TE_READONLY)
670 self.bottomExitButton = wx.Button(self, wx.ID_CLOSE, "Close Help")
671
672 self.layout = wx.BoxSizer(wx.VERTICAL)
673 self.layout.Add(self.topExitButton, 1, wx.EXPAND)
674 self.layout.Add(self.helpDisplay, 10, wx.EXPAND)
675 self.layout.Add(self.bottomExitButton, 1, wx.EXPAND)
676 self.SetSizer(self.layout)
677
678 self.Fit()
679 self.Bind(wx.EVT_BUTTON, self.closeHelp, id = wx.ID_CLOSE)
680
681 #-----------------------------------------------------------------------
682
683 def closeHelp(self, event=None):
684 self.EndModal(wx.ID_ANY)
685
686 #---------------------------------------------------------------------------
687
688 if __name__ == "__main__":
689 app = wx.App()
690 theApp = OthelloGameFrame(parent=None, id=wx.ID_ANY, size=(700, 800), title="wxOthello")
691 app.MainLoop()
Chess
1 # 8queens_wx_pos.py
2
3 """
4
5 File : 8queens_wx_pos.py
6 Author : Shido
7 Link : http://www.shido.info/py/python5.html
8
9 Eight queens, whose gui uses wx absolute positioning
10
11 """
12
13 import wx
14 import queen as q
15
16 # Global parameter
17 Q_font = ("Times", 14)
18 X_Margin = 20
19 Y_Margin = 20
20
21 #---------------------------------------------------------------------------
22
23 # class Board
24 # class Queen
25
26 #---------------------------------------------------------------------------
27
28 class Board(wx.Panel):
29 """
30 Gui
31 """
32 def init_title(self):
33 self.i_title = wx.Image('8qsubtitle.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap()
34 wx.StaticBitmap(self, -1, self.i_title, \
35 (5, 5), (self.i_title.GetWidth(), self.i_title.GetHeight()))
36
37
38 def init_board(self):
39 self.cell_images = [wx.Image(png, wx.BITMAP_TYPE_PNG).ConvertToBitmap() \
40 for png in ('bw.png', 'bg.png', 'qw.png', 'qg.png')]
41 answer = self.q_answers[0]
42 self.i_width = self.cell_images[0].GetWidth()
43 self.i_height = self.cell_images[0].GetHeight()
44 for i in range(64):
45 j = (int(q.qmod(i)) + (((i in answer) and 2) or 0))
46 print(j)
47 wx.StaticBitmap(self, -1, self.cell_images[j],
48 (int(self.i_width*(i%8))+int(self.xmargin),
49 int(self.i_height*(i/8))+int(self.ymargin)),
50 (int(self.i_width), int(self.i_height)))
51
52
53 def init_footer(self):
54 self.counter = 0
55 btn1 = wx.Button(self, 10, "&Forward", (20, 420))
56 self.Bind(wx.EVT_BUTTON, self.show_next, btn1)
57 btn2 = wx.Button(self, 20, "&Backward", (100, 420))
58 self.Bind(wx.EVT_BUTTON, self.show_prev, btn2)
59 self.label = wx.StaticText(self, -1, ("%d/12" % (self.counter+1)), (180, 430))
60
61
62 def init_all(self):
63 self.q_answers = q.eight_queens()
64 self.init_title()
65 self.init_board()
66 self.init_footer()
67
68 #-----------------------------------------------------------------------
69
70 def __init__(self, frame):
71 wx.Panel.__init__(self, frame, style=wx.NO_FULL_REPAINT_ON_RESIZE)
72 self.xmargin = 40
73 self.ymargin = 60
74 self.init_all()
75 self.Layout()
76
77 def refresh(self, forward):
78 """
79 Refresh board and counter.
80 """
81
82 i_now = self.counter
83 self.counter += forward and 1 or -1
84 self.label.SetLabel("%d/12" % (1 + self.counter))
85 a_next = self.q_answers[self.counter]
86 a_now = self.q_answers[i_now]
87 q_or_b=0
88 for cells in [q.set_difference(a_now, a_next), q.set_difference(a_next, a_now)]:
89 for i in cells:
90 j = int(q.qmod(i)) + int(q_or_b)
91 print(j)
92 wx.StaticBitmap(self, -1, self.cell_images[j],
93 (int(self.i_width*(i%8))+int(self.xmargin),
94 int(self.i_height*(i/8))+int(self.ymargin)),
95 (int(self.i_width), int(self.i_height)))
96 q_or_b += 2
97 self.Refresh()
98
99
100 def show_next(self, event):
101 if(self.counter < 11):
102 self.refresh(True)
103
104
105 def show_prev(self, event):
106 if(self.counter > 0):
107 self.refresh(False)
108
109 #---------------------------------------------------------------------------
110
111 class Queen(wx.App):
112 def OnInit(self):
113
114 frame = wx.Frame(None, -1, "8 queens", pos=(150, 150), size=(420, 500))
115 frame.SetIcon(wx.Icon('./icons/wxwin.ico', wx.BITMAP_TYPE_ICO))
116 Board(frame)
117 self.SetTopWindow(frame)
118 frame.Show(True)
119
120 return True
121
122 #---------------------------------------------------------------------------
123
124 if __name__ == "__main__":
125 que = Queen(redirect=False)
126 que.MainLoop()
Snake
1 # snake.py
2
3 """
4
5 Created on 2011-03-23
6 Classic game - Snake
7 Author : 123
8 Website : https://www.programmersought.com/article/9994279643/
9
10 """
11
12 import wx
13 import random,time
14
15 # class MyWesticeSnakeBody
16 # class MyWesticeSnake
17 # class MyFrame
18
19 #---------------------------------------------------------------------------
20
21 class MyWesticeSnakeBody():
22 def __init__(self):
23
24 randnum=int(random.random()*4)
25 imagename='snakeskin'+str(randnum)+'.jpg'
26 img1=wx.Image(imagename,wx.BITMAP_TYPE_ANY)
27 self.img1=img1.Scale(30, 30) # Reduce the image.
28 self.x=-1
29 self.y=-1
30
31 #---------------------------------------------------------------------------
32
33 class MyWesticeSnake():
34 def __init__(self):
35
36 self.bodys=[]
37 self.headx=int(random.random()*(10))+5
38 self.heady=int(random.random()*(10))+5
39 self.direct=int(random.random()*4)
40 self.img1=wx.Image('snakehead.jpg',wx.BITMAP_TYPE_ANY)
41 self.headimg90=self.img1.Rotate90(True)
42 self.headimg180=self.headimg90.Rotate90(True)
43 self.headimg_90=self.img1.Rotate90(False)
44 self.headimg1=self.img1
45 self.prev_snakex=self.headx
46 self.prev_snakey=self.heady
47
48 #-----------------------------------------------------------------------
49
50 def update(self):
51 """
52 ...
53 """
54
55 # Save the last position of the snake before the moment.
56 if len(self.bodys)!=0:
57 self.prev_snakex=self.bodys[len(self.bodys)-1].x
58 self.prev_snakey=self.bodys[len(self.bodys)-1].y
59 else:
60 self.prev_snakex=self.headx
61 self.prev_snakey=self.heady
62
63 if len(self.bodys)!=0:
64 for index in range(len(self.bodys)-1,0,-1):
65 self.bodys[index].x=self.bodys[index-1].x
66 self.bodys[index].y=self.bodys[index-1].y
67 self.bodys[0].x=self.headx
68 self.bodys[0].y=self.heady
69
70 if self.direct==0:
71 self.headx+=1 # To the right.
72 if self.direct==1:
73 self.heady+=1 # Down.
74 if self.direct==2:
75 self.headx-=1 # To the left.
76 if self.direct==3:
77 self.heady-=1 # Up.
78
79 self.headimg1=self.img1
80 if self.direct==0:
81 self.headimg1=self.headimg90
82 if self.direct==1:
83 self.headimg1=self.headimg180
84 if self.direct==2:
85 self.headimg1=self.headimg_90
86 self.headimg1=self.headimg1.Scale(30, 30)
87
88 #---------------------------------------------------------------------------
89
90 class MyFrame(wx.Frame):
91 gridwidth=20
92 gridheight=20
93 landsqurelist=[]
94 first=True
95 def __init__(self):
96 wx.Frame.__init__(self, None, -1,
97 "Snake game",
98 style=wx.SYSTEM_MENU |
99 wx.MINIMIZE_BOX |
100 wx.CLOSE_BOX |
101 wx.CAPTION)
102
103 self.SetIcon(wx.Icon('./icons/wxwin.ico', wx.BITMAP_TYPE_ICO))
104
105 #------------
106
107 self.InitUI()
108
109 #------------
110
111 # wx.Font(pointSize, family, style, weight, underline, faceName)
112 font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
113 font.SetWeight(wx.BOLD)
114
115 #------------
116
117 self.panel=wx.Panel(self,-1)
118 self.panel.SetBackgroundColour("#696767")
119 self.score=0
120
121 self.command0 = wx.StaticText(self.panel,-1,'Commands (AZERTY) :',pos=(630,20))
122 self.command0.SetFont(font)
123 self.command1 = wx.StaticText(self.panel,-1,'(Q) Left',pos=(630,50))
124 self.command2 = wx.StaticText(self.panel,-1,'(D) Right',pos=(630,80))
125 self.command3 = wx.StaticText(self.panel,-1,'(Z) Top',pos=(630,110))
126 self.command4 = wx.StaticText(self.panel,-1,'(S) Bottom',pos=(630,140))
127 self.command0.SetForegroundColour("#f38e3c")
128 self.command1.SetForegroundColour(wx.WHITE)
129 self.command2.SetForegroundColour(wx.WHITE)
130 self.command3.SetForegroundColour(wx.WHITE)
131 self.command4.SetForegroundColour(wx.WHITE)
132
133 self.scoretxt=wx.StaticText(self.panel,-1,'Score : '+str(self.score),pos=(630,300))
134 self.gamestatustxt=wx.StaticText(self.panel, -1, 'Game status : Running', pos=(630,350))
135 self.scoretxt.SetForegroundColour(wx.WHITE)
136 self.gamestatustxt.SetForegroundColour(wx.WHITE)
137
138 fgs=wx.FlexGridSizer(cols=self.gridwidth,hgap=0,vgap=0)
139
140
141 self.panel.SetFocus()
142
143 for col in range(self.gridwidth):
144 random.seed(time.time())
145 for row in range(self.gridheight):
146
147 # Loading grass.
148 randnum=int(random.random()*4)
149
150 if random.random()<0.02:
151 randnum=-1
152 imagename='land'+str(randnum)+'.jpg'
153 # print(imagename)
154 img1=wx.Image(imagename,wx.BITMAP_TYPE_ANY)
155 img1=img1.Scale(30, 30)# Reduce the image.
156 sb1=wx.StaticBitmap(self.panel,-1,wx.Bitmap(img1))
157 sb1.randnum=randnum # Save the image name.
158 fgs.Add(sb1)
159 self.landsqurelist.append(sb1)
160 self.panel.SetSizerAndFit(fgs)
161
162 # Initialize position.
163 self.westicesnake=MyWesticeSnake()
164
165 self.timer1=wx.Timer(self)
166 self.Bind(wx.EVT_TIMER,self.frameUpdate,self.timer1)
167 self.timer1.Start(300) # Can set the speed here.
168
169 # wx.EVT_KEY_DOWN, self.OnKeyDown
170 self.panel.Bind(wx.EVT_KEY_UP,self.OnKeyUp)
171
172 #-----------------------------------------------------------------------
173
174 def InitUI(self):
175 """
176 ...
177 """
178
179 menuBar = wx.MenuBar()
180 filemenu = wx.Menu()
181
182 qmi = wx.MenuItem(filemenu, wx.ID_EXIT, "&Quit\tCtrl+Q")
183 qmi.SetBitmap(wx.Bitmap("./images/exit.png"))
184 filemenu.Append(qmi)
185
186 self.Bind(wx.EVT_MENU, self.OnQuit, id=wx.ID_EXIT)
187
188 menuBar.Append(filemenu, '&File')
189 self.SetMenuBar(menuBar)
190
191 self.statusbar = self.CreateStatusBar()
192 self.statusbar.SetStatusText('Ready')
193
194 self.SetSize((800, 683))
195 self.Centre()
196
197
198 def OnKeyUp(self,event):
199 """
200 ...
201 """
202
203 if ord('Q')==event.GetKeyCode()and self.westicesnake.direct!=0:
204 # To the left.
205 self.westicesnake.direct=2
206 if ord('D')==event.GetKeyCode()and self.westicesnake.direct!=2:
207 # To the right.
208 self.westicesnake.direct=0
209 if ord('S')==event.GetKeyCode()and self.westicesnake.direct!=3:
210 # To the bottom.
211 self.westicesnake.direct=1
212 if ord('Z')==event.GetKeyCode()and self.westicesnake.direct!=1:
213 # To the top.
214 self.westicesnake.direct=3
215
216
217 def frameUpdate(self,event):
218 """
219 ...
220 """
221
222 if self.westicesnake.headx>=0and self.westicesnake.headx<self.gridwidth\
223 and self.westicesnake.heady>=0and self.westicesnake.heady<self.gridheight:
224 tempindex=self.getIndex(self.westicesnake.headx,self.westicesnake.heady)
225
226 self.landsqurelist[tempindex].SetBitmap(wx.Bitmap(self.westicesnake.headimg1))
227
228 # Show the snake body.
229 for body in self.westicesnake.bodys:
230 tempindex=self.getIndex(body.x,body.y)
231 self.landsqurelist[tempindex].SetBitmap(wx.Bitmap(body.img1))
232
233 # Show the last vacated location.
234 if not self.first:
235 tempindex=self.getIndex(self.westicesnake.prev_snakex,self.westicesnake.prev_snakey)
236 tempimagenum=self.landsqurelist[tempindex].randnum
237 tempimagename='land'+str(tempimagenum)+'.jpg'
238 img1=wx.Image(tempimagename,wx.BITMAP_TYPE_ANY)
239 img1=img1.Scale(30, 30)
240 self.landsqurelist[tempindex].SetBitmap(wx.Bitmap(img1))
241 else:
242 self.first=False
243
244 # Long snake body, replace the cake with land.
245 if self.landsqurelist[tempindex].randnum==(-1):
246 # print('Eat the cake')
247 self.score+=1
248 self.scoretxt.SetLabel('Score : '+str(self.score))
249 self.landsqurelist[tempindex].randnum=int(random.random()*4)
250
251 # Body, set the coordinates, it should be added in the last vacated place.
252 snakebody=MyWesticeSnakeBody()
253 snakebody.x=self.westicesnake.prev_snakex
254 snakebody.y=self.westicesnake.prev_snakey
255 self.westicesnake.bodys.append(snakebody)
256
257 # Randomly generate cakes in the land.
258 tempindex=int(random.random()*self.gridwidth*self.gridheight)
259
260 if self.landsqurelist[tempindex].randnum==-1:
261 randnum=int(random.random()*4)
262 imagename='land'+str(randnum)+'.jpg'
263 self.landsqurelist[tempindex].randnum=randnum
264 else:
265 imagename='land-1.jpg'
266 self.landsqurelist[tempindex].randnum=-1
267
268 img1=wx.Image(imagename,wx.BITMAP_TYPE_ANY)
269 img1=img1.Scale(30, 30)
270 self.landsqurelist[tempindex].SetBitmap(wx.Bitmap(img1))
271 else:
272 self.gamestatustxt.SetLabel('Game status : Game over !')
273
274 self.westicesnake.update()
275
276
277 def getX_Y(self,imageindex):
278 """
279 Get the x,y coordinates of the image.
280 """
281
282 x=imageindex%self.gridwidth
283 y=imageindex/self.gridwidth
284
285 return [x,y]
286
287
288 def getIndex(self,x,y):
289 """
290 ...
291 """
292
293 return y*self.gridwidth+x
294
295
296 def OnQuit(self, event):
297 self.Close()
298
299 #---------------------------------------------------------------------------
300
301 def main():
302 app = wx.App()
303 frame = MyFrame()
304 frame.Show(True)
305 app.MainLoop()
306
307 #---------------------------------------------------------------------------
308
309 if __name__ == '__main__':
310 main()
Download source
Additional Information
Link :
https://wiki.python.org/moin/GameProgramming
http://mientki.ruhosting.nl/data_www/pylab_works/pw_bricks_2d_scene.html
- - - - -
https://wiki.wxpython.org/TitleIndex
Thanks to
Masaharu Kanda (break-wall.py coding), Keamest (othello.py coding), Shido (chess.py coding), 123 (snake.py coding), the wxPython community...
About this page
Date(d/m/y) Person (bot) Comments :
05/04/21 - Ecco (Created page for wxPython Phoenix).
Comments
- blah, blah, blah...