So, I tried working on a version of this game with enemies, but I keep running into issues. I think I'll spin that off into its own thread, and count this version centered around ring-collecting as complete.
Code: Select all
style scoreboard:
color "#8B0000" # Set text color to red
size 50 # Set font size to 50
xpos 880 # Set x position
ypos 20 # Set y position
style timekeeper:
color "#8B0000"
size 30
xpos 930
ypos 80
style tester:
color "#8B0000"
size 30
xpos 930
ypos 140
style tester2:
color "#8B0000"
size 30
xpos 930
ypos 200
style positioned_image:
xpos 400
ypos 330
style title:
size 30
color "#FFFFFF"
align (0.5, 0.5)
xpos 0.5
ypos 0.05
style table_header:
size 30
color "#FFFFFF"
align (0.5, 0.5)
xpos 0.5
style table_entry:
size 26
color "#FFFFFF"
align (0.5, 0.5)
xpos 0.5
style menu_button:
size 20
color "#FFFFFF"
hover_color "#FFD700"
xpos 0.5
ypos 0.9
style w_buttons:
color "#8B0000" # Set text color to red
size 50 # Set font size to 50
xalign 0.5 # Center align the hbox
yalign 0.95
spacing 10 # Adjust spacing between buttons
style frame_easy:
xsize 384
ysize 648
background "#00FF00"
style frame_medium:
xsize 384
ysize 648
background "#0000FF"
style frame_hard:
xsize 384
ysize 648
background "#FFA500"
style frame_ultra_hard:
xsize 384
ysize 648
background "#FF0000"
style white_frame:
xpadding 20 # Adjust the horizontal padding as needed
ypadding 20 # Adjust the vertical padding as needed
background Color("#FFFFFF") # Set the background color to white
xpos 0.5 # Center the frame horizontally
ypos 0.5 # Center the frame vertically
xalign 0.5 # Center the frame horizontally
yalign 0.5 # Center the frame vertically
init python:
import random
import pygame
renpy.music.register_channel("sfx", "sound")
renpy.music.register_channel("weapon", "sound")
weapon_variables = {
"basic": {
"weapon_type": "basic",
"damage": 10,
"fire_rate": 0.5,
"projectile_frames": 2,
"projectile_speed": 800,
"animation_frames": [
f"images/Projectiles/Basic{i:03}.png"
for i in range(1, 3)
],
"projectile_types": ["projectile1"],
"frame_delay": 0.01,
"spos": (300, 95), # Relative to the sleigh
"fire_sound": ["audio/Blaster.mp3"],
"initial_y_velocity": 0, # Set initial y velocity
"gravity": 0 # Set gravity
},
"basic2": {
"weapon_type": "basic2",
"damage": 20,
"fire_rate": 1.0,
"projectile_frames": 60,
"projectile_speed": 1000,
"animation_frames": [
f"images/Projectiles/tile{i:03}.png"
for i in range(0, 60)
],
"projectile_types": ["projectile1"],
"frame_delay": 0.001,
"spos": (252, 70), # Relative to the sleigh
"fire_sound": ["audio/Blaster2.mp3"],
"initial_y_velocity": 0, # Set initial y velocity
"gravity": 0 # Set gravity
},
"basic3": {
"weapon_type": "basic3",
"damage": 80,
"fire_rate": 2,
"projectile_frames": 4,
"projectile_speed": 750,
"animation_frames": [
f"images/Projectiles/FB{i:03}.png"
for i in range(1, 4)
],
"projectile_types": ["projectile1"],
"frame_delay": 0.1,
"spos": (291, 91), # Relative to the sleigh
"fire_sound": ["audio/Blaster3.mp3"],
"initial_y_velocity": 0, # Set initial y velocity
"gravity": 0 # Set gravity
},
"tree": {
"weapon_type": "tree",
"damage": 20,
"fire_rate": 1.5,
"projectile_frames": 0,
"projectile_speed": 800,
"animation_frames": [
f"images/Projectiles/Tree{i:03}.png"
for i in range(1, 3)
],
"projectile_types": ["projectile1", "projectile2", "projectile3", "projectile4", "projectile5", "projectile6"],
"frame_delay": 0.1,
"spos": (230, 50), # Relative to the sleigh
"fire_sound": ["audio/Tree.mp3"],
"initial_y_velocity": 0, # Set initial y velocity
"gravity": 0 # Set gravity
},
"tree2": {
"weapon_type": "tree2",
"damage": 20,
"fire_rate": 0.5,
"projectile_frames": 2,
"projectile_speed": 600,
"animation_frames": [
f"images/Projectiles/Tree2{i:03}.png"
for i in range(1, 3)
],
"projectile_types": ["projectile1"],
"frame_delay": 0.01,
"spos": (230, 50), # Relative to the sleigh
"fire_sound": ["audio/Tree.mp3"],
"initial_y_velocity": 0, # Set initial y velocity
"gravity": 0 # Set gravity
},
"gbread": {
"weapon_type": "gbread",
"damage": 40,
"fire_rate": 2,
"projectile_frames": 2,
"projectile_speed": 1000,
"animation_frames": [
f"images/Projectiles/gs{i:03}.png"
for i in range(1, 3)
],
"projectile_types": ["projectile1"],
"frame_delay": 0.1,
"spos": (291, 91), # Relative to the sleigh
"fire_sound": ["audio/Cannon.mp3"],
"initial_y_velocity": 0, # Set initial y velocity
"gravity": 0 # Set gravity
},
"rdeer": {
"weapon_type": "rdeer",
"damage": 50,
"fire_rate": 1.75,
"projectile_frames": 4,
"projectile_speed": 700,
"animation_frames": {
f"projectile{i}": [f"images/Projectiles/bs{i}-{j}.png" for j in range(1, 5)]
for i in range(1, 5)
},
"projectile_types": ["projectile1", "projectile2", "projectile3", "projectile4"],
"frame_delay": 0.1,
"spos": (291, 50), # Relative to the sleigh
"fire_sound": [
"audio/Clink1.mp3",
"audio/Clink2.mp3",
"audio/Clink3.mp3",
"audio/Clink4.mp3",
"audio/Clink5.mp3"
],
"initial_y_velocity": -300, # Adjust as needed for the desired arc
"gravity": 500 # Adjust to achieve the desired arc
},
# Define more weapon presets
}
basic_weapon = weapon_variables["basic"]
basic_weapon_2 = weapon_variables["basic2"]
basic_weapon_3 = weapon_variables["basic3"]
gingerbread_weapon = weapon_variables["gbread"]
# heavy_weapon = weapon_variables["heavy"]
rdeer_weapon = weapon_variables["rdeer"]
tree_weapon = weapon_variables["tree"]
tree_weapon_2 = weapon_variables["tree2"]
weapon_type = "basic"
left_frames = [
"Ring1-1.png",
"Ring2-1.png",
"Ring3-1.png",
"ClosedRing1-1.png",
"ClosedRing2-1.png"
# Add more animation frame paths here
]
right_frames = [
"Ring1-2.png",
"Ring2-2.png",
"Ring3-2.png",
"ClosedRing1-2.png",
"ClosedRing2-2.png"
]
# Create a list to hold the Ring instances
rings = []
def update_weapon_type(weapon_type):
player.current_weapon_type = weapon_type
player.update_player_image() # Update the player's image based on the new weapon type
class CloudGenerator(renpy.Displayable):
def __init__(self, small_count, medium_count, large_count, outer_count, over_count):
renpy.Displayable.__init__(self)
self.small_count = small_count
self.medium_count = medium_count
self.large_count = large_count
self.outer_count = outer_count
self.over_count = over_count
self.small_y_options = range(128, 1080 - 128) # Adjust this range as needed
self.medium_y_options = range(128, 1080 - 128) # Adjust this range as needed
self.large_y_options = range(100, 900)
self.outer_y_options = [-50, 0, 50, 1030, 1000, 970]
self.over_y_options = range(-50, 1130)
self.clouds = [] # List to hold cloud instances
self.cloud_size_images = {
"small": [
"images/Clouds/White/cloud_shape3_5.png",
"images/Clouds/White/cloud_shape4_5.png",
"images/Clouds/White/cloud_shape2_5.png",
"images/Clouds/White/cloud_shape3_4.png",
"images/Clouds/White/cloud_shape3_3.png",
"images/Clouds/White/cloud_shape3_2.png",
"images/Clouds/White/cloud_shape3_1.png",
"images/Clouds/White/cloud_shape4_4.png",
"images/Clouds/White/cloud_shape4_3.png",
"images/Clouds/White/cloud_shape4_2.png",
"images/Clouds/White/cloud_shape4_1.png",
"images/Clouds/White/cloud_shape2_4.png",
"images/Clouds/White/cloud_shape2_3.png",
"images/Clouds/White/cloud_shape2_2.png",
"images/Clouds/White/cloud_shape2_1.png",
# Add more small cloud image paths here
],
"medium": [
"images/Clouds/White/cloud_shape3_4.png",
"images/Clouds/White/cloud_shape3_3.png",
"images/Clouds/White/cloud_shape3_2.png",
"images/Clouds/White/cloud_shape3_1.png",
"images/Clouds/White/cloud_shape4_4.png",
"images/Clouds/White/cloud_shape4_3.png",
"images/Clouds/White/cloud_shape4_2.png",
"images/Clouds/White/cloud_shape4_1.png",
"images/Clouds/White/cloud_shape2_4.png",
"images/Clouds/White/cloud_shape2_3.png",
"images/Clouds/White/cloud_shape2_2.png",
"images/Clouds/White/cloud_shape2_1.png",
# Add more medium cloud image paths here
],
"large": [
"images/Clouds/White/cloud_large1.png",
"images/Clouds/White/cloud_large2.png",
# Add more large cloud image paths here
]
}
cloud_counts = [self.small_count, self.medium_count, self.large_count, self.outer_count, self.over_count]
s_buffer_distance = 300
m_buffer_distance = 300
l_buffer_distance = 500
self.oldst = None
# Initialize cloud instances based on provided counts
for i in range(small_count):
cloud_size = "small"
cloud_image = random.choice(self.cloud_size_images[cloud_size])
speed = random.choice([0.1, 0.5])
cloud = {
"count_type" : "small",
"x": 1920 + 128 + i * s_buffer_distance,
"y": random.randint(128, 1080 - 128),
"speed": speed,
"image": Image(cloud_image)
}
cloud["delay"] = random.uniform(0, 7)
self.clouds.append(cloud)
cloud["delay"] += 1
for i in range(medium_count):
cloud_size = "medium"
cloud_image = random.choice(self.cloud_size_images[cloud_size])
speed = random.choice([0.7, 0.8, 0.9])
cloud = {
"count_type" : "medium",
"x": 1920 + 128 + i * m_buffer_distance,
"y": random.randint(128, 1080 - 128),
"speed": speed,
"image": Image(cloud_image)
}
cloud["delay"] = random.uniform(0, 7)
self.clouds.append(cloud)
cloud["delay"] += 1
for i in range(large_count):
cloud_size = "large"
cloud_image = random.choice(self.cloud_size_images[cloud_size])
speed = random.choice([0.7, 0.8, 0.9])
cloud = {
"count_type" : "large",
"x": 1920 + 128 + i * l_buffer_distance,
"y": random.randint(100, 900),
"speed": speed,
"image": Image(cloud_image)
}
cloud["delay"] = random.uniform(0, 7)
self.clouds.append(cloud)
cloud["delay"] += 1
for i in range(outer_count):
cloud_size = "large"
cloud_image = random.choice(self.cloud_size_images[cloud_size])
speed = random.choice([0.5, 0.6])
cloud = {
"count_type" : "outer",
"x": 1920 + 128 + i * l_buffer_distance,
"y": random.choice([-50, 0, 50, 1030, 1000, 970]),
"speed": speed,
"image": Image(cloud_image)
}
cloud["delay"] = random.uniform(0, 7)
self.clouds.append(cloud)
cloud["delay"] += 1
for i in range(over_count):
cloud_size = "small"
cloud_image = random.choice(self.cloud_size_images[cloud_size])
speed = random.choice([0.6, 0.7])
cloud = {
"count_type" : "over",
"x": 1920 + 128 + i * s_buffer_distance,
"y": random.randint(-50, 1130),
"speed": speed,
"image": Image(cloud_image)
}
cloud["delay"] = random.uniform(0, 7)
self.clouds.append(cloud)
cloud["delay"] += 1
self.oldst = None
def render(self, width, height, st, at):
r = renpy.Render(width, height)
if self.oldst is None:
self.oldst = st
dtime = st - self.oldst
self.oldst = st
for cloud in self.clouds:
# Check if the cloud's delay has elapsed
if cloud["delay"] <= 0:
cloud["x"] -= cloud["speed"] + player.velocity
if cloud["x"] < -600:
cloud["x"] = width + 300
if cloud["count_type"] == "small":
cloud["y"] = random.choice(self.small_y_options)
elif cloud["count_type"] == "medium":
cloud["y"] = random.choice(self.medium_y_options)
elif cloud["count_type"] == "large":
cloud["y"] = random.choice(self.large_y_options)
elif cloud["count_type"] == "outer":
cloud["y"] = random.choice(self.outer_y_options)
elif cloud["count_type"] == "over":
cloud["y"] = random.choice(self.over_y_options)
cloud_image = renpy.render(cloud["image"], width, height, st, at)
r.blit(cloud_image, (int(cloud["x"]), int(cloud["y"])))
else:
cloud["delay"] -= at + st # Reduce the delay
renpy.redraw(self, 0)
return r
class Player(renpy.Displayable):
def __init__(self, x, y, speed):
self.px = x
self.py = y
self.speed = speed
self.width = 326
self.height = 238
self.pymin = 10
self.pymax = 1080 - 238
self.pxmin = 0
self.pxmax = 960 - 326
self.velocity = 0
self.gauge = 0
self.accelerate = False
self.health = 4
self.key_up = False
self.key_down = False
self.key_left = False
self.key_right = False
# Load the player images.
self.weapon_image_paths = {
"basic": "images/Sleigh1.png",
"basic2": "images/Sleigh2W.png",
"basic3": "images/Sleigh3W.png",
"tree": "images/SleighT1.png",
"tree2": "images/SleighTG2.png",
"gbread": "images/SleighG2.png",
"rdeer": "images/SleighRP1.png"
# Add more mappings for other weapon types
}
self.player_image = Image("Sleigh1.png") # Initialize with default image
self.current_weapon_type = "basic" # Default weapon type
self.update_player_image()
# Set player dimensions.
self.width = 326
self.height = 238
self.player_last_fire_time = 0 # Initialize with 0
self.projectiles = []
self.explosion_images = [
Image("images/Projectiles/Layer 23.png"),
Image("images/Projectiles/Layer 24.png"),
Image("images/Projectiles/Layer 25.png"),
Image("images/Projectiles/Layer 26.png")
]
self.explosion_duration = 1.0 # Duration of the explosion animation in seconds
self.explosion_timer = 0.0
self.explosion_frame = 0
self.is_exploding = False
self.destroyed = False
return
def update_player_image(self):
weapon_image_path = self.weapon_image_paths.get(self.current_weapon_type, "images/Sleigh1.png") # Default to Sleigh1.png if no mapping found
self.player_image = Image(weapon_image_path)
def move(self, dtime):
if self.key_up:
self.py -= self.speed * dtime
if self.key_down:
self.py += self.speed * dtime
if self.key_left:
self.velocity -= 1.5
self.px -= (self.speed + self.gauge) * dtime
if self.key_right:
self.velocity += 1.5
self.px += (self.speed + self.gauge) * dtime
self.accelerate = True
# Sleigh's travel boundaries
self.py = max(self.pymin, min(self.py, self.pymax))
self.px = max(self.pxmin, min(self.px, self.pxmax))
def fire_projectile(self, current_time, weapon_type):
player_fire_rate = 15
if current_time - self.player_last_fire_time >= 1.0 / player_fire_rate:
weapon_attributes = weapon_variables.get(weapon_type, {})
projectile_spos = weapon_attributes.get("spos", (0, 0)) # Get the starting position
fire_sound_options = weapon_attributes.get("fire_sound", ["audio/Blaster.mp3"])
fire_sound = random.choice(fire_sound_options) # Randomly select a fire sound
renpy.play(fire_sound, "weapon") # Play the randomly selected fire sound
projectile_types = weapon_attributes.get("projectile_types", [])
selected_projectile_type = random.choice(projectile_types) if projectile_types else None
selected_projectile_frames = weapon_attributes.get("animation_frames", [])
if isinstance(selected_projectile_frames, dict):
selected_projectile_frames = selected_projectile_frames.get(selected_projectile_type, [])
elif not isinstance(selected_projectile_frames, list):
selected_projectile_frames = []
projectile = Projectile(
self.px + projectile_spos[0], # Adjust starting x position
self.py + projectile_spos[1], # Adjust starting y position
weapon_attributes.get("projectile_speed"),
frame_delay=weapon_attributes.get("frame_delay"),
animation_frames=selected_projectile_frames, # Use the selected projectile's animation frames
is_player=True,
damage=weapon_attributes.get("damage"),
fire_rate=weapon_attributes.get("fire_rate"),
initial_y_velocity=weapon_attributes.get("initial_y_velocity"),
gravity=weapon_attributes.get("gravity")
)
self.projectiles.append(projectile)
renpy.play(fire_sound, "weapon")
self.player_last_fire_time = current_time # Update the last fire time
def overlaps_with(self, other):
left = self.px
right = self.px + self.width
top = self.py
bottom = self.py + self.height
other_left = other.x
other_right = other.x + other.width
other_top = other.y
other_bottom = other.y + other.height
horizontal_hit = (left <= other_right) and (right >= other_left)
vertical_hit = (top <= other_bottom) and (bottom >= other_top)
return horizontal_hit and vertical_hit
def render(self, width, height, st, at):
r = renpy.Render(width, height)
if not self.destroyed:
if self.is_exploding:
if self.explosion_frame < len(self.explosion_images):
explosion_frame = self.explosion_images[self.explosion_frame]
explosion_render = renpy.render(explosion_frame, width, height, st, at)
r.blit(explosion_render, (int(self.px), int(self.py))) # Render explosion frame
else:
player_image = renpy.render(self.player_image, width, height, st, at)
r.blit(player_image, (int(self.px), int(self.py))) # Render the player's image
return r
def handle_explosion(self):
if not self.is_exploding:
self.explosion_timer = 0.0
self.explosion_frame = 0
self.is_exploding = True
self.velocity = 0 # Reset the player's velocity
def update(self, dtime, st, at):
if self.is_exploding:
self.explosion_timer += dtime
# Calculate the current frame based on the elapsed time
frame_duration = self.explosion_duration / len(self.explosion_images)
self.explosion_frame = int(self.explosion_timer / frame_duration) # Use integer division to get the frame
# Check if the animation is completed
if self.explosion_frame >= len(self.explosion_images):
self.is_exploding = False # Reset the is_exploding flag
self.destroyed = True # Set destroyed to True when the explosion is completed
self.explosion_timer = 0.0 # Reset the explosion timer
self.explosion_frame = 0 # Reset the explosion frame
def event(self, ev, x, y, st):
if self.is_exploding:
return # Ignore events during explosion
if ev.type == pygame.KEYDOWN and ev.key == pygame.K_LEFT:
self.key_left = True
if ev.type == pygame.KEYUP and ev.key == pygame.K_LEFT:
self.key_left = False
if ev.type == pygame.KEYDOWN and ev.key == pygame.K_RIGHT:
self.key_right = True
if ev.type == pygame.KEYUP and ev.key == pygame.K_RIGHT:
self.key_right = False
if ev.type == pygame.KEYDOWN and ev.key == pygame.K_UP:
self.key_up = True
if ev.type == pygame.KEYUP and ev.key == pygame.K_UP:
self.key_up = False
if ev.type == pygame.KEYDOWN and ev.key == pygame.K_DOWN:
self.key_down = True
if ev.type == pygame.KEYUP and ev.key == pygame.K_DOWN:
self.key_down = False
if ev.type == pygame.KEYDOWN and ev.key == pygame.K_SPACE:
self.fire_projectile(st, weapon_type)
# Update gauge rendering based on velocity
if self.velocity >= 56:
self.gauge = 7
elif self.velocity >= 48:
self.gauge = 6
elif self.velocity >= 40:
self.gauge = 5
elif self.velocity >= 32:
self.gauge = 4
elif self.velocity >= 24:
self.gauge = 3
elif self.velocity >= 16:
self.gauge = 2
elif self.velocity >= 8:
self.gauge = 1
elif self.velocity == 1:
self.gauge = 0
# Update player's position based on key presses
if self.key_up:
self.py -= self.speed
if self.key_down:
self.py += self.speed
if self.key_left:
self.velocity -= 1.5
self.px -= self.speed + self.gauge
if self.key_right:
self.velocity += 1.5
self.px += self.speed + self.gauge
self.accelerate = True
# Handle player's velocity boundaries
if self.velocity >= 56:
if self.velocity == 70:
self.px += self.speed + 100
else:
self.px += self.speed + 10
if self.accelerate == False:
if self.px <= 700:
self.px = 700
elif self.velocity >= 40:
if self.accelerate == False:
if self.px <= 500:
self.px = 500
elif self.velocity >= 24:
if self.accelerate == False:
if self.px <= 300:
self.px = 300
elif self.velocity >= 8:
if self.accelerate == False:
if self.px <= 100:
self.px = 100
if self.velocity <= 1:
self.velocity = 1
if self.velocity >= 56 and self.velocity <= 69:
self.velocity = 56
# Update player's position within screen boundaries
if self.velocity != 70:
if self.py < self.pymin:
self.py = self.pymin
if self.py > self.pymax:
self.py = self.pymax
if self.px < self.pxmin:
self.px = self.pxmin
if self.px > self.pxmax:
self.px = self.pxmax
if sleighgame.difficulty == "Easy":
if sleighgame.totalrings == 30:
sleighgame.gameover = True
self.velocity = 70
renpy.show_screen("scoreshow")
elif sleighgame.difficulty == "Medium":
if sleighgame.totalrings == 35:
sleighgame.gameover = True
self.velocity = 70
renpy.show_screen("scoreshow")
elif sleighgame.difficulty == "Hard":
if sleighgame.totalrings == 40:
sleighgame.gameover = True
self.velocity = 70
renpy.show_screen("scoreshow")
elif sleighgame.difficulty == "Ultra Hard":
if sleighgame.totalrings == 45:
sleighgame.gameover = True
self.velocity = 70
renpy.show_screen("scoreshow")
class Ring(renpy.Displayable):
def __init__(self, x, y, images_left, images_right, ringspeed, ring_type, buffer):
renpy.Displayable.__init__(self)
self.x = x
self.y = y
self.height = 322
self.width = 144
self.images_left = [Image(image) for image in left_frames]
self.images_right = [Image(image) for image in right_frames]
self.frame_index = 0
self.collected = False
self.missed = False
self.ringspeed = 100
self.ring_type = ring_type
self.buffer = buffer
self.hit_by_projectile = False
self.hit_by_player = False
self.right_half_hit = False
self.ring_instance = None # Initialize the ring_instance attribute
# Add frame indices for different stages of animation
self.animation_frames = [0, 1, 2, 3, 4]
self.current_frame = self.animation_frames[0]
# Lists of image paths for each frame
self.left_frames = images_left
self.right_frames = images_right
# New attributes for the moving behavior
self.moving_y_range = 200 # Adjust the range as needed
self.moving_direction = 1 # Start moving down
self.y_initial = y # Define y_initial here
def collides_with_player(self, player):
ring_left = self.x + self.width * 1.2
sleigh_right = player.px + player.width
horizontal_hit = (ring_left <= sleigh_right) and (ring_left + self.width >= sleigh_right)
vertical_hit = (self.y <= player.py + player.height) and (self.y + self.height >= player.py)
if not player.destroyed:
return horizontal_hit and vertical_hit
def collides_with_projectile(self, projectile):
if projectile is None:
return False
proj_x, proj_y = projectile.get_position()
proj_width, proj_height = projectile.get_dimensions()
proj_left = proj_x
proj_right = proj_x + proj_width
proj_top = proj_y
proj_bottom = proj_y + proj_height
horizontal_hit = (proj_left <= self.x + self.width) and (proj_right >= self.x)
vertical_hit = (proj_top <= self.y + self.height) and (proj_bottom >= self.y)
return horizontal_hit and vertical_hit
def render_left_half(self, width, height, st, at):
if self.missed or self.x < -self.width:
return None
# Determine the current frame index based on animation status and type
if self.ring_type == "Moving":
current_frame_index = 1
elif self.ring_type == "Static":
current_frame_index = 0
elif self.ring_type == "ClosedMoving":
if self.hit_by_projectile == False:
current_frame_index = 4
else:
current_frame_index = 1
elif self.ring_type == "ClosedStatic":
if self.hit_by_projectile == False:
current_frame_index = 3
else:
current_frame_index = 0
if self.collected:
current_frame_index = 2
# Render the appropriate frame based on the current animation frame
ring_image_left = renpy.render(self.images_left[current_frame_index], width, height, st, at)
r = renpy.Render(width, height)
r.blit(ring_image_left, (int(self.x), int(self.y)))
return r
def render_right_half(self, width, height, st, at):
if self.missed or self.x < -self.width:
return None
# Determine the current frame index based on animation status and type
if self.ring_type == "Moving":
current_frame_index = 1
elif self.ring_type == "Static":
current_frame_index = 0
elif self.ring_type == "ClosedMoving":
if self.hit_by_projectile == False:
current_frame_index = 4
else:
current_frame_index = 1
elif self.ring_type == "ClosedStatic":
if self.hit_by_projectile == False:
current_frame_index = 3
else:
current_frame_index = 0
if self.collected:
current_frame_index = 2
# Render the appropriate frame based on the current animation frame
ring_image_right = renpy.render(self.images_right[current_frame_index], width, height, st, at)
r = renpy.Render(width, height)
r.blit(ring_image_right, (int(self.x) + self.width // 2 - 72.5, int(self.y)))
return r
def collect(self):
self.collected = True
renpy.play("audio/bells.mp3", "sound")
sleighgame.totalrings += 1
def miss(self):
if self.missed == False:
self.missed = True
sleighgame.totalrings += 1
def update(self, dtime):
self.x -= self.ringspeed * dtime + player.velocity
if self.x <= -100 and self.collected == False:
self.miss()
if self.ring_type == "Moving" or self.ring_type == "ClosedMoving":
self.y += self.moving_direction * 200 * dtime # Adjust the speed as needed
if self.y <= self.y_initial - self.moving_y_range:
self.moving_direction = 1
elif self.y >= self.y_initial + self.moving_y_range:
self.moving_direction = -1
class Projectile:
def __init__(self, x, y, speed, frame_delay, animation_frames=None, image_path=None, is_player=False, damage=0, fire_rate=0, spos=None, initial_y_velocity=0, gravity=0, width=0, height=0):
self.x = x
self.y = y
self.speed = speed
self.animation_frames = animation_frames or []
self.image_path = image_path
self.frame_index = 0
self.frame_delay = frame_delay # Adjust as needed
self.time_since_last_frame = 0
self.is_player = is_player
self.damage = damage # Include the damage parameter
self.fire_rate = fire_rate
self.frame_delay = frame_delay
self.spos = spos
self.initial_y_velocity = initial_y_velocity # Initial vertical velocity
self.gravity = gravity # Gravity effect
self.width = width # Add width attribute
self.height = height # Add height attribute
def update(self, dt):
if self.animation_frames:
self.time_since_last_frame += dt
if self.time_since_last_frame >= self.frame_delay:
self.frame_index = (self.frame_index + 1) % len(self.animation_frames)
self.time_since_last_frame = 0
# Update x position based on speed
self.x += self.speed * dt
# Update y position based on initial_y_velocity and gravity
self.y += self.initial_y_velocity * dt
self.initial_y_velocity += self.gravity * dt
def get_current_frame(self):
if self.animation_frames:
return self.animation_frames[self.frame_index]
else:
return None
def get_position(self):
return self.x, self.y
def get_dimensions(self):
return self.width, self.height
def render(self, dtime, width, height, st, at):
if self.is_player:
self.x += self.speed * dtime
else:
self.x -= self.speed * dtime
self.y += self.initial_y_velocity * dtime
self.initial_y_velocity += self.gravity * dtime
projectile_image_path = self.get_current_frame()
if projectile_image_path:
projectile_image = renpy.ImageReference(projectile_image_path)
r.blit(projectile_image, (int(self.x), int(self.y)))
class SleighShooter(renpy.Displayable):
def __init__(self, player, difficulty):
renpy.Displayable.__init__(self)
self.score = 0
self.misses = 0
self.oldst = None
self.lose = False
self.difficulty = sleighring_difficulty
self.enemies = []
self.player = player
self.active_enemy_projectiles = [] # List to store active enemy projectiles=
self.introd = False
self.starttimer = 0
self.timer = 0 # Initialize the timer
self.gameover = False
# Initialize the rings with their attributes
if self.difficulty == "Easy":
rings = initialize_rings(ring_count=23, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="Static", buffer_range=(700, 2000))
rings += initialize_rings(ring_count=7, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="Moving", buffer_range=(700, 2000))
elif self.difficulty == "Medium":
rings = initialize_rings(ring_count=20, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="Static", buffer_range=(700, 2000))
rings += initialize_rings(ring_count=5, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="Moving", buffer_range=(700, 2000))
rings += initialize_rings(ring_count=5, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="ClosedStatic", buffer_range=(1000, 2000))
rings += initialize_rings(ring_count=5, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="ClosedMoving", buffer_range=(1000, 2000))
elif self.difficulty == "Hard":
rings = initialize_rings(ring_count=10, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="Static", buffer_range=(700, 2000))
rings += initialize_rings(ring_count=10, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="Moving", buffer_range=(700, 2000))
rings += initialize_rings(ring_count=10, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="ClosedStatic", buffer_range=(1000, 2000))
rings += initialize_rings(ring_count=10, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="ClosedMoving", buffer_range=(1000, 2000))
elif self.difficulty == "Ultra Hard":
rings = initialize_rings(ring_count=5, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="Static", buffer_range=(700, 2000))
rings += initialize_rings(ring_count=10, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="Moving", buffer_range=(700, 2000))
rings += initialize_rings(ring_count=15, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="ClosedStatic", buffer_range=(1000, 2000))
rings += initialize_rings(ring_count=15, ring_width=50, images_left=left_frames, images_right=right_frames, ring_type="ClosedMoving", buffer_range=(1000, 2000))
# Shuffle the rings list
import random
random.shuffle(rings)
# Generate rings with proper spacing
current_x = renpy.config.screen_width # Start offscreen to the right
for ring in rings:
ring.x = current_x
current_x += ring.buffer + ring.width
self.rings = rings # Assign the shuffled rings back to the class attribute
self.totalrings = 0
return
@property
def timer_formatted(self):
# Format the timer value with 1 decimal place
return "{:.0f}".format(self.timer)
def calculate_dtime(self, st):
if self.oldst is None:
self.oldst = st
dtime = st - self.oldst
self.oldst = st
return dtime
def update_game_state(self):
if self.introd and not self.gameover:
if player.health <= 0:
player.handle_explosion() # Trigger the player's explosion
renpy.play("audio/Destroyed.mp3", "sfx") # Play explosion sound
# Draws the screen
def render(self, width, height, st, at):
r = renpy.Render(width, height)
# Figure out the time elapsed since the previous frame.
if self.oldst is None:
self.oldst = st
dtime = st - self.oldst
self.oldst = st
self.starttimer += dtime
if self.starttimer >= 5:
self.introd = True
# Increment the timer
if self.introd == True and self.gameover == False:
self.timer += dtime
# Collect the render objects for left and right halves of rings
left_ring_images = []
right_ring_images = []
projectiles_to_remove = []
# Update and render rings
if self.introd == True:
for ring in self.rings:
ring.update(dtime)
# Render the left half of the ring below the sleigh
ring_left_half_render = ring.render_left_half(width, height, st, at)
if ring_left_half_render:
r.blit(ring_left_half_render, (0, 0))
if not self.gameover:
if player.health > 0 and not player.is_exploding:
# Render the player's image
player_image = renpy.render(player.player_image, width, height, st, at)
r.blit(player_image, (int(player.px), int(player.py)))
elif player.is_exploding:
if player.explosion_frame < len(player.explosion_images):
explosion_frame = player.explosion_images[player.explosion_frame]
explosion_render = renpy.render(explosion_frame, width, height, st, at)
r.blit(explosion_render, (int(player.px), int(player.py)))
player.update(st - self.starttimer, st, at) # Advance the explosion animation and update the timer
# Update and render projectiles
for projectile in self.player.projectiles:
projectile.x += projectile.speed * dtime
projectile.update(dtime) # Update the current frame of the projectile
projectile_image_path = projectile.get_current_frame() # Get the current frame path
projectile_image = renpy.display.im.Image(projectile_image_path) # Create an ImageReference object
projectile_image = renpy.render(projectile_image, width, height, st, at) # Render the image
r.blit(projectile_image, (int(projectile.x), int(projectile.y)))
# Remove projectiles that go off-screen
if projectile.x > width:
self.player.projectiles.remove(projectile)
# Call player.update(dtime) here
player.update(dtime, st, at)
if self.introd == True:
for ring in self.rings:
ring_right_half_render = ring.render_right_half(width, height, st, at)
if ring_right_half_render:
r.blit(ring_right_half_render, (0, 0))
if ring.collected == False and ring.collides_with_player(player):
# Collision with player logic
if ring.ring_type == "ClosedStatic" or ring.ring_type == "ClosedMoving":
if ring.hit_by_projectile == False and ring.hit_by_player == False:
player.health -= 1
ring.hit_by_player = True
renpy.play("audio/Crash1.mp3", "sound") # Play collision sound
elif ring.hit_by_projectile == True:
ring.collected = True
ring.collect()
self.score +=1
elif ring.ring_type == "Static" or ring.ring_type == "Moving":
ring.collected = True
ring.collect() # Call the collect method
self.score += 1
for projectile in player.projectiles:
if ring.collected == False and ring.collides_with_projectile(projectile):
# Collision with projectile logic
if ring.ring_type == "ClosedStatic" or ring.ring_type == "ClosedMoving":
if ring.hit_by_projectile == False:
ring.hit_by_projectile = True
renpy.play("audio/RingDown.mp3", "sfx") # Play collision sound
projectiles_to_remove.append(projectile)
# Check game over conditions
self.update_game_state()
# Remove projectiles outside the loop
for projectile in projectiles_to_remove:
self.player.projectiles.remove(projectile)
# Ask that we be re-rendered ASAP, so we can show the next
# frame.
renpy.redraw(self, 0)
# Return the Render object.
return r
# Handles events.
def event(self, ev, x, y, st):
# Pass the events to the Player instance
player.event(ev, x, y, st)
# Ensure the screen updates.
renpy.restart_interaction()
# Check if the player's health is zero or below and not destroyed.
if player.health <= 0 and not player.destroyed:
player.handle_explosion()
renpy.play("audio/Destroyed.mp3", "sfx")
# Set self.lose based on player.destroyed
self.lose = player.destroyed
if self.lose:
sleighgame.gameover = True
renpy.show_screen("scoreshow")
else:
raise renpy.IgnoreEvent()
def initialize_rings(ring_count, ring_width, images_left, images_right, ring_type, buffer_range=(600, 800)):
rings = []
for i in range(ring_count):
buffer = random.uniform(*buffer_range)
ring_x = renpy.config.screen_width + buffer + i * ring_width # Start offscreen to the right
ring_y = random.randint(128, renpy.config.screen_height - 300)
if ring_type == "Moving":
ring = Ring(ring_x, ring_y, images_left, images_right, ringspeed=100, ring_type="Moving", buffer=buffer)
elif ring_type == "Static":
ring = Ring(ring_x, ring_y, images_left, images_right, ringspeed=100, ring_type="Static", buffer=buffer)
elif ring_type == "ClosedMoving":
ring = Ring(ring_x, ring_y, images_left, images_right, ringspeed=80, ring_type="ClosedMoving", buffer=buffer)
elif ring_type == "ClosedStatic":
ring = Ring(ring_x, ring_y, images_left, images_right, ringspeed=80, ring_type="ClosedStatic", buffer=buffer)
rings.append(ring)
return rings
screen sleigh_ride():
add Image("bg Sky.png")
add cloudcover
add cloudfore
# Add the left side of the rings below the sleigh
for ring in rings:
add ring.render_left_half(width, height, st, at)
add sleighgame
# Add the right side of the rings above the sleigh
for ring in rings:
add ring.render_right_half(width, height, st, at)
# Display "Get Ready" image at starttimer 1 and remove at starttimer 4
if sleighgame.starttimer >= 1 and sleighgame.starttimer < 4:
add Image("images/GetReady.png", style="positioned_image")
# Display "Fly!" image at starttimer 4 and remove at starttimer 5
if sleighgame.starttimer >= 4 and sleighgame.starttimer < 5:
add Image("images/Fly.png", style="positioned_image")
# Add a text element to display the score at the top
vbox:
text "Score: [sleighgame.score]" style "scoreboard"
vbox:
text "Time: [sleighgame.timer_formatted]" style "timekeeper"
# vbox:
# text "Explosion Frame: [player.explosion_frame]" style "tester"
# vbox:
# text "Explosion Timer: [player.explosion_timer]" style "tester2"
# vbox:
# text "Total Rings: [sleighgame.totalrings]" style "tester"
# vbox:
# text "Velocity: [player.velocity]" style "tester2"
hbox:
style "w_buttons"
textbutton "Basic 1" action [SetVariable("weapon_type", "basic"), lambda: update_weapon_type("basic")]
textbutton "Basic 2" action [SetVariable("weapon_type", "basic2"), lambda: update_weapon_type("basic2")]
textbutton "Basic 3" action [SetVariable("weapon_type", "basic3"), lambda: update_weapon_type("basic3")]
textbutton "Tree 1" action [SetVariable("weapon_type", "tree"), lambda: update_weapon_type("tree")]
textbutton "Tree 2" action [SetVariable("weapon_type", "tree2"), lambda: update_weapon_type("tree2")]
textbutton "Gingerbread" action [SetVariable("weapon_type", "gbread"), lambda: update_weapon_type("gbread")]
textbutton "Reindeer" action [SetVariable("weapon_type", "rdeer"), lambda: update_weapon_type("rdeer")]
if player.health == 1:
vbox:
add Image("images/SleighShield4.png")
xpos 30 ypos 10
elif player.health == 2:
vbox:
add Image("images/SleighShield3.png")
xpos 30 ypos 10
elif player.health == 3:
vbox:
add Image("images/SleighShield2.png")
xpos 30 ypos 10
elif player.health == 4:
vbox:
add Image("images/SleighShield1.png")
xpos 30 ypos 10
if player.gauge == 0:
vbox:
add Image("images/Gauge/gauge0.png")
xpos 20 ypos 120
elif player.gauge == 1:
vbox:
add Image("images/Gauge/gauge1.png")
xpos 20 ypos 120
elif player.gauge == 2:
vbox:
add Image("images/Gauge/gauge2.png")
xpos 20 ypos 120
elif player.gauge == 3:
vbox:
add Image("images/Gauge/gauge3.png")
xpos 20 ypos 120
elif player.gauge == 4:
vbox:
add Image("images/Gauge/gauge4.png")
xpos 20 ypos 120
elif player.gauge == 5:
vbox:
add Image("images/Gauge/gauge5.png")
xpos 20 ypos 120
elif player.gauge == 6:
vbox:
add Image("images/Gauge/gauge6.png")
xpos 20 ypos 120
elif player.gauge == 7:
vbox:
add Image("images/Gauge/gauge7.png")
xpos 20 ypos 120
screen scoreshow():
vbox:
imagebutton:
idle "images/bg transparency.png"
action Jump("game_over")
if player.health == 0:
add Image("images/GameOver.png", style="positioned_image")
else:
if sleighgame.difficulty == "Easy":
if sleighgame.score == 30:
add Image("images/Perfect_Score.png", style="positioned_image")
elif sleighgame.score >= 25:
add Image("images/Great_Score.png", style="positioned_image")
elif sleighgame.score >= 20:
add Image("images/Good_Score.png", style="positioned_image")
elif sleighgame.score >= 15:
add Image("images/Okay_Score.png", style="positioned_image")
elif sleighgame.score <= 14:
add Image("images/Bad_Score.png", style="positioned_image")
elif sleighgame.difficulty == "Medium":
if sleighgame.score == 35 and player.health == 4:
add Image("images/Perfect_Game.png", style="positioned_image")
elif sleighgame.score == 35:
add Image("images/Perfect_Score.png", style="positioned_image")
elif sleighgame.score >= 30:
add Image("images/Great_Score.png", style="positioned_image")
elif sleighgame.score >= 20:
add Image("images/Good_Score.png", style="positioned_image")
elif sleighgame.score >= 15:
add Image("images/Okay_Score.png", style="positioned_image")
elif sleighgame.score <= 14:
add Image("images/Bad_Score.png", style="positioned_image")
elif sleighgame.difficulty == "Hard":
if sleighgame.score == 40 and player.health == 4:
add Image("images/Perfect_Game.png", style="positioned_image")
elif sleighgame.score == 40:
add Image("images/Perfect_Score.png", style="positioned_image")
elif sleighgame.score >= 30:
add Image("images/Great_Score.png", style="positioned_image")
elif sleighgame.score >= 20:
add Image("images/Good_Score.png", style="positioned_image")
elif sleighgame.score >= 15:
add Image("images/Okay_Score.png", style="positioned_image")
elif sleighgame.score <= 14:
add Image("images/Bad_Score.png", style="positioned_image")
elif sleighgame.difficulty == "Ultra Hard":
if sleighgame.score == 45 and player.health == 4:
add Image("images/Perfect_Game.png", style="positioned_image")
elif sleighgame.score == 40:
add Image("images/Perfect_Score.png", style="positioned_image")
elif sleighgame.score >= 35:
add Image("images/Great_Score.png", style="positioned_image")
elif sleighgame.score >= 25:
add Image("images/Good_Score.png", style="positioned_image")
elif sleighgame.score >= 15:
add Image("images/Okay_Score.png", style="positioned_image")
elif sleighgame.score <= 14:
add Image("images/Bad_Score.png", style="positioned_image")
screen highscore_table():
hbox:
spacing 30 # Adjust the spacing between frames as needed
xalign 0.5
yalign 0.5
frame:
style "frame_easy"
vbox:
text "Easy" style "title"
xalign 0.5 yalign 0.05
# Display the Easy high score entries
for i, (name, score, time) in enumerate(persistent.easy_scores, 1):
hbox:
spacing 40
text "[i]. [name]" style "table_entry"
text "[score]" style "table_entry"
text "[time]" style "table_entry"
frame:
style "frame_medium"
vbox:
text "Medium" style "title"
xalign 0.5 yalign 0.05
# Display the Medium high score entries
for i, (name, score, time) in enumerate(persistent.medium_scores, 1):
hbox:
spacing 40
text "[i]. [name]" style "table_entry"
text "[score]" style "table_entry"
text "[time]" style "table_entry"
frame:
style "frame_hard"
vbox:
text "Hard" style "title"
xalign 0.5 yalign 0.05
# Display the Hard high score entries
for i, (name, score, time) in enumerate(persistent.hard_scores, 1):
hbox:
spacing 40
text "[i]. [name]" style "table_entry"
text "[score]" style "table_entry"
text "[time]" style "table_entry"
frame:
style "frame_ultra_hard"
vbox:
text "Ultra Hard" style "title"
xalign 0.5 yalign 0.05
# Display the Ultra Hard high score entries
for i, (name, score, time) in enumerate(persistent.ultra_hard_scores, 1):
hbox:
spacing 20
text "[i]. [name]" style "table_entry"
text "[score]" style "table_entry"
text "[time]" style "table_entry"
vbox:
imagebutton:
idle "images/bg transparency.png"
action Jump("playagain")
screen play_again_prompt():
modal True
frame:
style "white_frame"
vbox:
text "{color=#FF0000}Do you want to play again?{/color}"
textbutton "{color=#FF0000}Yes{/color}" action Jump("start")
textbutton "{color=#FF0000}No{/color}" action Return()