def show_statistics(qdicts, qdictsAll, categories): tot_n_questions = len(qdictsAll) # create message lines = [] lines.append(i18n.statisticsHeader[i18n.lang()][0]) lines.append(i18n.statisticsColHeader[i18n.lang()]) for default, longName, shortName in categories: lines.append( (longName + ': ', str(len(qdicts[shortName])), '{:.0f} %'.format( 100 * len(qdicts[shortName]) / tot_n_questions))) lines.append(i18n.statisticsHeader[i18n.lang()][1]) lines.append(i18n.statisticsColHeader[i18n.lang()]) count_dict = collections.Counter([x[2] for x in qdictsAll.values()]) keys = list(count_dict.keys()) keys.sort() for key in keys: lines.append( (key + ': ', str(count_dict[key]), '{:.0f} %'.format(100 * count_dict[key] / tot_n_questions))) root = tk.Tk() if sys.platform == 'win32': root.iconbitmap(files.FOX_ICO_PATH) root.title('F*x!') gui.InfoWindow(root, lines) root.focus_force() root.mainloop() root.destroy()
def read_data(questNumbers, questionFile, zipFile, zipPasswd): zipPasswd_bytes = str.encode(zipPasswd) qdicts = {} for key in questNumbers.keys(): qdicts[key] = {} qdictsAll = {} questCounter = 0 questLines = [] if questionFile.endswith('.zip'): base = os.path.basename(questionFile) with zipFile.open(os.path.splitext(base)[0]+'.txt', pwd=zipPasswd_bytes) as data: for byteLine in data: line = byteLine.decode('utf8') questLines.append(line) else: with open(questionFile, 'r', encoding='utf8') as data: for line in data: questLines.append(line) for line in questLines: line = line.rstrip() if line.startswith('#') or not len(line): continue splitlist = [] try: splitlist = line.split("#", 4) except ValueError: continue splitlist = [x for x in map(lambda a: a.strip(), splitlist)] try: difficulty, question, answer, category, vspace = splitlist except ValueError: errorIdx = 2 root = tk.Tk() if sys.platform == 'win32': root.iconbitmap(files.FOX_ICO_PATH) root.title(i18n.errorTitle[i18n.lang()]) lines = [] lines.append(i18n.errorText[i18n.lang()][errorIdx] + ' ' + line) gui.InfoWindow(root, lines) root.focus_force() root.mainloop() root.destroy() zipPasswd = '' questionFile = '' continue qdicts[difficulty][len(qdicts[difficulty])] = question, answer, category, vspace qdictsAll[questCounter] = question, answer, category, difficulty, vspace questCounter += 1 return qdicts, qdictsAll
def interactive_quiz(qdicts, questNumbers): ran_qdicts = randomize_questions(qdicts, questNumbers, exclude=['J', 'P']) questionList = functools.reduce(operator.add, ran_qdicts.values()) questionList = map(lambda x: x[0], questionList) answersCount = [0, 0, 0] root = tk.Tk() if sys.platform == 'win32': root.iconbitmap(files.FOX_ICO_PATH) root.title(i18n.quizTitle[i18n.lang()]) questionList = [ str(idx + 1) + '. ' + question for idx, question in enumerate(questionList) ] app = gui.QuizWindow(root, questionList) root.focus_force() root.mainloop() root.destroy() if app.quit.get(): return success = app.success.get() failure = app.failure.get() skip = app.skip.get() if not (success + failure): return answersCount = [success, failure, skip] lines = [] lines.append(i18n.quizHeader[i18n.lang()][0]) lines.append(i18n.statisticsColHeader[i18n.lang()]) tot_n_questions = functools.reduce(operator.add, answersCount) successRate = answersCount[0] / (tot_n_questions - answersCount[2]) successIndex = int(successRate * (len(i18n.quizInterpretation[i18n.lang()]) - 1)) quizInterpretation = i18n.quizInterpretation[i18n.lang()][successIndex] if successRate == 1: quizInterpretation = i18n.quizInterpretation[i18n.lang()][-1] keys = i18n.answerCorrect[i18n.lang()] for idx, key in enumerate(keys): lines.append( (key + ': ', str(answersCount[idx]), '{:.0f} %'.format(100 * answersCount[idx] / tot_n_questions))) interpretationText = i18n.quizHeader[i18n.lang()][1] + ': ' interpretationText += str(int(100 * successRate)) + ' % ' interpretationText += i18n.quizCorrect[i18n.lang()] + '. ' interpretationText += quizInterpretation + '!' lines.append(interpretationText) root = tk.Tk() if sys.platform == 'win32': root.iconbitmap(files.FOX_ICO_PATH) root.title('F*x!') app = gui.InfoWindow(root, lines) root.focus_force() root.mainloop() root.destroy()
def _set_username(): userName = simpledialog.askstring( i18n.snakeUserNameRequest[i18n.lang()][2], i18n.snakeUserNameRequest[i18n.lang()][0] + ':') if not userName: return self.userName = userName self.userNameButton['text'] = self.userName + ' ({0})'.format( i18n.snakeUserNameRequest[i18n.lang()][1]) with open(files.SNAKE_CONFIG_FILE, 'w') as outfile: yaml.dump({'username': self.userName}, outfile, default_flow_style=False)
def open_data(questionFile, zipPasswd): fileOpenOptions = dict(initialdir='.', defaultextension='.txt', filetypes=[('', '*.txt;*.zip')]) if not questionFile: questionFile = filedialog.askopenfilename(**fileOpenOptions) passwordError = False if questionFile != () and questionFile.endswith('.zip'): zipFile = zipfile.ZipFile(questionFile) for zinfo in zipFile.infolist(): isEncrypted = zinfo.flag_bits & 0x1 if isEncrypted and zipPasswd == '': zipPasswd = simpledialog.askstring(i18n.passwordText[i18n.lang()][0], i18n.passwordText[i18n.lang()][1], show='*') try: zipPasswd_bytes = str.encode(zipPasswd) except TypeError: zipPasswd_bytes = b'1234' print(os.path.splitext(questionFile)[0]) base = os.path.basename(questionFile) try: with zipFile.open(os.path.splitext(base)[0]+'.txt', pwd=zipPasswd_bytes): pass except RuntimeError: print('Bad password!') passwordError = True else: zipFile = '' if passwordError: errorIdx = 1 root = tk.Tk() if sys.platform == 'win32': root.iconbitmap(files.FOX_ICO_PATH) root.title(i18n.errorTitle[i18n.lang()]) lines = [] lines.append(i18n.errorText[i18n.lang()][errorIdx]) gui.InfoWindow(root, lines) root.focus_force() root.mainloop() root.destroy() zipPasswd = '' questionFile = '' return if not questionFile: return return zipFile, zipPasswd, questionFile
def _init_start(event): reset(self) _draw_new_fox(BOX_X_MAX * 0.15, BOX_Y_MIN * 0.4, 'scoreFox', 0.5) canv.create_text(BOX_X_MAX * 0.25, BOX_Y_MIN * 0.4, text=':' + str(self._nFoxes), font='b', tags=('foxText')) _draw_new_beer(BOX_X_MAX * 0.45, BOX_Y_MIN * 0.4, 'scoreBeer', 0.5) canv.create_text(BOX_X_MAX * 0.55, BOX_Y_MIN * 0.4, text=':' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1), font='b', tags=('beerText')) _draw_new_star(BOX_X_MAX * 0.75, BOX_Y_MIN * 0.4, 'scoreStar', 0.5) canv.create_text(BOX_X_MAX * 0.85, BOX_Y_MIN * 0.4, text=':' + str(self._nBeers), font='b', tags=('starText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN * 0.73, fill='red', text=i18n.snakeEventInfo[i18n.lang()][0], tags=('eventInfoText')) _start(event)
def _change_direction(event): if event.keysym == 'w': event.keysym = 'Up' if event.keysym == 'a': event.keysym = 'Left' if event.keysym == 's': event.keysym = 'Down' if event.keysym == 'd': event.keysym = 'Right' if not self._direction: canv.itemconfig('eventInfoText', text=i18n.snakeEventInfo[i18n.lang()][3]) if not self._nFoxes: self._direction = 'measingless' if event.keysym == 'Up' and self._direction != 'Down': self._yVel = -MOVEMENT_STEP_SIZE self._xVel = 0 self._direction = event.keysym if event.keysym == 'Down' and self._direction != 'Up': self._yVel = MOVEMENT_STEP_SIZE self._xVel = 0 self._direction = event.keysym if event.keysym == 'Right' and self._direction != 'Left': self._yVel = 0 self._xVel = MOVEMENT_STEP_SIZE self._direction = event.keysym if event.keysym == 'Left' and self._direction != 'Right': self._yVel = 0 self._xVel = -MOVEMENT_STEP_SIZE self._direction = event.keysym
def main(): print('Executing only snake!') root = tk.Tk() root.iconbitmap(foxIco) root.title(i18n.snakeWelcome[i18n.lang()]) SnakeWindow(root) root.focus_force() root.mainloop() root.destroy()
def play_snake(): root = tk.Tk() if sys.platform == 'win32': root.iconbitmap(files.FOX_ICO_PATH) root.title(i18n.snakeWelcome[i18n.lang()]) snake.SnakeWindow(root) root.focus_force() root.mainloop() root.destroy()
def __init__(self, master, lines): self.OKvalue = tk.IntVar() self.OKvalue.set(0) thisOKvalue = self.OKvalue center_window(master) master.protocol("WM_DELETE_WINDOW", master.quit) _row_count = 0 for line in lines: one_msg = tk.Message(master, text=line, width=400) one_msg.grid(row=_row_count, column=0, columnspan=2) _row_count += 1 def _quit(): thisOKvalue.set(0) master.quit() def _go(): thisOKvalue.set(1) master.quit() _OK_button = tk.Button(master, text=i18n.yesNo[i18n.lang()][0], command=_go, width=25) _OK_button.grid(row=_row_count, column=0) _cancel_button = tk.Button(master, text=i18n.yesNo[i18n.lang()][1], command=_quit, width=25) _cancel_button.grid(row=_row_count, column=1) def _quit_bind(self): _quit() def _go_bind(self): _go() master.bind('<Return>', _go_bind) master.bind('<Escape>', _quit_bind)
def main(): print('Executing snake game!') root = tk.Tk() if sys.platform == 'win32': root.iconbitmap(files.FOX_ICO_PATH) root.title(i18n.snakeWelcome[i18n.lang()]) SnakeWindow(root) root.focus_force() root.mainloop() root.destroy()
def show_questions(qdictsAll): header = i18n.allquestionsHeader[i18n.lang()] lines = [] lines.append(i18n.allquestionsColHeader[i18n.lang()]) for key in qdictsAll: lines.append(( qdictsAll[key][0], qdictsAll[key][1], qdictsAll[key][2], qdictsAll[key][3], qdictsAll[key][4], )) root = tk.Tk() if sys.platform == 'win32': root.iconbitmap(files.FOX_ICO_PATH) root.title('F*x!') gui.TextWindow(root, header, lines) root.focus_force() root.mainloop() root.destroy()
def _end_game(): cancel() remove_items() canv.itemconfig('eventInfoText', text='R.I.P.') canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.5, fill='red', font='b', text=i18n.gameOver[i18n.lang()][0], tags=('gameOverText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.6, fill='red', text=i18n.gameOver[i18n.lang()][1], tags=('gameOverCancelText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.7, fill='red', text=i18n.gameOver[i18n.lang()][2], tags=('gameOverRestartText')) master.bind('<Return>', _restart)
def new_exam(qdicts, questNumbers, categories): ran_qdicts = randomize_questions(qdicts, questNumbers) with open(i18n.examFile[i18n.lang()][0], 'w', encoding='utf8') as myfile: print(i18n.examTitle[i18n.lang()][0] + "\n", file=myfile) count = 0 for default, longName, shortName in categories: for question, answer, vspace in ran_qdicts[shortName]: count += 1 questionlines = question.split("\\\\") print('{}.'.format(count), questionlines[0], file=myfile) for item in questionlines[1:]: print('\to ' + item, file=myfile) print('\n' * int(vspace), file=myfile) with open(i18n.examFile[i18n.lang()][1], 'w', encoding='utf8') as myfile: print(i18n.examTitle[i18n.lang()][1] + "\n", file=myfile) count = 0 for default, longName, shortName in categories: for question, answer, vspace in ran_qdicts[shortName]: count += 1 print('{}.'.format(count), answer, file=myfile) if sys.platform == 'win32': sys_command = 'notepad ' + i18n.examFile[i18n.lang()][1] subprocess.Popen(sys_command) time.sleep(0.1) sys_command = 'notepad ' + i18n.examFile[i18n.lang()][0] subprocess.Popen(sys_command)
def display_highscore(): canv.create_text(self.infoBoxXCenter, BOX_Y_MIN + self.boxHeight * 0.5, text=i18n.snakeHighScore[i18n.lang()][0] + '...', font='b', tags=('load_highscore')) scores = web_client.read_highscore() keys = None errText = None try: keys = sorted(scores[0].keys()) except IndexError: errText = i18n.snakeWebErr[i18n.lang()][0] except TypeError: errText = i18n.snakeWebErr[i18n.lang()][1] delete_widget('load_highscore') hSpace = 10 vSpace = 20 subBoxXMin = self.infoBoxXMin + hSpace subBoxXMax = self.infoBoxXMax - hSpace topBoxYMin = BOX_Y_MIN + vSpace topBoxYMax = topBoxYMin + self.boxHeight * 0.4 gui_utils.draw_table(master, canv, subBoxXMin, subBoxXMax, topBoxYMin, topBoxYMax, headers=keys, values=scores, nRows=N_HIGHSCORES + 1, title=i18n.snakeHighScore[i18n.lang()][2], tags='global_highscore', errText=errText) try: userScores = [ score for score in scores if score['username'] == self.userName ] except TypeError: userScores = None lowBoxYMin = BOX_Y_MIN + self.boxHeight * 0.5 + vSpace * 0.5 lowBoxYMax = lowBoxYMin + self.boxHeight * 0.4 if not self.userName: errText = i18n.snakeWebErr[i18n.lang()][2] gui_utils.draw_table(master, canv, subBoxXMin, subBoxXMax, lowBoxYMin, lowBoxYMax, headers=keys, values=userScores, nRows=N_HIGHSCORES + 1, title=i18n.snakeHighScore[i18n.lang()][1], tags='personal_highscore', errText=errText)
def _end_game(): cancel() remove_items() canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.4, fill='orange', font=("Times", 25, "bold"), text=i18n.gameOver[i18n.lang()][0], tags=('gameOverText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.5, fill='orange', font=("Times", 25, "bold"), text=i18n.gameOver[i18n.lang()][1], tags=('gameOverCancelText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.6, fill='orange', font=("Times", 25, "bold"), text=i18n.gameOver[i18n.lang()][2], tags=('gameOverRestartText')) post_score() master.bind('<Return>', _restart)
def _end_game(): _cancel() canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.4, fill='red', font=("Times", 25, "bold"), text=i18n.hitKey[i18n.lang()][1], tags=('gameOverText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.5, fill='red', font=("Times", 25, "bold"), text=i18n.hitKey[i18n.lang()][2], tags=('gameOverCancelText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.6, fill='red', font=("Times", 25, "bold"), text=i18n.hitKey[i18n.lang()][3], tags=('gameOverRestartText')) _remove_objects() _post_score() master.bind('<Return>', _restart)
def _display_alerts(): self.webAlerts = web_client.read_alerts() if not self.webAlerts: return canv.create_text(self.infoBoxXCenter, BOX_Y_MIN + self.newsBoxYMax * 0.5, text=i18n.webNews[i18n.lang()][2], tags=('webAlertsHeader'), fill='red', font=("Times", 25, "bold")) for alert in self.webAlerts: alert = alert['message'] canv.create_text(self.infoBoxXCenter, BOX_Y_MIN + self.newsBoxYMax, text=utils.break_lines( alert, MAX_INFO_LINE_CHARS), tags=('webAlerts'))
def set_switch_language(): i18n.switch_language() set_image(_lang_button, i18n.lang_button_image(), 1, 20) set_text(_head_label, i18n.appHeader[i18n.lang()]) for idx, rad in enumerate(_radioButton): set_text(rad, i18n.dictInit[i18n.lang()][idx]) for idx, cat in enumerate(_cat_label): if cat is None: continue set_text(cat, i18n.longNames[i18n.lang()][idx]) set_text(_start_button, i18n.startButtonText[i18n.lang()][0]) set_text(_quit_button, i18n.startButtonText[i18n.lang()][1]) set_text(_link_label, i18n.linkLabelText[i18n.lang()])
def _restart(event): reset(self) delete_widget('gameOverText') delete_widget('gameOverCancelText') delete_widget('gameOverRestartText') delete_widget('bucket') tailFoxes = [item for item in itemRegister if 'tail' in item] for item in tailFoxes: delete_widget(item) canv.itemconfig('foxText', text=': ' + str(self._nFoxes)) canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) canv.itemconfig('starText', text=': ' + str(self._score)) canv.itemconfig('eventInfoText', text=i18n.snakeEventInfo[i18n.lang()][0]) canv.coords('major', FULL_WIDTH / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2) canv.majorImg = ImageTk.PhotoImage(majorImgObj.rotate(0)) canv.itemconfig('major', image=canv.majorImg) _start(event)
def __init__(self, master): gui_utils.center_window(master) master.geometry('%sx%s+%s+%s' % (FULL_WIDTH, FULL_HEIGHT, 100, 100)) master.resizable(0, 0) itemRegister = [] self._activeFoxes = [] self._currentRotation = 0 self._direction = None self._foxlastXvec = [] self._foxlastYvec = [] self._goldFox = None self._goldFoxLife = 0 self._job = {} self._nBeers = 0 self._nBucket = 0 self._nFoxes = 0 self._nJaegers = 0 self._nScoreStars = 0 self._rotationSpeed = 0 self._score = 0 self._speed = START_SPEED self._tumbleAngle = START_TUMBLE_ANGLE self._xPath = deque([], MAX_QUEUE_LEN) self._xVel = 0 self._xVelTumble = 0 self._yPath = deque([], MAX_QUEUE_LEN) self._yVel = 0 self._yVelTumble = 0 def _reset(self): self._activeFoxes = [] self._currentRotation = 0 self._direction = None self._foxlastXvec = [] self._foxlastYvec = [] self._goldFox = None self._goldFoxLife = 0 self._job = {} self._nBeers = 0 self._nBucket = 0 self._nFoxes = 0 self._nJaegers = 0 self._nScoreStars = 0 self._rotationSpeed = 0 self._score = 0 self._speed = START_SPEED self._tumbleAngle = START_TUMBLE_ANGLE self._xPath = deque([], MAX_QUEUE_LEN) self._xVel = 0 self._xVelTumble = 0 self._yPath = deque([], MAX_QUEUE_LEN) self._yVel = 0 self._yVelTumble = 0 for _ in range(N_FREE_FOXES): self._foxlastXvec.append(random.random()) self._foxlastYvec.append(random.random()) def _delete_widget(name): canv.delete(name) try: itemRegister.remove(name) except ValueError: pass def _check_box_boundary(x, y, xSize=FOX_SIZE, ySize=FOX_SIZE): if x > BOX_X_MAX - xSize / 2 or \ x < BOX_X_MIN + xSize / 2 or \ y > BOX_Y_MAX - ySize / 2 or \ y < BOX_Y_MIN + ySize / 2: return True def _check_clipping(x, y, xSize=MAJOR_SIZE, ySize=MAJOR_SIZE, exclude=None, include=None): for item in itemRegister: if exclude and item in exclude: continue if include and item not in include: continue itemX, itemY = canv.coords(item) x0, y0, x1, y1 = canv.bbox(item) itemSizeX = x1 - x0 itemSizeY = y1 - y0 # print('New item x/y', round(x), '/', round(y), item, itemX, '/', itemY) PROXIMITY = 3 isCloseX = abs(itemX - x) < xSize / PROXIMITY + itemSizeX / PROXIMITY isCloseY = abs(itemY - y) < ySize / PROXIMITY + itemSizeY / PROXIMITY if isCloseX and isCloseY: return item return '' def _get_new_random_pos(xSize, ySize): nTries = 0 while True: newX = BOX_X_MAX * random.random() newY = BOX_Y_MAX * random.random() # print(nTries, 'Trying newX newY', newX, '/', newY) if nTries > MAX_POSITION_LOOPS: return (None, None) else: nTries += 1 if _check_box_boundary(newX, newY, xSize, ySize): continue if _check_clipping(newX, newY, xSize, ySize): continue return (newX, newY) def _draw_new_fox(newX=None, newY=None, name='fox', size=1, gold=False): if not newX and not newY: newX, newY = _get_new_random_pos(FOX_SIZE, FOX_SIZE) if not newX and not newY: print('Warning: no new free fox position found!') return _delete_widget(name) if gold: thisFoxImgObj = goldFoxImgObj.resize( (int(FOX_SIZE * size), int(FOX_SIZE * size)), Image.ANTIALIAS) else: thisFoxImgObj = foxImgObj.resize( (int(FOX_SIZE * size), int(FOX_SIZE * size)), Image.ANTIALIAS) canv.foxImg[name] = ImageTk.PhotoImage(thisFoxImgObj) canv.create_image(newX, newY, image=canv.foxImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) raise_top_objects() def _draw_new_beer(newX=None, newY=None, name='beer', size=1): if not newX and not newY: newX, newY = _get_new_random_pos(BEER_SIZE, BEER_SIZE) if not newX and not newY: print('Warning: no new free beer position found!') return _delete_widget(name) thisBeerImgObj = beerImgObj.resize( (int(BEER_SIZE * size), int(BEER_SIZE * size)), Image.ANTIALIAS) canv.beerImg[name] = ImageTk.PhotoImage(thisBeerImgObj) canv.create_image(newX, newY, image=canv.beerImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) raise_top_objects() def _draw_new_bucket(newX=None, newY=None, name='bucket', size=1): if not newX and not newY: newX, newY = _get_new_random_pos(BUCKET_SIZE, BUCKET_SIZE) if not newX and not newY: print('Warning: no new free bucket position found!') return _delete_widget(name) thisBucketImgObj = bucketImgObj.resize( (int(BUCKET_SIZE * size), int(BEER_SIZE * size)), Image.ANTIALIAS) canv.bucketImg[name] = ImageTk.PhotoImage(thisBucketImgObj) canv.create_image(newX, newY, image=canv.bucketImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) raise_top_objects() def _draw_new_jaeger(newX=None, newY=None, name='jaeger', size=1): if not newX and not newY: newX, newY = _get_new_random_pos(JAEGER_SIZE, JAEGER_SIZE) if not newX and not newY: print('Warning: no new free jaeger position found!') return _delete_widget(name) thisJaegerImgObj = jaegerImgObj.resize( (int(JAEGER_SIZE * size), int(BEER_SIZE * size)), Image.ANTIALIAS) canv.jaegerImg[name] = ImageTk.PhotoImage(thisJaegerImgObj) canv.create_image(newX, newY, image=canv.jaegerImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) raise_top_objects() def _draw_new_star(newX=None, newY=None, name='star', size=1): if not newX and not newY: newX, newY = _get_new_random_pos(STAR_SIZE, STAR_SIZE) if not newX and not newY: print('Warning: no new free star position found!') return _delete_widget(name) thisStarImgObj = starImgObj.resize( (int(STAR_SIZE * size), int(STAR_SIZE * size)), Image.ANTIALIAS) canv.starImg[name] = ImageTk.PhotoImage(thisStarImgObj) canv.create_image(newX, newY, image=canv.starImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) raise_top_objects() def _move_fox_tail(): for idx in range(self._nFoxes): thisFoxTag = 'tail' + str(idx) try: canv.coords(thisFoxTag, self._xPath[(idx + 1) * TAIL_STEP_DISTANCE], self._yPath[(idx + 1) * TAIL_STEP_DISTANCE]) except IndexError: return self._activeFoxes.append(idx) def _keep_in_box(item): itemX, itemY = canv.coords(item) if itemX < BOX_X_MIN: canv.coords(item, BOX_X_MAX, itemY) if itemX > BOX_X_MAX: canv.coords(item, BOX_X_MIN, itemY) if itemY < BOX_Y_MIN: canv.coords(item, itemX, BOX_Y_MAX) if itemY > BOX_Y_MAX: canv.coords(item, itemX, BOX_Y_MIN) def _move_free_fox(): for idx in range(N_FREE_FOXES): name = 'fox' + str(idx) x, y = canv.coords(name) MAX_ALLOWED_ANGLE = 60 while True: yShift = (1 - 2 * random.random()) * MOVEMENT_STEP_SIZE xShift = (1 - 2 * random.random()) * MOVEMENT_STEP_SIZE angle = maths.get_angle(xShift, yShift, self._foxlastXvec[idx], self._foxlastYvec[idx]) if abs(angle) < MAX_ALLOWED_ANGLE: break x, y = x + xShift, y + yShift if not _check_clipping( x, y, xSize=FOX_SIZE, ySize=FOX_SIZE, exclude=name): self._foxlastXvec[idx] = xShift self._foxlastYvec[idx] = yShift canv.move(name, xShift, yShift) _keep_in_box(name) else: self._foxlastXvec[idx] = -self._foxlastXvec[idx] self._foxlastYvec[idx] = -self._foxlastYvec[idx] canv.move(name, self._foxlastXvec[idx], self._foxlastYvec[idx]) _keep_in_box(name) if self._goldFox == name: self._goldFoxLife += 1 if self._goldFoxLife > GOLD_FOX_LIFE_STEPS: self._goldFox = None self._goldFoxLife = 0 _delete_widget(name) _draw_new_fox(x, y, name) self._job['move_free_fox'] = master.after(int(1 / START_SPEED), _move_free_fox) def _get_new_tail_pos(): newX, newY = canv.coords('major') try: newX = self._xPath[(self._nFoxes) * TAIL_STEP_DISTANCE] newY = self._yPath[(self._nFoxes) * TAIL_STEP_DISTANCE] return (newX, newY) except IndexError: try: if self._nFoxes: newX, newY = canv.coords('tail' + str(self._nFoxes - 1)) except ValueError: pass return (newX, newY) def _raise_score(name): value = int(name.split('value_')[-1]) self._score += value canv.itemconfig('starText', text=': ' + str(self._score)) def _move_score_star(name, origX, origY, randVar=None): targetX, targetY = canv.coords('scoreStar') itemX, itemY = canv.coords(name) arrived = False if itemY > targetY: arrived = True if arrived: _delete_widget(name) _raise_score(name) return if randVar is None: randVar = 1 - 2 * random.random() if targetX != origX: xVel = SCORE_STAR_MOVEMENT_STEP_SIZE * ( targetX - origX) / targetX * (1 + randVar * 0.25) peakX = origX + randVar * (targetX - origX) / 4 yVel = maths.get_parabola( origX, origY, targetX, targetY, itemX + xVel, peakX=peakX) - itemY else: xVel = 0 yVel = SCORE_STAR_MOVEMENT_STEP_SIZE * ( 1 + abs(origY - itemY) / targetY) * (1 + randVar * 0.25) canv.move(name, xVel, yVel) def helpFunc(): return _move_score_star(name, origX, origY, randVar) self._job['move_' + name] = master.after(int(1 / SCORE_STAR_SPEED), helpFunc) def raise_top_objects(): for item in itemRegister: if item.startswith('scoreStar'): canv.tag_raise(item) def _move(): if self._direction is not None: canv.move('major', self._xVelTumble, self._yVelTumble) itemX, itemY = canv.coords('major') self._xPath.appendleft(itemX) self._yPath.appendleft(itemY) _keep_in_box('major') _move_fox_tail() beerList = list(map(lambda x: 'beer' + str(x), range(N_BEERS))) freeFoxList = list( map(lambda x: 'fox' + str(x), range(N_FREE_FOXES))) # catch foxes foxCollision = _check_clipping(itemX, itemY, include=freeFoxList) if foxCollision: sound.play_sound(files.BLOP_WAV_PATH) self._nFoxes += 1 canv.itemconfig('foxText', text=': ' + str(self._nFoxes)) goldFoxTail = False if foxCollision == self._goldFox: goldFoxTail = True self._goldFox = None self._goldFoxLife = 0 newX, newY = _get_new_tail_pos() _draw_new_fox(newX=newX, newY=newY, name='tail' + str(self._nFoxes - 1), gold=goldFoxTail) for item in reversed(itemRegister): canv.tag_raise(item) goldFox = False if self._goldFox is None and random.random( ) < GOLD_FOX_CHANCE: goldFox = True self._goldFox = foxCollision _draw_new_fox(name=foxCollision, gold=goldFox) foxIdx = int(foxCollision.lstrip('fox')) self._foxlastXvec[foxIdx] = random.random() self._foxlastYvec[foxIdx] = random.random() if not any(i in itemRegister for i in beerList): for beerName in beerList: if random.random() < BEER_RESPAWN_CHANCE: _draw_new_beer(name=beerName) if self._nJaegers == 0 and random.random() < JAEGER_CHANCE: _draw_new_jaeger(name='jaeger') self._nJaegers += 1 if self._nBeers > 0: foxValue = self._nBeers starScale = min(0.3 + self._nBeers / MAX_BEER * 0.3, 0.7) if goldFoxTail: for _ in range(GOLD_FOX_MULTIPLIER): starName = 'scoreStar_' + str( self._nScoreStars) + '_value_' + str( foxValue) _draw_new_star(itemX, itemY, starName, starScale) _move_score_star(starName, itemX, itemY) self._nScoreStars += 1 else: starName = 'scoreStar_' + str( self._nScoreStars) + '_value_' + str(foxValue) _draw_new_star(itemX, itemY, starName, starScale) _move_score_star(starName, itemX, itemY) self._nScoreStars += 1 def set_alc_effect(weight=1): for _ in range(weight): step = (MAX_SPEED - START_SPEED) / N_SPEED_STEPS self._speed = min(self._speed + step, MAX_SPEED) if self._nBeers == MAX_BEER or ( self._rotationSpeed == 0 and self._nBeers > MAX_BEER): self._rotationSpeed = START_ROTATION_SPEED elif self._nBeers > MAX_BEER: step = (MAX_ROTATION_SPEED - START_ROTATION_SPEED ) / N_ROTATION_SPEED_STEPS self._rotationSpeed = min( self._rotationSpeed + step, MAX_ROTATION_SPEED) step = (MAX_TUMBLE_ANGLE - START_TUMBLE_ANGLE) / N_TUMBLE_STEPS self._tumbleAngle = min(self._tumbleAngle + step, MAX_TUMBLE_ANGLE) # drink beer beerCollision = _check_clipping(itemX, itemY, include=beerList) if beerCollision: sound.play_sound(files.SLURP_WAV_PATH) self._nBeers += 1 set_alc_effect() canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) if self._nBeers >= MAX_BEER + 5 and self._nBucket == 0: _draw_new_bucket(name='bucket') self._nBucket += 1 if random.random() < BEER_RESPAWN_CHANCE: _draw_new_beer(name=beerCollision) else: _delete_widget(beerCollision) if self._nJaegers == 0 and random.random() < JAEGER_CHANCE: _draw_new_jaeger(name='jaeger') self._nJaegers += 1 # drink jaeger if _check_clipping(itemX, itemY, include='jaeger'): sound.play_sound(files.SLURP_WAV_PATH) self._nBeers += JAEGER_MULTIPLIER set_alc_effect(JAEGER_MULTIPLIER) canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) if self._nBeers >= MAX_BEER + 5 and self._nBucket == 0: _draw_new_bucket(name='bucket') self._nBucket += 1 _delete_widget('jaeger') self._nJaegers -= 1 # hit bucket if _check_clipping(itemX, itemY, include='bucket'): sound.play_sound(files.HICCUP_WAV_PATH) self._nBeers = MAX_BEER - 1 canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) _delete_widget('bucket') self._nBucket -= 1 self._currentRotation = 0 self._rotationSpeed = 0 self._tumbleAngle = START_TUMBLE_ANGLE # rotate major and its direction # print('speed', self._speed, 'rotationSpeed', self._rotationSpeed, 'tumbleDegree', self._tumbleAngle) self._currentRotation += self._rotationSpeed canv.majorImg = ImageTk.PhotoImage( majorImgObj.rotate(self._tumbleAngle * 2 * math.sin(self._currentRotation))) canv.itemconfig('major', image=canv.majorImg) angle = maths.get_angle(1, 0, self._xVel, self._yVel) angle += self._tumbleAngle * math.sin(-self._currentRotation) angle = math.radians(angle) self._xVelTumble = MOVEMENT_STEP_SIZE * math.cos(angle) self._yVelTumble = MOVEMENT_STEP_SIZE * math.sin(angle) # check tail overlap noTailFoxes = [ item for item in itemRegister if 'tail' not in item ] noTailFoxes.extend(['tail' + str(idx) for idx in range(2)]) noTailFoxes.extend([ 'tail' + str(idx) for idx in range(self._nFoxes) if idx not in self._activeFoxes ]) crashFox = _check_clipping(itemX, itemY, exclude=noTailFoxes, xSize=MAJOR_SIZE * 0.1, ySize=MAJOR_SIZE * 0.1) if crashFox: sound.play_sound(files.BLAST_WAV_PATH) print('Overlapping with tail', crashFox) _end_game() return self._job['move'] = master.after(int(1 / self._speed), _move) def _set_username(): userName = simpledialog.askstring( i18n.snakeUserNameRequest[i18n.lang()][2], i18n.snakeUserNameRequest[i18n.lang()][0] + ':') if not userName: return self.userName = userName self.userNameButton['text'] = self.userName + ' ({0})'.format( i18n.snakeUserNameRequest[i18n.lang()][1]) with open(files.SNAKE_CONFIG_FILE, 'w') as outfile: yaml.dump({'username': self.userName}, outfile, default_flow_style=False) def _post_score(): if not self.userName: _set_username() if not self.userName: return web_client.post_score(username=self.userName, score=self._score) def _display_highscore(): canv.create_text(self.infoBoxXCenter, BOX_Y_MIN + self.boxHeight * 0.5, text=i18n.snakeHighScore[i18n.lang()][0] + '...', font='b', tags=('load_highscore')) alertThread.join() newsThread.join() scores = web_client.read_highscore() keys = None errText = None try: keys = sorted(scores[0].keys()) except IndexError: errText = i18n.snakeWebErr[i18n.lang()][0] except TypeError: errText = i18n.snakeWebErr[i18n.lang()][1] _delete_widget('load_highscore') hSpace = 10 vSpace = 20 subBoxXMin = self.infoBoxXMin + hSpace subBoxXMax = self.infoBoxXMax - hSpace topBoxYMin = BOX_Y_MIN + vSpace topBoxYMax = topBoxYMin + self.boxHeight * 0.4 gui_utils.draw_table(master, canv, subBoxXMin, subBoxXMax, topBoxYMin, topBoxYMax, headers=keys, values=scores, nRows=N_HIGHSCORES + 1, title=i18n.snakeHighScore[i18n.lang()][2], tags='global_highscore', errText=errText) try: userScores = [ score for score in scores if score['username'] == self.userName ] except TypeError: userScores = None lowBoxYMin = BOX_Y_MIN + self.boxHeight * 0.5 + vSpace * 0.5 lowBoxYMax = lowBoxYMin + self.boxHeight * 0.4 if not self.userName: errText = i18n.snakeWebErr[i18n.lang()][2] gui_utils.draw_table(master, canv, subBoxXMin, subBoxXMax, lowBoxYMin, lowBoxYMax, headers=keys, values=userScores, nRows=N_HIGHSCORES + 1, title=i18n.snakeHighScore[i18n.lang()][1], tags='personal_highscore', errText=errText) raise_top_objects() def _display_news(): alertThread.join() news = web_client.read_news() if news is None: return self.webNews = news['message'] canv.itemconfig('webNews', text=utils.break_lines(self.webNews, MAX_INFO_LINE_CHARS)) def _display_alerts(): self.webAlerts = web_client.read_alerts() if not self.webAlerts: return canv.create_text(self.infoBoxXCenter, BOX_Y_MIN + self.newsBoxYMax * 0.5, text=i18n.webNews[i18n.lang()][2], tags=('webAlertsHeader'), fill='red', font=("Times", 25, "bold")) for alert in self.webAlerts: alert = alert['message'] canv.create_text(self.infoBoxXCenter, BOX_Y_MIN + self.newsBoxYMax, text=utils.break_lines( alert, MAX_INFO_LINE_CHARS), tags=('webAlerts')) def _quit(event=None): time.sleep(0.1) master.quit() def _cancel(): for job in self._job: master.after_cancel(self._job[job]) self._job = {} def _remove_objects(): removeList = [] for item in itemRegister: if item.startswith('scoreStar_'): _raise_score(item) removeList.append(item) for item in removeList: _delete_widget(item) def _end_game(): _cancel() canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.4, fill='red', font=("Times", 25, "bold"), text=i18n.hitKey[i18n.lang()][1], tags=('gameOverText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.5, fill='red', font=("Times", 25, "bold"), text=i18n.hitKey[i18n.lang()][2], tags=('gameOverCancelText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.6, fill='red', font=("Times", 25, "bold"), text=i18n.hitKey[i18n.lang()][3], tags=('gameOverRestartText')) _remove_objects() _post_score() master.bind('<Return>', _restart) def _init_start(event): _reset(self) _start() def _start(): _delete_widget('startKeystrokeText') _delete_widget('instructionText1') _delete_widget('instructionText2') _delete_widget('instructionText3') _delete_widget('instructionText4') _delete_widget('instructionText5') _delete_widget('instructionHeader') _delete_widget('instrBeer') _delete_widget('instrFox') _delete_widget('instrGoldFox') _delete_widget('instrJaeger') _delete_widget('instrBucket') _delete_widget('news_line') for widgetID in canv.find_all(): widget = canv.gettags(widgetID)[0] if 'webAlerts' in widget or 'webNews' in widget: _delete_widget(widget) for idx in range(N_FREE_FOXES): _draw_new_fox(name='fox' + str(idx)) for idx in range(N_BEERS): _draw_new_beer(name='beer' + str(idx)) master.bind('<Up>', _change_direction) master.bind('<Down>', _change_direction) master.bind('<Right>', _change_direction) master.bind('<Left>', _change_direction) master.bind('w', _change_direction) master.bind('a', _change_direction) master.bind('s', _change_direction) master.bind('d', _change_direction) master.unbind('<Return>') _move() _move_free_fox() highScoreThread = threading.Thread(target=_display_highscore) highScoreThread.start() def _restart(event): _reset(self) _delete_widget('gameOverText') _delete_widget('gameOverCancelText') _delete_widget('gameOverRestartText') _delete_widget('bucket') _delete_widget('jaeger') tailFoxes = [item for item in itemRegister if 'tail' in item] for item in tailFoxes: _delete_widget(item) canv.itemconfig('foxText', text=': ' + str(self._nFoxes)) canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) canv.itemconfig('starText', text=': ' + str(self._score)) canv.coords('major', BOX_X_MIN + self.boxWidth * 0.5, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2) canv.majorImg = ImageTk.PhotoImage(majorImgObj.rotate(0)) canv.itemconfig('major', image=canv.majorImg) for widgetID in canv.find_all(): widget = canv.gettags(widgetID)[0] if 'global_highscore' in widget: _delete_widget(widget) if 'personal_highscore' in widget: _delete_widget(widget) _start() def _change_direction(event): if event.keysym == 'w': event.keysym = 'Up' if event.keysym == 'a': event.keysym = 'Left' if event.keysym == 's': event.keysym = 'Down' if event.keysym == 'd': event.keysym = 'Right' if not self._nFoxes: self._direction = 'meaningless' if event.keysym == 'Up' and self._direction != 'Down': self._yVel = -MOVEMENT_STEP_SIZE self._xVel = 0 self._direction = event.keysym if event.keysym == 'Down' and self._direction != 'Up': self._yVel = MOVEMENT_STEP_SIZE self._xVel = 0 self._direction = event.keysym if event.keysym == 'Right' and self._direction != 'Left': self._yVel = 0 self._xVel = MOVEMENT_STEP_SIZE self._direction = event.keysym if event.keysym == 'Left' and self._direction != 'Right': self._yVel = 0 self._xVel = -MOVEMENT_STEP_SIZE self._direction = event.keysym canv = tk.Canvas(master, highlightthickness=0) canv.pack(fill='both', expand=True) self.userNameButton = tk.Button( master, text=i18n.snakeUserNameRequest[i18n.lang()][0], command=_set_username) if self.userName: self.userNameButton['text'] = self.userName + ' ({0})'.format( i18n.snakeUserNameRequest[i18n.lang()][1]) self.userNameButton.place(x=FULL_WIDTH, y=BOX_Y_MIN * 0.4, anchor='e') majorImgObj = Image.open(files.MAJOR_IMG_PATH) majorImgObj = majorImgObj.resize((MAJOR_SIZE, MAJOR_SIZE), Image.ANTIALIAS) canv.majorImg = ImageTk.PhotoImage(majorImgObj) foxImgObj = Image.open(files.FOX_ICO_PATH) foxImgObj = foxImgObj.resize((FOX_SIZE, FOX_SIZE), Image.ANTIALIAS) goldFoxImgObj = Image.open(files.GOLD_FOX_ICO_PATH) goldFoxImgObj = goldFoxImgObj.resize((FOX_SIZE, FOX_SIZE), Image.ANTIALIAS) beerImgObj = Image.open(files.BEER_IMG_PATH) beerImgObj = beerImgObj.resize((BEER_SIZE, BEER_SIZE), Image.ANTIALIAS) starImgObj = Image.open(files.STAR_IMG_PATH) starImgObj = starImgObj.resize((STAR_SIZE, STAR_SIZE), Image.ANTIALIAS) bucketImgObj = Image.open(files.BUCKET_IMG_PATH) bucketImgObj = bucketImgObj.resize((BUCKET_SIZE, BUCKET_SIZE), Image.ANTIALIAS) jaegerImgObj = Image.open(files.JAEGER_IMG_PATH) jaegerImgObj = jaegerImgObj.resize((JAEGER_SIZE, JAEGER_SIZE), Image.ANTIALIAS) floorImgObj = Image.open(files.FLOOR_IMG_PATH) floorImgObj = floorImgObj.resize( (BOX_X_MAX - BOX_X_MIN, BOX_Y_MAX - BOX_Y_MIN), Image.ANTIALIAS) canv.floorImg = ImageTk.PhotoImage(floorImgObj) canv.foxImg = {} canv.beerImg = {} canv.starImg = {} canv.bucketImg = {} canv.jaegerImg = {} canv.create_image((BOX_X_MAX + BOX_X_MIN) / 2, (BOX_Y_MAX + BOX_Y_MIN) / 2, image=canv.floorImg, tags=('floor')) canv.create_line(0, BOX_Y_MIN, FULL_WIDTH, BOX_Y_MIN, fill='black', tags=('top'), width=10) canv.create_line(BOX_X_MIN, BOX_Y_MIN, BOX_X_MIN, BOX_Y_MAX, fill='black', tags=('left'), width=10) canv.create_line(BOX_X_MAX - 1, BOX_Y_MIN, BOX_X_MAX - 1, BOX_Y_MAX, fill='black', tags=('center'), width=10) canv.create_line(FULL_WIDTH, BOX_Y_MIN, FULL_WIDTH, BOX_Y_MAX, fill='black', tags=('right'), width=10) canv.create_line(0, BOX_Y_MAX - 2, FULL_WIDTH, BOX_Y_MAX - 2, fill='black', tags=('bottom'), width=10) canv.create_text(FULL_WIDTH / 2, BOX_Y_MIN * 0.4, text=i18n.snakeWelcome[i18n.lang()], tags=('welcomeText'), font=("Times", 25, "bold"), fill='orange') deltaY = self.boxHeight * 0.07 instructionY = BOX_Y_MIN + self.boxHeight * 0.35 canv.create_text(self.infoBoxXCenter, instructionY, text=i18n.snakeInstruction[i18n.lang()][0], tags=('instructionHeader'), fill='green', font=("Times", 25, "bold")) instructionY += deltaY _draw_new_beer(self.infoBoxXMin + self.infoBoxWidth * 0.15, instructionY, "instrBeer", 0.5) canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.2, instructionY, tags=('instructionText1'), anchor='w', text=i18n.snakeInstruction[i18n.lang()][1]) instructionY += deltaY _draw_new_fox(self.infoBoxXMin + self.infoBoxWidth * 0.15, instructionY, "instrFox", 0.5) canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.2, instructionY, tags=('instructionText2'), anchor='w', text=i18n.snakeInstruction[i18n.lang()][2]) instructionY += deltaY _draw_new_fox(self.infoBoxXMin + self.infoBoxWidth * 0.15, instructionY, "instrGoldFox", 0.5, gold=True) canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.2, instructionY, tags=('instructionText3'), anchor='w', text=i18n.snakeInstruction[i18n.lang()][3].format( GOLD_FOX_MULTIPLIER)) instructionY += deltaY _draw_new_jaeger(self.infoBoxXMin + self.infoBoxWidth * 0.15, instructionY, "instrJaeger", 0.5) canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.2, instructionY, tags=('instructionText4'), anchor='w', text=i18n.snakeInstruction[i18n.lang()][4].format( JAEGER_MULTIPLIER)) instructionY += deltaY _draw_new_bucket(self.infoBoxXMin + self.infoBoxWidth * 0.15, instructionY, "instrBucket", 0.5) canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.2, instructionY, tags=('instructionText5'), anchor='w', text=i18n.snakeInstruction[i18n.lang()][5]) canv.create_text(self.infoBoxXCenter, BOX_Y_MAX - self.newsBoxYMax, text=i18n.webNews[i18n.lang()][1], tags=('webNewsHeader'), fill='orange', font=("Times", 25, "bold")) canv.create_text(self.infoBoxXCenter, BOX_Y_MAX - self.newsBoxYMax * 0.5, text=self.webNews, tags=('webNews')) canv.create_image(BOX_X_MIN + self.boxWidth * 0.5, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2, image=canv.majorImg, tags=('major')) itemRegister.append('major') canv.create_text(BOX_X_MAX * 0.5, BOX_Y_MIN + self.boxHeight * 0.75, fill='orange', font=("Times", 25, "bold"), text=i18n.hitKey[i18n.lang()][0], tags=('startKeystrokeText')) _draw_new_fox(BOX_X_MIN + self.boxWidth * 0.25, self.bottomRowY, 'scoreFox', 0.5) canv.create_text(BOX_X_MIN + self.boxWidth * 0.28, self.bottomRowY, text=': ' + str(self._nFoxes), font='b', tags=('foxText'), anchor="w") _draw_new_star(BOX_X_MIN + self.boxWidth * 0.5, self.bottomRowY, 'scoreStar', 0.5) canv.create_text(BOX_X_MIN + self.boxWidth * 0.53, self.bottomRowY, text=': ' + str(self._nBeers), font='b', tags=('starText'), anchor="w") _draw_new_beer(BOX_X_MIN + self.boxWidth * 0.75, self.bottomRowY, 'scoreBeer', 0.5) canv.create_text(BOX_X_MIN + self.boxWidth * 0.77, self.bottomRowY, text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1), font='b', tags=('beerText'), anchor="w") alertThread = threading.Thread(target=_display_alerts) alertThread.start() newsThread = threading.Thread(target=_display_news) newsThread.start() master.protocol("WM_DELETE_WINDOW", _quit) master.bind('<Up>', _init_start) master.bind('<Down>', _init_start) master.bind('<Right>', _init_start) master.bind('<Left>', _init_start) master.bind('w', _init_start) master.bind('a', _init_start) master.bind('s', _init_start) master.bind('d', _init_start) master.bind('<Escape>', _quit) master.bind('<Return>', _init_start)
def __init__(self, master): gui_utils.center_window(master) master.geometry('%sx%s+%s+%s' % (FULL_WIDTH, FULL_HEIGHT, 100, 100)) master.resizable(0, 0) itemRegister = [] self._score = 0 self._nFoxes = 0 self._nBeers = 0 def reset(self): self._xPath = deque([], MAX_QUEUE_LEN) self._yPath = deque([], MAX_QUEUE_LEN) self._xVel = 0 self._yVel = 0 self._xVelTumble = 0 self._yVelTumble = 0 self._direction = None self._score = 0 self._nFoxes = 0 self._nBeers = 0 self._speed = START_SPEED self._job = {} self._rotationSpeed = 0 self._currentRotation = 0 self._tumbleAngle = START_TUMBLE_ANGLE self._foxlastXvec = [] self._foxlastYvec = [] for idx in range(N_FREE_FOXES): self._foxlastXvec.append(random.random()) self._foxlastYvec.append(random.random()) def delete_widget(name): canv.delete(name) try: itemRegister.remove(name) except ValueError: pass def _set_username(): userName = simpledialog.askstring( i18n.snakeUserNameRequest[i18n.lang()][2], i18n.snakeUserNameRequest[i18n.lang()][0] + ':') if not userName: return self.userName = userName self.userNameButton['text'] = self.userName + ' ({0})'.format( i18n.snakeUserNameRequest[i18n.lang()][1]) with open(files.SNAKE_CONFIG_FILE, 'w') as outfile: yaml.dump({'username': self.userName}, outfile, default_flow_style=False) def _draw_new_fox(newX=None, newY=None, name='fox', size=1): if not newX and not newY: newX, newY = get_new_random_pos(FOX_SIZE, FOX_SIZE) if not newX and not newY: print('Warning: no new free fox position found!') _end_game() delete_widget(name) thisFoxImgObj = foxImgObj.resize( (int(FOX_SIZE * size), int(FOX_SIZE * size)), Image.ANTIALIAS) canv.foxImg[name] = ImageTk.PhotoImage(thisFoxImgObj) canv.create_image(newX, newY, image=canv.foxImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) def _draw_new_beer(newX=None, newY=None, name='beer', size=1): if not newX and not newY: newX, newY = get_new_random_pos(BEER_SIZE, BEER_SIZE) if not newX and not newY: print('Warning: no new free beer position found!') _end_game() delete_widget(name) thisBeerImgObj = beerImgObj.resize( (int(BEER_SIZE * size), int(BEER_SIZE * size)), Image.ANTIALIAS) canv.beerImg[name] = ImageTk.PhotoImage(thisBeerImgObj) canv.create_image(newX, newY, image=canv.beerImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) def _draw_new_bucket(newX=None, newY=None, name='bucket', size=1): if not newX and not newY: newX, newY = get_new_random_pos(BUCKET_SIZE, BUCKET_SIZE) if not newX and not newY: print('Warning: no new free bucket position found!') _end_game() delete_widget(name) thisBucketImgObj = bucketImgObj.resize( (int(BUCKET_SIZE * size), int(BEER_SIZE * size)), Image.ANTIALIAS) canv.bucketImg[name] = ImageTk.PhotoImage(thisBucketImgObj) canv.create_image(newX, newY, image=canv.bucketImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) def _draw_new_star(newX=None, newY=None, name='star', size=1): if not newX and not newY: newX, newY = get_new_random_pos(STAR_SIZE, STAR_SIZE) if not newX and not newY: print('Warning: no new free star position found!') _end_game() delete_widget(name) thisStarImgObj = starImgObj.resize( (int(FOX_SIZE * size), int(FOX_SIZE * size)), Image.ANTIALIAS) canv.starImg[name] = ImageTk.PhotoImage(thisStarImgObj) canv.create_image(newX, newY, image=canv.starImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) canv = tk.Canvas(master, highlightthickness=0) canv.pack(fill='both', expand=True) self.userNameButton = tk.Button( master, text=i18n.snakeUserNameRequest[i18n.lang()][0], command=_set_username) if self.userName: self.userNameButton['text'] = self.userName + ' ({0})'.format( i18n.snakeUserNameRequest[i18n.lang()][1]) self.userNameButton.place(x=FULL_WIDTH, y=BOX_Y_MIN * 0.4, anchor='e') majorImgObj = Image.open(files.MAJOR_IMG_PATH) majorImgObj = majorImgObj.resize((MAJOR_SIZE, MAJOR_SIZE), Image.ANTIALIAS) canv.majorImg = ImageTk.PhotoImage(majorImgObj) foxImgObj = Image.open(files.FOX_ICO_PATH) foxImgObj = foxImgObj.resize((FOX_SIZE, FOX_SIZE), Image.ANTIALIAS) beerImgObj = Image.open(files.BEER_IMG_PATH) beerImgObj = beerImgObj.resize((BEER_SIZE, BEER_SIZE), Image.ANTIALIAS) starImgObj = Image.open(files.STAR_IMG_PATH) starImgObj = starImgObj.resize((STAR_SIZE, STAR_SIZE), Image.ANTIALIAS) bucketImgObj = Image.open(files.BUCKET_IMG_PATH) bucketImgObj = bucketImgObj.resize((BUCKET_SIZE, BUCKET_SIZE), Image.ANTIALIAS) floorImgObj = Image.open(files.FLOOR_IMG_PATH) floorImgObj = floorImgObj.resize( (BOX_X_MAX - BOX_X_MIN, BOX_Y_MAX - BOX_Y_MIN), Image.ANTIALIAS) canv.floorImg = ImageTk.PhotoImage(floorImgObj) canv.foxImg = {} canv.beerImg = {} canv.starImg = {} canv.bucketImg = {} canv.create_image((BOX_X_MAX + BOX_X_MIN) / 2, (BOX_Y_MAX + BOX_Y_MIN) / 2, image=canv.floorImg, tags=('floor')) canv.create_line(0, BOX_Y_MIN, FULL_WIDTH, BOX_Y_MIN, fill='black', tags=('top'), width=10) canv.create_line(BOX_X_MIN, BOX_Y_MIN, BOX_X_MIN, BOX_Y_MAX, fill='black', tags=('left'), width=10) canv.create_line(BOX_X_MAX - 1, BOX_Y_MIN, BOX_X_MAX - 1, BOX_Y_MAX, fill='black', tags=('middle'), width=10) canv.create_line(FULL_WIDTH, BOX_Y_MIN, FULL_WIDTH, BOX_Y_MAX, fill='black', tags=('right'), width=10) canv.create_line(0, BOX_Y_MAX - 2, FULL_WIDTH, BOX_Y_MAX - 2, fill='black', tags=('bottom'), width=10) canv.create_text(FULL_WIDTH / 2, BOX_Y_MIN * 0.4, text=i18n.snakeWelcome[i18n.lang()], tags=('welcomeText'), font=("Times", 25, "bold"), fill='orange') deltaY = self.boxHeight * 0.07 instructionY = BOX_Y_MIN + self.boxHeight * 0.35 canv.create_text(self.infoBoxXCenter, instructionY, text=i18n.snakeInstruction[i18n.lang()][0], tags=('instructionText')) instructionY += deltaY canv.create_text(self.infoBoxXCenter, instructionY, text=i18n.snakeInstruction[i18n.lang()][1] + ':', tags=('instructionText2')) instructionY += deltaY _draw_new_star(self.infoBoxXMin + self.infoBoxWidth * 0.30, instructionY, "instrStar", 0.5) canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.40, instructionY, text='=', tags=('instructionEquals')) _draw_new_beer(self.infoBoxXMin + self.infoBoxWidth * 0.50, instructionY, "instrBeer", 0.5) canv.create_text(self.infoBoxXMin + self.infoBoxWidth * 0.60, instructionY, text='X', tags=('instructionTimes')) _draw_new_fox(self.infoBoxXMin + self.infoBoxWidth * 0.70, instructionY, "instrFox", 0.5) instructionY += deltaY canv.create_text(self.infoBoxXCenter, instructionY, text=i18n.snakeInstruction[i18n.lang()][2], tags=('instructionText3')) instructionY += deltaY canv.create_text(self.infoBoxXCenter, instructionY, text=i18n.snakeInstruction[i18n.lang()][3], tags=('instructionText4')) canv.create_image(BOX_X_MIN + self.boxWidth * 0.5, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2, image=canv.majorImg, tags=('major')) itemRegister.append('major') _draw_new_fox(FULL_WIDTH * 0.27, self.bottomRowY, 'scoreFox', 0.5) canv.create_text(FULL_WIDTH * 0.30, self.bottomRowY, text=': ' + str(self._nFoxes), font='b', tags=('foxText')) _draw_new_beer(FULL_WIDTH * 0.50, self.bottomRowY, 'scoreBeer', 0.5) canv.create_text(FULL_WIDTH * 0.55, self.bottomRowY, text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1), font='b', tags=('beerText')) _draw_new_star(FULL_WIDTH * 0.77, self.bottomRowY, 'scoreStar', 0.5) canv.create_text(FULL_WIDTH * 0.80, self.bottomRowY, text=': ' + str(self._nBeers), font='b', tags=('starText')) def move_fox_tail(): for idx in range(self._nFoxes): thisFoxTag = 'tail' + str(idx) try: canv.coords(thisFoxTag, self._xPath[(idx + 1) * TAIL_STEP_DISTANCE], self._yPath[(idx + 1) * TAIL_STEP_DISTANCE]) except IndexError: pass def move_free_fox(): for idx in range(N_FREE_FOXES): name = 'fox' + str(idx) x, y = canv.coords(name) MAX_ALLOWED_ANGLE = 60 while True: yShift = (1 - 2 * random.random()) * MOVEMENT_STEP_SIZE xShift = (1 - 2 * random.random()) * MOVEMENT_STEP_SIZE angle = maths.get_angle(xShift, yShift, self._foxlastXvec[idx], self._foxlastYvec[idx]) if abs(angle) < MAX_ALLOWED_ANGLE: break x, y = x + xShift, y + yShift if not check_clipping( x, y, xSize=FOX_SIZE, ySize=FOX_SIZE, exclude=name): self._foxlastXvec[idx] = xShift self._foxlastYvec[idx] = yShift canv.move(name, xShift, yShift) keep_in_box(name) else: self._foxlastXvec[idx] = -self._foxlastXvec[idx] self._foxlastYvec[idx] = -self._foxlastYvec[idx] canv.move(name, self._foxlastXvec[idx], self._foxlastYvec[idx]) keep_in_box(name) self._job['move_free_fox'] = master.after(int(1 / START_SPEED), move_free_fox) def get_new_tail_pos(): newX, newY = canv.coords('major') try: newX = self._xPath[(self._nFoxes) * TAIL_STEP_DISTANCE] newY = self._yPath[(self._nFoxes) * TAIL_STEP_DISTANCE] return (newX, newY) except IndexError: try: if self._nFoxes: newX, newY = canv.coords('tail' + str(self._nFoxes - 1)) except ValueError: pass return (newX, newY) def keep_in_box(item): itemX, itemY = canv.coords(item) if itemX < BOX_X_MIN: canv.coords(item, BOX_X_MAX, itemY) if itemX > BOX_X_MAX: canv.coords(item, BOX_X_MIN, itemY) if itemY < BOX_Y_MIN: canv.coords(item, itemX, BOX_Y_MAX) if itemY > BOX_Y_MAX: canv.coords(item, itemX, BOX_Y_MIN) def move(): if self._direction is not None: canv.move('major', self._xVelTumble, self._yVelTumble) itemX, itemY = canv.coords('major') self._xPath.appendleft(itemX) self._yPath.appendleft(itemY) keep_in_box('major') move_fox_tail() beerList = list(map(lambda x: 'beer' + str(x), range(N_BEERS))) freeFoxList = list( map(lambda x: 'fox' + str(x), range(N_FREE_FOXES))) # catch foxes foxCollision = check_clipping(itemX, itemY, include=freeFoxList) if foxCollision: sound.play_sound(files.BLOP_WAV_PATH) self._score += self._nBeers self._nFoxes += 1 canv.itemconfig('foxText', text=': ' + str(self._nFoxes)) canv.itemconfig('starText', text=': ' + str(self._score)) newX, newY = get_new_tail_pos() _draw_new_fox(newX=newX, newY=newY, name='tail' + str(self._nFoxes - 1)) for item in reversed(itemRegister): canv.tag_raise(item) _draw_new_fox(name=foxCollision) foxIdx = int(foxCollision.lstrip('fox')) self._foxlastXvec[foxIdx] = random.random() self._foxlastYvec[foxIdx] = random.random() if not any(i in itemRegister for i in beerList): for beerName in beerList: if random.random() < BEER_RESPAWN_CHANCE: _draw_new_beer(name=beerName) # drink beer beerCollision = check_clipping(itemX, itemY, include=beerList) if beerCollision: sound.play_sound(files.SLURP_WAV_PATH) self._nBeers += 1 canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) canv.itemconfig('starText', text=': ' + str(self._score)) step = (MAX_SPEED - START_SPEED) / N_SPEED_STEPS self._speed = min(self._speed + step, MAX_SPEED) if self._nBeers == MAX_BEER: self._rotationSpeed = START_ROTATION_SPEED elif self._nBeers > MAX_BEER: step = (MAX_ROTATION_SPEED - START_ROTATION_SPEED) / N_ROTATION_SPEED_STEPS self._rotationSpeed = min(self._rotationSpeed + step, MAX_ROTATION_SPEED) step = (MAX_TUMBLE_ANGLE - START_TUMBLE_ANGLE) / N_TUMBLE_STEPS self._tumbleAngle = min(self._tumbleAngle + step, MAX_TUMBLE_ANGLE) if self._nBeers == MAX_BEER + 5: _draw_new_bucket() if random.random() < BEER_RESPAWN_CHANCE: _draw_new_beer(name=beerCollision) else: delete_widget(beerCollision) # hit bucket if check_clipping(itemX, itemY, include='bucket'): sound.play_sound(files.HICCUP_WAV_PATH) self._nBeers = MAX_BEER - 1 canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) delete_widget('bucket') self._currentRotation = 0 self._rotationSpeed = 0 self._tumbleAngle = START_TUMBLE_ANGLE # rotate major and its direction # print('speed', self._speed, 'rotationSpeed', self._rotationSpeed, 'tumbleDegree', self._tumbleAngle) self._currentRotation += self._rotationSpeed canv.majorImg = ImageTk.PhotoImage( majorImgObj.rotate(self._tumbleAngle * 2 * math.sin(self._currentRotation))) canv.itemconfig('major', image=canv.majorImg) angle = maths.get_angle(1, 0, self._xVel, self._yVel) angle += self._tumbleAngle * math.sin(-self._currentRotation) angle = math.radians(angle) self._xVelTumble = MOVEMENT_STEP_SIZE * math.cos(angle) self._yVelTumble = MOVEMENT_STEP_SIZE * math.sin(angle) # check tail overlap noTailFoxes = [ item for item in itemRegister if 'tail' not in item ] noTailFoxes.extend(['tail' + str(idx) for idx in range(2)]) crashFox = check_clipping(itemX, itemY, exclude=noTailFoxes, xSize=MAJOR_SIZE * 0.1, ySize=MAJOR_SIZE * 0.1) if crashFox: sound.play_sound(files.BLAST_WAV_PATH) print('Overlapping with tail', crashFox) _end_game() return self._job['move'] = master.after(int(1 / self._speed), move) def check_box_boundary(x, y, xSize=FOX_SIZE, ySize=FOX_SIZE): if x > BOX_X_MAX - xSize / 2 or \ x < BOX_X_MIN + xSize / 2 or \ y > BOX_Y_MAX - ySize / 2 or \ y < BOX_Y_MIN + ySize / 2: return True def check_clipping(x, y, xSize=MAJOR_SIZE, ySize=MAJOR_SIZE, exclude=[], include=[]): for item in itemRegister: if item in exclude: continue if include and item not in include: continue itemX, itemY = canv.coords(item) x0, y0, x1, y1 = canv.bbox(item) itemSizeX = x1 - x0 itemSizeY = y1 - y0 # print('New item x/y', round(x), '/', round(y), item, itemX, '/', itemY) PROXIMITY = 3 isCloseX = abs(itemX - x) < xSize / PROXIMITY + itemSizeX / PROXIMITY isCloseY = abs(itemY - y) < xSize / PROXIMITY + itemSizeY / PROXIMITY if isCloseX and isCloseY: return item return '' def get_new_random_pos(xSize, ySize): nTries = 0 while True: newX = BOX_X_MAX * random.random() newY = BOX_Y_MAX * random.random() # print(nTries, 'Trying newX newY', newX, '/', newY) if nTries > MAX_POSITION_LOOPS: return (None, None) else: nTries += 1 if check_box_boundary(newX, newY, xSize, ySize): continue if check_clipping(newX, newY, xSize, ySize): continue return (newX, newY) def post_score(): if not self.userName: _set_username() if not self.userName: return web_client.post_score(username=self.userName, score=self._score) def display_highscore(): canv.create_text(self.infoBoxXCenter, BOX_Y_MIN + self.boxHeight * 0.5, text=i18n.snakeHighScore[i18n.lang()][0] + '...', font='b', tags=('load_highscore')) scores = web_client.read_highscore() keys = None errText = None try: keys = sorted(scores[0].keys()) except IndexError: errText = i18n.snakeWebErr[i18n.lang()][0] except TypeError: errText = i18n.snakeWebErr[i18n.lang()][1] delete_widget('load_highscore') hSpace = 10 vSpace = 20 subBoxXMin = self.infoBoxXMin + hSpace subBoxXMax = self.infoBoxXMax - hSpace topBoxYMin = BOX_Y_MIN + vSpace topBoxYMax = topBoxYMin + self.boxHeight * 0.4 gui_utils.draw_table(master, canv, subBoxXMin, subBoxXMax, topBoxYMin, topBoxYMax, headers=keys, values=scores, nRows=N_HIGHSCORES + 1, title=i18n.snakeHighScore[i18n.lang()][2], tags='global_highscore', errText=errText) try: userScores = [ score for score in scores if score['username'] == self.userName ] except TypeError: userScores = None lowBoxYMin = BOX_Y_MIN + self.boxHeight * 0.5 + vSpace * 0.5 lowBoxYMax = lowBoxYMin + self.boxHeight * 0.4 if not self.userName: errText = i18n.snakeWebErr[i18n.lang()][2] gui_utils.draw_table(master, canv, subBoxXMin, subBoxXMax, lowBoxYMin, lowBoxYMax, headers=keys, values=userScores, nRows=N_HIGHSCORES + 1, title=i18n.snakeHighScore[i18n.lang()][1], tags='personal_highscore', errText=errText) def _init_start(event): reset(self) _start(event) def _start(event): # delete_widget('welcomeText') delete_widget('instructionText') delete_widget('instructionText2') delete_widget('instructionText3') delete_widget('instructionText4') delete_widget('instrStar') delete_widget('instrBeer') delete_widget('instrFox') delete_widget('instructionEquals') delete_widget('instructionTimes') for idx in range(N_FREE_FOXES): _draw_new_fox(name='fox' + str(idx)) for idx in range(N_BEERS): _draw_new_beer(name='beer' + str(idx)) master.bind('<Up>', _change_direction) master.bind('<Down>', _change_direction) master.bind('<Right>', _change_direction) master.bind('<Left>', _change_direction) master.bind('w', _change_direction) master.bind('a', _change_direction) master.bind('s', _change_direction) master.bind('d', _change_direction) master.unbind('<Return>') move() move_free_fox() t1 = threading.Thread(target=display_highscore) t1.start() def _quit(self): time.sleep(0.1) master.quit() def _click_quit(): _quit(self) def cancel(): for job in self._job: master.after_cancel(self._job[job]) self._job = {} def remove_items(): # keepItems = ['scoreFox', 'scoreBeer', 'scoreStar'] # for item in itemRegister: # if item not in keepItems: # canv.delete(item) pass def _end_game(): cancel() remove_items() canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.4, fill='orange', font=("Times", 25, "bold"), text=i18n.gameOver[i18n.lang()][0], tags=('gameOverText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.5, fill='orange', font=("Times", 25, "bold"), text=i18n.gameOver[i18n.lang()][1], tags=('gameOverCancelText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.6, fill='orange', font=("Times", 25, "bold"), text=i18n.gameOver[i18n.lang()][2], tags=('gameOverRestartText')) post_score() master.bind('<Return>', _restart) def _restart(event): reset(self) delete_widget('gameOverText') delete_widget('gameOverCancelText') delete_widget('gameOverRestartText') delete_widget('bucket') tailFoxes = [item for item in itemRegister if 'tail' in item] for item in tailFoxes: delete_widget(item) canv.itemconfig('foxText', text=': ' + str(self._nFoxes)) canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) canv.itemconfig('starText', text=': ' + str(self._score)) canv.coords('major', BOX_X_MIN + self.boxWidth * 0.5, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2) canv.majorImg = ImageTk.PhotoImage(majorImgObj.rotate(0)) canv.itemconfig('major', image=canv.majorImg) for widgetID in canv.find_all(): widget = canv.gettags(widgetID)[0] if 'global_highscore' in widget: print('Deleting', widget) delete_widget(widget) if 'personal_highscore' in widget: print('Deleting', widget) delete_widget(widget) _start(event) def _change_direction(event): if event.keysym == 'w': event.keysym = 'Up' if event.keysym == 'a': event.keysym = 'Left' if event.keysym == 's': event.keysym = 'Down' if event.keysym == 'd': event.keysym = 'Right' if not self._nFoxes: self._direction = 'measingless' if event.keysym == 'Up' and self._direction != 'Down': self._yVel = -MOVEMENT_STEP_SIZE self._xVel = 0 self._direction = event.keysym if event.keysym == 'Down' and self._direction != 'Up': self._yVel = MOVEMENT_STEP_SIZE self._xVel = 0 self._direction = event.keysym if event.keysym == 'Right' and self._direction != 'Left': self._yVel = 0 self._xVel = MOVEMENT_STEP_SIZE self._direction = event.keysym if event.keysym == 'Left' and self._direction != 'Right': self._yVel = 0 self._xVel = -MOVEMENT_STEP_SIZE self._direction = event.keysym master.protocol("WM_DELETE_WINDOW", _click_quit) master.bind('<Up>', _init_start) master.bind('<Down>', _init_start) master.bind('<Right>', _init_start) master.bind('<Left>', _init_start) master.bind('w', _init_start) master.bind('a', _init_start) master.bind('s', _init_start) master.bind('d', _init_start) master.bind('<Escape>', _quit) master.bind('<Return>', _init_start)
sound.start_sound() taskVar = 0 zipPasswd = '' questionFile = '' categoryUpdate = {} foxIco = files.resource_path('', r'images\fox.ico') while True: lang_button_png = i18n.lang_button_image() sound_buttong_png = sound.sound_button_image() categories = [ [16, i18n.longNames[i18n.lang()][0], i18n.shortNames[i18n.lang()][0]], [6, i18n.longNames[i18n.lang()][1], i18n.shortNames[i18n.lang()][1]], [4, i18n.longNames[i18n.lang()][2], i18n.shortNames[i18n.lang()][2]], [1000, i18n.longNames[i18n.lang()][3], i18n.shortNames[i18n.lang()][3]], [5, i18n.longNames[i18n.lang()][4], i18n.shortNames[i18n.lang()][4]], [0, i18n.longNames[i18n.lang()][5], i18n.shortNames[i18n.lang()][5]], ] change_catagories(categories, categoryUpdate) category_numbers = map(lambda x: x[0], categories) mainroot = tk.Tk() mainroot.iconbitmap(foxIco) mainroot.title('F*x!') mainapp = gui.InitWindow(mainroot, category_numbers, taskVar) mainroot.focus_force() mainroot.mainloop() taskVar = mainapp.radio_var.get()
def __init__(self, master, categories, radioinit=0): center_window(master) master.protocol("WM_DELETE_WINDOW", sys.exit) self.inputDict = {} self.radio_var = tk.IntVar() self.radio_var.set(radioinit) _row_count = 0 _head_label = tk.Label(master, text=i18n.appHeader[i18n.lang()], font=("Helvetica", 16)) _head_label.grid(row=_row_count, columnspan=4) _row_count += 1 _photo = tk.PhotoImage(file=foxPng) _photo = _photo.subsample(5, 5) _photo_label = tk.Label(master, image=_photo) _photo_label.photo = _photo _photo_label.grid(row=_row_count, columnspan=4) _row_count += 1 _col_idx = 0 _row_count += 2 _cat_label = [] for idx, default in enumerate(categories): longName = i18n.longNames[i18n.lang()][idx] shortName = i18n.shortNames[i18n.lang()][idx] if shortName == 'P' or shortName == 'A': _cat_label.append(None) continue _cat_label.append(tk.Label(master, text=longName)) _cat_label[-1].grid(row=_row_count - 2, column=_col_idx, columnspan=2) string_val = tk.StringVar() string_val.set(default) cat_entry = tk.Entry(master, textvariable=string_val, width=5) cat_entry.grid(row=_row_count - 1, column=_col_idx, columnspan=2) self.inputDict[shortName] = string_val _col_idx = (_col_idx + 2) % 4 if (_col_idx == 0): _row_count += 2 _radioButton = [] for idx, task in enumerate(i18n.dictInit[i18n.lang()]): _radioButton.append( tk.Radiobutton(master, text=task, variable=self.radio_var, value=idx)) _radioButton[idx].grid(row=_row_count, column=0, columnspan=4) _row_count += 1 _start_button = tk.Button(master, text=i18n.startButtonText[i18n.lang()][0], fg="green", font="bold", command=master.quit) _start_button.grid(row=_row_count, column=0, columnspan=2) _quit_button = tk.Button(master, text=i18n.startButtonText[i18n.lang()][1], fg="red", font="bold", command=sys.exit) _quit_button.grid(row=_row_count, column=2, columnspan=2) _row_count += 1 def set_switch_language(): i18n.switch_language() set_image(_lang_button, i18n.lang_button_image(), 1, 20) set_text(_head_label, i18n.appHeader[i18n.lang()]) for idx, rad in enumerate(_radioButton): set_text(rad, i18n.dictInit[i18n.lang()][idx]) for idx, cat in enumerate(_cat_label): if cat is None: continue set_text(cat, i18n.longNames[i18n.lang()][idx]) set_text(_start_button, i18n.startButtonText[i18n.lang()][0]) set_text(_quit_button, i18n.startButtonText[i18n.lang()][1]) set_text(_link_label, i18n.linkLabelText[i18n.lang()]) _lang_button = tk.Button(master, command=combine_funcs(set_switch_language)) set_image(_lang_button, i18n.lang_button_image(), 1, 20) _lang_button.grid(row=_row_count, column=0) _github_button = tk.Button(master) set_image(_github_button, github_button_png, 5, 20) _github_button.bind("<Button-1>", callback_GitHub) _github_button.grid(row=_row_count, column=3) def set_toggle_sound(): sound.toggle_sound() set_image(_sound_button, sound.sound_button_image(), 4, 20) _sound_button = tk.Button(master, command=combine_funcs(set_toggle_sound)) set_image(_sound_button, sound.sound_button_image(), 4, 20) _sound_button.grid(row=_row_count, column=1) _link_label = tk.Label(master, text=i18n.linkLabelText[i18n.lang()], fg="blue", cursor="hand2") _link_label.grid(row=_row_count, column=2) _link_label.bind("<Button-1>", callback_AGV) thisradio = self.radio_var def _toggleup(self): old = thisradio.get() new = max(old - 1, 0) thisradio.set(new) def _toggledown(self): old = thisradio.get() new = min(old + 1, len(i18n.dictInit[i18n.lang()]) - 1) thisradio.set(new) def _quit(self): master.quit() def _mute(self): set_toggle_sound() def _lang(self): set_switch_language() master.bind('<Escape>', sys.exit) master.bind('<Up>', _toggleup) master.bind('<Down>', _toggledown) master.bind('<Return>', _quit) master.bind('m', _mute) master.bind('l', _lang)
def __init__(self, master, questionList): self.quit = tk.IntVar() self.quit.set(0) thisQuit = self.quit self.success = tk.IntVar() self.success.set(0) thisSuccess = self.success self.failure = tk.IntVar() self.failure.set(0) thisFailure = self.failure self.skip = tk.IntVar() self.skip.set(0) thisSkip = self.skip self.currentQuestion = tk.IntVar() self.currentQuestion.set(0) thisCurrentQuestion = self.currentQuestion center_window(master) self.one_msg = [] self._row_count = 0 def _success(): augment(thisSuccess) _new_question() def _failure(): augment(thisFailure) _new_question() def _skip(): augment(thisSkip) _new_question() def _quit(): augment(thisQuit) master.quit() self._success_button = tk.Button(master, text=i18n.quizButton[i18n.lang()][0] + ' [k]', command=_success, width=15, font="bold") self._failure_button = tk.Button(master, text=i18n.quizButton[i18n.lang()][1] + ' [d]', command=_failure, width=15, font="bold") self._skip_button = tk.Button(master, text=i18n.quizButton[i18n.lang()][2] + ' [s]', command=_skip, width=15, font="bold") self._quit_button = tk.Button(master, text=i18n.quizButton[i18n.lang()][3] + ' [esc]', command=_quit, width=15, fg="red", font="bold") def print_question(one_msg): self._row_count = 0 splitlist = questionList[self.currentQuestion.get()].split('\\\\') for idx, item in enumerate(splitlist): if idx > 0: item = str(idx) + '. ' + item self.one_msg.append(tk.Message(master, text=item, width=575)) self.one_msg[idx].grid(row=self._row_count, column=0, columnspan=4) self._row_count += 1 self._failure_button.grid(row=self._row_count, column=1) self._success_button.grid(row=self._row_count, column=0) self._skip_button.grid(row=self._row_count, column=2) self._quit_button.grid(row=self._row_count, column=3) def remove_question(one_msg): while one_msg: msg = one_msg.pop() msg.grid_forget() print_question(self.one_msg) def _new_question(): augment(thisCurrentQuestion) remove_question(self.one_msg) try: print_question(self.one_msg) except IndexError: master.quit() self._failure_button.grid(row=self._row_count, column=1) self._success_button.grid(row=self._row_count, column=0) self._skip_button.grid(row=self._row_count, column=2) self._quit_button.grid(row=self._row_count, column=3) def _success_bind(self): _success() def _failure_bind(self): _failure() def _skip_bind(self): _skip() def _quit_bind(self): _quit() master.protocol("WM_DELETE_WINDOW", _quit) master.bind('k', _success_bind) master.bind('d', _failure_bind) master.bind('s', _skip_bind) master.bind('<Escape>', _quit_bind)
idx = list(map(lambda a: a[2], category)).index(key) except ValueError: continue category[idx][0] = categoryUpdate[key] return category sound.start_sound() taskVar = 0 zipPasswd = '' questionFile = '' categoryUpdate = {} while True: categories = [ [16, i18n.longNames[i18n.lang()][0], i18n.shortNames[i18n.lang()][0]], [6, i18n.longNames[i18n.lang()][1], i18n.shortNames[i18n.lang()][1]], [4, i18n.longNames[i18n.lang()][2], i18n.shortNames[i18n.lang()][2]], [ 1000, i18n.longNames[i18n.lang()][3], i18n.shortNames[i18n.lang()][3] ], [5, i18n.longNames[i18n.lang()][4], i18n.shortNames[i18n.lang()][4]], [0, i18n.longNames[i18n.lang()][5], i18n.shortNames[i18n.lang()][5]], ] change_catagories(categories, categoryUpdate) category_numbers = map(lambda x: x[0], categories) mainroot = tk.Tk() if sys.platform == 'win32': mainroot.iconbitmap(files.FOX_ICO_PATH) mainroot.title('F*x!')
def _toggledown(self): old = thisradio.get() new = min(old + 1, len(i18n.dictInit[i18n.lang()]) - 1) thisradio.set(new)
def __init__(self, master): gui.center_window(master) master.geometry('%sx%s+%s+%s' % (FULL_WIDTH, FULL_HEIGHT, 100, 100)) master.resizable(0, 0) itemRegister = [] def reset(self): self._xPath = deque([], MAX_QUEUE_LEN) self._yPath = deque([], MAX_QUEUE_LEN) self._xVel = 0 self._yVel = 0 self._xVelTumble = 0 self._yVelTumble = 0 self._direction = None self._score = 0 self._nFoxes = 0 self._nBeers = 0 self._speed = START_SPEED self._job = {} self._rotationSpeed = 0 self._currentRotation = 0 self._tumbleAngle = START_TUMBLE_ANGLE self._foxlastXvec = random.random() self._foxlastYvec = random.random() def delete_widget(name): canv.delete(name) try: itemRegister.remove(name) except ValueError: pass def _draw_new_fox(newX=None, newY=None, name='fox', size=1): if not newX and not newY: newX, newY = get_new_random_pos(FOX_SIZE, FOX_SIZE) if not newX and not newY: print('Warning: no new free fox position found!') _end_game() delete_widget(name) thisFoxImgObj = foxImgObj.resize( (int(FOX_SIZE * size), int(FOX_SIZE * size)), Image.ANTIALIAS) canv.foxImg[name] = ImageTk.PhotoImage(thisFoxImgObj) canv.create_image(newX, newY, image=canv.foxImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) def _draw_new_beer(newX=None, newY=None, name='beer', size=1): if not newX and not newY: newX, newY = get_new_random_pos(BEER_SIZE, BEER_SIZE) if not newX and not newY: print('Warning: no new free beer position found!') _end_game() delete_widget(name) thisBeerImgObj = beerImgObj.resize( (int(BEER_SIZE * size), int(BEER_SIZE * size)), Image.ANTIALIAS) canv.beerImg[name] = ImageTk.PhotoImage(thisBeerImgObj) canv.create_image(newX, newY, image=canv.beerImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) def _draw_new_bucket(newX=None, newY=None, name='bucket', size=1): if not newX and not newY: newX, newY = get_new_random_pos(BUCKET_SIZE, BUCKET_SIZE) if not newX and not newY: print('Warning: no new free bucket position found!') _end_game() delete_widget(name) thisBucketImgObj = bucketImgObj.resize( (int(BUCKET_SIZE * size), int(BEER_SIZE * size)), Image.ANTIALIAS) canv.bucketImg[name] = ImageTk.PhotoImage(thisBucketImgObj) canv.create_image(newX, newY, image=canv.bucketImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) def _draw_new_star(newX=None, newY=None, name='star', size=1): if not newX and not newY: newX, newY = get_new_random_pos(STAR_SIZE, STAR_SIZE) if not newX and not newY: print('Warning: no new free star position found!') _end_game() delete_widget(name) thisStarImgObj = starImgObj.resize( (int(FOX_SIZE * size), int(FOX_SIZE * size)), Image.ANTIALIAS) canv.starImg[name] = ImageTk.PhotoImage(thisStarImgObj) canv.create_image(newX, newY, image=canv.starImg[name], tags=(name)) if name not in itemRegister: itemRegister.append(name) canv = tk.Canvas(master, highlightthickness=0) canv.pack(fill='both', expand=True) majorImgObj = Image.open(majorImgPath) majorImgObj = majorImgObj.resize((MAJOR_SIZE, MAJOR_SIZE), Image.ANTIALIAS) canv.majorImg = ImageTk.PhotoImage(majorImgObj) foxImgObj = Image.open(foxImgPath) foxImgObj = foxImgObj.resize((FOX_SIZE, FOX_SIZE), Image.ANTIALIAS) beerImgObj = Image.open(beerImgPath) beerImgObj = beerImgObj.resize((BEER_SIZE, BEER_SIZE), Image.ANTIALIAS) starImgObj = Image.open(starImgPath) starImgObj = starImgObj.resize((STAR_SIZE, STAR_SIZE), Image.ANTIALIAS) bucketImgObj = Image.open(bucketImgPath) bucketImgObj = bucketImgObj.resize((BUCKET_SIZE, BUCKET_SIZE), Image.ANTIALIAS) floorImgObj = Image.open(floorImgPath) floorImgObj = floorImgObj.resize( (BOX_X_MAX - BOX_X_MIN, BOX_Y_MAX - BOX_Y_MIN), Image.ANTIALIAS) canv.floorImg = ImageTk.PhotoImage(floorImgObj) canv.foxImg = {} canv.beerImg = {} canv.starImg = {} canv.bucketImg = {} canv.create_image((BOX_X_MAX + BOX_X_MIN) / 2, (BOX_Y_MAX + BOX_Y_MIN) / 2, image=canv.floorImg, tags=('floor')) canv.create_line(BOX_X_MIN, BOX_Y_MIN, BOX_X_MAX, BOX_Y_MIN, fill='black', tags=('top'), width=10) canv.create_line(BOX_X_MIN, BOX_Y_MIN, BOX_X_MIN, BOX_Y_MAX, fill='black', tags=('left'), width=10) canv.create_line(BOX_X_MAX - 1, BOX_Y_MIN, BOX_X_MAX - 1, BOX_Y_MAX, fill='black', tags=('right'), width=10) canv.create_line(BOX_X_MIN, BOX_Y_MAX - 2, BOX_X_MAX, BOX_Y_MAX - 2, fill='black', tags=('bottom'), width=10) canv.create_text(FULL_WIDTH / 2, BOX_Y_MIN * 0.4, text=i18n.snakeWelcome[i18n.lang()], tags=('welcomeText'), font='b', fill='orange') canv.create_text(BOX_X_MAX / 2, BOX_Y_MAX * 2 / 8, text=i18n.snakeInstruction[i18n.lang()][0], tags=('instructionText')) canv.create_text(FULL_WIDTH / 2, BOX_Y_MAX * 6 / 8, text=i18n.snakeInstruction[i18n.lang()][1], tags=('instructionText2')) _draw_new_star(FULL_WIDTH * 0.30, BOX_Y_MAX * 0.9, "instrStar", 0.5) canv.create_text(FULL_WIDTH * 0.40, BOX_Y_MAX * 0.9, text='=', tags=('instructionEquals')) _draw_new_beer(FULL_WIDTH * 0.50, BOX_Y_MAX * 0.9, "instrBeer", 0.5) canv.create_text(FULL_WIDTH * 0.60, BOX_Y_MAX * 0.9, text='X', tags=('instructionTimes')) _draw_new_fox(FULL_WIDTH * 0.70, BOX_Y_MAX * 0.9, "instrFox", 0.5) canv.create_image(FULL_WIDTH / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2, image=canv.majorImg, tags=('major')) itemRegister.append('major') def move_fox_tail(): for idx in range(self._nFoxes): thisFoxTag = 'tail' + str(idx) try: canv.coords(thisFoxTag, self._xPath[(idx + 1) * TAIL_STEP_DISTANCE], self._yPath[(idx + 1) * TAIL_STEP_DISTANCE]) except IndexError: pass def move_free_fox(): x, y = canv.coords('fox') MAX_ALLOWED_ANGLE = 60 while True: yShift = (1 - 2 * random.random()) * MOVEMENT_STEP_SIZE xShift = (1 - 2 * random.random()) * MOVEMENT_STEP_SIZE angle = get_angle(xShift, yShift, self._foxlastXvec, self._foxlastYvec) if abs(angle) < MAX_ALLOWED_ANGLE: break x, y = x + xShift, y + yShift if not check_clipping( x, y, xSize=FOX_SIZE, ySize=FOX_SIZE, exclude='fox'): self._foxlastXvec = xShift self._foxlastYvec = yShift canv.move('fox', xShift, yShift) keep_in_box('fox') else: self._foxlastXvec = -self._foxlastXvec self._foxlastYvec = -self._foxlastYvec self._job['move_free_fox'] = master.after(int(1 / START_SPEED), move_free_fox) def get_new_tail_pos(): newX, newY = canv.coords('major') try: newX = self._xPath[(self._nFoxes) * TAIL_STEP_DISTANCE] newY = self._yPath[(self._nFoxes) * TAIL_STEP_DISTANCE] return (newX, newY) except IndexError: try: if self._nFoxes: newX, newY = canv.coords('tail' + str(self._nFoxes - 1)) except ValueError: pass return (newX, newY) def keep_in_box(item): itemX, itemY = canv.coords(item) if itemX < BOX_X_MIN: canv.coords(item, BOX_X_MAX, itemY) if itemX > BOX_X_MAX: canv.coords(item, BOX_X_MIN, itemY) if itemY < BOX_Y_MIN: canv.coords(item, itemX, BOX_Y_MAX) if itemY > BOX_Y_MAX: canv.coords(item, itemX, BOX_Y_MIN) def move(): if self._direction is not None: canv.move('major', self._xVelTumble, self._yVelTumble) itemX, itemY = canv.coords('major') self._xPath.appendleft(itemX) self._yPath.appendleft(itemY) keep_in_box('major') move_fox_tail() # catch foxes if check_clipping(itemX, itemY, include='fox'): self._score += self._nBeers self._nFoxes += 1 canv.itemconfig('foxText', text=': ' + str(self._nFoxes)) canv.itemconfig('starText', text=': ' + str(self._score)) newX, newY = get_new_tail_pos() _draw_new_fox(newX=newX, newY=newY, name='tail' + str(self._nFoxes - 1)) for item in reversed(itemRegister): canv.tag_raise(item) _draw_new_fox() self._foxlastXvec = random.random() self._foxlastYvec = random.random() if 'beer' not in itemRegister: _draw_new_beer() # drink beer if check_clipping(itemX, itemY, include='beer'): self._nBeers += 1 canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) canv.itemconfig('starText', text=': ' + str(self._score)) step = (MAX_SPEED - START_SPEED) / N_SPEED_STEPS self._speed = min(self._speed + step, MAX_SPEED) if self._nBeers == MAX_BEER - 1: canv.itemconfig( 'eventInfoText', text=i18n.snakeEventInfo[i18n.lang()][1]) elif self._nBeers == MAX_BEER: self._rotationSpeed = START_ROTATION_SPEED canv.itemconfig( 'eventInfoText', text=i18n.snakeEventInfo[i18n.lang()][2]) elif self._nBeers > MAX_BEER: step = (MAX_ROTATION_SPEED - START_ROTATION_SPEED) / N_ROTATION_SPEED_STEPS self._rotationSpeed = min(self._rotationSpeed + step, MAX_ROTATION_SPEED) step = (MAX_TUMBLE_ANGLE - START_TUMBLE_ANGLE) / N_TUMBLE_STEPS self._tumbleAngle = min(self._tumbleAngle + step, MAX_TUMBLE_ANGLE) if self._nBeers == MAX_BEER + 5: _draw_new_bucket() canv.itemconfig( 'eventInfoText', text=i18n.snakeEventInfo[i18n.lang()][4]) if random.random() < BEER_RESPAWN_CHANCE: _draw_new_beer() else: delete_widget('beer') # hit bucket if check_clipping(itemX, itemY, include='bucket'): self._nBeers = MAX_BEER - 1 canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) delete_widget('bucket') self._currentRotation = 0 self._rotationSpeed = 0 self._tumbleAngle = START_TUMBLE_ANGLE # rotate major and its direction # print('speed', self._speed, 'rotationSpeed', self._rotationSpeed, 'tumbleDegree', self._tumbleAngle) self._currentRotation += self._rotationSpeed canv.majorImg = ImageTk.PhotoImage( majorImgObj.rotate(self._tumbleAngle * 2 * math.sin(self._currentRotation))) canv.itemconfig('major', image=canv.majorImg) angle = get_angle(1, 0, self._xVel, self._yVel) angle += self._tumbleAngle * math.sin(-self._currentRotation) angle = math.radians(angle) self._xVelTumble = MOVEMENT_STEP_SIZE * math.cos(angle) self._yVelTumble = MOVEMENT_STEP_SIZE * math.sin(angle) # check tail overlap noTailFoxes = [ item for item in itemRegister if 'tail' not in item ] noTailFoxes.extend(['tail' + str(idx) for idx in range(2)]) crashFox = check_clipping(itemX, itemY, exclude=noTailFoxes, xSize=MAJOR_SIZE * 0.1, ySize=MAJOR_SIZE * 0.1) if crashFox: print('Overlapping with tail', crashFox) _end_game() return self._job['move'] = master.after(int(1 / self._speed), move) def check_box_boundary(x, y, xSize=FOX_SIZE, ySize=FOX_SIZE): if x > BOX_X_MAX - xSize / 2 or \ x < BOX_X_MIN + xSize / 2 or \ y > BOX_Y_MAX - ySize / 2 or \ y < BOX_Y_MIN + ySize / 2: return True def check_clipping(x, y, xSize=MAJOR_SIZE, ySize=MAJOR_SIZE, exclude=[], include=[]): for item in itemRegister: if item in exclude: continue if include and item not in include: continue itemX, itemY = canv.coords(item) x0, y0, x1, y1 = canv.bbox(item) itemSizeX = x1 - x0 itemSizeY = y1 - y0 # print('New item x/y', round(x), '/', round(y), item, itemX, '/', itemY) PROXIMITY = 3 isCloseX = abs(itemX - x) < xSize / PROXIMITY + itemSizeX / PROXIMITY isCloseY = abs(itemY - y) < xSize / PROXIMITY + itemSizeY / PROXIMITY if isCloseX and isCloseY: return item return '' def get_new_random_pos(xSize, ySize): nTries = 0 while True: newX = BOX_X_MAX * random.random() newY = BOX_Y_MAX * random.random() # print(nTries, 'Trying newX newY', newX, '/', newY) if nTries > MAX_POSITION_LOOPS: return (None, None) else: nTries += 1 if check_box_boundary(newX, newY, xSize, ySize): continue if check_clipping(newX, newY, xSize, ySize): continue return (newX, newY) def _init_start(event): reset(self) _draw_new_fox(BOX_X_MAX * 0.15, BOX_Y_MIN * 0.4, 'scoreFox', 0.5) canv.create_text(BOX_X_MAX * 0.25, BOX_Y_MIN * 0.4, text=':' + str(self._nFoxes), font='b', tags=('foxText')) _draw_new_beer(BOX_X_MAX * 0.45, BOX_Y_MIN * 0.4, 'scoreBeer', 0.5) canv.create_text(BOX_X_MAX * 0.55, BOX_Y_MIN * 0.4, text=':' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1), font='b', tags=('beerText')) _draw_new_star(BOX_X_MAX * 0.75, BOX_Y_MIN * 0.4, 'scoreStar', 0.5) canv.create_text(BOX_X_MAX * 0.85, BOX_Y_MIN * 0.4, text=':' + str(self._nBeers), font='b', tags=('starText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN * 0.73, fill='red', text=i18n.snakeEventInfo[i18n.lang()][0], tags=('eventInfoText')) _start(event) def _start(event): delete_widget('welcomeText') delete_widget('instructionText') delete_widget('instructionText2') delete_widget('instrStar') delete_widget('instrBeer') delete_widget('instrFox') delete_widget('instructionEquals') delete_widget('instructionTimes') _draw_new_fox() _draw_new_beer() master.bind('<Up>', _change_direction) master.bind('<Down>', _change_direction) master.bind('<Right>', _change_direction) master.bind('<Left>', _change_direction) master.bind('w', _change_direction) master.bind('a', _change_direction) master.bind('s', _change_direction) master.bind('d', _change_direction) master.unbind('<Return>') move() move_free_fox() def _quit(self): time.sleep(0.1) master.quit() def _click_quit(): _quit(self) def cancel(): for job in self._job: master.after_cancel(self._job[job]) self._job = {} def remove_items(): # keepItems = ['scoreFox', 'scoreBeer', 'scoreStar'] # for item in itemRegister: # if item not in keepItems: # canv.delete(item) pass def _end_game(): cancel() remove_items() canv.itemconfig('eventInfoText', text='R.I.P.') canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.5, fill='red', font='b', text=i18n.gameOver[i18n.lang()][0], tags=('gameOverText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.6, fill='red', text=i18n.gameOver[i18n.lang()][1], tags=('gameOverCancelText')) canv.create_text(BOX_X_MAX / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) * 0.7, fill='red', text=i18n.gameOver[i18n.lang()][2], tags=('gameOverRestartText')) master.bind('<Return>', _restart) def _restart(event): reset(self) delete_widget('gameOverText') delete_widget('gameOverCancelText') delete_widget('gameOverRestartText') delete_widget('bucket') tailFoxes = [item for item in itemRegister if 'tail' in item] for item in tailFoxes: delete_widget(item) canv.itemconfig('foxText', text=': ' + str(self._nFoxes)) canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) canv.itemconfig('starText', text=': ' + str(self._score)) canv.itemconfig('eventInfoText', text=i18n.snakeEventInfo[i18n.lang()][0]) canv.coords('major', FULL_WIDTH / 2, BOX_Y_MIN + (BOX_Y_MAX - BOX_Y_MIN) / 2) canv.majorImg = ImageTk.PhotoImage(majorImgObj.rotate(0)) canv.itemconfig('major', image=canv.majorImg) _start(event) def _change_direction(event): if event.keysym == 'w': event.keysym = 'Up' if event.keysym == 'a': event.keysym = 'Left' if event.keysym == 's': event.keysym = 'Down' if event.keysym == 'd': event.keysym = 'Right' if not self._direction: canv.itemconfig('eventInfoText', text=i18n.snakeEventInfo[i18n.lang()][3]) if not self._nFoxes: self._direction = 'measingless' if event.keysym == 'Up' and self._direction != 'Down': self._yVel = -MOVEMENT_STEP_SIZE self._xVel = 0 self._direction = event.keysym if event.keysym == 'Down' and self._direction != 'Up': self._yVel = MOVEMENT_STEP_SIZE self._xVel = 0 self._direction = event.keysym if event.keysym == 'Right' and self._direction != 'Left': self._yVel = 0 self._xVel = MOVEMENT_STEP_SIZE self._direction = event.keysym if event.keysym == 'Left' and self._direction != 'Right': self._yVel = 0 self._xVel = -MOVEMENT_STEP_SIZE self._direction = event.keysym master.protocol("WM_DELETE_WINDOW", _click_quit) master.bind('<Up>', _init_start) master.bind('<Down>', _init_start) master.bind('<Right>', _init_start) master.bind('<Left>', _init_start) master.bind('w', _init_start) master.bind('a', _init_start) master.bind('s', _init_start) master.bind('d', _init_start) master.bind('<Escape>', _quit) master.bind('<Return>', _init_start)
def move(): if self._direction is not None: canv.move('major', self._xVelTumble, self._yVelTumble) itemX, itemY = canv.coords('major') self._xPath.appendleft(itemX) self._yPath.appendleft(itemY) keep_in_box('major') move_fox_tail() # catch foxes if check_clipping(itemX, itemY, include='fox'): self._score += self._nBeers self._nFoxes += 1 canv.itemconfig('foxText', text=': ' + str(self._nFoxes)) canv.itemconfig('starText', text=': ' + str(self._score)) newX, newY = get_new_tail_pos() _draw_new_fox(newX=newX, newY=newY, name='tail' + str(self._nFoxes - 1)) for item in reversed(itemRegister): canv.tag_raise(item) _draw_new_fox() self._foxlastXvec = random.random() self._foxlastYvec = random.random() if 'beer' not in itemRegister: _draw_new_beer() # drink beer if check_clipping(itemX, itemY, include='beer'): self._nBeers += 1 canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) canv.itemconfig('starText', text=': ' + str(self._score)) step = (MAX_SPEED - START_SPEED) / N_SPEED_STEPS self._speed = min(self._speed + step, MAX_SPEED) if self._nBeers == MAX_BEER - 1: canv.itemconfig( 'eventInfoText', text=i18n.snakeEventInfo[i18n.lang()][1]) elif self._nBeers == MAX_BEER: self._rotationSpeed = START_ROTATION_SPEED canv.itemconfig( 'eventInfoText', text=i18n.snakeEventInfo[i18n.lang()][2]) elif self._nBeers > MAX_BEER: step = (MAX_ROTATION_SPEED - START_ROTATION_SPEED) / N_ROTATION_SPEED_STEPS self._rotationSpeed = min(self._rotationSpeed + step, MAX_ROTATION_SPEED) step = (MAX_TUMBLE_ANGLE - START_TUMBLE_ANGLE) / N_TUMBLE_STEPS self._tumbleAngle = min(self._tumbleAngle + step, MAX_TUMBLE_ANGLE) if self._nBeers == MAX_BEER + 5: _draw_new_bucket() canv.itemconfig( 'eventInfoText', text=i18n.snakeEventInfo[i18n.lang()][4]) if random.random() < BEER_RESPAWN_CHANCE: _draw_new_beer() else: delete_widget('beer') # hit bucket if check_clipping(itemX, itemY, include='bucket'): self._nBeers = MAX_BEER - 1 canv.itemconfig('beerText', text=': ' + str(self._nBeers) + ' / ' + str(MAX_BEER - 1)) delete_widget('bucket') self._currentRotation = 0 self._rotationSpeed = 0 self._tumbleAngle = START_TUMBLE_ANGLE # rotate major and its direction # print('speed', self._speed, 'rotationSpeed', self._rotationSpeed, 'tumbleDegree', self._tumbleAngle) self._currentRotation += self._rotationSpeed canv.majorImg = ImageTk.PhotoImage( majorImgObj.rotate(self._tumbleAngle * 2 * math.sin(self._currentRotation))) canv.itemconfig('major', image=canv.majorImg) angle = get_angle(1, 0, self._xVel, self._yVel) angle += self._tumbleAngle * math.sin(-self._currentRotation) angle = math.radians(angle) self._xVelTumble = MOVEMENT_STEP_SIZE * math.cos(angle) self._yVelTumble = MOVEMENT_STEP_SIZE * math.sin(angle) # check tail overlap noTailFoxes = [ item for item in itemRegister if 'tail' not in item ] noTailFoxes.extend(['tail' + str(idx) for idx in range(2)]) crashFox = check_clipping(itemX, itemY, exclude=noTailFoxes, xSize=MAJOR_SIZE * 0.1, ySize=MAJOR_SIZE * 0.1) if crashFox: print('Overlapping with tail', crashFox) _end_game() return self._job['move'] = master.after(int(1 / self._speed), move)