I’ve been working on a homemade Space Invaders game recently. During the development process, I used Pygame’s set_alpha()
to draw semi-transparent images. However, despite seemingly correct parameter settings, set_alpha()
didn’t work as expected.
I employed a CreateSprite class to easily set up characters, and used an opacity parameter to set transparency from 0 to 1. In the update() method, I used set_alpha(int(self.opacity*255))
on all costumes. The calculated value self.opacity*255
appears correct, yet set_alpha()
remains ineffective. Below are snippets of the code and the complete script.
"""Space Invaders"""
import pygame
import sys
import random
import math
from pygame.locals import *
pygame.init()
width, height = 1200, 675
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Space Invaders")
pygame.display.set_icon(pygame.image.load("image/master/3.png").convert_alpha())
clock = pygame.time.Clock()
idx = 0
tmr = 0
level = 0
count = 0
playerlife = 0
masterlife = 0
vx = 2
enemy_move_table = {300: [1, 0],
325: [0, 1],
625: [-1, 0],
650: [0, 1]}
key = []
sprite = []
enemy = []
lasers = []
class CreateSprite:
def __init__(self, costume, x=None, y=None, opacity=1, hidden=False, direction=0, scale=1):
self.costume = [pygame.image.load(i).convert_alpha() for i in costume]
self.id = 0
self.width = self.costume[self.id].get_width()
self.height = self.costume[self.id].get_height()
self.x = x if x is not None else self.center()[0]
self.y = y if y is not None else self.center()[1]
self.rect = self.costume[self.id].get_rect(topleft=(self.x, self.y))
self.opacity = opacity
self.hidden = hidden
self.direction = direction
self.scale = scale
sprite.append(self)
def _update(self):
self.width = self.costume[self.id].get_width()
self.height = self.costume[self.id].get_height()
self.rect = self.costume[self.id].get_rect(topleft=(self.x, self.y))
for i, c in enumerate(self.costume):
self.costume[i] = c.copy()
self.costume[i].set_alpha(int(self.opacity * 255))
def center(self):
return ((width - self.width) // 2,
(height - self.height) // 2)
def locate(self, x, y):
self.x = x
self.y = y
def collide(self, sprite):
return self.rect.colliderect(sprite.rect) if not self.hidden and not sprite.hidden else False
def delete(self):
self.hidden = True
del self
def step(self, distance):
self.x += distance * math.cos(math.radians(self.direction))
self.y -= distance * math.sin(math.radians(self.direction))
bg = CreateSprite(["image/bg.png"], 0, -1125, hidden=True)
player = CreateSprite(["image/player.png"], y=500, hidden=True)
master = CreateSprite([f"image/master/{i}.png" for i in range(1, 4)], y=0, hidden=True)
laser = CreateSprite(["image/laser/b.png"], y=600, hidden=True, direction=90)
title = CreateSprite(["image/info.png"], opacity=0.7)
fail = CreateSprite(["image/fail.png"], opacity=0)
fire = pygame.mixer.Sound("sound/laser.mp3")
boom = pygame.mixer.Sound("sound/boom.mp3")
died = pygame.mixer.Sound("sound/boom.mp3")
fire.set_volume(0.4)
died.set_volume(2)
pygame.mixer.music.load("sound/bgm.mp3")
pygame.mixer.music.set_volume(1.5)
pygame.mixer.music.play(-1)
def init_level():
global tmr, level, count, playerlife, masterlife
tmr = -40
level += 1
count = 0
playerlife = 10
masterlife = 10 * level
enemy.clear()
for y in range(level):
for x in range(10):
enemy.append(CreateSprite([f"image/enemy/{level}.png"], 40 + 80 * x, -320 + 80 * y, scale=0.8))
master.id = level - 1
master.y -= 500
master.hidden = False
def update():
screen.fill(0)
screen.blit(bg.costume[bg.id], (bg.x, bg.y))
screen.blit(bg.costume[bg.id], (bg.x, bg.y + 1800))
for s in sprite:
s._update()
if not s.hidden:
screen.blit(pygame.transform.rotozoom(s.costume[s.id], s.direction, s.scale), (s.x, s.y))
pygame.display.update()
clock.tick(60)
def move_bg():
bg.y += 2
if bg.y > 0:
bg.y -= 1800
def move_player():
if player.x > 0 and key[K_LEFT]:
player.x -= 6
if player.x < width - player.width and key[K_RIGHT]:
player.x += 6
if (laser.hidden or laser.y < 0) and key[K_SPACE]:
laser.locate(player.x + player.width / 2 - laser.width / 2, player.y)
laser.hidden = False
fire.play()
def move_master():
global vx, masterlife
if tmr < 0: master.y += 12.5
master.x += vx
if master.x > width - master.width or master.x < 0 or random.random() < 0.01:
vx = -vx
if master.collide(laser):
masterlife -= 1
laser.hidden = True
boom.play()
if masterlife <= 0 and not master.hidden:
master.hidden = True
died.play(1)
if random.random() < 0.01 * level and masterlife > 0:
fire_laser(master.x + master.width // 2 - laser.width // 2,
master.y + master.height - laser.height // 2, 270)
def move_enemy(e):
global count, playerlife
if tmr < 0: e.y += 12.5
if e.y > height - e.height - player.height: playerlife = 0
if e.collide(laser):
e.delete()
laser.hidden = True
count += 1
boom.play()
for i in range(0, 361, 72):
fire_laser(e.x+e.width//2-laser.width//2, e.y+e.height//2-laser.height//2, i)
for key, value in enemy_move_table.items():
if tmr % 650 < key:
e.x += value[0]
e.y += value[1]
break
def move_lasers():
laser.y -= 20
for l in lasers:
l.step(5)
def fire_laser(x, y, direction):
lasers.append(CreateSprite(["image/laser/r.png"], x, y, direction=direction))
def loop():
if playerlife > 0:
move_player()
move_master()
move_lasers()
for e in enemy:
move_enemy(e)
if master.hidden and count == 10 * level:
if level <= 2:
init_level()
else:
fail.opacity += 0.01
def main():
global idx, tmr, key, screen
fullscreen = False
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_F11 and not fullscreen:
screen = pygame.display.set_mode((width, height), pygame.FULLSCREEN)
fullscreen = True
if event.key == K_ESCAPE and fullscreen:
screen = pygame.display.set_mode((width, height))
fullscreen = False
if event.type == MOUSEBUTTONDOWN and idx == 0:
player.hidden = False
title.hidden = True
master.hidden = False
init_level()
idx = 1
key = pygame.key.get_pressed()
if idx == 1:
loop()
tmr += 1
move_bg()
update()
if __name__ == "__main__":
main()
I’ve tried title.costume[0].set_alpha(150)
on its own, but it had no effect. I also attempted to print(s.opacity and s.opacity*255)
in the update function, and everything appears normal. Where could the issue possibly lie?
2