The idea is just to make a basic tobogganing game, dodging obstacles and getting pickups. I've got my basic loop working so that my toboggan is displayed, and I can move it back and forth.
So here's what I have at the moment:
Vs what I'm envisioning:
I want the trees, when generated, to start off small, and near the horizon line. The ones generated on the left would increase in size as they move forwards, and eventually go offscreen left. Likewise for the ones generated on the right and offscreen right.
I ran a test just to see what my outside ranges would be, going from zoom 0.05 to zoom 1.0:
Code: Select all
screen treetest():
vbox:
add "images/pine.png"
xpos 600 ypos 170
at zoomquantum
vbox:
add "images/pine.png"
xpos 1220 ypos 170
at zoomquantum
vbox:
add "images/pine.png"
xpos -10 ypos 170
at zoomquantum
vbox:
add "images/pine.png"
xpos 1900 ypos 170
at zoomquantum
vbox:
add "images/pine.png"
xpos -500 ypos -600
vbox:
add "images/pine.png"
xpos 1810 ypos -400
So, I have no idea how to go about this. I spent a good amount of time trying different things, but kept getting errors with my render method. When I didn't get errors, the trees would generate at full-size right away.
Is there some other type of displayable I should be using for this? Some way to change the anchor for the trees to the bottom of the trunk that would be easier than the situation I currently have going?
Here's my current mess of code, just working with the one pine.png image for now:
Code: Select all
init python:
def quad_interp(a, b, c, t):
return a * (1 - t) ** 2 + 2 * b * (1 - t) * t + c * t ** 2
class TreeGenerator(renpy.Displayable):
def __init__(self, xpos_range, zoom):
renpy.Displayable.__init__(self)
self.image_path = Image("images/pine.png")
self.width = 32
self.height = 64
self.ypos = 170
self.zoom = 0.05
self.xpos = random.uniform(xpos_range[0], xpos_range[1])
self.inside_count = 10
self.zoom_speed = 15.0
self.start_time = 0
self.progress = 0
def update(self, dt, st):
if self.start_time == 0:
self.start_time = st
time_elapsed = st - self.start_time
start_xpos = random.uniform(-10, 600) if random.choice([True, False]) else random.uniform(1220, 1900)
self.side = "left" if start_xpos <= 600 else "right"
target_xpos = 1810 if self.side == "right" else -500
target_ypos = -400 if self.side == "right" else -600
divisor = self.ypos - target_ypos
self.progress = min(time_elapsed / self.zoom_speed, 1.0) if divisor != 0 else 0.0
# Calculate the ypos and zoom using quadratic interpolation
self.ypos = quad_interp(170, -600, 0, self.progress)
self.zoom = quad_interp(0.05, 1.0, 1.0, self.progress)
# Calculate the current xpos based on the initial xpos and progress
self.xpos = lerp(self.xpos, target_xpos, self.progress)
def is_offscreen(self):
return (self.xpos > 1910 or self.xpos < -10)
def render(self, width, height, st, at):
# Calculate the scaled width and height based on the zoom factor
scaled_width = self.width * self.zoom
scaled_height = self.height * self.zoom
# Render the tree with the scaled dimensions
tree_image = renpy.render(self.image_path, scaled_width, scaled_height, st, at)
return tree_image
class Toboggan(renpy.Displayable):
def __init__(self, x, y):
renpy.Displayable.__init__(self)
self.px = x
self.py = y
self.width = 283
self.height = 221
self.pxmin = 0
self.pxmax = 1920 - 283
self.velocity = 200 # Adjust the velocity as needed
self.key_left = False
self.key_right = False
self.tob_image = Image("tob.png")
def move(self, dt):
print(f"Key Left: {self.key_left}, Key Right: {self.key_right}")
print(f"Moving toboggan: {self.px}")
if self.key_left:
self.px -= 800 * dt
if self.key_right:
self.px += 800 * dt
def render(self, width, height, st, at):
print(f"Drawing toboggan at position: ({self.px}, {self.py})")
tob_image = renpy.render(self.tob_image, width, height, st, at)
return tob_image
def event(self, ev, x, y, st):
if ev.type == pygame.KEYDOWN and ev.key == pygame.K_LEFT:
print("Left key pressed")
self.key_left = True
if ev.type == pygame.KEYDOWN and ev.key == pygame.K_RIGHT:
print("Right key pressed")
self.key_right = True
if ev.type == pygame.KEYUP and ev.key == pygame.K_LEFT:
print("Left key released")
self.key_left = False
if ev.type == pygame.KEYUP and ev.key == pygame.K_RIGHT:
print("Right key released")
self.key_right = False
# if self.key_left:
# self.px -= 50
# if self.key_right:
# self.px += 50
# if self.px < self.pxmin:
# self.px = self.pxmin
# if self.px > self.pxmax:
# self.px = self.pxmax
class HillLoop(renpy.Displayable):
def __init__(self, toboggan, st):
renpy.Displayable.__init__(self)
self.toboggan = toboggan
self.st = st
self.oldst = None
self.end = False
self.tree_generators = [
TreeGenerator(xpos_range=(-10, 600), zoom=0.05),
TreeGenerator(xpos_range=(1220, 1900), zoom=0.05),
]
self.rendered_trees = [] # Separate list for rendered trees
def calculate_dt(self, st):
if self.oldst is None:
self.oldst = st
dt = st - self.oldst
self.oldst = st
return dt
def update(self, dt):
# Update toboggan position
self.toboggan.move(dt)
# Update tree generators
for tree in self.rendered_trees[:]:
tree.update(dt, self.st)
if tree.is_offscreen():
self.rendered_trees.remove(tree)
# Check game conditions (elapsed time, etc.)
elapsed_time = self.st
if elapsed_time >= 80:
# End the loop
self.end = True
if len(self.tree_generators) < 30:
xpos_range = (-10, 1900)
if not (600 < self.toboggan.px < 1220):
new_tree = TreeGenerator(xpos_range, 0.05)
self.rendered_trees.append(new_tree)
self.rendered_trees.append(new_tree)
renpy.redraw(self.toboggan, 0)
def render(self, width, height, st, at):
# The Render object we'll be drawing into.
r = renpy.Render(width, height)
# Figure out the time elapsed since the previous frame.
dt = st - self.st
self.st = st
# Draw trees
for tree in self.rendered_trees:
# Render the tree
tree_render = tree.render(width, height, st, at)
# Blit the tree onto the main Render object
r.blit(tree_render, (tree.xpos, 170), main=False)
# Draw toboggan after trees
tob_r = self.toboggan.render(width, height, st, at)
r.blit(tob_r, (int(self.toboggan.px), int(self.toboggan.py)))
renpy.redraw(self, 0)
# Update game state after drawing all elements
self.update(dt)
return r
def event(self, ev, x, y, st):
renpy.restart_interaction()
# Call toboggan's event method to handle key events
self.toboggan.event(ev, x, y, st)
screen go_tob():
add hill_loop
Looking at the documentation for renpy.Render, I see the zoom attribute, but am a bit confused by it.
If the width, height, and blit coordinates are not zoomed, will it not be able to achieve what I'm going for?zoom(xzoom, yzoom) link
Sets the zoom level of the children of this displayable in the horizontal and vertical axes. Only the children of the displayable are zoomed – the width, height, and blit coordinates are not zoomed.
Any help or insight would be greatly appreciated!