python and pygame shooting - python

I am working on a game in pygame, so far the player can walk around, 50 blue blocks spawn randomly on the screen and the player can walk around and shoot them, but there is one problem the player can only shoot up, I want the player to shoot towards the mouse but am having some trouble getting it to do this.
this is my code
import pygame
from pygame import *
import random
black = ( 0, 0, 0)
white = ( 255, 255, 255)
red = ( 255, 0, 0)
blue = ( 0, 0, 255)
player_x, player_y = 0, 0
move_player_x, move_player_y = 0, 0
class Block(pygame.sprite.Sprite):
def __init__(self, color):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20, 15])
self.image.fill(color)
self.rect = self.image.get_rect()
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20,20])
self.image.fill(red)
self.rect = self.image.get_rect()
def update(self):
pos = pygame.mouse.get_pos()
self.rect.x = player_x
self.rect.y = player_y
class Bullet(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([4, 10])
self.image.fill(black)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 5
pygame.init()
screen_width = 700
screen_height = 400
screen = pygame.display.set_mode([screen_width,screen_height])
all_sprites_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()
bullet_list = pygame.sprite.Group()
for i in range(50):
block = Block(blue)
block.rect.x = random.randrange(screen_width)
block.rect.y = random.randrange(350)
block_list.add(block)
all_sprites_list.add(block)
player = Player()
all_sprites_list.add(player)
done = False
clock = pygame.time.Clock()
score = 0
player.rect.y = 370
# -------- Main Program Loop -----------
while not done:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
bullet = Bullet()
bullet.rect.x = player.rect.x
bullet.rect.y = player.rect.y
all_sprites_list.add(bullet)
bullet_list.add(bullet)
if event.type== pygame.KEYDOWN:
if event.key==K_a:
move_player_x=-1
elif event.key==K_d:
move_player_x=+1
elif event.key==K_w:
move_player_y=-1
elif event.key==K_s:
move_player_y=+1
if event.type== pygame.KEYUP:
if event.key==K_a:
move_player_x=0
elif event.key==K_d:
move_player_x=0
elif event.key==K_w:
move_player_y=0
elif event.key==K_s:
move_player_y=0
# --- Game logic
all_sprites_list.update()
player_x += move_player_x
player_y += move_player_y
for bullet in bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, block_list, True)
for block in block_hit_list:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
score += 1
print( score )
if bullet.rect.y < -10:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
screen.fill(white)
all_sprites_list.draw(screen)
pygame.display.flip()
clock.tick(20)
pygame.quit()
so there the code, any help is much appreciated

here is what i came up with, I changed some code from an RPG me and a friend are making
Change your bullet class code to this:
class Bullet(pygame.sprite.Sprite):
def __init__(self, mouse, player):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([4, 10])
self.image.fill(black)
self.mouse_x, self.mouse_y = mouse[0], mouse[1]
self.player = player
self.rect = self.image.get_rect()
def update(self):
speed = 4.
range = 200
distance = [self.mouse_x - self.player[0], self.mouse_y - self.player[1]]
norm = math.sqrt(distance[0] ** 2 + distance[1] ** 2)
direction = [distance[0] / norm, distance[1 ] / norm]
bullet_vector = [direction[0] * speed, direction[1] * speed]
self.rect.x -= bullet_vector[0]
self.rect.y -= bullet_vector[1]
now it takes the players pos and the mouse click pos as arguments for the class
the math is a bit confusing but it basically take the vector from the two points and gets a direction and sends the bullet that way
when you create a new bullet instance call it like this:
bullet = Bullet(pygame.mouse.get_pos(), [player.rect.x, player.rect.y])
that way the class gets the two points when the mouse button is clicked!
when you run it you may notice that the bullet goes in the opposite direction of the mouse click thought that would add some challenge. You can change it if you need
P.S. the speed variable can be adjusted! Oh, and the math module needs to be imported

Related

Pygame 2D Platformer Full Platform Collision [duplicate]

