Last active
November 4, 2024 17:56
-
-
Save horstjens/86a875eda11ef2d5a78f6ca60f9128a4 to your computer and use it in GitHub Desktop.
pygame shooter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pygame | |
import random | |
class Game: | |
W, H = 1500, 751 | |
FPS = 60 | |
scrollspeed = -2 | |
stargroup = pygame.sprite.Group() | |
playergroup = pygame.sprite.Group() | |
lasergroup = pygame.sprite.Group() | |
enemygroup = pygame.sprite.Group() | |
plasmagroup = pygame.sprite.Group() | |
allgroup = pygame.sprite.LayeredDirty() | |
class Enemy1(pygame.sprite.DirtySprite): | |
def __init__(self, pos): | |
self.pos = pos | |
self.move = pygame.Vector2(random.randint(-100,-50), | |
random.randint(-20,20)) | |
#self.dirty = True | |
#self.visible = True | |
#self.blendmode = 0 | |
self._layer = 8 | |
pygame.sprite.DirtySprite.__init__(self, | |
Game.allgroup, | |
Game.enemygroup) | |
self.color = (random.randint(128, 255), 0, random.randint(128, 255)) | |
self.image = self.create_image() | |
self.rect = self.image.get_rect() | |
self.rect.center = self.pos | |
def create_image(self): | |
image = pygame.Surface((50,30)) | |
pygame.draw.polygon(image, | |
self.color, | |
((50,0),(0,15),(50,30),(40,15),(50,0))) | |
image.set_colorkey((0,0,0)) | |
image = image.convert_alpha() | |
return image | |
def update(self, dt): | |
self.pos += self.move * dt | |
if self.pos.x < 0: | |
self.kill() | |
if self.pos.y < 0: | |
self.pos.y = 0 | |
self.move.y *= -1 | |
if self.pos.y > Game.H: | |
self.pos.y = Game.H | |
self.move.y *= -1 | |
self.rect.center = self.pos | |
if random.random() < 1/Game.FPS / 10: | |
Plasma(self) | |
class Player(pygame.sprite.DirtySprite): | |
def __init__(self, pos): | |
self.pos = pos | |
self.speed = 55 | |
self.move = pygame.Vector2(0,0) | |
self.dirty = True | |
self.visible = True | |
self.blendmode = 0 | |
self._layer = 1 | |
self.hitpoints = 100 | |
self.hitpoints_full = 100 | |
pygame.sprite.DirtySprite.__init__(self, | |
Game.allgroup, | |
Game.playergroup) | |
self.create_image() | |
self.rect = self.image.get_rect() | |
self.rect.center = self.pos | |
self.laser_cooldown = 0.25 | |
self.laser_blocked = 0 | |
self.age = 0 | |
self.laser_version = 1 | |
self.wounds = [(0,0),(50,0),(-50,25)] | |
def fire_laser(self): | |
if self.age > self.laser_blocked: | |
#if self.laser_version == 1: | |
# pass | |
#elif self.laser_version == 2: | |
# pass | |
self.laser_blocked = self.age + self.laser_cooldown | |
match self.laser_version: | |
case 1: | |
Laser(self, move_direction=pygame.Vector2(5, 0)) | |
case 2: | |
Laser(self, move_direction=pygame.Vector2(15, 1)) | |
Laser(self, move_direction=pygame.Vector2(15, -1)) | |
case 3: | |
Laser(self, move_direction=pygame.Vector2(5, 1)) | |
Laser(self, move_direction=pygame.Vector2(5, 0)) | |
Laser(self, move_direction=pygame.Vector2(5, -1)) | |
case 4: | |
Laser(self, move_direction=pygame.Vector2(5, 2)) | |
Laser(self, move_direction=pygame.Vector2(15, 1)) | |
Laser(self, move_direction=pygame.Vector2(15, -1)) | |
Laser(self, move_direction=pygame.Vector2(5, -2)) | |
case 5: | |
Laser(self, move_direction=pygame.Vector2(5, 2)) | |
Laser(self, move_direction=pygame.Vector2(5, 1)) | |
Laser(self, move_direction=pygame.Vector2(5, 0)) | |
Laser(self, move_direction=pygame.Vector2(5, -1)) | |
Laser(self, move_direction=pygame.Vector2(5, -2)) | |
def create_image(self): | |
self.image = pygame.Surface((100,50)) | |
pygame.draw.polygon(self.image, | |
(100,100,255), | |
[(0,0),(100,25),(0,50),(15,25)]) | |
self.image.set_colorkey((0,0,0)) | |
self.image = self.image.convert_alpha() | |
def update(self, dt): | |
self.age += dt | |
pressed_keys = pygame.key.get_pressed() | |
self.move = pygame.Vector2(0,0) | |
if pressed_keys[pygame.K_w] or pressed_keys[pygame.K_UP]: | |
self.move.y -= self.speed | |
if pressed_keys[pygame.K_s] or pressed_keys[pygame.K_DOWN]: | |
self.move.y += self.speed | |
if pressed_keys[pygame.K_a] or pressed_keys[pygame.K_LEFT]: | |
self.move.x -= self.speed | |
if pressed_keys[pygame.K_d] or pressed_keys[pygame.K_RIGHT]: | |
self.move.x += self.speed | |
# bubble | |
#if self.move.x != 0 or self.move.y != 0: | |
# if random.random() < 0.25: | |
# # left top corner | |
# Bubble(pos=pygame.Vector2(self.pos.x - 50, self.pos.y-50), | |
# #move=pygame.Vector2(-self.speed * random.uniform(0.5, 1.5), 0), | |
# move = pygame.Vector2(-self.move.x, -self.move.y), | |
# radius_start=1, | |
# radius_end=5, | |
# radius_plusminus=5, | |
# color_start=(255, 255, 0), # gelb | |
# color_end=(255, 0, 0), # rot | |
# ) | |
# # left bottom corner | |
# Bubble(pos=pygame.Vector2(self.pos.x - 50, self.pos.y + 50), | |
# # move=pygame.Vector2(-self.speed * random.uniform(0.5, 1.5), 0), | |
# move=pygame.Vector2(-self.move.x, -self.move.y), | |
# radius_start=1, | |
# radius_end=5, | |
# radius_plusminus=5, | |
# color_start=(255, 255, 0), # gelb | |
# color_end=(255, 0, 0), # rot | |
# ) | |
# bewegung | |
self.pos += self.move * dt | |
self.rect.center = self.pos | |
# --- wounds --- | |
for w_pos in self.wounds: | |
c = (255, random.randint(0,255),0) # red or yellow | |
if random.random() < 3*1/Game.FPS: | |
Bubble(pos=(self.pos.x + w_pos[0], self.pos.y+w_pos[1]), | |
move=pygame.Vector2(Game.scrollspeed*5*sdrandom.uniform(0.9,1.1),random.uniform(-0.2,0.2)), | |
color_start=c, | |
color_end = (32,32,32), | |
alpha_end = 128, | |
radius_end=random.randint(5,10)) | |
# hp | |
if self.hitpoints <= 0: | |
self.kill() | |
class Plasma(pygame.sprite.DirtySprite): | |
x_speed = -80 | |
def __init__(self, | |
shooter, | |
): | |
pygame.sprite.DirtySprite.__init__(self, | |
Game.allgroup, | |
Game.plasmagroup) | |
self.image = self.create_image() | |
self.rect = self.image.get_rect() | |
self.pos = pygame.Vector2(shooter.pos.x, | |
shooter.pos.y) | |
self.rect.center = self.pos | |
self.x_speed += random.randint(-20,20) | |
def update(self, dt): | |
self.pos.x += self.x_speed * dt | |
self.image = self.create_image() | |
self.rect.center = self.pos | |
if self.pos.x < 0: | |
self.kill() | |
def create_image(self): | |
# green pulsating balls | |
image = pygame.Surface((100,50)) | |
for n,x in enumerate((25,45,60,70)): | |
c = (0,random.randint(128,255),0) | |
if n == 0: | |
r = random.randint(20,25) | |
elif n == 1: | |
r = random.randint(15,19) | |
elif n == 2: | |
r = random.randint(9,14) | |
elif n == 3: | |
r = random.randint(4,8) | |
pygame.draw.circle(image,c,(x,25),r) | |
image.set_colorkey((0,0,0)) | |
image = image.convert_alpha() | |
return image | |
class Laser(pygame.sprite.DirtySprite): | |
x_speed = 250 | |
def __init__(self, | |
shooter, | |
move_direction=pygame.Vector2(2,0), | |
color=(255, 0, 0), | |
speed_plusminus = 25, | |
): | |
pygame.sprite.DirtySprite.__init__(self, | |
Game.allgroup, | |
Game.lasergroup) | |
self.speed_plusminus = speed_plusminus | |
self.pos = pygame.Vector2(shooter.pos.x+50,shooter.pos.y) | |
move = move_direction.normalize() | |
self.move = move * (self.x_speed + random.randint(-self.speed_plusminus, self.speed_plusminus)) | |
self.color = color | |
self.image = self.create_image() | |
# rotate image ? | |
self.rect = self.image.get_rect() | |
self.rect.center = self.pos | |
def create_image(self): | |
image = pygame.Surface((10,10)) | |
#image.fill(self.color) | |
pygame.draw.rect(image, self.color,((0,6),(10,8))) | |
image.set_colorkey((0,0,0)) | |
image = image.convert_alpha() | |
image = pygame.transform.rotate(image, self.move.angle_to(pygame.Vector2(1,0))) | |
return image | |
def update(self,dt): | |
self.pos += self.move * dt | |
self.rect.center = self.pos | |
if self.pos.x > Game.W or self.pos.x < 0 or self.pos.y > Game.H or self.pos.y < 0: | |
self.kill() | |
class Bubble(pygame.sprite.DirtySprite): | |
def __init__(self, | |
pos, | |
move=pygame.Vector2(0,0), | |
radius_start = 1, | |
radius_end = 10, | |
radius_plusminus = 3, | |
color_start=(0,0,200), | |
color_end=(0,0,200), | |
#colordelta=30, | |
acc=1.0, | |
age_min = 2.0, | |
age_max = 4.0, | |
age_max_plusminus = 1.0, | |
alpha_start=255, | |
alpha_end=0, | |
): | |
self.dirty = True | |
self.visible = True | |
self.blendmode = 0 | |
self._layer = 2 | |
pygame.sprite.DirtySprite.__init__(self, Game.allgroup,) | |
self.pos = pygame.Vector2(pos[0],pos[1]) | |
self.move = pygame.Vector2(move[0], move[1]) | |
self.image = pygame.Surface((radius_end*2, radius_end*2)) | |
self.radius = radius_start | |
self.radius_start = radius_start | |
self.radius_end = radius_end + random.randint(-radius_plusminus, radius_plusminus) | |
self.color = [color_start[0], color_start[1], color_start[2]] | |
self.color_start = color_start | |
self.color_end = color_end | |
self.alpha = alpha_start | |
self.alpha_start = alpha_start | |
self.alpha_end = alpha_end | |
self.acc = acc | |
#self.age_max_plusminus = age_max_plusminus | |
self.age_max = age_max + random.uniform(-age_max_plusminus, age_max_plusminus) | |
self.age = 0 | |
self.draw_image() | |
self.rect = self.image.get_rect() | |
self.rect.center = self.pos | |
def draw_image(self): | |
pygame.draw.circle(self.image, # surface | |
self.color, # color | |
(self.radius_end, self.radius_end), # pos | |
self.radius, # radius | |
) | |
self.image.set_colorkey((0, 0, 0)) # black is transparent | |
self.image.set_alpha(self.alpha) | |
self.image = self.image.convert_alpha() | |
def update(self, dt): | |
self.age += dt | |
if self.age > self.age_max: | |
self.kill() | |
self.pos += self.move * dt | |
self.move *= self.acc | |
# kill on screen edge | |
if self.pos.x < 0 or self.pos.y < 0 or self.pos.x > Game.W or self.pos.y > Game.H: | |
self.kill() | |
self.age_percent = self.age / self.age_max | |
#self.color = [0,0,0] | |
for i in (0,1,2): | |
self.color[i] = int(self.color_start[i] + self.age_percent * (self.color_end[i] - self.color_start[i])) | |
self.color[i] = max(0, self.color[i]) | |
self.color[i] = min(255, self.color[i]) | |
#print(i, self.color[i]) | |
#print(self.age_percent, self.color) | |
# alpha: 0 is fully transparent, 255 is fully opaque | |
self.alpha = self.alpha_start + (self.alpha_end - self.alpha_start) * self.age_percent | |
self.image.fill((0,0,0)) # black | |
self.radius = self.radius_start + self.age_percent * (self.radius_end - self.radius_start) | |
self.draw_image() | |
self.rect.center = self.pos | |
class TextSprite(pygame.sprite.DirtySprite): | |
def __init__(self, pos, color, textsize, text, age_max, anchor="center" ): | |
self.dirty = True | |
self.visible = True | |
self.blendmode = 0 | |
self._layer = 9 | |
self.anchor = anchor | |
pygame.sprite.DirtySprite.__init__(self, Game.uigroup, Game.allgroup) | |
self.pos = pygame.Vector2(pos[0],pos[1]) | |
self.color = color | |
self.textsize = textsize | |
self.text = text | |
self.age = 0 | |
self.age_max = age_max | |
self.change_color = False | |
self.move = pygame.Vector2(0, 0) | |
self.bounce = False | |
self.create_text(self.text) | |
def create_text(self, text): | |
font = pygame.font.SysFont("System", self.textsize) | |
if self.change_color: | |
r,g,b = self.color | |
new_colors = [] | |
for old_color in r,g,b: | |
new_color = old_color + random.randint(-100,100) | |
new_color = max(10, new_color) | |
new_color = min(255, new_color) | |
new_colors.append(new_color) | |
else: | |
new_colors = self.color | |
self.image = font.render(text, True, new_colors) | |
self.rect = self.image.get_rect() | |
self.image.set_colorkey((0,0,0)) | |
self.image = self.image.convert_alpha() | |
self.rect.center = self.pos | |
def update(self, dt): | |
self.age += dt | |
if self.age_max is not None: | |
if self.age > self.age_max: | |
self.kill() | |
self.pos += self.move * dt | |
if self.change_color: | |
self.create_text(self.text) | |
if self.bounce: | |
if self.pos.x < 0: | |
self.pos.x = 0 | |
self.move.x *= -1 | |
if self.pos.x > W: | |
self.pos.x = W | |
self.move.x *= -1 | |
if self.pos.y < 0: | |
self.pos.y = 0 | |
self.move.y *= -1 | |
if self.pos.y > H: | |
self.pos.y = H | |
self.move.y *= -1 | |
if self.anchor == "center": | |
self.rect.center = self.pos | |
elif self.anchor == "topleft": | |
self.rect.topleft = self.pos | |
class Star(pygame.sprite.DirtySprite): | |
def __init__(self): | |
self.dirty = True | |
self.visible = True | |
self.blendmode = 0 | |
self._layer = 4 | |
pygame.sprite.DirtySprite.__init__(self, | |
Game.allgroup, Game.stargroup) | |
x = random.random() * Game.W | |
y = random.random() * Game.H | |
z = random.random() # 0...1 | |
self.pos = pygame.Vector3(x, y, z) | |
self.create_image() | |
def create_image(self): | |
size = int(self.pos.z * 5) + 1 | |
self.image = pygame.Surface((size,size)) | |
if size <= 2: | |
self.image.fill((255,255,255)) | |
else: | |
pygame.draw.circle(self.image, | |
(255,255,255), | |
(size/2, size/2), | |
size/2) | |
self.image.set_colorkey((0,0,0)) | |
self.image = self.image.convert_alpha() | |
self.rect = self.image.get_rect() | |
def create_background(): | |
Game.background = pygame.Surface((Game.W, Game.H)) | |
for _ in range(200): | |
Star() | |
#light = random.randint(64, 172) | |
#radius_max = 5 | |
#pygame.draw.circle(Game.background, (light, light, light), (random.randint(0, W), random.randint(0, H)), | |
# random.randint(1, radius_max)) | |
# big Asteroids font on center of background | |
font = pygame.font.SysFont("System", 256) | |
textsurface = font.render("Shooter", # text | |
True, # antialias | |
(32, 32, 32), # color | |
) | |
w, h = textsurface.get_rect().size | |
Game.background.blit(textsurface, | |
(Game.W / 2 - w / 2, Game.H / 2 - h / 2)) | |
# little "created by" font on right bottom corner of background | |
font = pygame.font.SysFont("System", 32) | |
textsurface = font.render("created 2024 by spielend-programmieren.at", # text | |
True, # antialias | |
(64, 64, 0), # color | |
) | |
w, h = textsurface.get_rect().size | |
Game.background.blit(textsurface, (Game.W - w - 10, Game.H - h - 5)) | |
def setup(): | |
# pygame setup | |
pygame.init() | |
#print("joystick:", pygame.joystick.get_init()) | |
#FPS = 60 # frames per seconds that we wish for (reality will be sometimes lower) | |
Game.screen = pygame.display.set_mode((Game.W, Game.H)) | |
Game.clock = pygame.time.Clock() | |
running = True | |
#dt = 0 | |
# sterne malen | |
create_background() | |
# sprites | |
Game.player1 = Player(pos=pygame.Vector2(200,400)) | |
#create_ui_layer() | |
#player1 = Player() | |
#ufo1 = Ufo(aliengroup, allgroup) | |
#score = 0 | |
#time_without_ufo = 0 | |
#ufo_timeout = 10 | |
#Game.scoretext1 = TextSprite((0,0),(0,255,0),32, | |
# "Score: 0 Shield: 5 s",None) | |
#w, h = Game.scoretext1.image.get_rect().size | |
#Game.scoretext1.pos = pygame.Vector2(w/2,h/2) | |
#new_wave() | |
#Game.energytext1 = TextSprite((0,40), (255,255,0), 32, f"energy: {int(Game.player1.energy/5000*50)}",None) | |
#w, h = Game.energytext1.image.get_rect().size | |
#Game.energytext1.pos = pygame.Vector2(w/2, h/2+20) | |
def mainloop(): | |
running = True | |
Game.screen.blit(Game.background, (0,0)) | |
pygame.display.flip() # once! | |
while running: | |
dt = Game.clock.tick(Game.FPS) / 1000 | |
pygame.display.set_caption(f"player one hp: {Game.player1.hitpoints} fps: {Game.clock.get_fps():.2f} ") | |
#pygame.display.flip() | |
for event in pygame.event.get(): | |
if event.type == pygame.QUIT: | |
running = False | |
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: | |
running = False | |
# --- cheats ---- | |
if event.type == pygame.KEYDOWN and event.key == pygame.K_1: | |
Game.player1.laser_version = 1 | |
if event.type == pygame.KEYDOWN and event.key == pygame.K_2: | |
Game.player1.laser_version = 2 | |
if event.type == pygame.KEYDOWN and event.key == pygame.K_3: | |
Game.player1.laser_version = 3 | |
if event.type == pygame.KEYDOWN and event.key == pygame.K_4: | |
Game.player1.laser_version = 4 | |
if event.type == pygame.KEYDOWN and event.key == pygame.K_5: | |
Game.player1.laser_version = 5 | |
pressed_keys = pygame.key.get_pressed() | |
# stars bewegen | |
for star in Game.stargroup: | |
star.pos.x += Game.scrollspeed * star.pos.z | |
if star.pos.x < 0: | |
star.pos.y = random.random() * Game.H | |
star.pos.x = (1+random.random()) * Game.W | |
#star.pos.y += Game.player1.move.y * star.pos.z | |
star.rect.center = pygame.Vector2(star.pos.x, star.pos.y) # - Game.screenpos | |
# enemy spawn | |
if random.random() < 1/Game.FPS /8 : | |
for _ in range(5): | |
Enemy1(pos=pygame.Vector2(Game.W + 10, | |
random.randint(10, Game.H-10))) | |
# enemy bewegen | |
for e in Game.enemygroup: | |
e.update(dt) | |
# plasma bewegen | |
for p in Game.plasmagroup: | |
p.update(dt) | |
# player bewegen | |
for p in Game.playergroup: | |
p.update(dt) | |
# fire Laser | |
if pressed_keys[pygame.K_SPACE]: | |
Game.player1.fire_laser() | |
# collide player and enemy | |
for player in Game.playergroup: | |
crashgroup = pygame.sprite.spritecollide(player, Game.enemygroup, False) | |
for enemy in crashgroup: | |
enemy.kill() | |
player.hitpoints -= 1 | |
# collide laser and enemy | |
for beam in Game.lasergroup: | |
crashgroup = pygame.sprite.spritecollide(beam, Game.enemygroup, False) | |
for enemy in crashgroup: | |
for _ in range(20): | |
m = pygame.Vector2(1 + random.random() * 40, 0) | |
m.rotate_ip(random.random() * 360) | |
Bubble(enemy.pos, m,color_start=enemy.color, color_end=(0,0,255 )) | |
enemy.kill() | |
beam.kill() | |
# sprites zeichnen | |
Game.allgroup.clear(Game.screen, Game.background) | |
Game.allgroup.update(dt) | |
for s in Game.allgroup: | |
s.dirty = True | |
dirty = Game.allgroup.draw(Game.screen) | |
pygame.display.update(dirty) | |
# game over: | |
if len(Game.playergroup) == 0: | |
running = False | |
pygame.quit() | |
if __name__ == "__main__": | |
setup() | |
mainloop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment