def showChoice(self, ch_idx, game_no=None, round_no=None, rounds_tot=None, won_sf=None, drew_sf=None, lost_sf=None): """Show player's choice on NeoPixels or display. The display also has game and round info and win/draw summary. This removes all the graphical objects and re-adds them which causes visible flickering during an update - this could be improved by only replacing / updating what needs changing. """ if self.disp is None: self.pix.fill(BLACK) self.pix[self.choiceToPixIdx(ch_idx)] = CHOICE_COL[ch_idx] return self.emptyGroup(self.disp_group) # Would be slightly better to create this Group once and re-use it round_choice_group = Group(max_size=3) if round_no is not None: title_dob = Label(self.font, text="Game {:d} Round {:d}/{:d}".format( game_no, round_no, rounds_tot), scale=2, color=TITLE_TXT_COL_FG) title_dob.x = round( (self.width - len(title_dob.text) * 2 * self.font_width) // 2) title_dob.y = round(self.font_height // 2) round_choice_group.append(title_dob) if won_sf is not None: gamesum_dob = Label(self.font, text="Won {:d} Drew {:d} Lost {:d}".format( won_sf, drew_sf, lost_sf), scale=2, color=TITLE_TXT_COL_FG) gamesum_dob.x = round( (self.width - len(gamesum_dob.text) * 2 * self.font_width) // 2) gamesum_dob.y = round(self.height - 2 * self.font_height // 2) round_choice_group.append(gamesum_dob) s_group = Group(scale=3, max_size=1) s_group.x = 32 s_group.y = (self.height - 3 * self.sprite_size) // 2 s_group.append(self.sprites[ch_idx]) round_choice_group.append(s_group) self.showGroup(round_choice_group)
def showChoice(self, ch_idx, game_no=None, round_no=None, rounds_tot=None, won_sf=None, drew_sf=None, lost_sf=None): """TODO DOC""" if self.disp is None: self.pix.fill(BLACK) self.pix[self.choiceToPixIdx(ch_idx)] = CHOICE_COL[ch_idx] return self.emptyGroup(self.disp_group) ### Would be slightly better to create this Group once and re-use it round_choice_group = Group(max_size=3) if round_no is not None: title_dob = Label(self.font, text="Game {:d} Round {:d}/{:d}".format( game_no, round_no, rounds_tot), scale=2, color=TITLE_TXT_COL_FG) title_dob.x = round( (self.width - len(title_dob.text) * 2 * self.font_width) // 2) title_dob.y = round(self.font_height // 2) round_choice_group.append(title_dob) if won_sf is not None: gamesum_dob = Label(self.font, text="Won {:d} Drew {:d} Lost {:d}".format( won_sf, drew_sf, lost_sf), scale=2, color=TITLE_TXT_COL_FG) gamesum_dob.x = round( (self.width - len(gamesum_dob.text) * 2 * self.font_width) // 2) gamesum_dob.y = round(self.height - 2 * self.font_height // 2) round_choice_group.append(gamesum_dob) s_group = Group(scale=3, max_size=1) s_group.x = 32 s_group.y = (self.height - 3 * self.sprite_size) // 2 s_group.append(self.sprites[ch_idx]) round_choice_group.append(s_group) self.showGroup(round_choice_group)
def showPlayerVPlayerScreen(self, me_name, op_name, my_ch_idx, op_ch_idx, result, summary, win, draw, void): # pylint: disable=too-many-locals,too-many-branches,too-many-statements """Display a win, draw, lose or error message.""" self.fadeUpDown("down") self.emptyGroup(self.disp_group) if void: error_tot = 3 error_group = Group(max_size=error_tot + 1) # Opponent's name helps pinpoint the error op_dob = Label(self.font, text=op_name, scale=2, color=OPP_NAME_COL_FG) op_dob.x = 40 op_dob.y = self.font_height error_group.append(op_dob) self.showGroup(error_group) self.fadeUpDown("up", duration=0.4) if result is not None: self.sample.play(result) font_scale = 2 # Attempting to put the three pieces of "Error!" text on screen # synchronised with the sound sample repeating the word for idx in range(error_tot): error_dob = Label(self.font, text="Error!", scale=font_scale, color=ERROR_COL_FG) error_dob.x = 40 error_dob.y = 60 + idx * 60 error_group.append(error_dob) time.sleep(0.5) # Small attempt to synchronise audio with text font_scale += 1 else: # Would be slightly better to create this Group once and re-use it pvp_group = Group(max_size=3) # Add player's name and sprite just off left side of screen # and opponent's just off right player_detail = [[ me_name, self.sprites[my_ch_idx], -16 - 3 * self.sprite_size, PLAYER_NAME_COL_FG, PLAYER_NAME_COL_BG ], [ op_name, self.opp_sprites[op_ch_idx], 16 + self.width, OPP_NAME_COL_FG, OPP_NAME_COL_BG ]] idx_lr = [0, 1] # index for left and right sprite if win: player_detail.reverse() # this player is winner so put last idx_lr.reverse() # Add some whitespace around winner's name player_detail[1][0] = " " + player_detail[1][0] + " " for (name, sprite, start_x, fg, bg) in player_detail: s_group = Group(scale=2, max_size=2) # Audio is choppy at scale=3 s_group.x = start_x s_group.y = (self.height - 2 * (self.sprite_size + self.font_height)) // 2 s_group.append(sprite) p_name_dob = Label( self.font, text=name, scale=1, # This is scaled by the group color=fg, background_color=bg) # Centre text below sprite - values are * Group scale p_name_dob.x = (self.sprite_size - len(name) * self.font_width) // 2 p_name_dob.y = self.sprite_size + 4 s_group.append(p_name_dob) pvp_group.append(s_group) if draw: sum_text = "Draw" elif win: sum_text = "You win" else: sum_text = "You lose" # Text starts invisible (BLACK) and color is later changed summary_dob = Label(self.font, text=sum_text, scale=3, color=BLACK) summary_dob.x = round( (self.width - 3 * self.font_width * len(sum_text)) / 2) summary_dob.y = round(self.height - (3 * self.font_height / 2)) pvp_group.append(summary_dob) self.showGroup(pvp_group) self.fadeUpDown("up", duration=0.4) # Start audio half way through animations if draw: # Move sprites onto the screen leaving them at either side for idx in range(16): pvp_group[idx_lr[0]].x += 6 pvp_group[idx_lr[1]].x -= 6 if idx == 8 and result is not None: self.sample.play(result) time.sleep(0.2) else: # Move sprites together, winning sprite overlaps and covers loser for idx in range(16): pvp_group[idx_lr[0]].x += 10 pvp_group[idx_lr[1]].x -= 10 if idx == 8 and result is not None: self.sample.play(result) time.sleep(0.2) self.sample.wait() # Wait for first sample to finish if summary is not None: self.sample.play(summary) # Flash colours for win, fad up to blue for rest if not draw and win: colours = [YELLOW_COL, ORANGE_COL, RED_COL] * 5 else: colours = [DRAWLOSE_COL * sc // 15 for sc in range(1, 15 + 1)] for col in colours: summary_dob.color = col time.sleep(0.120) self.sample.wait() # Ensure second sample has completed
def introductionScreen(self): # pylint: disable=too-many-locals,too-many-branches,too-many-statements """Introduction screen.""" if self.disp is not None: self.emptyGroup(self.disp_group) intro_group = Group(max_size=7) welcometo_dob = Label(self.font, text="Welcome To", scale=3, color=IWELCOME_COL_FG) welcometo_dob.x = (self.width - 10 * 3 * self.font_width) // 2 # Y pos on screen looks lower than I would expect welcometo_dob.y = 3 * self.font_height // 2 intro_group.append(welcometo_dob) extra_space = 8 spacing = 3 * self.sprite_size + extra_space y_adj = (-6, -2, -2) for idx, sprite in enumerate(self.sprites): s_group = Group(scale=3, max_size=1) s_group.x = -96 s_group.y = round((self.height - 1.5 * self.sprite_size) / 2 + (idx - 1) * spacing) + y_adj[idx] s_group.append(sprite) intro_group.append(s_group) arena_dob = Label(self.font, text="Arena", scale=3, color=IWELCOME_COL_FG) arena_dob.x = (self.width - 5 * 3 * self.font_width) // 2 arena_dob.y = self.height - 3 * self.font_height // 2 intro_group.append(arena_dob) self.showGroup(intro_group) # The color modification here is fragile as it only works # if the text colour is blue, i.e. data is in lsb only self.sample.play("welcome-to") while self.sample.playing(): if self.disp is not None and intro_group[0].color < WELCOME_COL_FG: intro_group[0].color += 0x10 time.sleep(0.120) onscreen_x_pos = 96 # Move each sprite onto the screen while saying its name with wav file anims = (("rock", 10, 1, 0.050), ("paper", 11, 2, 0.050), ("scissors", 7, 3, 0.050)) for idx, (audio_name, x_shift, grp_idx, delay_s) in enumerate(anims): if self.disp is None: self.showChoice(idx) # Use for NeoPixels self.sample.play(audio_name) # Audio needs to be long enough to finish movement while self.sample.playing(): if self.disp is not None: if intro_group[grp_idx].x < onscreen_x_pos: intro_group[grp_idx].x += x_shift time.sleep(delay_s) # Set NeoPixels back to black if self.disp is None: self.pix.fill(BLACK) self.sample.play("arena") while self.sample.playing(): if self.disp is not None and intro_group[4].color < WELCOME_COL_FG: intro_group[4].color += 0x10 time.sleep(0.060) # Button Guide for those with a display if self.disp is not None: left_dob = Label(self.font, text="< Select ", scale=2, color=INFO_COL_FG, background_color=INFO_COL_BG) left_width = len(left_dob.text) * 2 * self.font_width left_dob.x = -left_width left_dob.y = self.button_y_pos intro_group.append(left_dob) right_dob = Label(self.font, text=" Transmit >", scale=2, color=INFO_COL_FG, background_color=INFO_COL_BG) right_width = len(right_dob.text) * 2 * self.font_width right_dob.x = self.width right_dob.y = self.button_y_pos intro_group.append(right_dob) # Move left button text onto screen, then right steps = 20 for x_pos in [ left_dob.x + round(left_width * x / steps) for x in range(1, steps + 1) ]: left_dob.x = x_pos time.sleep(0.06) for x_pos in [ right_dob.x - round(right_width * x / steps) for x in range(1, steps + 1) ]: right_dob.x = x_pos time.sleep(0.06) time.sleep(8) # leave on screen for further 8 seconds