This question already has answers here:
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
How do I detect collision in pygame?
(5 answers)
Closed 2 years ago.
I have been trying to create a 2D platformer in pygame, and I have encountered a problem with the collision of the player sprite with the platform. I hope to implement full collision for the platforms, so that the player sprite will stop when it hits the platform from any direction. Currently, the sprite stops when it hits the top of the platforms, but if it collides with the bottom or sides of a platform it instantly jumps to the top of the platform. I have tried various things to solve this, but to no avail. Any help would be appreciated.
I have seperated my code into 3 files.
This is my main file:
import pygame
from settings import *
from sprites import *
#Game Class
class Game:
def __init__(self):
pygame.init()
pygame.mixer.init()
self.gameDisplay = pygame.display.set_mode((displayWidth, displayHeight))
self.clock = pygame.time.Clock()
self.gameRunning = True
#Stars the game
def new(self):
self.allSprites = pygame.sprite.Group()
self.platforms = pygame.sprite.Group()
self.player = Player(self)
self.allSprites.add(self.player)
floor = Platform(0, 680, displayWidth, 40)
plat2 = Platform( 500, 400, 100, 40)
self.allSprites.add(floor, plat2)
self.platforms.add(floor, plat2)
self.run()
#Game Loop
def run(self):
self.gameRunning = True
while self.gameRunning == True:
self.clock.tick(FPS)
self.events()
self.update()
self.draw()
#Updates the screen
def update(self):
self.allSprites.update()
hits = pygame.sprite.spritecollide(self.player, self.platforms, False)
if hits:
self.player.pos.y = hits[0].rect.top
self.player.spd.y = 0
self.player.rect.midbottom = self.player.pos
if self.player.rect.left >= displayHeight - 200:
self.player.pos.x -= abs(self.player.spd.x)
for plat in self.platforms:
plat.rect.x -= abs(self.player.spd.x)
if self.player.rect.right <= displayHeight / 4:
self.player.pos.x += abs(self.player.spd.x)
for plat in self.platforms:
plat.rect.x += abs(self.player.spd.x)
#Events loop
def events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
self.player.jump()
#Draws things to the screen
def draw(self):
self.gameDisplay.fill(LIGHT_BLUE)
self.allSprites.draw(self.gameDisplay)
pygame.display.update()
def runGame():
game = Game()
game.new()
runGame()
Sprites file:
import pygame
from settings import *
vec = pygame.math.Vector2
#Player Class
class Player(pygame.sprite.Sprite):
def __init__(self, game):
pygame.sprite.Sprite.__init__(self)
self.game = game
self.image = pygame.Surface([40, 40])
self.image.fill(DARK_BLUE)
self.rect = self.image.get_rect()
self.rect.center = (displayWidth / 2, displayHeight / 2)
self.pos = vec(displayWidth / 2, displayHeight / 2)
self.spd = vec(0,0)
self.acc = vec(0,0)
def update(self):
self.acc = vec(0, playerGrav)
keysPressed = pygame.key.get_pressed()
if keysPressed[pygame.K_LEFT]:
self.acc.x = - playerAcc
if keysPressed[pygame.K_RIGHT]:
self.acc.x = playerAcc
self.acc.x += self.spd.x * playerFric
self.spd += self.acc
self.pos += self.spd + 0.5 * self.acc
self.rect.midbottom = self.pos
def jump(self):
self.rect.y +=1
hits = pygame.sprite.spritecollide(self, self.game.platforms, False)
self.rect.y -= 1
if hits:
self.spd.y = -20
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y, w, h):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((w, h))
self.image.fill((GREEN))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
Settings File:
import pygame
pygame.font.init()
#Setup
FPS = 60
displayWidth = 1280
displayHeight = 720
pygame.display.set_caption("2D Platformer")
gameDisplay = pygame.display.set_mode((displayWidth, displayHeight))
clock = pygame.time.Clock()
#Player
playerAcc = 0.5
playerFric = -0.1
playerGrav = 0.5
#Colour Pallette
BLACK = (0, 0, 0 )
WHITE = (255, 255, 255)
RED = (200, 0, 0 )
GREEN = (0, 200, 0 )
BLUE = (0, 0, 200)
LIGHT_BLUE = (0, 191, 255)
DARK_BLUE = (0, 50, 150)
#Score
score = 0
This is the code that is responsible for collision:
hits = pygame.sprite.spritecollide(self.player, self.platforms, False)
if hits:
self.player.pos.y = hits[0].rect.top
self.player.spd.y = 0
self.player.rect.midbottom = self.player.pos
I understand that the reason why the sprite jumps to the top of the platform is due to these lines of code:
if hits:
self.player.pos.y = hits[0].rect.top
However, I don't know how to implement full collision.

Space Invaders - Pygame - Random Shoot

