Just to put a bow on things, so to speak, I uploaded a standalone version of the minigame to itch.io:
https://thexerox123.itch.io/christmas-cranes
And I'll put the final code here for posterity!
crane_game_displayable.rpy:
Code: Select all
image blue_crane = Image("BlueCrane.png", xysize=(200,200))
image red_crane = Image("RedCrane.png", xysize=(200,200))
image green_crane = Image("GreenCrane.png", xysize=(200,200))
image gold_crane = Image("GoldCrane.png", xysize=(200,200))
image a_right = Image("Right_Idle.png", xysize=(100,100))
image a_left = Image("Left_Idle.png", xysize=(100,100))
image a_up = Image("Up_Idle.png", xysize=(100,100))
image bear_one = Image("Bear1.png", xysize=(100,100))
image bear_two = Image("Bear2.png", xysize=(100,100))
image bear_three = Image("Bear3.png", xysize=(100,100))
image bear_four = Image("Bear4.png", xysize=(100,100))
image bear_five = Image("Bear5.png", xysize=(100,100))
init python:
class TimerObj(renpy.Displayable):
def __init__(self, obj, name, **kwargs):
super(TimerObj, self).__init__(**kwargs)
self.obj = obj
self.name = name
setattr(self.obj, self.name, 0)
def render(self, width, height, st, at):
if getattr(self.obj, self.name) < st:
setattr(self.obj, self.name, st)
r = renpy.Render(width, height)
cr = renpy.render(Text("{:.2f}".format(getattr(self.obj, self.name))), width, height, st, at)
r.blit(cr, (0,0))
renpy.redraw(self, 0)
return renpy.Render(0, 0)
class Crane():
def __init__(self, crane_type, toy_image, box_image, start_st, duration,
number_of_arrows = 3, dt_start = 5.0, dt_end = 3.0):
self.d = crane_type
self.toy_image = toy_image
self.box_image = box_image
self.start_st = start_st
self.duration = duration
self.dt_start = dt_start
self.dt_end = dt_end
self.arrows = []
for i in range(0,number_of_arrows):
self.arrows.append(renpy.random.choice(
["a_left", "a_up", "a_right"]))
self.progress = "start"
def input_handler(self, key, st, game):
try:
if self.arrows[self.progress] == key and self.progress == game.progress:
self.progress += 1
game.reset_progress = False
if self.progress == len(self.arrows):
self.progress = "done"
self.end_st = st
game.reset_progress = True
return True
else:
self.progress = 0
except TypeError:
return
def time_handler(self, st):
if self.progress == "start":
if self.timer(st) <= 0:
self.progress = 0
else:
if self.timer(st) <= 0:
if self.progress == "done" or self.progress == "miss":
return True
else:
self.end_st = st
renpy.play(Wrong)
self.progress = "miss"
def timer(self, st):
if self.progress == "start":
return self.start_st + self.dt_start - st
elif self.progress == "done" or self.progress == "miss":
return self.end_st + self.dt_end - st
else:
return self.start_st + self.dt_start + self.duration - st
class CraneGame():
def __init__(self, difficulty):
self.game_finished = False
self.score = 0
self.difficulty = difficulty
self.time = 0
if difficulty == "easy":
self.cranes_left = [30,15,0,0]
elif difficulty == "medium":
self.cranes_left = [20,24,5,1]
elif difficulty == "hard":
self.cranes_left = [20,20,10,5]
else:
self.cranes_left = [20,20,20,10]
self.columns = [[],[],[],[],[]]
self.progress = 0
def generate_crane(self):
if self.cranes_left == [0,0,0,0]:
return
# generate crane in empty columns
weights = [(1 if i == [] else 0) for i in self.columns]
if weights == [0]*len(self.columns):
weights = [1]*len(self.columns)
column = renpy.random.choices(range(0,5), weights=weights, k=1)[0]
crane_types = ["blue_crane", "red_crane", "green_crane", "gold_crane"]
toy_image = renpy.random.choices(["Bear1.png", "Bear2.png", "Bear3.png", "Bear4.png", "Bear5.png", "Doll1.png", "Doll2.png", "Doll3.png", "Doll4.png", "Doll5.png", "Robot1.png", "Robot2.png", "Robot3.png", "Robot4.png", "Robot5.png", "Car1.png", "Car2.png", "Car3.png", "Car4.png", "Car5.png"])
box_image = renpy.random.choices(["Box1.png", "Box2.png", "Box3.png", "Box4.png", "Box5.png", "Box6.png", "Box7.png", "Box8.png", "Box9.png", "Box10.png", "Box11.png", "Box12.png", "Box13.png", "Box14.png", "Box15.png", "Box16.png", "Box17.png", "Box18.png", "Box19.png", "Box20.png"])
crane_id = renpy.random.choices(range(0,4), weights=self.cranes_left, k=1)[0]
self.cranes_left[crane_id] -= 1
crane_type = crane_types[crane_id]
duration = 14.0 - 2.0*crane_id
dt_start = 0.2 + 0.2*column
dt_end = 1.0 - 0.2*column
crane = Crane(crane_type, toy_image, box_image, self.time, duration, dt_start = dt_start, dt_end = dt_end)
self.columns[column].append(crane)
def number_of_shown_cranes(self):
n = 0
for column in self.columns:
for crane in column:
n += 1
return n
def set_screen_timer(self):
t = 1000
for column in self.columns:
for crane in column:
new_t = crane.timer(self.time)
if new_t < t:
t = new_t
if t != 1000:
self.timer = t
else:
self.game_finished = True
def handler(self, key = None):
if key:
self.reset_progress = True
for column in self.columns:
for crane in column:
if crane.input_handler(key, self.time, self):
self.score += 1
if self.reset_progress:
self.progress = 0
else:
self.progress += 1
self.reset_progress = True
for column in self.columns:
for crane in column:
remove_crane = crane.time_handler(self.time)
if remove_crane:
column.pop()
elif crane.progress == self.progress:
self.reset_progress = False
if self.reset_progress:
self.progress = 0
# Check if necessary to generate new cranes
n = self.number_of_shown_cranes()
if n < 5:
for i in range(0, 5-n):
self.generate_crane()
self.set_screen_timer()
transform crane_appear(col, left_st):
xalign (0.1 + 0.2*col - left_st) yalign -0.1
linear left_st xalign (0.1 + 0.2*col)
transform toy_appear(col, left_st):
xalign (0.155 + 0.175*col - left_st) yalign 0.34
linear (left_st*0.9378) xalign (0.155 + 0.175*col)
transform crane_remove(col, left_st):
xalign (1.1 - left_st) yalign -0.1
linear left_st xalign 1.1
transform toy_remove(col, left_st):
xalign (1.1 - left_st) yalign 0.34
linear left_st xalign 1.1
transform box_remove(col, left_st):
xalign (1.1 - left_st) yalign 0.35
linear left_st xalign 1.1
transform zoommuch:
zoom 0.08
screen s_crane_game():
for col, column in enumerate(crane_game.columns):
for crane in column:
$ left_time = crane.timer(crane_game.time)
if crane.progress == "start":
# move_in animation
add crane.d at crane_appear(col, left_time)
add crane.toy_image at toy_appear(col, left_time)
pass
elif crane.progress == "done":
# success animation
# add crane.d:
# xalign (0.1 + 0.2*col) yalign -0.1
# add crane.box_image:
# xalign (0.14 + 0.182*col) yalign 0.35 zoom 0.6
add crane.d at crane_remove(col, left_time)
add crane.box_image at box_remove(col, left_time)
pass
elif crane.progress == "miss":
add crane.d at crane_remove(col, left_time)
add crane.toy_image at toy_remove(col, left_time)
else:
add crane.d:
xalign (0.1 + 0.2*col) yalign -0.1
add crane.toy_image:
xalign (0.155 + 0.175*col) yalign 0.34
hbox:
xalign (0.15 + 0.175*col) yalign 0.025
for j, arrow in enumerate(crane.arrows):
frame:
if crane.progress > j:
background "#8f8"
else:
background "#737373"
add arrow at zoommuch
bar:
xsize 200 ysize 50
xalign (0.15 + 0.175*col) yalign 0.5
value AnimatedValue(value=0.0,
range=crane.duration,
delay=left_time,
old_value=left_time)
hbox:
xalign 0.5 yalign 0.9 spacing 100
for btn_img in ["a_left", "a_up", "a_right"]:
imagebutton:
idle btn_img action Return(btn_img)
hover Transform(btn_img, matrixcolor=TintMatrix("#10e91a"))
text "Score = {}".format(crane_game.score) xalign 0.97 yalign 0.98
text "Cranes left = {}".format(sum(crane_game.cranes_left)) xalign 0.5 yalign 0.98
timer crane_game.timer action Return(False)
key "input_left" action Return("a_left")
key "input_right" action Return("a_right")
key "input_up" action Return("a_up")
Code: Select all
label start:
pass
label l_crane_game:
scene bg wild1
menu:
"Easy":
$ crane_difficulty = "easy"
"Medium":
$ crane_difficulty = "medium"
"Hard":
$ crane_difficulty = "hard"
"Ultra Hard":
$ crane_difficulty = "ultra"
label gamestart:
scene bg cranedesk
if crane_difficulty == "easy":
"{color=228C22}Your task is to wrap 45 gifts using the arrow keys!{/color}"
if crane_difficulty == "medium":
"{color=228C22}Your task is to wrap 50 gifts using the arrow keys!{/color} "
if crane_difficulty == "hard":
"{color=228C22}Your task is to wrap 55 gifts using the arrow keys!{/color}"
if crane_difficulty == "ultra":
"{color=228C22}Your task is to wrap 70 gifts using the arrow keys! Good luck!{/color}"
scene bg getready
play sound Bell
pause 3
scene bg wrap
play sound Bell
pause 1
label minigame_begin:
scene bg cranedesk
play music MountainKing
$ _rollback = False
$ crane_game = CraneGame(crane_difficulty)
show expression TimerObj(crane_game, "time") as crane_timer
$ key = None
label .loop:
$ crane_game.handler(key)
if crane_game.game_finished:
jump .results
call screen s_crane_game
if _return:
$ key = _return
else:
$ key = None
jump .loop
label .results:
hide crane_timer
play music ChristmasChill
if crane_difficulty == "easy":
"Your score is [crane_game.score] out of 45."
elif crane_difficulty == "medium":
"Your score is [crane_game.score] out of 50."
elif crane_difficulty == "hard":
"Your score is [crane_game.score] out of 55."
elif crane_difficulty == "ultra":
"Your score is [crane_game.score] out of 70."
menu:
"Do you want to play again?"
"Yes, same difficulty":
jump gamestart
"Yes, change difficulty":
jump l_crane_game
"No, return to main menu":
return