1
0
forked from ndyer/pygame-dvd

Compare commits

..

No commits in common. "main" and "main" have entirely different histories.
main ... main

10 changed files with 163 additions and 241 deletions

View File

@ -1,3 +1,3 @@
# Steam Logo Screensaver
# pygame-dvd
It's the Steam logo bouncing around in Pygame.
It's the DVD logo bouncing around in pygame.

View File

@ -1,4 +1,4 @@
import steam_saver
import dvd_bounce
import sys
import os
@ -11,4 +11,4 @@ if __name__ == '__main__':
if arg == '--window':
windowed_mode = True
steam_saver.main.main(windowed_mode)
dvd_bounce.main.main(windowed_mode)

View File

@ -1,26 +1,14 @@
import pygame
import subprocess
import steam_saver.surfaces as surfaces
import dvd_bounce.surfaces as surfaces
# Global variables
FPS = 90
SCREEN_SIZE = (1920, 1080)
FPS = 60
VALID_SURFACES = [
'steam_screen'
'dvd_screen'
]
def get_screen_resolution():
"""
Gets the current resolution using xrandr
Returns:
tuple: The current resolution as a tuple.
"""
command_output = subprocess.check_output(['xrandr']).decode('utf-8')
for line in command_output.split('\n'):
if '*' in line:
return tuple(map(int, line.split()[0].split('x')))
def main(windowed_mode=False):
"""
Main scene manager to display the scenes of the application
@ -28,16 +16,13 @@ def main(windowed_mode=False):
"""
pygame.init()
clock = pygame.time.Clock()
screen_size = get_screen_resolution()
if windowed_mode:
window = pygame.display.set_mode(screen_size)
window = pygame.display.set_mode(SCREEN_SIZE)
else:
window = pygame.display.set_mode(screen_size, pygame.FULLSCREEN)
window = pygame.display.set_mode(SCREEN_SIZE, pygame.FULLSCREEN)
# Starts the program with the surface 'steam_screen' as the default
surface = getattr(globals()['surfaces'], 'steam_screen').Surface(screen_size)
# Starts the program with the surface 'dial' as the default
surface = getattr(globals()['surfaces'], 'dvd_screen').Surface(SCREEN_SIZE)
running = True
while running:
clock.tick(FPS)
@ -52,7 +37,7 @@ def main(windowed_mode=False):
next_surface = surface.next_surface
if next_surface not in VALID_SURFACES:
raise Exception('Given surface is not a valid surface!')
surface = getattr(globals()['surfaces'], next_surface).Surface(screen_size)
surface = getattr(globals()['surfaces'], next_surface).Surface(SCREEN_SIZE)
pygame.display.flip()
pygame.quit()

View File

@ -0,0 +1 @@
from . import dvd_screen

View File