I am making the game Space Invaders in Pygame and I want to let the enemy shoot randomly at the player. At this moment I can only let the enemy shoot at the player by pressing the tab button. But it should do this automatically and with a random interval. How can I get this working, without needing to press tab?
Thanks.
import pygame, sys
from pygame.locals import *
import random
screenWidth = 800
screenHeight = 600
FPS = 60
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((screenWidth,screenHeight))
pygame.display.set_caption("Space Invaders")
clock = pygame.time.Clock()
shipWidth = 67
#colors
black=(0,0,0)
blue=(0,0, 255)
green=(0,128,0)
red=(255,0,0)
white=(255,255,255)
yellow=(255,255,0)
def app_quit():
pygame.quit()
sys.exit("System exit.")
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("spaceship3.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.centerx = screenWidth / 2
self.rect.bottom = screenHeight - 10
def update(self):
self.speedx = 0
if event.type == KEYDOWN and event.key == K_LEFT:
self.speedx = -2
elif event.type == KEYDOWN and event.key == K_RIGHT:
self.speedx = 2
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.right = screenWidth
if self.rect.left < 0:
self.rect.left = 0
def shootPlayer(self):
bulletPlayer = BulletPlayer(self.rect.centerx, self.rect.top)
allSprites.add(bulletPlayer)
bulletsPlayer.add(bulletPlayer)
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("enemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.x = 0
self.rect.y = random.randrange(0, 200)
self.speedx = random.randrange(1, 2)
def update(self):
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.x = 0
self.rect.y = random.randrange(0, 250)
self.speedx = random.randrange(1, 3)
# if self.rect.x > screenWidth: #kill when of the screen
# self.kill()
def shootEnemy(self):
bulletEnemy = BulletEnemy(self.rect.centerx, self.rect.bottom)
allSprites.add(bulletEnemy)
bulletsEnemy.add(bulletEnemy)
class BulletPlayer(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bullet.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill()
class BulletEnemy(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bulletenemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = 2
def update(self):
self.rect.y += self.speedy
if self.rect.bottom > screenHeight:
self.kill()
class Wall(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("wall.png").convert()
self.rect = self.image.get_rect()
self.rect.center = 100, 300
allSprites = pygame.sprite.Group()
player = Player()
enemy = pygame.sprite.Group()
bulletsPlayer = pygame.sprite.Group()
bulletsEnemy = pygame.sprite.Group()
wall = Wall()
allSprites.add(player, enemy, bulletsPlayer, bulletsEnemy, wall)
for i in range(1):
e = Enemy()
allSprites.add(e)
enemy.add(e)
running = True
while True:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
running = False
app_quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
if event.key == pygame.K_TAB:
random.choice(enemy.sprites()).shootEnemy()
allSprites.update()
hitplayer = pygame.sprite.spritecollide(player, bulletsEnemy, True)
if hitplayer:
running = app_quit()
hitenemy = pygame.sprite.groupcollide(enemy, bulletsPlayer, True, True)
if hitenemy:
running = app_quit()
screen.fill(black)
allSprites.draw(screen)
pygame.display.flip()
pygame.quit()
You need a random timer variable which you can decrement by the dt (delta time) each frame. When it's below zero, create a bullet instance, add it to the group and reset the timer. I use the random.uniform function here which gives you a float, but you could also use random.randrange or randint if you want ints. To get the delta time (the time since the last tick) just assign the value that clock.tick(fps) returns to a variable.
# The timer is the time in seconds until the enemy shoots.
timer = random.uniform(2, 6) # Random float between 2 and 6.
dt = 0
running = True
while True:
# Event handling omitted.
# Decrease the timer by the delta time.
timer -= dt
if timer <= 0: # Ready to fire.
# Pick a random enemy to get the x and y coords.
random_enemy = random.choice(enemy.sprites())
enemy_x, enemy_y = random_enemy.rect.center
# Create a bullet and add it to the sprite groups.
bullet = BulletEnemy(enemy_x, enemy_y)
allSprites.add(bullet)
enemy.add(bullet)
timer = random.uniform(2, 6) # Reset the timer.
# Collision detection and drawing omitted.
# clock.tick returns the time that has passed since the last frame.
dt = clock.tick(60) / 1000 # / 1000 to convert it to seconds.
One way to do it is to create a custom event and trigger it based off some conditions, such as time.
You can use pygame.event.Event() and pygame.event.post() to trigger an event manually instead of using the Tab key. To setup this event on time you can use pygame.time.set_timer(myEvent, time). After that your main loop just needs to check for the event with pygame.event.get().
There is a good example of how to use custom events in pygame here: PyGame Custom Event
The author's example is even a Space Invaders type game so it will be useful to look at how it is written.

Collision is not working Bullet vs Mob

I've tried numerous things to let my bullets collide with my mob, but it doesn't work. The bullet just goes straight through the mob. I also tried spritecollide and groupcollide codes, but they all failed. Maybe i'm putting my code in the wrong line or the wrong place. I also want the bullet and mob to be removed from the list.
import pygame
import random
import math
GRAD = math.pi / 180
black = (0,0,0)
Bulleti = pygame.image.load('bullet.png')
Monster = pygame.image.load('Monster1re.png')
class Config(object):
fullscreen = True
width = 1366
height = 768
fps = 60
class Player(pygame.sprite.Sprite):
maxrotate = 180
down = (pygame.K_DOWN)
up = (pygame.K_UP)
def __init__(self, startpos=(102,579), angle=0):
super().__init__()
self.pos = list(startpos)
self.image = pygame.image.load('BigShagHoofdzzz.gif')
self.orig_image = self.image
self.rect = self.image.get_rect(center=startpos)
self.angle = angle
def update(self, seconds):
pressedkeys = pygame.key.get_pressed()
if pressedkeys[self.down]:
self.angle -= 2
self.rotate_image()
if pressedkeys[self.up]:
self.angle += 2
self.rotate_image()
def rotate_image(self):
self.image = pygame.transform.rotate(self.orig_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
class Mob(pygame.sprite.Sprite):
def __init__(self, image):
super().__init__()
self.image = image
self.rect = self.image.get_rect()
self.rect.x = 1400
self.rect.y = random.randrange(500,600)
self.speedy = random.randrange(-8, -1)
def update(self):
self.rect.x += self.speedy
if self.rect.x < -100 :
self.rect.x = 1400
self.speedy = random.randrange(-8, -1)
class Bullet(pygame.sprite.Sprite):
"""This class represents the bullet."""
def __init__(self, pos, angle, image):
super().__init__()
self.image = image
self.image = pygame.transform.rotate(self.image, angle)
self.rect = self.image.get_rect()
speed = 15
self.velocity_x = math.cos(math.radians(-angle)) * speed
self.velocity_y = math.sin(math.radians(-angle)) * speed
self.pos = list(pos)
def update(self):
""" Move the bullet. """
self.pos[0] += self.velocity_x
self.pos[1] += self.velocity_y
self.rect.center = self.pos
player = Player()
#this is the mob group
mobs = []
for x in range(0,10):
mob = Mob(Monster)
mobs.append(mob)
print(mobs)
#sprite lists
bullet_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()
allgroup = pygame.sprite.LayeredUpdates()
allgroup.add(player)
for mob in mobs:
all_sprites_list.add(mob)
def main():
#game
pygame.mixer.pre_init(44100, -16, 1, 512)
pygame.mixer.init()
pygame.init()
screen=pygame.display.set_mode((Config.width, Config.height),
pygame.FULLSCREEN)
background = pygame.image.load('BGGameBig.png')
sound = pygame.mixer.Sound("shoot2.wav")
clock = pygame.time.Clock()
FPS = Config.fps
mainloop = True
while mainloop:
millisecond = clock.tick(Config.fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
mainloop = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
mainloop = False
if event.key == pygame.K_SPACE: #Bullet schiet knop op space
# Pass the position and angle of the player.
bullet = Bullet(player.rect.center, player.angle,
Bulleti)
all_sprites_list.add(bullet)
bullet_list.add(bullet)
sound.play()
if event.key == pygame.K_ESCAPE:
mailoop = False
pygame.display.set_caption("hi")
allgroup.update(millisecond)
all_sprites_list.update()
for bullet in bullet_list:
if bullet.rect.x > 1380:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
#this is the code for collission
hits = pygame.sprite.groupcollide(bullet_list, mobs, True, True)
screen.blit(background, (0,0))
allgroup.draw(screen)
all_sprites_list.draw(screen)
pygame.display.flip()
if __name__ == '__main__':
main()
pygame.quit()
if anyone could help me out on this one it would really be appreciated. I spent alot of time working on the solution but I haven't found any yet. Watched alot of youtubers and did the same thing but it just won't work.
I get a different error when I run the program, an AttributeError caused by this line hits = pygame.sprite.groupcollide(bullet_list, mobs, True, True). That happens because the mobs list should be a pygame.sprite.Group.
mobs = pygame.sprite.Group()
for x in range(0,10):
mob = Mob(Monster)
mobs.add(mob)
After I changed this part of the code, it worked correctly.

How do I make enemies drop money after they die?

I'm looking to make some enemies in my game drop "UP Points" (Upgrade Points in the form of small yellow squares) when I shoot them. I've tried a few different things but can't seem to figure out how to spawn these collectable points in place of where an enemy just died. Does anyone have any ideas about how I could implement this?
UP class:
class Up(pygame.sprite.Sprite):
def __init__(self, color):
super().__init__()
self.image = pygame.Surface([5, 5])
self.image.fill(color)
self.rect = self.image.get_rect()
Here's the loop for when an enemy gets shot and dies:
for bullet in bullet_list: #For each bullet:
# Whenever a bullet collides with a zombie,
block_hit_list = pygame.sprite.spritecollide(bullet, zombie_list, True)
for i in block_hit_list:
# Destroy the bullet and zombie and add to the score
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
score += 100
Sorry for not posting my whole code, the main game loop is at the bottom :)
import pygame
import math
import random
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
ORANGE = (255, 119, 0)
ZOMBIE_GREEN = (122, 172, 34)
YELLOW = (255, 255, 0)
cursor_x = 100
cursor_y = 100
class Player(pygame.sprite.Sprite):
def __init__(self, color):
super().__init__()
# pygame.Surface will create a rectangle with the width and height given
# and the command below it tells it to fill it in with that color
self.image = pygame.Surface([15, 15])
self.image.fill(color)
self.rect = self.image.get_rect()
# This defines the starting position (x, y)
# of whatever sprite is passed through
self.rect.x = 600
self.rect.y = 300
# This is the current speed it will move when drawn
self.change_x = 0
self.change_y = 0
self.walls = None
# Defines how the player will move
def movement(self, x, y):
self.change_x += x
self.change_y += y
# Updates the information so the screen shows the player moving
def update(self):
self.rect.x += self.change_x
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.change_x > 0:
self.rect.right = block.rect.left
else:
self.rect.left = block.rect.right
self.rect.y += self.change_y
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.change_y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
class Enemy(pygame.sprite.Sprite):
def __init__(self, color):
super().__init__()
self.image = pygame.Surface([20, 20])
self.image.fill(color)
self.rect = self.image.get_rect()
self.pos_x = self.rect.x = random.randrange(35, screen_width - 35)
self.pos_y = self.rect.y = random.randrange(35, screen_height - 135)
# How Zombies move towards player
def update(self):
zombie_vec_x = self.rect.x - player.rect.x
zombie_vec_y = self.rect.y - player.rect.y
vec_length = math.sqrt(zombie_vec_x ** 2 + zombie_vec_y ** 2)
if self.rect.x != player.rect.x and self.rect.y != player.rect.y:
zombie_vec_x = (zombie_vec_x / vec_length) * 1 # These numbers determine
zombie_vec_y = (zombie_vec_y / vec_length) * 1 # zombie movement speed
self.pos_x -= zombie_vec_x
self.pos_y -= zombie_vec_y
self.rect.x = self.pos_x
self.rect.y = self.pos_y
block_hit_list = pygame.sprite.spritecollide(self, sprites_list, False)
for block in block_hit_list:
if self.rect.x > 0:
self.rect.right = block.rect.left
elif self.rect.x < 0:
self.rect.left = block.rect.right
elif self.rect.y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
class Wall(pygame.sprite.Sprite):
def __init__(self, color, x, y, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
class Cursor(pygame.sprite.Sprite):
def __init__(self, width, height):
self.groups = all_sprites_list
self._layer = 1
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([width, height])
self.image.fill(RED)
self.rect = self.image.get_rect()
self.walls = None
# This updates the cursor to move along with your
# mouse position (defined in control logic)
def update(self):
self.rect.x = cursor_x
self.rect.y = cursor_y
class Bullet(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface([8, 8])
self.image.fill(ORANGE)
self.rect = self.image.get_rect()
# Instead of using the rect. positions, we'll use pos_ variables
# to calculate position. This is because the rect. uses integers
# while a variable can have exact float numbers. This will keep
# the bullets trajectory exact istead of useing a general
# (rounded) whole number <3
self.pos_x = player.rect.x + 4 # Set up pos_x and pos_y here
self.pos_y = player.rect.y + 4 # rather than rect.x and rect.y
self.walls = None
self.change_x = 0
self.change_y = 0
speed = 6
bullet_vec_x = (cursor.rect.x - 4) - player.rect.x
bullet_vec_y = (cursor.rect.y - 4) - player.rect.y
vec_length = math.sqrt(bullet_vec_x ** 2 + bullet_vec_y ** 2)
bullet_vec_x = (bullet_vec_x / vec_length) * speed
bullet_vec_y = (bullet_vec_y / vec_length) * speed
self.change_x += bullet_vec_x
self.change_y += bullet_vec_y
def update(self):
self.pos_x += self.change_x # Update pos_x and pos_y. They will become floats
self.pos_y += self.change_y # which will let them maintain sub-pixel accuracy.
self.rect.x = self.pos_x # Copy the pos values into the rect, where they will be
self.rect.y = self.pos_y # rounded off. That's OK since we never read them back.
pygame.init()
screen_size = pygame.display.Info()
size = (1300, 720)
screen = pygame.display.set_mode(size)
#size = (screen_size.current_w, screen_size.current_h)
#screen = pygame.display.set_mode(
# ((screen_size.current_w, screen_size.current_h)),pygame.FULLSCREEN
# )
screen_width = screen_size.current_w
screen_height = screen_size.current_h
pygame.display.set_caption("Zombie Shooter")
wall_list = pygame.sprite.Group()
zombie1_list = pygame.sprite.Group()
sprites_list = pygame.sprite.Group()
bullet_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()
# Walls are made here = (x_coord for where it starts,
# y_coord for where it starts, width of wall, height of wall)
# These walls are made with fullscreen dimentions, not any set dimentions
# Left
wall = Wall(BLUE, 0, 0, 10, screen_height)
wall_list.add(wall)
all_sprites_list.add(wall)
# Top
wall = Wall(BLUE, 0, 0, screen_width, 10)
wall_list.add(wall)
all_sprites_list.add(wall)
# Bottom
wall = Wall(BLUE, 0, screen_height - 10, screen_width, 10)
wall_list.add(wall)
all_sprites_list.add(wall)
# Right
wall = Wall(BLUE, screen_width - 10, 0, 10, screen_width)
wall_list.add(wall)
all_sprites_list.add(wall)
# HUD Border
wall = Wall(BLUE, 0, screen_height - 100, screen_width, 10)
wall_list.add(wall)
all_sprites_list.add(wall)
# This creates the actual player with the parameters set in ( ).
# However, we must add the player to the all_sprites_list
# so that it will actually be drawn to the screen with the draw command
# placed right after the screen.fill(BLACK) command.
player = Player(WHITE)
player.walls = wall_list
all_sprites_list.add(player)
zombie = Enemy(ZOMBIE_GREEN)
zombie.walls = wall_list
for i in range(5):
zombie = Enemy(ZOMBIE_GREEN)
all_sprites_list.add(zombie)
zombie1_list.add(zombie)
sprites_list.add(zombie)
cursor = Cursor(7, 7)
cursor.walls = wall_list
all_sprites_list.add(cursor)
bullet = Bullet()
font = pygame.font.SysFont("crushed", 30)
score = 0
up_score = 0
done = False
clock = pygame.time.Clock()
pygame.mouse.set_visible(0)
# -------- Main Program Loop -----------
while not done:
# --- Main event loop ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Press 'P' to quit the game_____
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
done = True
#________________________________
# Keyboard controls. The numbers inside change the speed of the player
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
player.movement(-4, 0)
elif event.key == pygame.K_d:
player.movement(4, 0)
elif event.key == pygame.K_w:
player.movement(0, -4)
elif event.key == pygame.K_s:
player.movement(0, 4)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a:
player.movement(4, 0)
elif event.key == pygame.K_d:
player.movement(-4, 0)
elif event.key == pygame.K_w:
player.movement(0, 4)
elif event.key == pygame.K_s:
player.movement(0, -4)
# ___________________________________________________________________
# Mouse Controls----------------------------
pos = pygame.mouse.get_pos()
cursor_x = pos[0]
cursor_y = pos[1]
if cursor_x <= 10:
cursor_x = 10
if cursor_x >= (screen_width - 17):
cursor_x = (screen_width - 17)
if cursor_y <= 10:
cursor_y = 10
if cursor_y >= (screen_height - 107):
cursor_y = (screen_height - 107)
elif event.type == pygame.MOUSEBUTTONDOWN:
bullet = Bullet()
all_sprites_list.add(bullet)
bullet_list.add(bullet)
#--------------------------------------------
all_sprites_list.update()
# How bullets vanish when they hit a sprite or a wall______________________
for bullet in bullet_list: #For each bullet:
# Whenever a bullet collides with a zombie,
block_hit_list = pygame.sprite.spritecollide(bullet, zombie1_list, True)
for i in block_hit_list:
# Destroy the bullet and zombie and add to the score
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
score += 100
for bullet in bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, wall_list, False)
for i in block_hit_list:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
#--------------------------------------------------------------------------
cursor.update()
bullet_list.update()
sprites_list.update()
pygame.mouse.set_visible(0)
screen.fill(BLACK)
all_sprites_list.draw(screen)
text = font.render("Score: " + str(score), True, WHITE)
screen.blit(text, [30, screen_height - 64])
pygame.display.flip()
clock.tick(60)
pygame.quit()
What you will have to do is before you destroy the zombie sprite grab its location and draw the UP coin. Then make sure that whenever the player controlled sprite, in this case the bullet, upon contact "collects" the coin. I haven't worked with python that much but the main code would look something like this:
def drawCoin():
zombieCoords = grabZombieCoords()
drawSprite(zombieCoords())
This would essentially just get the coordinates of the zombie, destroy it, and then place the coin at the last known location of the zombie.
Hope this helps.
Change your Up class to accept an argument pos, and use it to set the starting position:
class Up(pygame.sprite.Sprite):
def __init__(self, color, pos):
super().__init__()
self.image = pygame.Surface([5, 5])
self.image.fill(color)
self.rect = self.image.get_rect(center=pos)
Now, when you hit a zombie, create an Up, using the position of the zombie you just killed.
for bullet in bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, zombie_list, True)
for i in block_hit_list:
# just use .kill() to remove a Sprite from all of its Groups
# kill() may get called multiple times, but that does not hurt
bullet.kill()
score += 100
# create an Up for each killed zombie
# takes two arguments: color and pos
# we call .add() to add the Sprite immediately to
# the all_sprites_list and the up_list
Up((255, 0, 0), i.rect.center).add(all_sprites_list, up_list)
You didn't show the rest of your code, but I guess you call .draw and .update on your all_sprites_list and create a Group called up_list.

Two enemy movement glitches

So this is my game I've bean working on and so have things are going very well, the player can move around and shoot down the boxes which are ment to be moving but theres these small glitches, but before I go on heres the code:
import pygame, math, random, sys
from pygame import *
import random, math, cmath
pygame.init()
#variables end----------------------------------------------------------------
#imagers
grass = "grass_shit.png" #grass image
player_img = "shithead.png" #player name
ali_img = "shit_head2.png" #alien image
dead_screen = "dead_shit.png"
cross_hair = "crosshair.png"
playButton = "playbutton.png"
#screen
screen = pygame.display.set_mode((850, 640),0,32) #set screen
background = pygame.image.load(grass).convert() #load image to screen
health = 100
#mouse things
crosshair = pygame.image.load(cross_hair).convert_alpha()
#variables end----------------------------------------------------------------
pygame.mouse.set_visible(False)
black = ( 0, 0, 0)
white = ( 255, 255, 255)
red = ( 255, 0, 0)
blue = ( 0, 0, 255)
player_x, player_y = 0, 0
move_player_x, move_player_y = 0, 0
move_ali_x, move_ali_y = 0, 0
class Block(pygame.sprite.Sprite):
def __init__(self, color):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20, 15])
self.image.fill(color)
self.rect = self.image.get_rect()
def update(self):
global move_ali_x
global move_ali_y
if block.rect.x < player_x:
move_ali_x =+ 0.05
elif block.rect.x > player_x:
move_ali_x =- 0.05
if block.rect.y < player_y:
move_ali_y =+ 0.05
elif block.rect.y > player_y:
move_ali_y =- 0.05
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20,20])
self.image.fill(red)
self.rect = self.image.get_rect()
def update(self):
pos = pygame.mouse.get_pos()
self.rect.x = player_x
self.rect.y = player_y
class Bullet(pygame.sprite.Sprite):
def __init__(self, mouse, player):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([4, 10])
self.image.fill(black)
self.mouse_x, self.mouse_y = mouse[0], mouse[1]
self.player = player
self.rect = self.image.get_rect()
def update(self):
speed = 10
range = 50000
distance = [self.mouse_x - self.player[0], self.mouse_y - self.player[1]]
norm = math.sqrt(distance[0] ** 2 + distance[1] ** 2)
direction = [distance[0] / norm, distance[1] / norm]
bullet_vector = [direction[0] * speed, direction[1] * speed]
self.rect.x += bullet_vector[0]
self.rect.y += bullet_vector[1]
pygame.init()
screen_width = 850
screen_height = 640
screen = pygame.display.set_mode([screen_width,screen_height])
all_sprites_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()
bullet_list = pygame.sprite.Group()
for i in range(5):
block = Block(blue)
block.rect.x = random.randrange(screen_width)
block.rect.y = random.randrange(350)
block_list.add(block)
all_sprites_list.add(block)
player = Player()
all_sprites_list.add(player)
done = False
clock = pygame.time.Clock()
score = 0
player.rect.y = 370
# -------- Main Program Loop -----------
while not done:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
bullet = Bullet(event.pos, [player.rect.x, player.rect.y])
bullet.rect.x = player.rect.x
bullet.rect.y = player.rect.y
all_sprites_list.add(bullet)
bullet_list.add(bullet)
if event.type== pygame.KEYDOWN:
if event.key==K_a:
move_player_x=-4
elif event.key==K_d:
move_player_x=+4
elif event.key==K_w:
move_player_y=-4
elif event.key==K_s:
move_player_y=+4
if event.type== pygame.KEYUP:
if event.key==K_a:
move_player_x=0
elif event.key==K_d:
move_player_x=0
elif event.key==K_w:
move_player_y=0
elif event.key==K_s:
move_player_y=0
# --- Game logic
all_sprites_list.update()
player_x += move_player_x
player_y += move_player_y
block.rect.y += move_ali_y
block.rect.x += move_ali_x
for bullet in bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, block_list, True)
for block in block_hit_list:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
score += 1
print( score )
if bullet.rect.y < -10:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
if player.rect.colliderect(block.rect):
health =- 35
mouse_x, mouse_y = pygame.mouse.get_pos()
mouse_x -= crosshair.get_width() / 2
mouse_y -= crosshair.get_height() / 2
screen.blit(background,(0,0))
all_sprites_list.draw(screen)
screen.blit(crosshair,(mouse_x, mouse_y))
pygame.display.flip()
pygame.display.update()
clock.tick(20)
pygame.quit()
So glitch number one:
only one of the boxers moves, I cant figure out why it only one of them is moving towards the player, all the boxers are meant to move towards the player as this is hoping to become a zombie shooter.
Glitch two:
At a random point the box that does move does stops moving in all directions but one, so lets say this happens when the box in in the center of the screen, if the player goes to the left of the box, nothing, but when the player moves to thr right of the player it moves right, but only right not up or down, and this seams to happen at soem point everytime.
Well thats it, hope you can help thanks heaps stackoverflow
Your code should looks like this:
import pygame
from pygame import *
import sys
import math
import random
import cmath
#----------------------------------------------------------------------
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
#imagers
IMAGE_GRASS = "grass_shit.png" #grass image
IMAGE_PLAYER = "shithead.png" #player name
IMAGE_ALI = "shit_head2.png" #alien image
IMAGE_DEAD_SCREEN = "dead_shit.png"
IMAGE_CROSSHAIR = "crosshair.png"
IMAGE_PLAYBUTTON = "playbutton.png"
#~ IMAGE_GRASS = "ball3.png" #grass image
#~ IMAGE_PLAYER = "ball2.png" #player name
#~ IMAGE_ALI = "ball3.png" #alien image
#~ IMAGE_DEAD_SCREEN = "ball3.png"
#~ IMAGE_CROSSHAIR = "ball1.png"
#~ IMAGE_PLAYBUTTON = "ball3.png"
#----------------------------------------------------------------------
class Block(pygame.sprite.Sprite):
def __init__(self, color, x, y, player = None):
pygame.sprite.Sprite.__init__(self)
self.player = player
self.image = pygame.Surface([20, 15])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.move_x = self.move_y = 0
def update(self):
if self.player:
player_x, player_y = self.player.rect.center
if self.rect.x < player_x:
self.rect.x += 1
elif self.rect.x > player_x:
self.rect.x -= 1
if self.rect.y < player_y:
self.rect.y += 1
elif self.rect.y > player_y:
self.rect.y -= 1
#----------------------------------------------------------------------
class Player(pygame.sprite.Sprite):
def __init__(self, screen_rect, x=0, y=0):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20,20])
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.min_x = screen_rect.left
self.min_y = screen_rect.top
self.max_x = screen_rect.right
self.max_y = screen_rect.bottom
self.move_x = self.move_y = 0
self.health = 100
def update(self):
pos = pygame.mouse.get_pos()
self.rect.x += self.move_x
self.rect.y += self.move_y
if self.rect.top < self.min_x:
self.rect.top = self.min_x
elif self.rect.bottom > self.max_y:
self.rect.bottom = self.max_y
if self.rect.left < self.min_x:
self.rect.left = self.min_x
elif self.rect.right > self.max_x:
self.rect.right = self.max_x
def event_handler(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
self.move_x = -4
elif event.key == pygame.K_d:
self.move_x = +4
elif event.key == pygame.K_w:
self.move_y = -4
elif event.key == pygame.K_s:
self.move_y = +4
if event.type == pygame.KEYUP:
if event.key in (pygame.K_a, pygame.K_d):
self.move_x = 0
elif event.key in (pygame.K_w, pygame.K_s):
self.move_y = 0
#----------------------------------------------------------------------
class Bullet(pygame.sprite.Sprite):
def __init__(self, start_pos, mouse_pos):
pygame.sprite.Sprite.__init__(self)
self.start_rect = start_pos.rect.copy()
self.mouse_x, self.mouse_y = mouse_pos # mouse[0], mouse[1]
self.image = pygame.Surface([5, 5])
self.image.fill(BLACK)
self.rect = self.image.get_rect()
self.rect.centerx = self.start_rect.centerx
self.rect.centery = self.start_rect.centery
self.speed = 10
self.max_range = 50
self.current_range = 0
distance_x = self.mouse_x - self.start_rect.centerx
distance_y = self.mouse_y - self.start_rect.centery
norm = math.sqrt(distance_x ** 2 + distance_y ** 2)
direction_x = distance_x / norm
direction_y = distance_y / norm
self.bullet_vector_x = direction_x * self.speed
self.bullet_vector_y = direction_y * self.speed
def update(self):
self.current_range += 1
if self.current_range < self.max_range:
print self.start_rect.centerx + (self.bullet_vector_x*self.current_range),
print self.rect.centerx + self.bullet_vector_x,
#self.rect.centerx += self.bullet_vector_x
self.rect.centerx = self.start_rect.centerx + (self.bullet_vector_x*self.current_range)
print self.rect.centerx
#self.rect.centery += self.bullet_vector_y
self.rect.centery = self.start_rect.centery + (self.bullet_vector_y*self.current_range)
else:
self.kill()
#----------------------------------------------------------------------
class Crosshair(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(IMAGE_CROSSHAIR).convert_alpha()
self.rect = self.image.get_rect()
def update(self):
mouse_x, mouse_y = pygame.mouse.get_pos()
self.rect.centerx = mouse_x
self.rect.centery = mouse_y
def draw(self, screen):
screen.blit(self.image,self.rect.topleft)
#----------------------------------------------------------------------
class Background(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(IMAGE_GRASS).convert_alpha()
self.rect = self.image.get_rect()
def draw(self, screen):
screen.fill((128,128,128))
screen.blit(self.image,(0,0))
#----------------------------------------------------------------------
class Game():
def __init__(self):
pygame.init()
screen_width = 850
screen_height = 640
self.screen = pygame.display.set_mode( (screen_width,screen_height) )
pygame.mouse.set_visible(False)
#-----
self.all_sprites_list = pygame.sprite.Group()
self.block_list = pygame.sprite.Group()
self.bullet_list = pygame.sprite.Group()
# --- create sprites ---
self.background = Background()
self.player = Player(self.screen.get_rect(), 0, 370)
self.all_sprites_list.add(self.player)
for i in range(5):
block = Block(BLUE, random.randrange(100, screen_width), random.randrange(10, screen_height-10), self.player)
self.block_list.add(block)
self.all_sprites_list.add(block)
self.crosshair = Crosshair()
#-----
font = pygame.font.SysFont("", 72)
self.text_pause = font.render("PAUSE", -1, RED)
self.text_pause_rect = self.text_pause.get_rect(center=self.screen.get_rect().center) # center text
#-----
self.score = 0
def bullet_create(self, start_pos, mouse_pos):
bullet = Bullet(start_pos, mouse_pos)
self.all_sprites_list.add(bullet)
self.bullet_list.add(bullet)
def bullets_update(self):
for bullet in self.bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, self.block_list, True)
for block in block_hit_list:
self.bullet_list.remove(bullet)
self.all_sprites_list.remove(bullet)
self.score += 1
print self.score
if bullet.rect.y < -10:
self.bullet_list.remove(bullet)
self.all_sprites_list.remove(bullet)
if pygame.sprite.collide_rect(self.player, block):
self.player.health =- 35
# -------- Main Program Loop -----------
def run(self):
clock = pygame.time.Clock()
RUNNING = True
PAUSED = False
while RUNNING:
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUNNING = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
RUNNING = false
elif event.key == pygame.K_SPACE:
PAUSED = not PAUSED
elif event.type == pygame.MOUSEBUTTONDOWN:
self.bullet_create(self.player, event.pos)
# send event to player
self.player.event_handler(event)
# send event to crosshair for mousebuttondown
#if not PAUSED:
# self.crosshair.event_handler(event)
# --- updates ---
if not PAUSED:
self.all_sprites_list.update()
self.bullets_update()
self.crosshair.update()
# --- draws ---
self.background.draw(self.screen)
self.all_sprites_list.draw(self.screen)
self.crosshair.draw(self.screen)
if PAUSED:
self.screen.blit(self.text_pause, self.text_pause_rect.topleft)
pygame.display.update() # use flip() OR update()
# --- FPS ---
clock.tick(20)
# --- quit ---
pygame.quit()
#----------------------------------------------------------------------
Game().run()
Changes:
player can move but can leave screen
press space to pause game - but you can still move cursor and fire :)
bullet has max range - than it is removed
i change bullet vetor calculations because value was rounded to integer every frame and bullet trajectory was incorrect
bullet never change trajectory when player is moving
all code is in classes except some constant values. I add class Crosshair and Background
you can see how class (Player) handle events in event_handle
I use pygame.Rect() (screen.get_rect(), image.get_rect()) to get rect.top, rect.left, rect.center, rect.centerx, rect.topleft, etc.
There is still many things to do.
ps. if someone needs images 'ball1.png', 'ball2.png', 'ball3.png' to run this example you can find it in answer to
Space invaders project
Pygame- window and sprite class - python

Categories