Subin Park
Subin Park

Reputation: 211

How do I make my code wait for a click?

I am trying to write a code for a pvp battleship game and I'm kinda stuck.

I will show you the codes first then explain how they work.

Here is the first code. This function is used to locate each ships on a grid:

def ship_builder(name):
# client ship value = 6, server ship value = 7
    v_or_h = randrange(2)
    if v_or_h == 0:
        vertical = True
    else:
        vertical = False

    if name == 'destroyer':
        print('Click a cell to build a destroyer.')
        if vertical == True:
            print('Vertical')
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    break
                if event.type == pygame.MOUSEBUTTONDOWN:
                    pos = pygame.mouse.get_pos()
                    col = (pos[0] // (cell_side + margin)) + 1
                    row = (pos[1] // (cell_side + margin)) + 1
                    grid[row][col] = 7
                    for i in range(3):
                        row += 1
                        grid[row][col] = 7

        elif vertical == False:
            print('Horizontal')
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    break
                if event.type == pygame.MOUSEBUTTONDOWN:
                    pos = pygame.mouse.get_pos()
                    col = (pos[0] // (cell_side + margin)) + 1
                    row = (pos[1] // (cell_side + margin)) + 1
                    grid[row][col] = 7
                    for i in range(3):
                        col += 1
                        grid[row][col] = 7

    elif name == 'frigate':
        print('Click a cell to build a frigate')
        if vertical == True:
            print('Vertical')
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    break
                if event.type == pygame.MOUSEBUTTONDOWN:
                    pos = pygame.mouse.get_pos()
                    col = (pos[0] // (cell_side + margin)) + 1
                    row = (pos[1] // (cell_side + margin)) + 1
                    grid[row][col] = 7
                    for i in range(2):
                        row += 1
                        grid[row][col] = 7
        elif vertical == False:
            print('Horizontal')
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    break
                if event.type == pygame.MOUSEBUTTONDOWN:
                    pos = pygame.mouse.get_pos()
                    col = (pos[0] // (cell_side + margin)) + 1
                    row = (pos[1] // (cell_side + margin)) + 1
                    grid[row][col] = 7
                    for i in range(2):
                        col += 1
                        grid[row][col] = 7

Second is a for loop for the function above:

for ship in ['destroyer','frigate']:
    ship_builder(ship)
    color_change()

    #color_change() is a function that colors the responding cells for the ships.

This is how they are supposed to work. First, ship_builder is called with a name of a ship (say, 'battleship'). The first thing the code does is to check whether the ship should be placed vertically or horizontally. According to its value, the user can click on a cell to determine the location. This is where I am having an issue; the code just jumps over that part and proceeds without doing anything.

My question is: Why is it jumping over the mouse click part? Is pygame.event.get() not supposed to make Python 'wait' for an action?

I am not sure if I explained it substantially. Leave me a comment if I need to provide further information. I really need some help!

Thank you!

Upvotes: 4

Views: 4033

Answers (1)

bbastu
bbastu

Reputation: 508

The short answer: No, pygame.event.get() -> EventList is not supposed to 'wait' for an action. Use pygame.event.wait() -> EventType instead.

The longer answer: Pygame is using an event queue in which it stores events that have happened. Let us have a look at the pygame.event.get() documentation.

pygame.event.get()  
  get events from the queue 
  get() -> Eventlist  
  get(type) -> Eventlist
  get(typelist) -> Eventlist

This will get all the messages and remove them from the queue. If a type or sequence of types is given only those messages will be removed from the queue. If you are only taking specific events from the queue, be aware that the queue could eventually fill up with the events you are not interested.

So basically, pygame.event.get() returns every event that has happened since the last time we called it. If our event did not happen yet, it will not be in the returned EventList.

But there is another function called pygame.event.wait() that is behaving in the way asked for (although it only returns a single event).

pygame.event.wait()
  wait for a single event from the queue
  wait() -> EventType instance

Returns a single event from the queue. If the queue is empty this function will wait until one is created. The event is removed from the queue once it has been returned.

So it is possible to wait for a mousedown event with something like

event_happened = False
while not event_happened:
    event = pygame.event.wait()
    if event.type == pygame.MOUSEBUTTONDOWN:
        do_something()
        event_happened = True

However, we need to be carefull here, because as stated in the documentation the events are removed from the queue, meaning that all the events that are not of the type pygame.MOUSEBUTTONDOWN will be lost. We would have to handle them or pass them on/safe them manually, if we needed them.

 

That was the longer answer, but I have one addition/warning. Getting the events at different points in the code like this can lead to confusion very quickly (e.g. because of lost events as described above etc.). The decision in this case could have to do with the lack of a main game loop in the program (I cannot tell for sure because I don't know the surrounding code, but the current implementation seems to suggest something like that).

Usually, events are accessed in a continous main game loop which could look like this

while True:
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
            build_ship_on_event(event)

        elif event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

And the build_ship_on_event(event) function could try to do something like

def build_ship_on_event(event):
    if event_is_mouse_click(event):
        ship_builder(selected_ship_type, event.pos)

and build the ship for a previously selected type at the given position (of course checking if the ship has been build before and so forth).

Upvotes: 4

Related Questions