From ba88887a72a4dbeeeeddaa60a4c683813b9a6710 Mon Sep 17 00:00:00 2001 From: En Yi Date: Tue, 11 Jun 2019 19:10:04 +0100 Subject: [PATCH] Implement mouse clicking for playing cards --- main.py | 24 +++++++++---------- players.py | 56 +++++++++++++++++++++++++++++++++++++------- table.py | 69 +++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 112 insertions(+), 37 deletions(-) diff --git a/main.py b/main.py index 39a4904..cab5c2a 100644 --- a/main.py +++ b/main.py @@ -37,16 +37,6 @@ class GameScreen(view.PygView): pygame.display.flip() - def process_events(self): - for event in pygame.event.get(): - if event.type == pygame.QUIT: - self.running = False - elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_ESCAPE: - self.running = False - if event.key == pygame.K_p: - if not self.table.ongoing: - self.table.ongoing = True #def get_player_inputs(self): # while self.running: @@ -58,10 +48,20 @@ class GameScreen(view.PygView): self.running = True #self.player_thread.start() while self.running: - self.process_events() + + all_events = pygame.event.get() + for event in all_events: + if event.type == pygame.QUIT: + self.running = False + elif event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE: + self.running = False + if event.key == pygame.K_p: + if not self.table.ongoing: + self.table.ongoing = True if self.table.ongoing: - self.table.continue_game() + self.table.continue_game(all_events) #if not self.player_commands.empty(): # player_cmd = self.player_commands.get() # print("Player Command Received: " + player_cmd) diff --git a/players.py b/players.py index edea2d3..eae53a2 100644 --- a/players.py +++ b/players.py @@ -1,5 +1,6 @@ import cards import pprint +import pygame from game_consts import GameState, PlayerRole, STARTING_HAND @@ -37,11 +38,12 @@ class Player(cards.Deck): ai_comp.connect_to_player(self) self.selectable = False - def make_decision(self, game_state, sub_state): + def make_decision(self, game_state, sub_state, game_events=None): """ The player will need to make a decision depending on the game state and sub-state :param game_state: Current game state :param sub_state: Sub-state which affects the output for the current game state + :param game_events: Pygame events :return: For Bidding: Either a bid or a partner call, int For Playing: A Card For Reshuffle: bool, True to reshuffle, False otherwise @@ -65,7 +67,7 @@ class Player(cards.Deck): play = self.AI.make_a_play(sub_state) [_, pos] = self.check_card_in(play) return self.remove_card(pos) - return self.make_a_play(sub_state) + return self.make_a_play(sub_state, game_events=game_events) def make_a_bid(self): """ @@ -111,7 +113,7 @@ class Player(cards.Deck): else: print("Invalid card call") - def make_a_play(self, substate): + def make_a_play(self, substate, game_events=None): """ The procedure to make a play in a round :return: A valid Card @@ -124,10 +126,7 @@ class Player(cards.Deck): else: play = cards.convert_input_string(play) if play > 0: - if substate == 0: - valid = self.check_for_valid_plays(play, True) - else: - valid = self.check_for_valid_plays(play, False) + valid = self.check_for_valid_plays(play, substate == 0) if valid: [_, pos] = self.check_card_in(play) @@ -189,8 +188,47 @@ class MainPlayer(Player): self.AI = ai_component self.table_status = None # This is found in Table and updated through Table self.selectable = True + self.left_mouse_down = False + self.double_clicking = False + self.double_click_event = pygame.USEREVENT + 1 + self.double_click_timing = 300 - def make_a_play(self): - pass + def make_a_play(self, substate, game_events=None): + card = None + if game_events: + for event in game_events: + mouse_clicks = event.type == pygame.MOUSEBUTTONDOWN + if self.left_mouse_down and not mouse_clicks: + print('mouse click') + mouse_pos = pygame.mouse.get_pos() + if self.rect.collidepoint(mouse_pos): + reselect = self.get_selected_card(mouse_pos) + if self.selected_card >= 0 and not reselect: + card = 1 + + if self.double_clicking: + pygame.time.set_timer(self.double_click_event, 0) + print('Double clicked') + if reselect: + card_value = self.cards[self.selected_card].value + if self.check_for_valid_plays(card_value, substate == 0): + card = self.remove_selected_card() + self.deselect_card() + self.double_clicking = False + else: + self.double_clicking = True + pygame.time.set_timer(self.double_click_event, self.double_click_timing) + if reselect: + self.deselect_card() + card = 1 + + if event.type == self.double_click_event: + pygame.time.set_timer(self.double_click_event, 0) + self.double_clicking = False + print('double click disabled') + + self.left_mouse_down = mouse_clicks + + return card diff --git a/table.py b/table.py index 68c08bf..3ece989 100644 --- a/table.py +++ b/table.py @@ -142,11 +142,19 @@ class Table: reveal_mode = cards.DeckReveal.HIDE_ALL if i == 0 or view_all_cards: reveal_mode = cards.DeckReveal.SHOW_ALL - self.players.append(players.Player(playerx[i], playery[i], - l_deck, w_deck, - spacing, vert_orientation=vert, - deck_reveal=reveal_mode, flip=(i == 1 or i == 2), - draw_from_last=(i == 2 or i == 3))) + + if i == 0: + self.players.append(players.MainPlayer(playerx[i], playery[i], + l_deck, w_deck, + spacing, vert_orientation=vert, + deck_reveal=reveal_mode)) + else: + self.players.append(players.Player(playerx[i], playery[i], + l_deck, w_deck, + spacing, vert_orientation=vert, + deck_reveal=reveal_mode, flip=(i == 1 or i == 2), + draw_from_last=(i == 2 or i == 3))) + self.players[i].connect_to_table(self.table_status) if i > 0: self.players[i].add_ai(ai.RandomAI(self.table_status)) @@ -183,8 +191,6 @@ class Table: self.ongoing = False self.require_player_input = False - - def center_text_on_surface(self, surf, rendered_text, clear_colour): line_center = surf.get_rect().center text_rect = rendered_text.get_rect(center=line_center) @@ -274,7 +280,7 @@ class Table: def get_pos(self): return self.x, self.y - def continue_game(self): + def continue_game(self, game_events): """ This is where the FSM is. State transition should occur here. What takes place in the state should be in a function. @@ -303,7 +309,7 @@ class Table: self.update_team_scores() elif self.game_state == GameState.PLAYING: - self.play_a_round() + self.play_a_round(game_events) if self.current_round == 13: self.write_message("Game Set! Press P to play again!") self.ongoing = False @@ -410,23 +416,54 @@ class Table: self.write_message(msg, line=1, delay_time=1) return True - def play_a_round(self): + def play_a_round(self, game_events): """ Ask each player to play a valid card and determine the winner of the round + This must work without pause if only bots are playing + The function will exit after every player decision or if a user input is needed. + If a user input is required, the function will continuously exit without proceeding to the next player + until a valid input is received. + :return: None """ if not any(self.table_status["played cards"]): # Leading player starts with the leading card, which determines the leading suit - self.current_player = self.table_status['leading player'] - self.display_current_player(self.current_player) - card = self.players[self.current_player].make_decision(self.game_state, 0) + if not self.require_player_input: + self.current_player = self.table_status['leading player'] + self.display_current_player(self.current_player) + if not self.players[self.current_player].AI: + self.require_player_input = True + return + else: + card = self.players[self.current_player].make_decision(self.game_state, 0) + else: + card = self.players[self.current_player].make_decision(self.game_state, 0, game_events) + + if not type(card) is cards.Card: + if card: + self.update_table.emit() + return + self.require_player_input = False + self.table_status["played cards"][self.current_player] = card self.players_playzone[self.current_player].add_card(card) elif not all(self.table_status["played cards"]): # Subsequent player make their plays, following suit if possible - self.display_current_player(self.current_player) - print("Player {0:d}\n".format(self.current_player)) - card = self.players[self.current_player].make_decision(self.game_state, 1) + if not self.require_player_input: + self.display_current_player(self.current_player) + if not self.players[self.current_player].AI: + self.require_player_input = True + return + else: + card = self.players[self.current_player].make_decision(self.game_state, 1) + else: + card = self.players[self.current_player].make_decision(self.game_state, 1, game_events) + if not type(card) is cards.Card: + if card: + self.update_table.emit() + return + self.require_player_input = False + self.players_playzone[self.current_player].add_card(card) self.table_status["played cards"][self.current_player] = card else: