5 Asterioids Pygame Project
6 Python과 Pygame으로 소행성 게임 만들기
이 폴더의 코드는 Python과 Pygame으로 소행성 게임 만들기 튜토리얼을 보충합니다.
프로젝트의 10단계 각각에 대한 하위 폴더 1개와 전체 게임의 최종 소스 코드가 포함된 하위 폴더 1개, 총 11개의 하위 폴더가 있습니다.
6.1 파일: source_code_final/space_rocks/__main__.py
from game import SpaceRocks
if __name__ == "__main__":
space_rocks = SpaceRocks()
space_rocks.main_loop()6.2 파일: source_code_final/space_rocks/game.py
import pygame
from models import Asteroid, Spaceship
from utils import get_random_position, load_sprite, print_text
class SpaceRocks:
MIN_ASTEROID_DISTANCE = 250
def __init__(self):
self._init_pygame()
self.screen = pygame.display.set_mode((800, 600))
self.background = load_sprite("space", False)
self.clock = pygame.time.Clock()
self.font = pygame.font.Font(None, 64)
self.message = ""
self.asteroids = []
self.bullets = []
self.spaceship = Spaceship((400, 300), self.bullets.append)
for _ in range(6):
while True:
position = get_random_position(self.screen)
if (
position.distance_to(self.spaceship.position)
> self.MIN_ASTEROID_DISTANCE
):
break
self.asteroids.append(Asteroid(position, self.asteroids.append))
def main_loop(self):
while True:
self._handle_input()
self._process_game_logic()
self._draw()
def _init_pygame(self):
pygame.init()
pygame.display.set_caption("Space Rocks")
def _handle_input(self):
for event in pygame.event.get():
if event.type == pygame.QUIT or (
event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE
):
quit()
elif (
self.spaceship
and event.type == pygame.KEYDOWN
and event.key == pygame.K_SPACE
):
self.spaceship.shoot()
is_key_pressed = pygame.key.get_pressed()
if self.spaceship:
if is_key_pressed[pygame.K_RIGHT]:
self.spaceship.rotate(clockwise=True)
elif is_key_pressed[pygame.K_LEFT]:
self.spaceship.rotate(clockwise=False)
if is_key_pressed[pygame.K_UP]:
self.spaceship.accelerate()
def _process_game_logic(self):
for game_object in self._get_game_objects():
game_object.move(self.screen)
if self.spaceship:
for asteroid in self.asteroids:
if asteroid.collides_with(self.spaceship):
self.spaceship = None
self.message = "You lost!"
break
for bullet in self.bullets[:]:
for asteroid in self.asteroids[:]:
if asteroid.collides_with(bullet):
self.asteroids.remove(asteroid)
self.bullets.remove(bullet)
asteroid.split()
break
for bullet in self.bullets[:]:
if not self.screen.get_rect().collidepoint(bullet.position):
self.bullets.remove(bullet)
if not self.asteroids and self.spaceship:
self.message = "You won!"
def _draw(self):
self.screen.blit(self.background, (0, 0))
for game_object in self._get_game_objects():
game_object.draw(self.screen)
if self.message:
print_text(self.screen, self.message, self.font)
pygame.display.flip()
self.clock.tick(60)
def _get_game_objects(self):
game_objects = [*self.asteroids, *self.bullets]
if self.spaceship:
game_objects.append(self.spaceship)
return game_objects6.3 파일: source_code_final/space_rocks/models.py
from pygame.math import Vector2
from pygame.transform import rotozoom
from utils import get_random_velocity, load_sound, load_sprite, wrap_position
UP = Vector2(0, -1)
class GameObject:
def __init__(self, position, sprite, velocity):
self.position = Vector2(position)
self.sprite = sprite
self.radius = sprite.get_width() / 2
self.velocity = Vector2(velocity)
def draw(self, surface):
blit_position = self.position - Vector2(self.radius)
surface.blit(self.sprite, blit_position)
def move(self, surface):
self.position = wrap_position(self.position + self.velocity, surface)
def collides_with(self, other_obj):
distance = self.position.distance_to(other_obj.position)
return distance < self.radius + other_obj.radius
class Spaceship(GameObject):
MANEUVERABILITY = 3
ACCELERATION = 0.25
BULLET_SPEED = 3
def __init__(self, position, create_bullet_callback):
self.create_bullet_callback = create_bullet_callback
self.laser_sound = load_sound("laser")
# Make a copy of the original UP vector
self.direction = Vector2(UP)
super().__init__(position, load_sprite("spaceship"), Vector2(0))
def rotate(self, clockwise=True):
sign = 1 if clockwise else -1
angle = self.MANEUVERABILITY * sign
self.direction.rotate_ip(angle)
def accelerate(self):
self.velocity += self.direction * self.ACCELERATION
def draw(self, surface):
angle = self.direction.angle_to(UP)
rotated_surface = rotozoom(self.sprite, angle, 1.0)
rotated_surface_size = Vector2(rotated_surface.get_size())
blit_position = self.position - rotated_surface_size * 0.5
surface.blit(rotated_surface, blit_position)
def shoot(self):
bullet_velocity = self.direction * self.BULLET_SPEED + self.velocity
bullet = Bullet(self.position, bullet_velocity)
self.create_bullet_callback(bullet)
self.laser_sound.play()
class Asteroid(GameObject):
def __init__(self, position, create_asteroid_callback, size=3):
self.create_asteroid_callback = create_asteroid_callback
self.size = size
size_to_scale = {3: 1.0, 2: 0.5, 1: 0.25}
scale = size_to_scale[size]
sprite = rotozoom(load_sprite("asteroid"), 0, scale)
super().__init__(position, sprite, get_random_velocity(1, 3))
def split(self):
if self.size > 1:
for _ in range(2):
asteroid = Asteroid(
self.position, self.create_asteroid_callback, self.size - 1
)
self.create_asteroid_callback(asteroid)
class Bullet(GameObject):
def __init__(self, position, velocity):
super().__init__(position, load_sprite("bullet"), velocity)
def move(self, surface):
self.position = self.position + self.velocity6.4 파일: source_code_final/space_rocks/utils.py
import random
from pygame import Color
from pygame.image import load
from pygame.math import Vector2
from pygame.mixer import Sound
def load_sprite(name, with_alpha=True):
path = f"assets/sprites/{name}.png"
loaded_sprite = load(path)
if with_alpha:
return loaded_sprite.convert_alpha()
else:
return loaded_sprite.convert()
def load_sound(name):
path = f"assets/sounds/{name}.wav"
return Sound(path)
def wrap_position(position, surface):
x, y = position
w, h = surface.get_size()
return Vector2(x % w, y % h)
def get_random_position(surface):
return Vector2(
random.randrange(surface.get_width()),
random.randrange(surface.get_height()),
)
def get_random_velocity(min_speed, max_speed):
speed = random.randint(min_speed, max_speed)
angle = random.randrange(0, 360)
return Vector2(speed, 0).rotate(angle)
def print_text(surface, text, font, color=Color("tomato")):
text_surface = font.render(text, False, color)
rect = text_surface.get_rect()
rect.center = Vector2(surface.get_size()) / 2
surface.blit(text_surface, rect)