2

In the code I have simply tried to make two objects move and one shoots. But as soon as one shoots the two stops moving until the bullet has reached the end. Is there a way to shoot bullets and move the rest of the objects at the same time.

As the square moves it shoots bullets when you enter space but when shooting the square stops moving until a bullet has reached its end of code in its loop. Any ways are there to simultaneously operate both bullets and squares Here is the code below:

import pygame
Max_w=400
Max_h=400
window=pygame.display.set_mode((Max_w,Max_h))
pygame.display.set_caption("Game")
pygame.QUIT
x_1=0
y_1=0
x=360
y=360
velocity=5
width=40
height=40
run=True
while run:
    def Bullet():
        pygame.time.delay(100)
        global x,y
        x1=x
        y1=y
        while y1>=0:
            pygame.time.delay(2)
            if x_1<x1+15<x_1+40 and y1<=y_1+40:
                break
            keys=pygame.key.get_pressed()
            
            window.fill((0,0,0))
            pygame.draw.rect(window,(0,0,255),(x,y,width,height))
            pygame.draw.rect(window,(0,255,0),(x_1,y_1,width,height))  
            
            pygame.draw.rect(window,(255,0,0),(x1+15,y1-10,10,10))
            
            y1-=1
            pygame.display.update()
        
    
    pygame.time.delay(50)
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            run=False
    window.fill((0,0,0))
    keys=pygame.key.get_pressed()

    if keys[ord("w")] and y_1<Max_h-height:
        y_1-=velocity
        
    if keys[ord("a")]  and x_1>0:
        x_1-=velocity
        
    if keys[ord("s")] and y_1<Max_h-height:
        y_1+=velocity
        
    if keys[ord("d")] and x_1<Max_w-width:
        x_1+=velocity
        
    
    if keys[pygame.K_LEFT] and x>0:
        x-=velocity

    if keys[pygame.K_RIGHT] and x<Max_w-width:
        x+=velocity

    if keys[pygame.K_UP] and y>0:
        y-=velocity

    if keys[pygame.K_DOWN] and y<Max_h-height:
        y+=velocity

    if keys[pygame.K_SPACE]:
        Bullet()
    pygame.draw.rect(window,(0,0,255),(x,y,width,height))
    pygame.draw.rect(window,(0,255,0),(x_1,y_1,width,height))  
        
    pygame.display.update()
pygame.quit()

2 Answers2

0

Your problem is caused by having multiple events loops - this is almost always a bad idea. Once the code enters the Bullet function, control is not returned to the players until the bullet leaves the screen. Obviously this is the reported problem.

It's better to store the bullets as a list of "data-points" and use some other method to draw and paint them. This new method can then be integrated into the main loop, interleaving with the existing player movement code.

In the example code below, I have created an all_bullets list, which holds tuples defining a bullet. But what do you need to define a bullet: The (x,y) co-ordinates, next move time, and which direction it travels. So literally a bullet might be something like ( 12500, 50, 100, -5 ). This represents: next move is after 12500 milliseconds, current position is (50, 100), and the bullet travels -5 pixels each step.

The beauty of this solution, is on-firing, it's only a matter of adding a new tuple to the list. The movement and drawing functions can maintain the list.

So to move a bullet, we only need to add the y-change value (last value in the tuple) to the current y. However it it would also be handy to "clean up" bullets that go off-screen. Since we're already moving the bullets, it's a convenient place to handle this too.

This leads us to the function moveBullets():

def moveBullets( bullet_list ):
    """ Given a list of bullet tuples (move-time, x, y, dy) 
        Move the bullets along their trajectory.
        If they go off-screen, delete them  """

    time_now = pygame.time.get_ticks()
    for i in range( len( bullet_list )-1, -1, -1):   # iterate in reverse so we can del() safely
        next_move_time, x, y, dy = bullet_list[i]    # unpack tuple

        # is it time to move this bullet again?
        if ( time_now > next_move_time ):
            y -= dy
            # Did the bullet go off-screen?
            if ( x < 0 or x > Max_w or y < 0 or y > Max_h ):
                # bullet has left screen, delete it it from the list
                print("DEBUG: erasing bullet at index " + str( i ) )
                del( bullet_list[i] )
            else:
                bullet_list[i] = ( time_now+bullet_speed, x, y, dy )  # save new time, and position

The most complicated part is the loop iteration in reverse. We do this because when you remove an item from a list, it changes the list ordering. Imagine we del() list item 3, now items 4,5,6... have moved to a -1 index. But if your go in reverse, you've already processed the tail-end of the list, so it doesn't matter if they move.

