Initial Commit
This commit is contained in:
572
lib/level.py
Normal file
572
lib/level.py
Normal file
@@ -0,0 +1,572 @@
|
||||
#!~/.pyenv/versions/3.11.6/bin/python
|
||||
#
|
||||
# Copyright (c) 2024 Cutieguwu | Olivia Brooks
|
||||
#
|
||||
# -*- coding:utf-8 -*-
|
||||
# @Title: Levels in a game.
|
||||
# @Author: Cutieguwu | Olivia Brooks
|
||||
# @Email: owen.brooks77@gmail.com | obroo2@ocdsb.ca
|
||||
# @Description: Classes descibing different levels in a pygame game.
|
||||
#
|
||||
# @Script: level.py
|
||||
# @Date Created: 16 Apr, 2024
|
||||
# @Last Modified: 19 Jun, 2024
|
||||
# @Last Modified by: Cutieguwu | Olivia Brooks
|
||||
# ----------------------------------------------------------
|
||||
|
||||
import pygame
|
||||
from pygame import mixer
|
||||
from pygame.image import load
|
||||
from icecream import ic
|
||||
from lib.system import DIRWORKING, FEATURES
|
||||
from lib.section import Section, Blocks
|
||||
from lib.interface import Button, Checkbox
|
||||
from lib.entity import * # Bad practise and loads player class, but loads all entities for easy reference.
|
||||
|
||||
|
||||
class Level():
|
||||
"""
|
||||
Creates and manages the level scape.
|
||||
"""
|
||||
|
||||
def __init__(self, game):
|
||||
self.GAME = game
|
||||
self.WINDOW = self.GAME.WINDOW
|
||||
self.SCALE = self.GAME.SCALE
|
||||
self.SECTION = Section(self.GAME)
|
||||
self.FRAMES = Frames(self.GAME)
|
||||
|
||||
self.layout = Menus.Blank()
|
||||
|
||||
self.dx = 0
|
||||
self.dy = 0
|
||||
|
||||
self.musicStartTime = 0
|
||||
|
||||
if self.layout.TYPE == "level":
|
||||
self.get_level_size()
|
||||
|
||||
def draw(self):
|
||||
"""
|
||||
Draws the level on the screen.
|
||||
"""
|
||||
|
||||
if self.layout.TYPE == "level":
|
||||
self.SECTION.draw(self.layout.LAYOUT)
|
||||
elif self.layout.TYPE == "scene":
|
||||
self.FRAMES.draw()
|
||||
|
||||
try:
|
||||
if pygame.time.get_ticks() - self.musicStartTime >= self.layout.MUSIC.get_length() * 1000:
|
||||
ic(self.layout.MUSIC.play())
|
||||
self.musicStartTime = pygame.time.get_ticks()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def load_layout(self, layout:object, startPositionKey="default"):
|
||||
"""
|
||||
Load a new layout configuration.
|
||||
"""
|
||||
|
||||
self.GAME.playerActionMove = "neutral"
|
||||
|
||||
try:
|
||||
ic(self.layout.MUSIC.stop())
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if self.layout.TYPE == "menu":
|
||||
for interactable in self.layout.INTERACTABLES:
|
||||
interactable.remove()
|
||||
|
||||
layout = layout(game=self.GAME)
|
||||
|
||||
if isinstance(layout, Menus.Pause): # Save the level state before loading something that isn't the next level.
|
||||
self.save_level_state()
|
||||
|
||||
if self.layout.TYPE == "level" and layout.TYPE != "level":
|
||||
self.GAME.levelOn = False
|
||||
elif self.layout.TYPE == "menu" and layout.TYPE != "menu":
|
||||
self.GAME.menuOn = False
|
||||
elif self.layout.TYPE == "scene" and layout.TYPE != "scene":
|
||||
self.GAME.sceneOn = False
|
||||
|
||||
if self.layout.TYPE == "level":
|
||||
for entity in self.GAME.entityList:
|
||||
entity.destroy()
|
||||
|
||||
self.layout = layout
|
||||
ic(self.layout.__class__)
|
||||
|
||||
if self.layout.TYPE == "level":
|
||||
self.update_level_size()
|
||||
|
||||
self.GAME.PLAYER.health = 100
|
||||
self.GAME.PLAYER.effects = []
|
||||
self.GAME.PLAYER.x = self.layout.STARTPOSITIONS[startPositionKey][0]
|
||||
self.GAME.PLAYER.y = self.layout.STARTPOSITIONS[startPositionKey][1]
|
||||
|
||||
self.update_deltas_relative_to_player()
|
||||
|
||||
elif self.layout.TYPE == "scene":
|
||||
self.FRAMES.load_images()
|
||||
|
||||
# The following shouldn't need to exist, however pygame does not like using a low musicStartTime to trigger the first audio playback.
|
||||
try:
|
||||
self.layout.MUSIC.play()
|
||||
self.musicStartTime = pygame.time.get_ticks()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def load_level_state(self):
|
||||
"""
|
||||
Loads the last state of a level.
|
||||
"""
|
||||
|
||||
self.layout = self.layoutOld
|
||||
self.GAME.entityList = self.entityOld
|
||||
self.GAME.levelLoad = True
|
||||
|
||||
def save_level_state(self):
|
||||
"""
|
||||
Saves the last state of a level.
|
||||
"""
|
||||
|
||||
self.layoutOld = self.layout
|
||||
self.entityOld = self.GAME.entityList
|
||||
|
||||
def update_deltas_relative_to_player(self):
|
||||
"""
|
||||
Called with a scale update.
|
||||
Recalculates self.dx and self.dy so that player is centered properly.
|
||||
"""
|
||||
|
||||
borderWidthX = (self.SCALE.gameX // 2) + 1
|
||||
borderWidthY = (self.SCALE.gameY // 2) + 1
|
||||
|
||||
if self.GAME.PLAYER.x < borderWidthX:
|
||||
# Player is in left border
|
||||
self.dx = 0
|
||||
|
||||
elif self.GAME.PLAYER.x > self.width - borderWidthX:
|
||||
# Player is in right border
|
||||
self.dx = self.width - self.SCALE.gameX
|
||||
|
||||
else:
|
||||
# Player is within x boundaries
|
||||
self.dx = self.GAME.PLAYER.x - borderWidthX
|
||||
|
||||
|
||||
if self.GAME.PLAYER.y < borderWidthY:
|
||||
# Player is in the top border
|
||||
self.dy = 0
|
||||
|
||||
elif self.GAME.PLAYER.y > self.height - borderWidthY:
|
||||
# Player is in bottom border.
|
||||
self.dy = self.height - self.SCALE.gameY
|
||||
|
||||
else:
|
||||
# Player is within y boundaries.
|
||||
self.dy = self.GAME.PLAYER.y - borderWidthY
|
||||
|
||||
self.dx = int(self.dx)
|
||||
self.dy = int(self.dy)
|
||||
|
||||
def update_level_size(self):
|
||||
"""
|
||||
Updates the size of the active layout
|
||||
"""
|
||||
width = 0
|
||||
height = 0
|
||||
|
||||
for coords, block in self.layout.LAYOUT.items():
|
||||
try:
|
||||
if coords[2] > width:
|
||||
width = coords[2]
|
||||
|
||||
if coords[3] > height:
|
||||
height = coords[3]
|
||||
|
||||
except IndexError:
|
||||
if coords[0] > width:
|
||||
width = coords[0]
|
||||
|
||||
if coords[1] > height:
|
||||
height = coords[1]
|
||||
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
||||
"""
|
||||
NAME :str
|
||||
HAS_PLAYER :bool
|
||||
TYPE :str = "scene", "menu", "level"
|
||||
|
||||
scene # Does not scale with scaleGame or scaleUi
|
||||
# Each obj in LAYOUT is a different frame, not block sections.
|
||||
# Does not have a player, so HAS_PLAYER is not checked, and can be removed from definition.
|
||||
|
||||
menu # Does not scale with scaleGame
|
||||
# Has a custom event handler used while menu is active. Handler defined in run().
|
||||
|
||||
LAYOUT :dict = {(x, y, rangeX, rangeY): obj}
|
||||
BGFILL :tuple = (r, g, b)
|
||||
:pygame.surface.Surface
|
||||
FOLLOW_UP_LEVEL :level.Levels, level.Menus, level.Scenes
|
||||
"""
|
||||
|
||||
class Scenes():
|
||||
"""
|
||||
Class for organising scenes.
|
||||
"""
|
||||
|
||||
"""
|
||||
class Example():
|
||||
def __init__(self):
|
||||
self.IS_SKIPPABLE = True
|
||||
self.LAYOUT = [
|
||||
{
|
||||
"frame": Textures.EXAMPLE_0, # Frame image
|
||||
"frameTime": 5 # Time in seconds that this frame is displayed.
|
||||
},
|
||||
{
|
||||
"frame": Textures.EXAMPLE_1,
|
||||
"frameTime": 2
|
||||
}
|
||||
]
|
||||
|
||||
"""
|
||||
|
||||
class Intro():
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
self.TYPE = "scene"
|
||||
self.LAYOUT = [
|
||||
DIRWORKING + "/data/image/game/blocks/wool_colored_blue.png",
|
||||
DIRWORKING + "/data/image/game/blocks/wool_colored_cyan.png",
|
||||
DIRWORKING + "/data/image/game/blocks/wool_colored_light_blue.png"
|
||||
]
|
||||
self.FOLLOW_UP_LEVEL = Menus.Main
|
||||
self.IS_SKIPPABLE = True
|
||||
self.TIME_PER_FRAME = 1
|
||||
self.BG_FILL = (0, 0, 0)
|
||||
|
||||
class Commencing_Slaughter():
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
self.TYPE = "scene"
|
||||
self.LAYOUT = [
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_4.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png",
|
||||
DIRWORKING + "/data/image/game/scenes/commencing_slaughter/commencing_slaughter_3.png"
|
||||
]
|
||||
self.FOLLOW_UP_LEVEL = Levels.Example
|
||||
self.IS_SKIPPABLE = False
|
||||
self.TIME_PER_FRAME = 0.25
|
||||
|
||||
self.MUSIC = mixer.Sound(DIRWORKING + "/data/sound/game/scenes/commencing_slaughter.mp3")
|
||||
|
||||
class Player_Died():
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
self.TYPE = "scene"
|
||||
self.LAYOUT = [
|
||||
DIRWORKING + "/data/image/game/blocks/wool_colored_red.png"
|
||||
]
|
||||
self.FOLLOW_UP_LEVEL = Menus.Player_Died
|
||||
self.IS_SKIPPABLE = False
|
||||
|
||||
self.MUSIC = mixer.Sound(DIRWORKING + "/data/sound/game/weapon/Explosion_Ultra_Bass-Mark_DiAngelo-1810420658.wav")
|
||||
|
||||
self.TIME_PER_FRAME = self.MUSIC.get_length()
|
||||
|
||||
class Player_Won():
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
self.TYPE = "scene"
|
||||
self.LAYOUT = [
|
||||
DIRWORKING + "/data/image/game/blocks/wool_colored_lime.png"
|
||||
]
|
||||
self.FOLLOW_UP_LEVEL = Menus.Player_Won
|
||||
self.IS_SKIPPABLE = True
|
||||
|
||||
self.MUSIC = mixer.Sound(DIRWORKING + "/data/sound/game/weapon/Explosion_Ultra_Bass-Mark_DiAngelo-1810420658.wav")
|
||||
|
||||
self.TIME_PER_FRAME = self.MUSIC.get_length()
|
||||
|
||||
class Menus():
|
||||
"""
|
||||
Class for organising menus.
|
||||
"""
|
||||
|
||||
class Blank():
|
||||
def __init__(self, **kwargs):
|
||||
self.TYPE = "menu"
|
||||
self.HAS_PLAYER = False
|
||||
self.INTERACTABLES = []
|
||||
self.BG_FILL = (0, 0, 0)
|
||||
|
||||
class Main():
|
||||
def __init__(self, game):
|
||||
|
||||
self.TYPE = "menu"
|
||||
self.HAS_PLAYER = False
|
||||
self.INTERACTABLES = [
|
||||
Button(
|
||||
game,
|
||||
"start",
|
||||
100,
|
||||
100,
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_neutral.png").convert_alpha(),
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_hover.png").convert_alpha(),
|
||||
game.LEVEL.load_layout,
|
||||
args=Scenes.Commencing_Slaughter
|
||||
),
|
||||
Button(
|
||||
game,
|
||||
"settings",
|
||||
100,
|
||||
200,
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_neutral.png").convert_alpha(),
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_hover.png").convert_alpha(),
|
||||
game.LEVEL.load_layout,
|
||||
#args=Menus.Settings
|
||||
args=Menus.Main
|
||||
),
|
||||
Button(
|
||||
game,
|
||||
"exit_to_desktop",
|
||||
100,
|
||||
300,
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_neutral.png").convert_alpha(),
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_hover.png").convert_alpha(),
|
||||
game.MENU_FUNCTIONS.exit_to_desktop
|
||||
)
|
||||
]
|
||||
|
||||
self.BG_FILL = pygame.image.load(DIRWORKING + "/data/image/game/blocks/wool_colored_silver.png").convert()
|
||||
self.MUSIC = mixer.Sound(DIRWORKING + "/data/sound/ui/menu_main/Backwards-Souls-SoundBible.com-87826574.wav")
|
||||
|
||||
class Settings():
|
||||
def __init__(self, game):
|
||||
|
||||
self.TYPE = "menu"
|
||||
self.HAS_PLAYER = False
|
||||
self.INTERACTABLES = [
|
||||
Checkbox(
|
||||
game,
|
||||
"fullscreen",
|
||||
100,
|
||||
100,
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/icons/checkbox_neutral.png").convert_alpha(),
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/icons/checkbox_hover.png").convert_alpha(),
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/icons/checkbox_active.png").convert_alpha(),
|
||||
lambda: FEATURES["fullscreen"]["is_active"], # Needs to be re-evaluated. Thus lambda function.
|
||||
game.MENU_FUNCTIONS.enter_fullscreen
|
||||
)
|
||||
]
|
||||
|
||||
self.BG_FILL = pygame.image.load(DIRWORKING + "/data/image/game/blocks/wool_colored_silver.png").convert()
|
||||
|
||||
class Pause():
|
||||
def __init__(self, game):
|
||||
|
||||
self.TYPE = "menu"
|
||||
self.HAS_PLAYER = False
|
||||
self.INTERACTABLES = [
|
||||
Button(
|
||||
game,
|
||||
"return_to_game",
|
||||
100,
|
||||
100,
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_neutral.png").convert_alpha(),
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_hover.png").convert_alpha(),
|
||||
game.MENU_FUNCTIONS.return_to_game
|
||||
),
|
||||
Button(
|
||||
game,
|
||||
"settings",
|
||||
100,
|
||||
200,
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_neutral.png").convert_alpha(),
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_hover.png").convert_alpha(),
|
||||
game.MENU_FUNCTIONS.return_to_game
|
||||
#game.LEVEL.load_layout,
|
||||
#args=Menus.Settings
|
||||
),
|
||||
Button(
|
||||
game,
|
||||
"exit_to_menu",
|
||||
100,
|
||||
300,
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_neutral.png").convert_alpha(),
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_hover.png").convert_alpha(),
|
||||
game.LEVEL.load_layout,
|
||||
args=Menus.Main
|
||||
)
|
||||
]
|
||||
|
||||
# Save a snapshot of the window to overlay the pause menu on.
|
||||
pygame.image.save(game.WINDOW.window, DIRWORKING + "/temp/pausescreen.png")
|
||||
self.BG_FILL = pygame.image.load(DIRWORKING + "/temp/pausescreen.png").convert()
|
||||
|
||||
class Player_Died():
|
||||
def __init__(self, game):
|
||||
self.TYPE = "menu"
|
||||
self.HAS_PLAYER = False
|
||||
self.INTERACTABLES = [
|
||||
Button(
|
||||
game,
|
||||
"exit_to_menu",
|
||||
100,
|
||||
300,
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_neutral.png").convert_alpha(),
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_hover.png").convert_alpha(),
|
||||
game.LEVEL.load_layout,
|
||||
args=Menus.Main
|
||||
)
|
||||
]
|
||||
self.BG_FILL = load(DIRWORKING + "/data/image/game/blocks/wool_colored_red.png")
|
||||
|
||||
class Player_Won():
|
||||
def __init__(self, game):
|
||||
self.TYPE = "menu"
|
||||
self.HAS_PLAYER = False
|
||||
self.INTERACTABLES = [
|
||||
Button(
|
||||
game,
|
||||
"exit_to_menu",
|
||||
100,
|
||||
300,
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_neutral.png").convert_alpha(),
|
||||
pygame.image.load(DIRWORKING + "/data/image/ui/menu_main/start_hover.png").convert_alpha(),
|
||||
game.LEVEL.load_layout,
|
||||
args=Menus.Main
|
||||
)
|
||||
]
|
||||
self.BG_FILL = load(DIRWORKING + "/data/image/game/blocks/wool_colored_lime.png")
|
||||
|
||||
class Levels():
|
||||
"""
|
||||
Class for organising levels.
|
||||
"""
|
||||
|
||||
class Example():
|
||||
def __init__(self, game, **kwargs):
|
||||
|
||||
self.TYPE = "level"
|
||||
self.HAS_PLAYER = True
|
||||
self.LAYOUT = {
|
||||
(0, 0, 96, 64): Blocks.block_blue(),
|
||||
(2, 1): Blocks.block_rainbow(layer=1),
|
||||
(14, 5): Blocks.block_rainbow(layer=1),
|
||||
(3, 3, 5, 5): Blocks.puddle_of_souls(game, layer=1),
|
||||
(7, 7): Blocks.puddle_of_souls(game, layer=1),
|
||||
(4, 9): Blocks.puddle_of_souls(game, layer=1)
|
||||
}
|
||||
self.ENTITIES = [
|
||||
Unnamed(game, 16, 16),
|
||||
Unnamed(game, 16, 17),
|
||||
Unnamed(game, 17, 16),
|
||||
Unnamed(game, 17, 17),
|
||||
Unnamed(game, 15, 23),
|
||||
Unnamed(game, 41, 52),
|
||||
Unnamed(game, 5, 17)
|
||||
]
|
||||
self.STARTPOSITIONS = {"default": (0, 0)}
|
||||
self.BG_FILL = (0, 0, 0)
|
||||
self.FOLLOW_UP_LEVEL = Scenes.Player_Won
|
||||
|
||||
class Frames():
|
||||
"""
|
||||
Class for methods pertaining to scenes.
|
||||
"""
|
||||
|
||||
def __init__(self, game):
|
||||
|
||||
self.GAME = game
|
||||
self.WINDOW = self.GAME.WINDOW
|
||||
self.clear()
|
||||
|
||||
def clear(self):
|
||||
"""
|
||||
Clear the frames from memory.
|
||||
"""
|
||||
|
||||
self.images = [
|
||||
pygame.image.load(DIRWORKING + "/data/image/game/blocks/wool_colored_silver.png").convert()
|
||||
]
|
||||
self.imageNumber = -1
|
||||
self.frames = 0 # Frames rendered by system
|
||||
|
||||
def draw(self):
|
||||
"""
|
||||
Draws the scene.
|
||||
"""
|
||||
|
||||
if self.frames / self.GAME.clock.get_fps() > self.GAME.LEVEL.layout.TIME_PER_FRAME: # Use number of frames displaying an image / framerate to get time in sec.
|
||||
self.imageNumber = self.imageNumber + 1 # Increment the image index
|
||||
self.frames = 0
|
||||
|
||||
if len(self.images) == self.imageNumber:
|
||||
self.GAME.LEVEL.load_layout(self.GAME.LEVEL.layout.FOLLOW_UP_LEVEL)
|
||||
self.clear()
|
||||
else:
|
||||
self.WINDOW.window.blit(self.images[self.imageNumber], (0, 0))
|
||||
elif self.imageNumber == -1:
|
||||
self.imageNumber = 0
|
||||
self.WINDOW.window.blit(self.images[self.imageNumber], (0, 0))
|
||||
|
||||
else:
|
||||
self.frames = self.frames + 1
|
||||
|
||||
def load_images(self):
|
||||
"""
|
||||
Load frames for a scene.
|
||||
"""
|
||||
|
||||
self.images = []
|
||||
|
||||
for path in self.GAME.LEVEL.layout.LAYOUT:
|
||||
self.images.append(load(path).convert_alpha())
|
||||
|
||||
self.scale_images()
|
||||
|
||||
def scale_images(self):
|
||||
"""
|
||||
Scales all images currently loaded.
|
||||
"""
|
||||
|
||||
for image in self.images:
|
||||
self.images[self.images.index(image)] = pygame.transform.scale(image, (self.WINDOW.width, self.WINDOW.height))
|
||||
|
||||
def skip(self):
|
||||
"""
|
||||
Skips the level.
|
||||
"""
|
||||
|
||||
self.clear()
|
||||
self.GAME.LEVEL.load_layout(self.GAME.LEVEL.layout.FOLLOW_UP_LEVEL)
|
||||
|
||||
def update_scale(self):
|
||||
"""
|
||||
Updates the scaling of the active frames.
|
||||
"""
|
||||
|
||||
if self.WINDOW.width > self.images[0].get_width() or self.WINDOW.height > self.images[0].get_height():
|
||||
self.load_images()
|
||||
else:
|
||||
self.scale_images()
|
||||
Reference in New Issue
Block a user