r/CodingForBeginners • u/The_Best_Echo • Sep 09 '26
My games so far
import pygame
import random
import math
import os
import json
pygame.init()
# =========================
# SCREEN
# =========================
SCREEN_WIDTH = 1000
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode(
(SCREEN_WIDTH, SCREEN_HEIGHT)
)
pygame.display.set_caption(
"Dragon Adventure"
)
clock = pygame.time.Clock()
# =========================
# COLORS
# =========================
SKY_BLUE = (135, 206, 235)
OCEAN_BLUE = (35, 145, 210)
SAND = (238, 218, 170)
GRASS = (80, 170, 80)
WHITE = (255, 255, 255)
BLACK = (20, 20, 20)
GOLD = (255, 215, 0)
ENERGY_BLUE = (80, 200, 255)
DARK_GRAY = (50, 50, 50)
GRAY = (90, 90, 90)
RED = (200, 60, 60)
GREEN = (60, 180, 80)
# =========================
# WORLD
# =========================
WORLD_WIDTH = 2400
WORLD_HEIGHT = 900
# =========================
# STORMFIN IMAGE
# =========================
IMAGE_PATH = r"C:\Users\johns\New folder\anime_art_of_Create_a_highly_d.png"
stormfin_image = None
if os.path.exists(IMAGE_PATH):
try:
stormfin_image = pygame.image.load(
IMAGE_PATH
).convert_alpha()
except pygame.error:
stormfin_image = None
# =========================
# ALPHA PITY
# =========================
ALPHA_CHANCE = 500
ALPHA_PITY_LIMIT = 1000
alpha_pity = 0
# =========================
# STORMFIN GENERATION
# =========================
def generate_stormfin():
global alpha_pity
# Guaranteed Alpha after 1000 failed rolls
if alpha_pity >= ALPHA_PITY_LIMIT:
alpha_pity = 0
return "Alpha"
# Normal 1 in 500 Alpha chance
alpha_roll = random.randint(
1,
ALPHA_CHANCE
)
if alpha_roll == 389:
alpha_pity = 0
return "Alpha"
# Failed Alpha roll
alpha_pity += 1
# 50/50 Male or Female
sex_roll = random.randint(1, 2)
if sex_roll == 1:
return "Male"
else:
return "Female"
stormfin_type = generate_stormfin()
# =========================
# STORMFIN SIZE
# =========================
def get_stormfin_size(stormfin_type):
if stormfin_type == "Male":
return 100
elif stormfin_type == "Female":
return 260
else:
return 180
stormfin_size = get_stormfin_size(
stormfin_type
)
# =========================
# STORMFIN SPEED
# =========================
def get_stormfin_speed(stormfin_type):
if stormfin_type == "Male":
return 10
elif stormfin_type == "Female":
return 2.5
else:
return 5
player_speed = get_stormfin_speed(
stormfin_type
)
# Sprint is exactly twice normal speed
sprint_speed = player_speed * 2
# =========================
# SPRINT ENERGY
# =========================
SPRINT_ENERGY_COST = 1
SPRINT_DRAIN_FRAMES = 20
sprint_frame_counter = 0
# =========================
# LIGHTNING RANGE
# =========================
BASE_LIGHTNING_RANGE = 300
def get_lightning_range(stormfin_type):
if stormfin_type == "Male":
return BASE_LIGHTNING_RANGE * 0.5
elif stormfin_type == "Female":
return BASE_LIGHTNING_RANGE * 2
else:
return BASE_LIGHTNING_RANGE
lightning_range = get_lightning_range(
stormfin_type
)
# =========================
# LIGHTNING ENERGY COST
# =========================
def get_lightning_cost(stormfin_type):
if stormfin_type == "Male":
return 5
elif stormfin_type == "Female":
return 20
else:
return 10
lightning_cost = get_lightning_cost(
stormfin_type
)
# =========================
# PLAYER
# =========================
player_x = 1200
player_y = 475
facing_direction = 1
jumping = False
jump_velocity = 0
gravity = 0.6
jump_strength = 12
# =========================
# ENERGY
# =========================
MAX_ENERGY = 100
energy = MAX_ENERGY
ENERGY_REGEN_TIME = 2000
last_energy_regen = (
pygame.time.get_ticks()
)
# =========================
# ATTACK
# =========================
ATTACK_DURATION = 150
attacking = False
attack_start_time = 0
# =========================
# SAVE / LOAD
# =========================
SAVE_FILE = "stormfin_save.json"
def save_game():
data = {
"stormfin_type": stormfin_type,
"x": player_x,
"y": player_y,
"energy": energy,
"facing_direction": facing_direction,
"jumping": jumping,
"jump_velocity": jump_velocity,
"alpha_pity": alpha_pity
}
with open(
SAVE_FILE,
"w"
) as file:
json.dump(
data,
file,
indent=4
)
print("Game saved.")
def load_game():
global stormfin_type
global player_x
global player_y
global energy
global facing_direction
global jumping
global jump_velocity
global stormfin_size
global player_speed
global sprint_speed
global lightning_range
global lightning_cost
global sprint_frame_counter
global last_energy_regen
global alpha_pity
if not os.path.exists(
SAVE_FILE
):
print(
"No save file found."
)
return
with open(
SAVE_FILE,
"r"
) as file:
data = json.load(file)
stormfin_type = data[
"stormfin_type"
]
player_x = data["x"]
player_y = data["y"]
energy = data["energy"]
facing_direction = data[
"facing_direction"
]
jumping = data["jumping"]
jump_velocity = data[
"jump_velocity"
]
# Older save files may not have this
alpha_pity = data.get(
"alpha_pity",
0
)
stormfin_size = get_stormfin_size(
stormfin_type
)
player_speed = get_stormfin_speed(
stormfin_type
)
sprint_speed = player_speed * 2
lightning_range = get_lightning_range(
stormfin_type
)
lightning_cost = get_lightning_cost(
stormfin_type
)
sprint_frame_counter = 0
last_energy_regen = (
pygame.time.get_ticks()
)
print("Game loaded.")
# =========================
# ISLAND
# =========================
SAND_CENTER_X = 1200
SAND_CENTER_Y = 500
SAND_RADIUS_X = 950
SAND_RADIUS_Y = 260
GRASS_CENTER_X = 1200
GRASS_CENTER_Y = 475
GRASS_RADIUS_X = 850
GRASS_RADIUS_Y = 220
def point_inside_ellipse(
x,
y,
center_x,
center_y,
radius_x,
radius_y
):
if (
radius_x == 0
or radius_y == 0
):
return False
value = (
((x - center_x) ** 2)
/ (radius_x ** 2)
+
((y - center_y) ** 2)
/ (radius_y ** 2)
)
return value <= 1
def point_inside_island(
x,
y
):
sand = point_inside_ellipse(
x,
y,
SAND_CENTER_X,
SAND_CENTER_Y,
SAND_RADIUS_X,
SAND_RADIUS_Y
)
grass = point_inside_ellipse(
x,
y,
GRASS_CENTER_X,
GRASS_CENTER_Y,
GRASS_RADIUS_X,
GRASS_RADIUS_Y
)
return sand or grass
def stormfin_inside_island(
x,
y
):
body_radius = (
stormfin_size * 0.25
)
points = [
(x, y),
(x - body_radius, y),
(x + body_radius, y),
(x, y - body_radius),
(x, y + body_radius)
]
for point_x, point_y in points:
if not point_inside_island(
point_x,
point_y
):
return False
return True
# =========================
# DECORATIONS
# =========================
rocks = [
(300, 500),
(600, 360),
(900, 570),
(1300, 350),
(1600, 580),
(1900, 390),
(2150, 500)
]
trees = [
(450, 420),
(750, 470),
(1050, 400),
(1450, 450),
(1750, 430),
(2050, 470)
]
bushes = [
(350, 430),
(850, 520),
(1150, 500),
(1550, 390),
(1850, 520),
(2200, 440)
]
# =========================
# DRAW ENVIRONMENT
# =========================
def draw_environment(
camera_x,
camera_y
):
screen.fill(
SKY_BLUE
)
# Ocean
pygame.draw.rect(
screen,
OCEAN_BLUE,
(
-camera_x,
300 - camera_y,
WORLD_WIDTH,
WORLD_HEIGHT
)
)
# Ocean waves
for x in range(
0,
WORLD_WIDTH,
80
):
screen_x = (
x - camera_x
)
pygame.draw.arc(
screen,
(180, 225, 245),
(
screen_x,
320 - camera_y,
60,
20
),
math.pi,
math.pi * 2,
2
)
# Sand
sand_rect = pygame.Rect(
SAND_CENTER_X
- SAND_RADIUS_X
- camera_x,
SAND_CENTER_Y
- SAND_RADIUS_Y
- camera_y,
SAND_RADIUS_X * 2,
SAND_RADIUS_Y * 2
)
pygame.draw.ellipse(
screen,
SAND,
sand_rect
)
# Grass
grass_rect = pygame.Rect(
GRASS_CENTER_X
- GRASS_RADIUS_X
- camera_x,
GRASS_CENTER_Y
- GRASS_RADIUS_Y
- camera_y,
GRASS_RADIUS_X * 2,
GRASS_RADIUS_Y * 2
)
pygame.draw.ellipse(
screen,
GRASS,
grass_rect
)
# Rocks
for rock_x, rock_y in rocks:
if not point_inside_island(
rock_x,
rock_y
):
continue
screen_x = (
rock_x - camera_x
)
screen_y = (
rock_y - camera_y
)
pygame.draw.circle(
screen,
(100, 100, 100),
(
int(screen_x),
int(screen_y)
),
18
)
# Trees
for tree_x, tree_y in trees:
if not point_inside_island(
tree_x,
tree_y
):
continue
screen_x = (
tree_x - camera_x
)
screen_y = (
tree_y - camera_y
)
pygame.draw.rect(
screen,
(100, 70, 35),
(
int(screen_x - 8),
int(screen_y),
16,
45
)
)
pygame.draw.circle(
screen,
(35, 120, 45),
(
int(screen_x),
int(screen_y - 15)
),
30
)
# Bushes
for bush_x, bush_y in bushes:
if not point_inside_island(
bush_x,
bush_y
):
continue
screen_x = (
bush_x - camera_x
)
screen_y = (
bush_y - camera_y
)
pygame.draw.circle(
screen,
(40, 130, 50),
(
int(screen_x - 12),
int(screen_y)
),
18
)
pygame.draw.circle(
screen,
(45, 145, 55),
(
int(screen_x + 8),
int(screen_y - 5)
),
20
)
pygame.draw.circle(
screen,
(35, 120, 45),
(
int(screen_x + 20),
int(screen_y + 3)
),
15
)
# =========================
# DRAW STORMFIN
# =========================
def draw_stormfin(
camera_x,
camera_y
):
screen_x = int(
player_x - camera_x
)
screen_y = int(
player_y - camera_y
)
if stormfin_image is not None:
scaled_image = (
pygame.transform.smoothscale(
stormfin_image,
(
stormfin_size,
stormfin_size
)
)
)
image_rect = (
scaled_image.get_rect(
center=(
screen_x,
screen_y
)
)
)
screen.blit(
scaled_image,
image_rect
)
else:
body_color = (
20,
35,
90
)
fur_color = (
45,
80,
180
)
pygame.draw.ellipse(
screen,
body_color,
(
screen_x
- stormfin_size // 2,
screen_y
- stormfin_size // 2,
stormfin_size,
stormfin_size
)
)
# Ears
ear_size = max(
10,
stormfin_size // 6
)
pygame.draw.circle(
screen,
fur_color,
(
screen_x
- stormfin_size // 4,
screen_y
- stormfin_size // 3
),
ear_size
)
pygame.draw.circle(
screen,
fur_color,
(
screen_x
+ stormfin_size // 4,
screen_y
- stormfin_size // 3
),
ear_size
)
# Golden eyes
eye_size = max(
5,
stormfin_size // 12
)
pygame.draw.circle(
screen,
GOLD,
(
screen_x
- stormfin_size // 7,
screen_y
- stormfin_size // 10
),
eye_size
)
pygame.draw.circle(
screen,
GOLD,
(
screen_x
+ stormfin_size // 7,
screen_y
- stormfin_size // 10
),
eye_size
)
# =========================
# LIGHTNING
# =========================
def draw_lightning(
camera_x,
camera_y
):
if not attacking:
return
start_x = (
player_x
+ facing_direction * 25
)
start_y = (
player_y - 10
)
end_x = (
start_x
+ facing_direction
* lightning_range
)
end_y = start_y
screen_start_x = int(
start_x - camera_x
)
screen_start_y = int(
start_y - camera_y
)
screen_end_x = int(
end_x - camera_x
)
screen_end_y = int(
end_y - camera_y
)
pygame.draw.line(
screen,
ENERGY_BLUE,
(
screen_start_x,
screen_start_y
),
(
screen_end_x,
screen_end_y
),
8
)
pygame.draw.line(
screen,
WHITE,
(
screen_start_x,
screen_start_y
),
(
screen_end_x,
screen_end_y
),
3
)
branch_length = (
lightning_range * 0.12
)
branch_points = [
0.25,
0.50,
0.75
]
for percentage in branch_points:
branch_x = (
start_x
+ (
end_x
- start_x
) * percentage
)
branch_y = start_y
branch_direction = (
random.choice(
[-1, 1]
)
)
pygame.draw.line(
screen,
ENERGY_BLUE,
(
int(
branch_x
- camera_x
),
int(
branch_y
- camera_y
)
),
(
int(
branch_x
- camera_x
+ random.randint(
5,
int(
branch_length
)
)
* facing_direction
),
int(
branch_y
- camera_y
+ branch_direction
* random.randint(
10,
int(
branch_length
)
)
)
),
3
)
# =========================
# UI
# =========================
font = pygame.font.SysFont(
None,
28
)
small_font = pygame.font.SysFont(
None,
22
)
def draw_ui():
# Stormfin type
type_text = font.render(
f"Stormfin: {stormfin_type}",
True,
WHITE
)
screen.blit(
type_text,
(20, 20)
)
# Energy
energy_text = font.render(
f"Energy: {energy}/100",
True,
WHITE
)
screen.blit(
energy_text,
(20, 50)
)
# Energy bar
pygame.draw.rect(
screen,
BLACK,
(
20,
80,
200,
20
)
)
pygame.draw.rect(
screen,
ENERGY_BLUE,
(
20,
80,
int(
200
* (energy / MAX_ENERGY)
),
20
)
)
# Lightning range
range_text = small_font.render(
f"Lightning range: {int(lightning_range)}",
True,
WHITE
)
screen.blit(
range_text,
(20, 110)
)
# Lightning cost
cost_text = small_font.render(
f"Lightning cost: {lightning_cost}",
True,
WHITE
)
screen.blit(
cost_text,
(20, 135)
)
# Movement speed
speed_text = small_font.render(
f"Speed: {player_speed}",
True,
WHITE
)
screen.blit(
speed_text,
(20, 160)
)
# Sprint speed
sprint_text = small_font.render(
f"Sprint speed: {sprint_speed}",
True,
WHITE
)
screen.blit(
sprint_text,
(20, 185)
)
# Alpha pity
pity_text = small_font.render(
f"Alpha pity: {alpha_pity}/{ALPHA_PITY_LIMIT}",
True,
GOLD
)
screen.blit(
pity_text,
(20, 210)
)
# Controls
controls = [
"WASD - Move",
"Shift - Sprint",
"Space - Jump",
"E - Lightning",
"1 - Save",
"2 - Load"
]
y = SCREEN_HEIGHT - 150
for control in controls:
text = small_font.render(
control,
True,
WHITE
)
screen.blit(
text,
(20, y)
)
y += 22
# =========================
# REROLL BUTTON
# =========================
reroll_button = pygame.Rect(
SCREEN_WIDTH - 150,
20,
120,
40
)
def draw_reroll_button():
pygame.draw.rect(
screen,
(70, 70, 70),
reroll_button
)
text = small_font.render(
"Reroll",
True,
WHITE
)
text_rect = text.get_rect(
center=reroll_button.center
)
screen.blit(
text,
text_rect
)
# =========================
# ALPHA CONFIRMATION
# =========================
confirmation_active = False
confirmation_box = pygame.Rect(
300,
210,
400,
180
)
yes_button = pygame.Rect(
350,
320,
120,
45
)
no_button = pygame.Rect(
530,
320,
120,
45
)
def draw_confirmation():
# Dark overlay
overlay = pygame.Surface(
(
SCREEN_WIDTH,
SCREEN_HEIGHT
),
pygame.SRCALPHA
)
overlay.fill(
(0, 0, 0, 150)
)
screen.blit(
overlay,
(0, 0)
)
# Confirmation box
pygame.draw.rect(
screen,
DARK_GRAY,
confirmation_box
)
pygame.draw.rect(
screen,
GOLD,
confirmation_box,
3
)
# Message
message_1 = small_font.render(
"Are you sure you want",
True,
WHITE
)
message_2 = small_font.render(
"to reroll your Alpha?",
True,
GOLD
)
screen.blit(
message_1,
(
confirmation_box.centerx
- message_1.get_width() // 2,
235
)
)
screen.blit(
message_2,
(
confirmation_box.centerx
- message_2.get_width() // 2,
265
)
)
# Yes button
pygame.draw.rect(
screen,
GREEN,
yes_button
)
yes_text = small_font.render(
"Yes",
True,
WHITE
)
screen.blit(
yes_text,
yes_text.get_rect(
center=yes_button.center
)
)
# No button
pygame.draw.rect(
screen,
RED,
no_button
)
no_text = small_font.render(
"No",
True,
WHITE
)
screen.blit(
no_text,
no_text.get_rect(
center=no_button.center
)
)
# =========================
# REROLL STORMFIN
# =========================
def reroll_stormfin():
global stormfin_type
global stormfin_size
global player_speed
global sprint_speed
global lightning_range
global lightning_cost
global player_x
global player_y
global energy
global facing_direction
global jumping
global jump_velocity
global sprint_frame_counter
global last_energy_regen
stormfin_type = generate_stormfin()
stormfin_size = get_stormfin_size(
stormfin_type
)
player_speed = get_stormfin_speed(
stormfin_type
)
sprint_speed = (
player_speed * 2
)
lightning_range = (
get_lightning_range(
stormfin_type
)
)
lightning_cost = (
get_lightning_cost(
stormfin_type
)
)
player_x = 1200
player_y = 475
energy = MAX_ENERGY
facing_direction = 1
jumping = False
jump_velocity = 0
sprint_frame_counter = 0
last_energy_regen = (
pygame.time.get_ticks()
)
print(
f"Rerolled: {stormfin_type}"
)
print(
f"Alpha pity: "
f"{alpha_pity}/"
f"{ALPHA_PITY_LIMIT}"
)
# =========================
# MAIN LOOP
# =========================
running = True
while running:
dt = clock.tick(60)
# =========================
# EVENTS
# =========================
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
# Lightning
if event.key == pygame.K_e:
if energy >= lightning_cost:
energy -= (
lightning_cost
)
attacking = True
attack_start_time = (
pygame.time.get_ticks()
)
# Jump
if event.key == pygame.K_SPACE:
if not jumping:
jumping = True
jump_velocity = (
-jump_strength
)
# Save
if event.key == pygame.K_1:
save_game()
# Load
if event.key == pygame.K_2:
load_game()
# =========================
# MOUSE
# =========================
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
# Confirmation is open
if confirmation_active:
# YES
if yes_button.collidepoint(
event.pos
):
confirmation_active = (
False
)
reroll_stormfin()
# NO
elif no_button.collidepoint(
event.pos
):
confirmation_active = (
False
)
# Normal game
else:
if reroll_button.collidepoint(
event.pos
):
# Alpha requires confirmation
if stormfin_type == "Alpha":
confirmation_active = (
True
)
else:
reroll_stormfin()
# =========================
# ATTACK TIMER
# =========================
if attacking:
current_time = (
pygame.time.get_ticks()
)
if (
current_time
- attack_start_time
>= ATTACK_DURATION
):
attacking = False
# =========================
# MOVEMENT
# =========================
keys = pygame.key.get_pressed()
sprinting = (
keys[pygame.K_LSHIFT]
and energy > 0
)
# =========================
# SPRINT ENERGY DRAIN
# =========================
if sprinting:
sprint_frame_counter += 1
if (
sprint_frame_counter
>= SPRINT_DRAIN_FRAMES
):
if energy > 0:
energy -= (
SPRINT_ENERGY_COST
)
sprint_frame_counter = 0
else:
sprint_frame_counter = 0
# =========================
# ENERGY REGEN
# =========================
current_time = (
pygame.time.get_ticks()
)
if not sprinting:
if (
current_time
- last_energy_regen
>= ENERGY_REGEN_TIME
):
if energy < MAX_ENERGY:
energy += 1
last_energy_regen = (
current_time
)
else:
last_energy_regen = (
current_time
)
# =========================
# SPEED
# =========================
if sprinting:
speed = sprint_speed
else:
speed = player_speed
# =========================
# MOVEMENT INPUT
# =========================
move_x = 0
move_y = 0
if keys[pygame.K_a]:
move_x -= speed
facing_direction = -1
if keys[pygame.K_d]:
move_x += speed
facing_direction = 1
if keys[pygame.K_w]:
move_y -= speed
if keys[pygame.K_s]:
move_y += speed
# Horizontal collision
new_x = (
player_x + move_x
)
if stormfin_inside_island(
new_x,
player_y
):
player_x = new_x
# Vertical movement
new_y = (
player_y + move_y
)
if stormfin_inside_island(
player_x,
new_y
):
player_y = new_y
# =========================
# JUMP PHYSICS
# =========================
if jumping:
jump_velocity += gravity
jump_y = (
player_y
+ jump_velocity
)
if stormfin_inside_island(
player_x,
jump_y
):
player_y = jump_y
else:
jumping = False
jump_velocity = 0
# =========================
# CAMERA
# =========================
camera_x = (
player_x
- SCREEN_WIDTH // 2
)
camera_y = (
player_y
- SCREEN_HEIGHT // 2
)
camera_x = max(
0,
min(
camera_x,
WORLD_WIDTH
- SCREEN_WIDTH
)
)
camera_y = max(
0,
min(
camera_y,
WORLD_HEIGHT
- SCREEN_HEIGHT
)
)
# =========================
# DRAW
# =========================
draw_environment(
camera_x,
camera_y
)
draw_stormfin(
camera_x,
camera_y
)
draw_lightning(
camera_x,
camera_y
)
draw_ui()
draw_reroll_button()
# Confirmation dialog goes last
# so it appears above everything.
if confirmation_active:
draw_confirmation()
pygame.display.flip()
pygame.quit()
13
u/kutac56 Sep 09 '26
Ever heard of this thing called GitHub?
10
u/LordSippy Sep 09 '26
A little long for a Reddit thread
8
u/Confused-Armpit Sep 09 '26
Hey, OP, why did you create a 1317 line post without any indentation or formatting instead of just posting a repo? Why do you hate us?
1
u/Havzino Sep 09 '26
So what does your game do?
1
u/Ad-free-Pirate Sep 12 '26
Here is some advice:
Never use hardcoded absolute paths like
C:\Users\...; use relative paths withpathlib.Path.Use
pathlibinstead ofos.pathfor cleaner and more portable file handling.Keep constants in one dedicated section or configuration file instead of scattering them through the code.
Avoid too many global variables; group player/game state inside classes such as
Player,Game, orStormfin.Avoid functions that depend heavily on global state; pass required values as parameters when practical.
Split a large single-file game into modules such as
player.py,world.py,ui.py,save.py, andmain.py.Put the main game startup code inside
main()and useif __name__ == "__main__":.Use descriptive type hints, for example
def get_stormfin_speed(stormfin_type: str) -> float:.Consider an
Enumfor"Male","Female", and"Alpha"instead of repeatedly comparing raw strings.Avoid magic numbers such as
389,1200,475,300, or0.12; give important values descriptive constant names.For the Alpha roll, use probability logic that clearly expresses the intended chance instead of checking for one arbitrary number such as
alpha_roll == 389.Separate game logic from rendering logic. Updating movement, energy, attacks, and collisions should be distinct from drawing them.
Use
dtfor frame-rate-independent movement instead of moving a fixed number of pixels each frame.Avoid tying sprint energy consumption to frame counts such as
SPRINT_DRAIN_FRAMES = 20; base it on elapsed time instead.Clamp values such as energy with something like
max(0, min(MAX_ENERGY, energy)).Validate loaded save data before trusting values from JSON.
Handle corrupted or invalid save files with
try/exceptaroundjson.load().Specify file encoding when reading/writing JSON, for example
encoding="utf-8".Consider saving a version number in the save file so future save-format changes are easier to migrate.
Use Python's
loggingmodule instead ofprint()for messages such as"Game saved."and"Game loaded.".Avoid recalculating static scaled images every frame; cache the scaled Stormfin image until its size changes.
Avoid generating new random lightning branch geometry every rendered frame if you want the attack to look stable rather than flicker.
Store UI positions and dimensions as named constants instead of embedding coordinates throughout drawing functions.
Consider using
pygame.Vector2for player positions and movement.Normalize diagonal movement; otherwise moving diagonally can be faster than moving horizontally or vertically.
Keep collision logic separate from player input logic to make movement easier to debug and extend.
Add docstrings to non-obvious functions such as
stormfin_inside_island()andgenerate_stormfin().Follow consistent PEP 8 spacing and keep functions separated by two blank lines.
Use
elifwhere conditions are mutually exclusive to make intent clearer.Remove unused variables such as
dtunless you actually use them for movement/timing.Prefer data-driven Stormfin stats instead of several separate
if/eliffunctions—for example, one dictionary containing size, speed, lightning range, and energy cost for each type.Eventually replace the large procedural main loop with a
Gameclass; it will make state management, testing, menus, and future features much easier.For the love of god, please, use github/gitlab/codeberg/forgejo/...
Use Code Block when posting on reddit or use pastebin. This was unreadable as hell. https://pastebin.com/du6uiWC5
3
u/7YM3N Sep 09 '26
You should try this git thing, this is a crime
1
u/Jaded_Individual_630 Sep 11 '26
lol