The other significant part is the movement-delay. The existing code moves the bullet every 100 milliseconds. So now the code stores the time of the next-movement along with the co-ordinates. If the clock-time now is later than this timestamp, that means it is we should move the bullet (otherwise we do nothing). When moving the bullet, we store the clock-time + delay as the future-time of the next movement. The time function pygame.time.get_ticks() returns the current time in milliseconds, so it's easy to use this with millisecond comparisons & delays.

The drawing function is similar to the moving, except we don't adjust the list, so it can be simpler.

def drawBullets( window, bullet_list ):
    """ Draw all the bullets to the window """

    for bullet in bullet_list:
        next_move_time, x, y, dy = bullet
        # draw the bullet
        pygame.draw.rect( window, (255, 0, 0), ( x, y, 10, 10 ) )

For every bullet in the list, we get its (x,y) position, and use that to draw the rectangle.

So now your main loop simply adds a new Bullet tuple to all_bullets to "fire" a bullet. Every frame it draws the bullets, and does any bullet movement.

Ref: test/example code: import pygame

Max_w=400
Max_h=400
bullet_speed=100

def moveBullets( bullet_list ):
    """ Move the bullets along their trajectory.
        If they go off-screen, delete them  """

    time_now = pygame.time.get_ticks()
    for i in range( len( bullet_list )-1, -1, -1):   # iterate in reverse order so we can del() safely
        next_move_time, x, y, dy = bullet_list[i]

        # is it time to move this bullet again?
        if ( time_now > next_move_time ):
            y -= dy
            # Did the bullet go off-screen?
            if ( x < 0 or x > Max_w or y < 0 or y > Max_h ):
                # bullet has left screen, delete it it from the list
                print("DEBUG: erasing bullet at index " + str( i ) )
                del( bullet_list[i] )
            else:
                bullet_list[i] = ( time_now+bullet_speed, x, y, dy )  # save new time, and position


def drawBullets( window, bullet_list ):
    """ Draw all the bullets to the window """

    for bullet in bullet_list:
        next_move_time, x, y, dy = bullet
        # draw the bullet
        pygame.draw.rect( window, (255, 0, 0), ( x, y, 10, 10 ) )



window=pygame.display.set_mode((Max_w,Max_h))
pygame.display.set_caption("Game")
x_1=0
y_1=0
x=360
y=360
velocity=5
width=40
height=40

all_bullets = []   # list of all bullet tuples: (time, x, y)

run=True
while run:
    
    pygame.time.delay(50)
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            run=False
    keys=pygame.key.get_pressed()

    if keys[ord("w")] and y_1<Max_h-height:
        y_1-=velocity
        
    if keys[ord("a")]  and x_1>0:
        x_1-=velocity
        
    if keys[ord("s")] and y_1<Max_h-height:
        y_1+=velocity
        
    if keys[ord("d")] and x_1<Max_w-width:
        x_1+=velocity

    if keys[ord("f")]:
        # create a new bullet
        all_bullets.append( ( pygame.time.get_ticks(), x_1+15, y_1+40, -5 ) )
        
    
    if keys[pygame.K_LEFT] and x>0:
        x-=velocity

    if keys[pygame.K_RIGHT] and x<Max_w-width:
        x+=velocity

    if keys[pygame.K_UP] and y>0:
        y-=velocity

    if keys[pygame.K_DOWN] and y<Max_h-height:
        y+=velocity

    if keys[pygame.K_SPACE]:
        # create a new bullet
        all_bullets.append( ( pygame.time.get_ticks(), x+15, y-10, 5 ) )

    # move the bullets
    moveBullets( all_bullets )

    # draw the screen
    window.fill((0,0,0))
    pygame.draw.rect(window,(0,0,255),(x,y,width,height))
    pygame.draw.rect(window,(0,255,0),(x_1,y_1,width,height))  
    drawBullets( window, all_bullets )
        
    pygame.display.update()

pygame.quit()

Note that I added f to allow the 2nd player to also fire a bullet.

You should consider renaming x, y and x_1, y_1 to something like player_x, player_y and opponent_x, etc. It really will make your code easier to read and therefore debug.

Kingsley
  • 14,398
  • 5
  • 31
  • 53
0

Try using threading to run the while loops that may be affected other parts of your program.

Epic Gamer
  • 101
  • 1
  • 10