I am trying to make a shooter in pygame. I am able to have the player move around, and when space is pressed, the bullet will go to its position. I am wondering how i can get it to move away from the player, until it hits the edge of the screen. Here is what i have so far:
if AMMO > 0:
if event.type == pygame.KEYDOWN and Gun.image == NOGUN:
if event.key == pygame.K_SPACE and Gun.image == NOGUN:
Bullet.rect.center = Player.rect.center
if Player.direction == 0:
Bullet.direction = 0 #WHERE THE BULLET WILL MOVE
shot.play()
print "BANG"
AMMO = AMMO - 1
time.sleep(0.09)
We'd need more code here.
In pseudocode:
def frameUpdate( timeBetweenFrame, bulletSpeed, playerDirectionVector ):
bullet.position = bullet.position + playerDirectionVector.MultiplyByScalar(bulletSpeed * timeBetweenFrame);
Where playerDirectionVector is a normalized vector in the direction the player is facing.
Try this
if AMMO > 0:
if event.type == pygame.KEYDOWN and Gun.image == NOGUN:
if event.key == pygame.K_SPACE and Gun.image == NOGUN:
#Initialize Bullet so it's not null and do the rest
Bullet.rect.center = Player.rect.center
if Player.direction == 0:
Bullet.direction = 0
if Bullet != null
Bullet.X += 10
if Bullet.X > ScreenWidth()
Bullet = null
#These are all examples so you can understand the logic, I don't remember exactly how pygame works, but since you can move a character around you can find this :P
Keep in mind that this code allows only one bullet!
What I use when I make bullet instances in psudocode
#making your starting bullet cords
Bulletx = playerx
Bullety = playery
#this stores the angle the bullet was shot from
Bulletangle = degreesplayerisrotated
This converts the angle to a radian
Bulletangle = Bulletangle×pi/180
#this line updates the cords speed is a set value of how fast you want the bullet to move
Bulletx = bulletx-cos(bulletangle)×speed
Bullety = bullety-sin (bulletangle)×speed
Screen.blit (bullet, (bulletx, bullety))
Or draw a circle with the cords
If you have a question be sure to ask hope this cleared things up
Related
I have a list with all my enemies and when the distance between the players bullet and the enemy is close enough, I can make a enemy disappear but its never the right one that was hit with the bullet, its always the enemy with the greatest x value(in my case the one at the end of the list) so my questions is how do I make the specific enemy disappear. here is my code for reference.
import pygame
import random
import math
# initalize pygame
pygame.init()
# creates game screen to display game
game_window = pygame.display.set_mode((800, 570))
# Title and icon for window
pygame.display.set_caption("Power of the Doctor")
icon = pygame.image.load('tardisShooter.png')
pygame.display.set_icon(icon)
# backgroun picture
background = pygame.image.load('SpaceTardissmall.png')
# player info
Playerimg = pygame.image.load('tardisShooter.png')
playerx = 370 # players x axis
playery = 470 # players y axis
playerx_change = 0 # adds constant change while added in loop
def player(x, y):
# blit draws image on screen: x axis y axis
game_window.blit(Playerimg, (x, y))
# enemy info
Enemyimg = []
enemyx = []
enemyy = []
enemyx_change = 1
enemyy_change = 0
num_enemies = 2
enemyspawnx = 50
enemyspawny = 200
for i in range(num_enemies):
Enemyimg.append(pygame.image.load('CybermanShooter.png'))
enemyx.append(enemyspawnx) # random x axis for enemy
enemyy.append(enemyspawny) # random y axis for enemy
enemyspawnx += 70
def enemy(x, y, i):
game_window.blit(Enemyimg[i], (x, y))
# bullet info
bulletimg = pygame.image.load('torpedo32.png')
bullety = playery
bulletx = playerx
bulletstate = "idle"
bullety_change = 5
def bullet(x, y):
global bulletstate
bulletstate = "FIRE"
game_window.blit(bulletimg, (x + 15.5, y - 25))
def collision(enemyx, enemyy, bulletx, bullety):
distance = math.sqrt((math.pow(bulletx - enemyx, 2)) + (math.pow(bullety - enemyy, 2)))
if distance < 27:
return True
else:
return False
rand = random.randint(0, num_enemies)
# timer info
bulletevent = pygame.USEREVENT
pygame.time.set_timer(bulletevent, 2000)
# get a rabdom number
# when the timer hits 2 secodsn spawsn bomb at the index of the random number that corresponds witht the enemy
# enemy bomb
bombimg = []
bombx = []
bomby = []
bomby_change = 1
bombstate = "idle"
num_bombs = 2
for i in range(num_bombs):
bombimg.append(pygame.image.load('bomb.png'))
bombx.append(enemyx[i])
bomby.append(enemyy[i])
def bomb(x, y, i):
global bombstate
bombstate = "fire"
game_window.blit(bombimg[i], (x + 15, y + 65))
# player hit detection
def enemyhit(bombx, bomby, x, y):
distance2 = math.sqrt((math.pow(bombx - x, 2)) + (math.pow(bomby - (y - 50), 2)))
if distance2 < 20:
return True
else:
return False
# loop to keep screen running
Running = True
while Running:
# background color
game_window.fill((0, 0, 0))
# background image in loop
game_window.blit(background, (0, 0))
# checks anything typed while game is running
for event in pygame.event.get():
# if they click x to quit close window
if event.type == pygame.QUIT:
Running = False
if event.type == bulletevent:
if bombstate == 'idle':
bomb(bombx[rand], bomby[rand], i)
bombx[rand] = enemyx[rand]
bomby[rand] = enemyy[rand]
# means key has been pressed(not released)
if event.type == pygame.KEYDOWN:
# escape key closes game
if event.key == pygame.K_ESCAPE:
Running = False
# right key moves player 5 spaces
if event.key == pygame.K_RIGHT:
playerx_change = 5
# left key moves players back 5 spaces
if event.key == pygame.K_LEFT:
playerx_change = -5
if event.key == pygame.K_SPACE:
bulletx = playerx
if bulletstate == "idle":
bullet(bulletx, bullety)
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or event.key == pygame.K_LEFT:
playerx_change = 0
playerx += playerx_change # constantly adds user input to player model
# player bounds
if playerx >= 740:
playerx = 740
if playerx <= 0:
playerx = 0
# player fucntion draws image
player(playerx, playery)
# loops through all the items in the lists named
for i in range(num_enemies):
# draws all enemies
enemy(enemyx[i], enemyy[i], i)
enemyx[i] += enemyx_change
if enemyx[i] >= 735:
enemyx_change = -.8
enemyy[i] += 10
if enemyx[i] <= 0:
enemyx_change = .8
enemyy[i] += 10
# is state is fire
if bulletstate == "FIRE":
# draws torpepd at coordinates
bullet(bulletx, bullety)
bullety -= bullety_change # decreases y axis moving bullet
if bullety <= 0: # if goes past border
bulletstate = "idle" # ittl switch back to idle
bullety = playery # moves bullet y back to player y
for i in range(num_enemies):
collided = collision(enemyx[i], enemyy[i], bulletx, bullety)
if collided == True:
bulletstate = 'idle'
bullety = playery
Enemyimg.remove(Enemyimg[i])
num_enemies -= 1
# when enemy fires
if bombstate == 'fire':
bomb(bombx[rand], bomby[rand], i)
bomby[rand] += bomby_change
if bomby[rand] > 570:
bombstate = 'idle'
bomby[rand] = enemyy[rand]
rand = random.randint(0, 1)
# enemy bullets hit player
enemyhits = enemyhit(bombx[rand], bomby[rand], playerx, playery)
if enemyhits == True:
playerx = 370
bombstate = 'idle'
bomby[rand] = enemyy[rand]
# updates the screen in loop
pygame.display.update()
A big problem with your code is having different lists for each attribute of your enemies.
You wrote this :
Enemyimg = []
enemyx = []
enemyy = []
Meaning that you always need to sync those three lists at all time to get coherent results. Which you are not doing, when you "remove" an enemy, you just remove the img from Enemyimg and not removing its coords in enemyy and enemyx.
While you could manage to make it work with three lists, you are just overcomplicating things. Let me show you what you may want to do to make your life way easier :)
I'm going to assume, you don't know about OOP (Object Oriented Programming) yet ? I Would be a great time to use it but it can be a little complexe if you are just starting out with programming.
So let's introduce python's dict !
What you really want to do is have one single list :
enemies = []
But how to store everything in one list you might wonder ?
Well, it will be a list of dict. A dict looks something like that :
example = {'image': pygame.image.load('CybermanShooter.png'), 'x': enemyspawnx, 'y': enemyspawny}
(Note that if you always use the same image, you don't need to put it here, you can just draw your image at the position)
Now if you do something like :
print(example['x'])
It will print your enemy's x value.
So, to sum up :
You want to have one single list : enemies = []
To add an enemy you will do :
enemies.append({'image': pygame.image.load('CybermanShooter.png'), 'x': enemyspawnx, 'y': enemyspawny})
To detect your collisions :
# Your collision function
def collision(enemy, bulletx, bullety):
distance = math.sqrt((math.pow(bulletx - enemy['x'], 2)) + (math.pow(bullety - enemy['y'], 2)))
if distance < 27:
return True
return False
# Your loop (in 2 steps: 1 - find enemies to remove, 2 - actually remove them)
enemies_to_remove = []
for enemy in enemies :
if collision(enemy, bulletx, bullety):
bulletstate = 'idle'
bullety = playery
enemies_to_remove.append(enemy)
num_enemies -= 1
for enemy in enemies_to_remove:
enemies.remove(enemy)
To draw your enemies:
# Your draw_enemy function (which you called `enemy(...)` for some reason)
def draw_enemy(enemy):
game_window.blit(enemy['image'], (enemy['x'], enemy['y']))
# Inside the main loop
for enemy in enemies:
draw_enemy(enemy)
To update the position of enemies:
# Make a move_enemy function
def move_enemy(enemy):
# put your moving logic here
# Inside the main loop:
for enemy in enemies:
move_enemy(enemy)
Do you get the principle ?
I've tried to stay as close as your original code as possible so it's not too many information to take in at once.
But technically you should apply the same principle for your bullets and to some extend to your player.
I am trying to recreate a game commonly known as Tron. The goal of the game is for the player to stay alive as long as possible. The player is constantly moving and can change direction only in 90-degree turns, if the player steps on a place which they have already stood on before, they die and the game resets.
I have an issue with the lists that store the coordinates of the places the player has already stood on. When the player moves for the first time it instantly registers a loss and resets the game.
Please take a look at my code below, and tell me the issue, especially with the final 'if block' at the end of the game loop.
import pygame
import sys
pygame.init()
screen = pygame.display.set_mode((600, 600))
clock = pygame.time.Clock()
player_y = 300
player_x = 300
player_x_list = [300]
player_y_list = [300]
player_rect = pygame.Rect(0, 0, 25, 25)
player_direction_y = 0
player_direction_x = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_s and player_direction_y == 0:
player_direction_y = 25
player_direction_x = 0
if event.key == pygame.K_w and player_direction_y == 0:
player_direction_y = -25
player_direction_x = 0
if event.key == pygame.K_d and player_direction_x == 0:
player_direction_x = 25
player_direction_y = 0
if event.key == pygame.K_a and player_direction_x == 0:
player_direction_x = -25
player_direction_y = 0
player_y += player_direction_y
player_x += player_direction_x
# This is supposed to record every x coord the player was located in on a list,
# and every y coord a player was located in on a list
# I only record the coord once as seen below
if player_x_list.count(player_x) == 0:
player_x_list.append(player_x)
if player_y_list.count(player_y) == 0:
player_y_list.append(player_y)
player_rect.center = player_x, player_y
# This right here is supposed to reset the game when the player steps on
# coords that were already stepped on previosly.
# If you remove this, the player is able to move freely, so the issue is here
if player_x_list.count(player_x) > 0 and player_y_list.count(player_y) > 0:
player_x = 300
player_y = 300
player_direction_x = 0
player_direction_y = 0
player_x_list.clear()
player_y_list.clear()
screen.fill((pygame.Color('black')))
pygame.draw.rect(screen, (pygame.Color('white')), player_rect)
pygame.display.update()
clock.tick(10)
I appreciate your time sincerely.
I believe the problem is that you're checking the coordinates after you've already updated and appended them to the coordinate list. So try moving your if statement to the top of the loop, before any changes to the coordinate lists are made.
Also, on an unrelated note, you could use a single list of tuples for coordinates, instead of two lists of integers.
I've been trying to make something cool with Python and Pygame for fun. I know a thing or two about Python in general but I'm quite a beginner with Pygame.
So the problem is: I have created a movable player and a moving enemy. I want to make the player shoot when I press the spacebar. I loaded a .png image, defined a function for shooting, and made so that the bullet keeps moving once shot. For some reason when I call the function, it just does nothing. It doesn't even give an error. I know I can shoot only one bullet with the current code and whatnot, but I would like to just get the current code working as a start.
"""
player and enemy functions are defined above and work well, I didn't include
them in this post for the sake of saving everyone's time
"""
# bullet
bullet_pic = pygame.image.load("bullet.png")
bullet_pic_reverse = pygame.image.load("bullet reverse.png")
bullet_state = "nope"
def shoot(pic, x, y):
global bullet_state
bullet_state = "jes"
screen.blit(pic, (x, y + 30))
player_dir = player_pic # direction of the player (left or right)
enemy_dir = enemy_pic # direction of the enemy
enemyX_change = 2.5
running = True
while running:
screen.blit(back, (0, 0)) # background picture
player(player_dir, playerX, playerY)
enemy(enemy_dir, enemyX, enemyY)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key == K_ESCAPE:
running = False
elif event.type == pygame.KEYDOWN:
# shooting
if event.key == K_SPACE:
if player_dir == player_pic:
bulletX = playerX + 100
bulletX_change = 20
bullet_dir = bullet_pic
else:
bulletX = playerX
bulletX_change = -20
bullet_dir = bullet_pic_reverse
shoot(bullet_dir, bulletX, playerY)
# player movement
hold = pygame.key.get_pressed()
if hold[K_LEFT] and playerX > 0:
playerX -= 7
player_dir = player_pic_reverse
if hold[K_RIGHT] and playerX < 1100:
playerX += 7
player_dir = player_pic
# enemy movement
enemyX += enemyX_change
if enemyX >= 1125:
enemyX_change = -2.5
enemy_dir = enemy_pic_reverse
elif enemyX <= 900:
enemyX_change = 2.5
enemy_dir = enemy_pic
# bullet constant movement
if bullet_state == "jes":
shoot(bullet_dir, bulletX, playerY)
bulletX += bulletX_change
I think the problem is with pygame.display.update(), you should put it always in the end of while running: loop. If you update display before calling shoot() background picture will be over bullet picture and you won't see it.
Another thing, you write K_ESCAPE instead of pygame.K_ESCAPE same with spacebar key. Does it work correctly for you? I didn't do anything with pygame for some time, maybe it's fine, but check it :)
So I have a platform game I made in PyGame that all works, so I am now trying to make it a bit more colourful. So the code that I changed used to be:
def draw(self, screen):
""" Draw everything on this level. """
# Draw the background
screen.fill(BLUE)
and I changed it to:
def draw(self, screen):
""" Draw everything on this level. """
# Image from http://freepik
background_image = pygame.image.load("pink background.jpg").convert()
# Draw the background
screen.blit(background_image, [0, 0])
to get the pink background to be the background :) Now this is the only thing I changed in the code but everything now moves much slower e.g. the player that is being controlled by the user and the moving platform. There are two levels and I didn't change the code for the second levels background and the player still moves fine there :)
I did think I might of changed the line:
# Limit to 60 frames per second
clock.tick(60)
by accident, but it is still exactly the same.
I hope someone can help :) and thank you in advance :)
The error occurs somewhere in this code:
`
def main():
pygame.init()
# Set the height and width of the screen
size = [SCREEN_WIDTH, SCREEN_HEIGHT]
screen = pygame.display.set_mode(size)
pygame.display.set_caption('Platformer with moving platforms')
# Create the player
player = Player()
# Create all the levels
level_list = []
level_list.append(Level_01(player))
# Set the current level
current_level_no = 0
current_level = level_list[current_level_no]
active_sprite_list = pygame.sprite.Group()
player.level = current_level
player.rect.x = 200
player.rect.y = SCREEN_HEIGHT - player.rect.height - 30
active_sprite_list.add(player)
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop --------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.go_left()
if event.key == pygame.K_RIGHT:
player.go_right()
if event.key == pygame.K_UP:
player.jump()
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and player.change_x < 0:
player.stop()
if event.key == pygame.K_RIGHT and player.change_x > 0:
player.stop()
# Update the player.
active_sprite_list.update()
# Update items in the level
current_level.update()
# If the player gets near the right side, shift the world left (-x)
if player.rect.right >= 500:
diff = player.rect.right - 500
player.rect.right = 500
current_level.shift_world(-diff)
# If the player gets near the left side, shift the world right (+x)
if player.rect.left <= 120:
diff = 120 - player.rect.left
player.rect.left = 120
current_level.shift_world(diff)
# If the player touches the floor they die.
if player.rect.y == SCREEN_HEIGHT - player.rect.height:
done = True
# If the player gets to the end of the level, go to the next level
current_position = player.rect.x + current_level.world_shift
if current_position < current_level.level_limit:
all_lines = []
list_of_files = os.listdir()
if username1 in list_of_files:
file1 = open(username1, "r")
for line in file1:
all_lines.append(line)
all_lines[2] = str(1)
with open(username1, 'w') as filehandle:
for listitem in all_lines:
filehandle.write(str(listitem))
done = True
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
current_level.draw(screen)
active_sprite_list.draw(screen)
# Select the font to use, size, bold, italics
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Limit to 60 frames per second
clock.tick(60)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit()
if __name__ == "__main__":
main()
`
Do not load the image in your main loop. Define (load) it outside of the loop and then use it via variable. This is your problem, because it loads the image (in this case FPS = 60) times per second from your disk.
I've got a really long code for my game, but I'll paste in the part that counts which is the bullet shooting part. The game is essentially a Mortal Kombat-esque game but with flying robots and bullets.
Before the game loop, I first predefined functions for the bullets and robots:
def robotr(xr,yr):
gameDisplay.blit(robrimg, (xr,yr))
def robotl(xl,yl):
gameDisplay.blit(roblimg, (xl,yl))
def bulletsr(xbr,ybr):
pygame.draw.circle(gameDisplay, THECOLORS['orange'],(xbr,ybr), 10)
def bulletsl(xbl,ybl):
pygame.draw.circle(gameDisplay, THECOLORS['orange'],(xbl,ybl), 10)
Then the numerous variables for the moving objects:
xr = 929
yr = 250
xl = 250
yl = 250
####
xbr=950
ybr=300
xbl=380
ybl=300
#####
xbr_change = 0
ybr_change = 0
ybl_change = 0
xbl_change = 0
####
xr_change = 0
yr_change = 0
xl_change = 0
yl_change = 0
robotr_speed = 3000
robotl_speed = 3000
After that, the code went for a really long run (about 300-400 lines more), but to the point where I shot the bullets I had an event like this to represent the bullets "moving" with the robot as it moved with the arrow keys.:
if event.type == pygame.KEYDOWN:
#-------PLAYER 1 MOVEMENT-------
#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
if event.key == pygame.K_a:
xr_change = -5
xbr_change = -5 #I have to change the position of the bullet as well so that it doesn't stay in one place and rather shoots from the robot (duh.)
And then a similar code to SHOOT the bullets:
#-------FIRE CANNON MK1-------
#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
if event.key == pygame.K_LSHIFT:
bulletsfx=pygame.mixer.Sound ('boomchickchickmp3.ogg')
bulletsfx.play()
bulletsfx.set_volume(0.2)
xbl_change = 5
if xbl_change == 5:
bulletsl(xbl,ybl)
xbl=xl
Of course, I defined such codes multiple times for the robot on the right as well.
Near the end of my program (this is as a short form of my end as I had extra variables so things wouldn't fall off the screen, but disregard that for now) I had a code like this so I could redefine the changes back to "0" so that the movements could be reused and so forth:
if event.type == pygame.KEYUP:
#Player 1 events
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_UP or event.key == pygame.K_DOWN or event.key == pygame.K_RCTRL or event.key == pygame.K_DELETE: #or event.key == pygame.K_RSHIFT:
xr_change = 0
yr_change = 0
xbr_change= 0
ybr_change= 0
#Player 2 events
if event.key == pygame.K_a or event.key == pygame.K_d or event.key == pygame.K_w or event.key == pygame.K_s or event.key == pygame.K_LCTRL or event.key == pygame.K_f: #or event.key == pygame.K_LSHIFT:
xl_change = 0
yl_change = 0
xbl_change= 0
ybl_change= 0
##
xr += xr_change
yr += yr_change
xl += xl_change
yl += yl_change
##
xbr += xbr_change
ybr += ybr_change
xbl += xbl_change
ybl += ybl_change
##
bulletsr(xbr,ybr)
bulletsl(xbl,ybl)
robotr(xr,yr)
robotl(xl,yl)
pygame.display.update()
clock.tick(320)
Now my problem is that when I shoot the bullets, it shoots, but I can only shoot it once until it goes off the screen of my program (It's okay, I made it so it returns to the robots once it goes off the screen as well). Otherwise, if I keep hitting the key to shoot, it just returns the bullet coordinates back to where it originally should be (as in I shoot, and if I shoot again, I can see the bullet disappearing to return to its original location).
There is not an infinite number of bullets and I want to know how I can modify the function and some of the variables (probably) to make it so that happens.
You need to use sprites in your code which is missing. It can be done without sprites also but it will be difficult task.
Make a class of bullets so you can make different objects of this.
After you just make a instance to the bullet object every time shoot button is pressed and keep updating it.
In update method you will make bullet move.
Last step is to destroy the bullet object once its out of your screen. One easy way is to put an if statement to check if certain x or y length is achieved and if so delete that sprite or object (bullet in this case).
Here is an example of bullet class I used. In this the char is assumed to be on bottom of screen and shoot bullets upwards as y += -10
class Bullet(pygame.sprite.Sprite):
def __init__(self):
super(Bullet, self).__init__()
self.image = pygame.Surface([10,40])
self.image.fill(RED)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 10
if you still need to see the full picture you can check out my code here : https://github.com/deepaksandhu/SpaceTurds/blob/master/game.py
also here is an excellent tutorial of making bullets:
http://programarcadegames.com/python_examples/show_file.php?file=bullets.py