@ -0,0 +1,149 @@
import pygame
import os
import random
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
LOGO_SCALING = 0.1
class DVDLogo(pygame.sprite.Sprite):
"""
A Pygame sprite representing a DVD logo that moves around the screen.
Attributes:
base_image (pygame.Surface): The original image of the DVD logo.
x_speed (int): Current speed in the X axis.
y_speed (int): Current speed in the Y axis.
max_x (int): Maximum X position on the screen.
max_y (int): Maximum Y position on the screen.
"""
def __init__(self, window_size: tuple):
"""
Initialize DVDLogo sprite with given window size.
Args:
window_size (tuple): Size of the game window (width, height).
"""
super().__init__()
# Load and scale original logo image
self.base_image = pygame.image.load(SCRIPT_DIR + '/resources/dvd.png')
self.base_image.convert_alpha()
self.base_image = pygame.transform.scale(self.base_image, (self.base_image.get_width() * LOGO_SCALING,
self.base_image.get_height() * LOGO_SCALING))
# Copy the base image and store it in a separate instance variable; this is the image that will be drawn.
self.image = self.base_image.copy()
# Generate random color and apply it to the sprite.
self.random_color()
# Initialize rectangle (position, size) and speed attributes.
self.rect = self.image.get_rect()
self.x_speed = 4
self.y_speed = 4
# Calculate maximum X and Y positions on the screen for boundary checking.
self.max_x = window_size[0] - self.rect.width
self.max_y = window_size[1] - self.rect.height
def random_color(self):
"""
Generate a new, random color and apply it to the sprite.
"""
# Create a surface with alpha channel for generating transparent colors.
color_surface = pygame.Surface(self.image.get_size(), pygame.SRCALPHA)
# Generate random RGB values and fill the color surface accordingly.
new_color = (random.randint(32, 255),
random.randint(32, 255),
random.randint(32, 255))
color_surface.fill(new_color)
# Replace the drawn image with a copy of the base image and apply the randomly generated color.
self.image = self.base_image.copy()
self.image.blit(color_surface, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
def update(self):
"""
Update DVDLogo sprite's position and speed based on its current state.
This method is called each frame during game execution to move the logo around
the screen and to handle collision/color changes.
"""
# Move the logo in the X and Y axis according to its current speed in those directions.
self.rect.x += self.x_speed
self.rect.y += self.y_speed
# Check for collisions with edges of the screen, change direction if necessary,
# and generate a new random color when hitting an edge.
if self.rect.x < 0 or self.rect.x > self.max_x:
self.x_speed *= -1
self.random_color()
if self.rect.y < 0 or self.rect.y > self.max_y:
self.y_speed *= -1
self.random_color()
# Ensure the logo stays within screen boundaries by clamping its position.
self.rect.x = max(0, min(self.rect.x, self.max_x))
self.rect.y = max(0, min(self.rect.y, self.max_y))
class Surface(pygame.Surface):
"""
A custom Pygame surface class for managing game logic and events.
Attributes:
running (bool): Flag indicating whether the surface is still running.
quit (bool): Flag signaling that the program should end rather than moving to a new surface.
next_surface (str): Name of the next surface to display after current one stops.
all_sprites (pygame.sprite.Group): A group containing sprites for easy sprite management.
"""
def __init__(self, window_size: tuple):
"""
Initialize Surface class with given window size.
Args:
window_size (tuple): Size of the game window (width, height).
"""
# Create a Pygame surface with alpha channel for generating transparent colors.
super().__init__(window_size, pygame.SRCALPHA)
# Initialize flags and attributes for managing game state.
self.running = True
self.quit = False
self.next_surface = ''
pygame.mouse.set_visible(False)
# Create a DVDLogo sprite instance and add it to the sprite group.
dvd_logo = DVDLogo(window_size)
self.all_sprites = pygame.sprite.Group(dvd_logo)
def update(self):
"""
Update game state by handling events, updating sprites, and redrawing surfaces.
This method is called every frame during game execution.
"""
# Fill the surface with a black background color
self.fill(pygame.colordict.THECOLORS.get('black'))
# Handle events such as mouse button clicks or key presses.
for event in pygame.event.get():
match event.type:
case pygame.MOUSEBUTTONDOWN:
# Stop the game when a user clicks anywhere on the screen.
self.running = False
self.quit = True
# Update positions and speeds of all sprites (in this case, just one logo sprite).
self.all_sprites.update()
# Draw all sprites onto this surface.
self.all_sprites.draw(self)

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View File

@ -1 +0,0 @@
from . import steam_screen

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

View File

@ -1,212 +0,0 @@
import pygame
import os
import random
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
SCALE_RATIO = (0.325 / 800.0)
SPEED_RATIO = (2.5 / 800.0)
class SteamLogo(pygame.sprite.Sprite):
"""
A Pygame sprite representing a Steam logo that moves around the screen.
Attributes:
base_image (pygame.Surface): The original image of the Steam logo.
x_speed (int): Current speed in the X axis.
y_speed (int): Current speed in the Y axis.
max_x (int): Maximum X position on the screen.
max_y (int): Maximum Y position on the screen.
is_mini (bool): Bool to determine whether the logo is a mini (background) logo or not.
"""
def __init__(self, window_size: tuple, is_mini: bool = False, *groups):
"""
Initialize SteamLogo sprite with given window size.
Args:
window_size (tuple): Size of the game window (width, height).
is_mini (bool): Determines if the logo is going to be a background logo (mini) or the foreground one.
"""
super().__init__(*groups)
self.is_mini = is_mini
# Load and scale original logo image
self.base_image = pygame.image.load(SCRIPT_DIR + '/resources/steam_logo.png')
self.base_image.convert_alpha()
logo_scaling = min(window_size) * SCALE_RATIO
# If the logo is mini, make it 2 to 3 times smaller
if is_mini:
logo_scaling /= random.uniform(2, 3)
self.base_image = pygame.transform.smoothscale(self.base_image,
(self.base_image.get_width() * logo_scaling,
self.base_image.get_height() * logo_scaling))
# Copy the base image and store it in a separate instance variable; this is the image that will be drawn.
self.image = self.base_image.copy()
# Generate random color and apply it to the sprite.
self.random_color()
# Initialize rectangle (position, size) and speed attributes.
self.rect = self.image.get_rect()
self.max_speed = min(window_size) * SPEED_RATIO
# Make it so that the logo travels in a random direction when created
self.x_speed = (self.max_speed - 1) * random.choice([-1, 1])
self.y_speed = (self.max_speed - 1) * random.choice([-1, 1])
# Calculate maximum X and Y positions on the screen for boundary checking.
self.max_x = window_size[0] - self.rect.width
self.max_y = window_size[1] - self.rect.height
# The position of the logo is determined by float values that are separate from the Pygame rect position.
# By storing the position as a float and drawing it to the screen after, we are able to apply more precise
# speed values (e.g. 2.124) and it will appear as though it is moving smoothly.
# The starting location of the logo is randomized.
self.float_x = random.random() * self.max_x
self.float_y = random.random() * self.max_y
self.rect.x = self.float_x
self.rect.y = self.float_y
def random_color(self):
"""
Generate a new, random color and apply it to the sprite.
"""
# Create a surface with alpha channel for generating transparent colors.
color_surface = pygame.Surface(self.image.get_size(), pygame.SRCALPHA)
# Generate random RGB values and fill the color surface accordingly.
new_color = (random.randint(64, 255),
random.randint(64, 255),
random.randint(64, 255))
# If this is a mini logo, make it 80% darker
if self.is_mini:
color_surface.fill(tuple(int(x / 5) for x in new_color))
else: # If not, make it the generated color.
color_surface.fill(new_color)
# Replace the drawn image with a copy of the base image and apply the randomly generated color.
self.image = self.base_image.copy()
self.image.blit(color_surface, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
def update(self):
"""
Update SteamLogo sprite's position and speed based on its current state.
This method is called each frame during game execution to move the logo around
the screen and to handle collision/color changes.
"""
# Move the logo in the X and Y axis according to its current speed in those directions.
self.float_x += self.x_speed
self.float_y += self.y_speed
# Check for collisions with edges of the screen, change direction if necessary,
# and generate a new random color when hitting an edge.
if self.float_x < 0 or self.float_x > self.max_x:
# Mini logos have some randomness built into their bounce function to make the background look more organic.
if self.is_mini:
# Reflect off the left or right wall, clamping the speed (in case it was raised too high)
# The speed gets clamped if it goes above the max speed or below the starting speed (max - 1)
if self.x_speed > 0:
self.x_speed = max(-1 * self.max_speed, min((self.x_speed * -1), (-1 * self.max_speed) + 1))
else:
self.x_speed = max(self.max_speed - 1, min((self.x_speed * -1), self.max_speed))
# Add or subtract anywhere from 0 to 10% of the max speed to the vertical speed component
self.y_speed += random.uniform(self.max_speed * 0.1, self.max_speed * -0.1)
# If the logo isn't mini, do a simple reflection with no fancy stuff.
else:
self.x_speed *= -1
self.random_color()
# Do the same stuff for the top and bottom walls
if self.float_y < 0 or self.float_y > self.max_y:
if self.is_mini:
if self.y_speed > 0:
self.y_speed = max(-1 * self.max_speed, min((self.y_speed * -1), (-1 * self.max_speed) + 1))
else:
self.y_speed = max(self.max_speed - 1, min((self.y_speed * -1), self.max_speed))
self.x_speed += random.uniform(self.max_speed * 0.1, self.max_speed * -0.1)
else:
self.y_speed *= -1
self.random_color()
# Ensure the logo stays within screen boundaries by clamping its position.
self.float_x = max(0, min(self.float_x, self.max_x))
self.float_y = max(0, min(self.float_y, self.max_y))
# Set the Pygame rectangle's position to the stored floating point position
self.rect.x = self.float_x
self.rect.y = self.float_y
class Surface(pygame.Surface):
"""
A custom Pygame surface class for managing game logic and events.
Attributes:
running (bool): Flag indicating whether the surface is still running.
quit (bool): Flag signaling that the program should end rather than moving to a new surface.
next_surface (str): Name of the next surface to display after current one stops.
all_sprites (pygame.sprite.Group): A group containing sprites for easy sprite management.
"""
def __init__(self, window_size: tuple):
"""
Initialize Surface class with given window size.
Args:
window_size (tuple): Size of the game window (width, height).
"""
# Create a Pygame surface with alpha channel for generating transparent colors.
super().__init__(window_size, pygame.SRCALPHA)
# Initialize flags and attributes for managing game state.
self.running = True
self.quit = False
self.next_surface = ''
pygame.mouse.set_visible(False)
self.all_sprites = pygame.sprite.Group()
# Create all the mini Steam logos
for i in range(25):
self.all_sprites.add(SteamLogo(window_size, is_mini=True))
# Create the big Steam logo
self.all_sprites.add(SteamLogo(window_size))
def update(self):
"""
Update game state by handling events, updating sprites, and redrawing surfaces.
This method is called every frame during game execution.
"""
# Fill the surface with a black background color
self.fill(pygame.colordict.THECOLORS.get('black'))
# Handle events such as mouse button clicks or key presses.
for event in pygame.event.get():
match event.type:
case pygame.MOUSEBUTTONDOWN:
# Stop the game when a user clicks anywhere on the screen.
self.running = False
self.quit = True
case pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
# Also stop the game if the Escape key is pressed.
self.running = False
self.quit = True
# Update positions and speeds of all sprites
self.all_sprites.update()
# Draw all sprites onto this surface.
self.all_sprites.draw(self)