Skip to content

Instantly share code, notes, and snippets.

@horstjens
Created November 12, 2024 08:08
Show Gist options
  • Save horstjens/23c1256ad45d0dc7488a6c9c332068c4 to your computer and use it in GitHub Desktop.
Save horstjens/23c1256ad45d0dc7488a6c9c332068c4 to your computer and use it in GitHub Desktop.
import pygame
import random
import math
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 Enemy2(pygame.sprite.DirtySprite):
def __init__(self, pos, dx=-50, yf=50, age=0):
self.y_factor = yf
self.pos = pos
self.age = age
self.dx = dx
#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,50))
pygame.draw.circle(image,self.color,(25,25),25)
pygame.draw.circle(image, (0,0,0), (25, 25), 18)
image.set_colorkey((0,0,0))
image = image.convert_alpha()
return image
def update(self, dt):
self.age += dt
self.dy = math.sin(self.age) * self.y_factor
self.move = pygame.Vector2(self.dx, self.dy)
self.pos += self.move * dt
if self.pos.x < 0:
self.kill()
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*random.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((20,30,40,50)):
c = (0,random.randint(128,255),0)
if n == 0:
r = random.randint(7,11)
elif n == 1:
r = random.randint(6,10)
elif n == 2:
r = random.randint(5,9)
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 > Game.W:
self.pos.x = Game.W
self.move.x *= -1
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
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
# enemy1 spawn
if random.random() < 1/Game.FPS /10 :
for _ in range(5):
Enemy1(pos=pygame.Vector2(Game.W + 10,
random.randint(10, Game.H-10)))
# enemy2 spawn
if random.random() < 1/Game.FPS / 5:
yf = random.randint(-100,100)
y = random.randint(50, Game.H - 50)
dx = random.randint(15,25)
delta_age = random.uniform(0.1, 0.3)
dx = random.uniform(10,30) * -1
for x in range(10):
Enemy2(pygame.Vector2(Game.W * 1.5 + dx*x, y),
dx,
yf,
x * delta_age)
# 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