Techoplite
Techoplite

Reputation: 655

Draw a shape which displays until next click

I am trying to show that a tile on a chessboard is selected by outlining it whit a green colour.

I have managed to draw the outline when that specific tile area has been clicked, but the outline disappears after a few milliseconds.

So, I thought had something to do with updating the display (a function that I am already calling inside the highlight_tile() method).

here is the main loop

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        sys.exit()

    # mouse handling
    for unit in white_army:
        if event.type == pygame.MOUSEBUTTONDOWN:
            mouse_position = pygame.mouse.get_pos()
            if unit.tile_area.collidepoint(mouse_position):
                highlight_tile(unit.tile_area)
            else:
                pygame.display.update()

and here the complete code

import pygame
import sys
from coordinator import coordinator

# set up the display
pygame.init()
window_size = (800, 800)
game_window = pygame.display.set_mode(size=window_size)
pygame.display.set_caption('My Game')


# defines classes and related methods

class WhiteSquare:
    def __init__(self):
        self.height = int(window_size[0] / 8)
        self.width = int(window_size[1] / 8)
        self.white_square = pygame.Surface((self.height, self.width))
        self.white_square.fill((255, 255, 255))


class BlackSquare:
    def __init__(self):
        self.height = int(window_size[0] / 8)
        self.width = int(window_size[1] / 8)
        self.black_square = pygame.Surface((self.height, self.width))
        self.black_square.fill((0, 0, 0))


class ChessBoard:
    def __init__(self):
        self.ws = ws
        self.bs = bs
        self.white_columns = white_columns
        self.black_columns = black_columns

    def draw(self):
        for w_columns in self.white_columns:
            game_window.blit(self.ws.white_square, w_columns)

        for b_columns in self.black_columns:
            game_window.blit(self.bs.black_square, b_columns)


# declare letters and numbers
letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
numbers = ['1', '2', '3', '4', '5', '6', '7', '8']

# create coordinates
coordinates = []
for item_letter in letters:
    letter = item_letter
    for item_number in numbers:
        number = item_number
        coordinates.append(letter + number)

# create coordinates values components
x_values = []
for number in range(0, 800, 100):
    x = number
    x_values.append(x)

y_values = []
for number in range(0, 800, 100):
    y = number
    y_values.append(y)

# create coordinate values
coordinate_values = []
for x in x_values:
    for y in y_values:
        coordinate_values.append((x, y))

# assign values to coordinates
squares_coordinates = dict(zip(coordinates, coordinate_values))


# Background for units
class CircleSurface:
    def __init__(self):
        self.circle_surface = pygame.Surface((100, 100), flags=pygame.SRCALPHA)
        pygame.draw.circle(self.circle_surface, (255, 0, 0), (50, 50), 45)


# define colours
black = (0, 0, 0)
white = (255, 255, 255)
gold = (153, 153, 0)
green = (0, 255, 0)
dark_green = (0, 200, 0)


class Unit:
    def __init__(self, colour, position):

        # define Unit colour
        self.colour = colour

        # define Unit position
        self.position = position


class Knight(Unit):
    def __init__(self, colour, position):
        # draw circle, inline, and outline
        super().__init__(colour, position)
        self.center_x = position[0]
        self.center_y = position[1]
        self.colour = colour
        self.position = position
        # define tile position
        self.tile_area = pygame.Rect(position[0] - 50, position[1] - 50, 100, 100)

        circle_radius = 40
        self.circle = pygame.draw.circle(game_window, colour, self.position, circle_radius)
        self.circle_outline = pygame.draw.circle(game_window, gold, self.position, circle_radius, 5)
        self.circle_inline = pygame.draw.circle(game_window, gold, self.position, (circle_radius - 7), 2)

        # draw letter
        pygame.font.init()
        my_font_size = 50
        my_font = pygame.font.SysFont('Time New Roman', my_font_size)
        text_surface = my_font.render('K', 1, gold)
        center_text = text_surface.get_rect(center=(self.center_x, self.center_y))
        game_window.blit(text_surface, center_text)


class Archer(Unit):
    def __init__(self, colour, first_point, second_point, third_point):
        self.colour = colour
        self.first_point = first_point
        self.second_point = second_point
        self.third_point = third_point
        self.position = [self.first_point, self.second_point, self.third_point]
        super().__init__(colour, self.position)
        self.center_x = self.second_point[0]
        self.center_y = (self.second_point[1] + ((self.first_point[1] - self.second_point[1]) / 2)) + 10
        self.inline_position = [(self.first_point[0] + 10, self.first_point[1] - 5),
                                (self.second_point[0], self.second_point[1] + 10),
                                (self.third_point[0] - 10, self.third_point[1] - 5)]
        # define_tile_centre
        self.tile_area = pygame.Rect(self.first_point[0] - 10, self.second_point[1] - 10, 100, 100)

        if self.colour == black:
            self.first_point = self.first_point[0], self.first_point[1] - 80
            self.second_point = self.second_point[0], self.second_point[1] + 80
            self.third_point = self.third_point[0], self.third_point[1] - 80
            self.position = [self.first_point, self.second_point, self.third_point]

            self.center_y = (self.second_point[1] + ((self.first_point[1] - self.second_point[1])
                                                     / 2)) - 10
            self.inline_position = [(self.first_point[0] + 10, self.first_point[1] + 5),
                                    (self.second_point[0], self.second_point[1] - 10),
                                    (self.third_point[0] - 10, self.third_point[1] + 5)]
        self.triangle = pygame.draw.polygon(game_window, colour, self.position)
        self.triangle_outline = pygame.draw.polygon(game_window, gold, self.position, 5)
        self.triangle_inline = pygame.draw.polygon(game_window, gold, self.inline_position, 2)

        # draw letter
        pygame.font.init()
        my_font_size = 50
        my_font = pygame.font.SysFont('Time New Roman', my_font_size)
        text_surface = my_font.render('A', 1, gold)
        center_text = text_surface.get_rect(center=(self.center_x, self.center_y))
        game_window.blit(text_surface, center_text)


class Pikeman(Unit):
    def __init__(self, colour, position):

        # draw circle, inline, and outline
        super().__init__(colour, position)
        self.dimension = (80, 80)
        self.center_x = position[0] + self.dimension[0] / 2
        self.center_y = position[1] + self.dimension[1] / 2
        self.colour = colour
        self.position = position

        # define_tile_centre
        self.tile_area = pygame.Rect(position[0] - 10, position[1] - 10, 100, 100)

        self.position_and_dimension = self.position + self.dimension
        self.inline_position_and_dimension = (self.position[0] + 5, self.position[1] + 5),\
                                             (self.dimension[0] - 10, self.dimension[1] - 10)
        self.square = pygame.draw.rect(game_window, colour, self.position_and_dimension, )
        self.square_outline = pygame.draw.rect(game_window, gold, self.position_and_dimension, 5)
        self.square_inline = pygame.draw.rect(game_window, gold, self.inline_position_and_dimension, 2)

        # draw letter
        pygame.font.init()
        my_font_size = 50
        my_font = pygame.font.SysFont('Time New Roman', my_font_size)
        text_surface = my_font.render('P', 1, gold)
        center_text = text_surface.get_rect(center=(self.center_x, self.center_y))
        game_window.blit(text_surface, center_text)


def highlight_tile(tile_area):
    pygame.draw.rect(game_window, dark_green, tile_area, 5)
    pygame.display.update()


# Sets and gets the coordinates for black and white squares
coordinator = coordinator()

black_columns = coordinator[2] + coordinator[3]
white_columns = coordinator[0] + coordinator[1]

# Creates needed objects
ws = WhiteSquare()
bs = BlackSquare()
cb = ChessBoard()
cs = CircleSurface()


# Event loop (outer)
while 1:

    # Draws the chessboard
    cb.draw()

    # set up white units
    white_knight_1 = Knight(white, (150, 650))
    white_knight_2 = Knight(white, (650, 650))
    white_archer_1 = Archer(white, (210, 790), (250, 710), (290, 790))
    white_archer_2 = Archer(white, (310, 790), (350, 710), (390, 790))
    white_archer_3 = Archer(white, (410, 790), (450, 710), (490, 790))
    white_archer_4 = Archer(white, (510, 790), (550, 710), (590, 790))
    white_pikeman_1 = Pikeman(white, (210, 610))
    white_pikeman_2 = Pikeman(white, (310, 610))
    white_pikeman_3 = Pikeman(white, (410, 610))
    white_pikeman_4 = Pikeman(white, (510, 610))

    white_army = [white_knight_1, white_knight_2,
                  white_archer_1, white_archer_2, white_archer_3, white_archer_4,
                  white_pikeman_1, white_pikeman_2, white_pikeman_3, white_pikeman_4]

    # set up black units
    black_knight_1 = Knight(black, (150, 150))
    black_knight_2 = Knight(black, (650, 150))
    black_archer_1 = Archer(black, (210, 90), (250, 10), (290, 90))
    black_archer_2 = Archer(black, (310, 90), (350, 10), (390, 90))
    black_archer_3 = Archer(black, (410, 90), (450, 10), (490, 90))
    black_archer_4 = Archer(black, (510, 90), (550, 10), (590, 90))
    black_pikeman_1 = Pikeman(black, (210, 110))
    black_pikeman_2 = Pikeman(black, (310, 110))
    black_pikeman_3 = Pikeman(black, (410, 110))
    black_pikeman_4 = Pikeman(black, (510, 110))

    # Event loop (inner)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

        # mouse handling
        for unit in white_army:
            if event.type == pygame.MOUSEBUTTONDOWN:
                mouse_position = pygame.mouse.get_pos()
                if unit.tile_area.collidepoint(mouse_position):
                    highlight_tile(unit.tile_area)
                else:
                    pygame.display.update()

    pygame.display.update()

EDIT

I have managed to not make it disappear, but now I want it to disappear when the mouse is being clicked again.

here is the new block of code updated

if event.type == pygame.MOUSEBUTTONDOWN:
            for unit in white_army:
                mouse_position = pygame.mouse.get_pos()
                if unit.tile_area.collidepoint(mouse_position):
                    print(mouse_position)
                    highlight_tile(unit.tile_area)

I tried with a while loop but it just makes the game crash, does not look like a good idea.

Upvotes: 3

Views: 98

Answers (1)

Rabbid76
Rabbid76

Reputation: 210948

So, I thought had something to do with updating the display (a function that I am already calling inside the highlight_tile() method)

Of course.

Create a variable (selected_unit) which states the unit which is currently selected. If the mouse button is pressed the clear the state and set the new selection state according to the mouse position.
Once the variable is selected, then highlight the shape in the main application loop rather than in the event loop. e.g.:

selected_unit = None
while 1:

    # Draws the chessboard
    cb.draw()

    # set up white units
    # [...] 

    # set up black units
    # [...]

    # Event loop (inner)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

        # mouse handling
        if event.type == pygame.MOUSEBUTTONDOWN:
            mouse_position = pygame.mouse.get_pos()

            if selected_unit:
                # reset the selection
                selected_unit = None
            else:
                # select a new unit
                for unit in white_army:
                    if unit.tile_area.collidepoint(mouse_position):
                        selected_unit = unit

    # highlight the selected unit
    if selected_unit:
        highlight_tile(selected_unit.tile_area)

    # update the dispaly
    pygame.display.update()

Upvotes: 3

Related Questions