class LevelEasyMediumScreen(Screen): def __init__(self, level, notes, goal_values, gear_values, **kwargs): super(LevelEasyMediumScreen, self).__init__(**kwargs) # set up notes for the level self.notes = notes # set up gear values for the levels self.goal_values = goal_values # set up gear values for the levels self.gear_values = gear_values self.level = level # only turn on tutorial for level 1 if self.level == 1: self.use_tutorial = True self.tutorial_screen = 'A' self.goal_play_status = None self.gear_play_status = None self.size_dim = min(Window.width / 6, Window.height / 6) self.tutorial_full_overlay = CRectangle(cpos=(Window.width / 2, Window.height / 2), csize=(Window.width, Window.height)) self.tutorial_options_overlay = Rectangle( pos=(0, 0), size=(Window.width, self.size_dim + Window.height / 25)) self.tutorial_musicbox_overlay = Rectangle( pos=(Window.width // 2, self.size_dim + Window.height / 25), size=(Window.width / 2, Window.height - (self.size_dim + Window.height / 25))) self.tutorial_gearbox_overlay = Rectangle( pos=(0, self.size_dim + Window.height / 25), size=(Window.width / 2, Window.height - (self.size_dim + Window.height / 25))) self.skip_image = CoreImage('images/skip_tutorial.png') self.tutorial_skip_button = Rectangle( pos=(0.98 * Window.width - (self.skip_image.width * self.size_dim / 300), 0.98 * Window.height - self.skip_image.height * self.size_dim / 300), size=(self.skip_image.width * self.size_dim / 300, self.skip_image.height * self.size_dim / 300), texture=self.skip_image.texture) else: self.use_tutorial = False ############################################ ### GOAL MUSIC ### ############################################ self.goal_audio = Audio(2) self.goal_synth = Synth('./data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.goal_tempo_map = SimpleTempoMap(120) self.goal_sched = AudioScheduler(self.goal_tempo_map) # connect scheduler into audio system self.goal_audio.set_generator(self.goal_sched) self.goal_sched.set_generator(self.goal_synth) # generate goal music self.goal_music = MusicPlayer(notes=self.notes, sched=self.goal_sched, synth=self.goal_synth, channel=1, tempo_map=self.goal_tempo_map) self.goal_music.update_tempo(self.goal_values[0]) self.goal_music.update_instrument(self.goal_values[1]) self.goal_music.update_pitch(self.goal_values[2]) self.goal_music.update_volume(self.goal_values[3]) self.goal_music_seq = self.goal_music.generate() ############################################ ### GEAR MUSIC ### ############################################ self.gear_audio = Audio(2) self.gear_synth = Synth('./data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.gear_tempo_map = SimpleTempoMap(120) self.gear_sched = AudioScheduler(self.gear_tempo_map) # connect scheduler into audio system self.gear_audio.set_generator(self.gear_sched) self.gear_sched.set_generator(self.gear_synth) # generate gear music self.gear_music = MusicPlayer(notes=self.notes, sched=self.gear_sched, synth=self.gear_synth, channel=1, tempo_map=self.gear_tempo_map) self.gear_music_seq = None ############################################ ### BACKGROUND UI COMPONENTS ### ############################################ self.gear_area = GearArea() self.canvas.add(self.gear_area) self.music_box_area = MusicBoxArea() self.canvas.add(self.music_box_area) self.options = LevelOptions( level=level, goal_music_seq=self.goal_music_seq, duration=self.goal_music.duration, edit_goal_play_status=self.edit_goal_play_status) self.canvas.add(self.options) self.label = Label(text=kwargs['name'], font_name='./fonts/PassionOne-Regular', color=(.165, .718, .792, 1)) self.add_widget(self.label) ########################################### ### GEAR LABELS ### ########################################### self.tempo_label = Label(text='Tempo (bpm)', font_name='./fonts/PassionOne-Regular', color=(0.7254901960784313, 0.5529411764705883, 0.8196078431372549, 1), center_x=(Window.width / 4), center_y=(Window.height / 5.25 * (0.5 + 0.5) + self.gear_area.position[1]), font_size=str(Window.width // 50) + 'sp') self.instrument_label = Label( text='Instrument', font_name='./fonts/PassionOne-Regular', color=(0.996078431372549, 0.8431372549019608, 0.4, 1), center_x=(Window.width / 4), center_y=(Window.height / 5.25 * (1.5 + 0.5) + self.gear_area.position[1]), font_size=str(Window.width // 50) + 'sp') self.pitch_label = Label(text='Pitch (semitones)', font_name='./fonts/PassionOne-Regular', color=(1.0, 0.6509803921568628, 0.09019607843137255, 1), center_x=(Window.width / 4), center_y=(Window.height / 5.25 * (2.5 + 0.5) + self.gear_area.position[1]), font_size=str(Window.width // 50) + 'sp') self.volume_label = Label( text='Volume', font_name='./fonts/PassionOne-Regular', color=(0.9254901960784314, 0.32941176470588235, 0.3176470588235294, 1), center_x=(Window.width / 4), center_y=(Window.height / 5.25 * (3.5 + 0.5) + self.gear_area.position[1]), font_size=str(Window.width // 50) + 'sp') self.add_widget(self.volume_label) self.add_widget(self.pitch_label) self.add_widget(self.instrument_label) self.add_widget(self.tempo_label) ########################################### ### GEAR CONSTRUCTION ### ########################################### self.gears = [] self.gear_centers = [] self.gears_group = AnimGroup() self.canvas.add(self.gears_group) ########################################### ### GEARS ### ########################################### self.gear_storage_locations = [] self.gear_music_locations = [] self.gear_labels = [] self.set_up_gears() ########################################### ### PARTICLE EFFECT ### ########################################### self.win_ps = ParticleSystem('particles/star_particle.pex') self.win_ps.emitter_x = Window.width / 2 self.win_ps.emitter_y = Window.height / 2 self.add_widget(self.win_ps) self.you_win_label = Label(text=' ', font_name='./fonts/PassionOne-Regular', color=(0.5843137254901961, 0.796078431372549, 0.37254901960784315, 1), center_x=Window.width / 2, center_y=Window.height / 2, font_size=str(Window.width // 10) + 'sp') self.add_widget(self.you_win_label) self.lose_ps = ParticleSystem('particles/lose_particle.pex') self.lose_ps.emitter_x = Window.width / 2 self.lose_ps.emitter_y = Window.height / 2 self.add_widget(self.lose_ps) self.you_lose_label = Label(text=' ', font_name='./fonts/PassionOne-Regular', color=(0.9254901960784314, 0.32941176470588235, 0.3176470588235294, 1), center_x=Window.width / 2, center_y=Window.height / 2, font_size=str(Window.width // 10) + 'sp') self.add_widget(self.you_lose_label) ########################################### ### ERROR MESSAGE ### ########################################### self.error_msg = Label(text=' ', font_name='./fonts/PassionOne-Regular', color=(0.9254901960784314, 0.32941176470588235, 0.3176470588235294, 1), center_x=Window.width / 2, center_y=Window.height / 2, font_size=str(Window.width // 20) + 'sp') self.add_widget(self.error_msg) # ########################################### # ### ADD TUTORIAL OVERLAYS ### # ########################################### if self.use_tutorial: self.canvas.add(Color(rgba=(0, 0, 0, 0.85))) self.canvas.add(self.tutorial_full_overlay) self.tutorial_label = Label( markup=True, text= "[font=./fonts/lato-bold]Welcome to the\n[/font] [font=./fonts/options-icons]|[/font] [font=./fonts/PassionOne-Regular]Play It By Gear Tutorial[/font] [font=./fonts/options-icons]|[/font] [font=./fonts/lato-bold]\n\nThe goal of this game is to make the \n goal song match the song you create by \nplacing the correct gears in a music box \n\n[/font] [font=./fonts/lato-light] (click to see the next \nstep of the tutorial)[/font]", color=(86 / 255, 189 / 255, 205 / 255, 1), center_x=Window.width / 2, center_y=Window.height / 2, font_size=str(Window.width // 40) + 'sp', halign='center') self.add_widget(self.tutorial_label) self.canvas.add(self.tutorial_skip_button) self.on_layout((Window.width, Window.height)) def clear_overlays(self): if self.tutorial_full_overlay in self.canvas.children: self.canvas.remove(self.tutorial_full_overlay) if self.tutorial_options_overlay in self.canvas.children: self.canvas.remove(self.tutorial_options_overlay) if self.tutorial_gearbox_overlay in self.canvas.children: self.canvas.remove(self.tutorial_gearbox_overlay) if self.tutorial_musicbox_overlay in self.canvas.children: self.canvas.remove(self.tutorial_musicbox_overlay) while self.tutorial_skip_button in self.canvas.children: self.canvas.remove(self.tutorial_skip_button) def activate_overlays(self, overlay_names): self.clear_overlays() self.canvas.add(Color(rgba=(0, 0, 0, 0.85))) if 'full' in overlay_names: self.canvas.add(self.tutorial_full_overlay) if 'options' in overlay_names: self.canvas.add(self.tutorial_options_overlay) if 'gearbox' in overlay_names: self.canvas.add(self.tutorial_gearbox_overlay) if 'musicbox' in overlay_names: self.canvas.add(self.tutorial_musicbox_overlay) def get_scaled_x_y(self, winsize, x, y): width, height = winsize # scaled_x = width/8 * (x+1) scaled_x = width / (len(self.gear_values) // 4 * 2) * (x + 0.5) scaled_y = height / 5.25 * (y + 0.5) + self.gear_area.position[1] return scaled_x, scaled_y def set_up_gears(self): self.gears = [] self.gears_group.remove_all() center_gear_location = (Window.width / 6 * 4.5, Window.height / 4 * 2.5) center_gear_size = min(Window.width / 10, Window.height / 10) self.center_gear = Gear(None, None, center_gear_size, 10, 'center', 0, center_gear_location, center_gear_location, 1, colors['dark_grey']) self.canvas.add(self.center_gear.color) self.gears_group.add(self.center_gear) self.center_gear_center = GearCenter(None, None, center_gear_location, center_gear_location, 'center', center_gear_size / 2, colors['dark_grey']) self.canvas.add(colors['dark_grey']) self.canvas.add(self.center_gear_center) self.play_center_gear = False self.music_gears = [] tempo_location = (center_gear_location[0], center_gear_location[1] + center_gear_size + center_gear_size / 5) instrument_location = (center_gear_location[0], center_gear_location[1] - center_gear_size - center_gear_size / 5) pitch_location = (center_gear_location[0] + center_gear_size + center_gear_size / 5, center_gear_location[1]) volume_location = (center_gear_location[0] - center_gear_size - center_gear_size / 5, center_gear_location[1]) self.music_box_gear_locations = [ tempo_location, instrument_location, pitch_location, volume_location ] counter = 0 label_font_size = min(Window.width // 80, Window.height // 80) for y in range(0, 4): for x in range(len(self.gear_values) // 4): gear_type = gear_type_map[y] size = min(Window.width / 10, Window.height / 10) music_pos = self.music_box_gear_locations[y] scaled_x, scaled_y = self.get_scaled_x_y( (Window.width, Window.height), x, y) gear = Gear(x, y, size, 8, gear_type, self.gear_values[counter], (scaled_x, scaled_y), music_pos, 0, colors['dark_grey']) self.gears.append(gear) self.canvas.add(gear.color) self.gears_group.add(gear) gear_center = GearCenter(x, y, (scaled_x, scaled_y), music_pos, gear_type, size / 2, colors['dark_grey']) self.gear_centers.append(gear_center) self.canvas.add(gear_center) ## white dots for storage purposes gear_loc = GearLocation((scaled_x, scaled_y), size / 2, x, y, gear_type) self.gear_storage_locations.append(gear_loc) self.canvas.add(gear_loc) text = str(self.gear_values[counter]) font_name = './fonts/PassionOne-Regular' if y == 3: # get volume as percent text = str(100 * self.gear_values[counter] // 127) + '%' if y == 1: # get icon for instrument font_name = './fonts/music-instruments' text = instruments[self.gear_values[counter]] label = Label(text=text, font_name=font_name, color=(0, 0, 0, 1), center_x=scaled_x, center_y=scaled_y, font_size=str(label_font_size) + 'sp') self.gear_labels.append(label) self.add_widget(label) counter += 1 for indx, loc in enumerate(self.music_box_gear_locations): gear_type = gear_type_map[indx % 4] gear_loc = GearLocation(loc, center_gear_size / 2, None, None, gear_type) self.gear_music_locations.append(gear_loc) self.canvas.add(gear_loc) def edit_goal_play_status(self, value): if self.use_tutorial: if self.goal_play_status == None and value == 'started': self.goal_play_status = 'started' elif self.goal_play_status == 'started' and value == 'finished': self.goal_play_status = 'finished' def _can_add_gear(self, new_gear): for gear in self.music_gears: if gear.type == new_gear.type: return False return True def _check_music_gears(self): all_types = ['volume', 'pitch', 'tempo', 'instrument'] for gear in self.music_gears: if gear.type in all_types: all_types.remove(gear.type) return len(all_types) == 0 def update_center_gear_on_layout(self, winsize): width, height = winsize center_gear_location = (width / 6 * 4.5, height / 4 * 2.5) center_gear_size = min(Window.width / 10, Window.height / 10) self.center_gear_center.update_storage_pos(center_gear_location) self.center_gear_center.update_music_pos(center_gear_location) self.center_gear.update_storage_pos(center_gear_location) self.center_gear.update_music_pos(center_gear_location) self.center_gear.on_layout(center_gear_location, center_gear_size) self.center_gear_center.on_layout(center_gear_location, center_gear_size / 2) tempo_location = (center_gear_location[0], center_gear_location[1] + center_gear_size + center_gear_size / 5) instrument_location = (center_gear_location[0], center_gear_location[1] - center_gear_size - center_gear_size / 5) pitch_location = (center_gear_location[0] + center_gear_size + center_gear_size / 5, center_gear_location[1]) volume_location = (center_gear_location[0] - center_gear_size - center_gear_size / 5, center_gear_location[1]) self.music_box_gear_locations = [ tempo_location, instrument_location, pitch_location, volume_location ] for indx, loc in enumerate(self.gear_music_locations): loc.on_layout(self.music_box_gear_locations[indx], center_gear_size / 2) def on_enter(self): if not self.use_tutorial and self.level == 1: while self.tutorial_skip_button in self.canvas.children: self.canvas.remove(self.tutorial_skip_button) def on_layout(self, winsize): mapped_dic = {'tempo': 0, 'instrument': 1, 'pitch': 2, 'volume': 3} self.update_center_gear_on_layout(winsize) self.size_dim = min(Window.width / 6, Window.height / 6) size = min(Window.width / 10, Window.height / 10) label_font_size = min(Window.width // 80, Window.height // 80) for loc in self.gear_storage_locations: scaled_x, scaled_y = self.get_scaled_x_y(winsize, loc.x, loc.y) loc.on_layout((scaled_x, scaled_y), size / 2) for indx, gear in enumerate(self.gears): scaled_x, scaled_y = self.get_scaled_x_y(winsize, gear.x, gear.y) gear.update_storage_pos((scaled_x, scaled_y)) gear.update_music_pos( self.music_box_gear_locations[mapped_dic[gear.type]]) gear.on_layout((scaled_x, scaled_y), size) self.gear_labels[indx].center_x = scaled_x self.gear_labels[indx].center_y = scaled_y self.gear_labels[indx].font_size = str(label_font_size) + 'sp' for center in self.gear_centers: scaled_x, scaled_y = self.get_scaled_x_y(winsize, center.x, center.y) center.update_storage_pos((scaled_x, scaled_y)) center.update_music_pos( self.music_box_gear_locations[mapped_dic[center.type]]) center.on_layout((scaled_x, scaled_y), size / 2) # update level label self.label.center_x = self.size_dim * 1.5 self.label.center_y = self.size_dim * 3 / 5 self.label.font_size = str(Window.width // 20) + 'sp' # update you win label self.you_win_label.center_x = (Window.width / 2) self.you_win_label.center_y = (Window.height / 2) self.you_win_label.font_size = str(Window.width // 10) + 'sp' self.tempo_label.center_x = (Window.width / 4) self.tempo_label.center_y = (Window.height / 5.25 * (0.5 + 0.5) + self.gear_area.position[1]) self.tempo_label.font_size = str(Window.width // 50) + 'sp' self.instrument_label.center_x = (Window.width / 4) self.instrument_label.center_y = (Window.height / 5.25 * (1.5 + 0.5) + self.gear_area.position[1]) self.instrument_label.font_size = str(Window.width // 50) + 'sp' self.pitch_label.center_x = (Window.width / 4) self.pitch_label.center_y = (Window.height / 5.25 * (2.5 + 0.5) + self.gear_area.position[1]) self.pitch_label.font_size = str(Window.width // 50) + 'sp' self.volume_label.center_x = (Window.width / 4) self.volume_label.center_y = (Window.height / 5.25 * (3.5 + 0.5) + self.gear_area.position[1]) self.volume_label.font_size = str(Window.width // 50) + 'sp' # update child components self.gear_area.on_layout((Window.width, Window.height)) self.music_box_area.on_layout((Window.width, Window.height)) self.options.on_layout((Window.width, Window.height)) # update particle effect and win/lose labels self.win_ps.emitter_x = Window.width / 2 self.win_ps.emitter_y = Window.height / 2 self.you_win_label.center_x = Window.width / 2 self.you_win_label.center_y = Window.height / 2 self.you_win_label.font_size = str(Window.width // 10) + 'sp' self.lose_ps.emitter_x = Window.width / 2 self.lose_ps.emitter_y = Window.height / 2 self.you_lose_label.center_x = Window.width / 2 self.you_lose_label.center_y = Window.height / 2 self.you_lose_label.font_size = str(Window.width // 10) + 'sp' # update error message location self.error_msg.center_x = Window.width / 2 self.error_msg.center_y = Window.height / 2 self.error_msg.font_size = str(Window.width // 20) + 'sp' # update tutorial overlays, label, and skip button if self.use_tutorial: self.update_tutorial_screen(self.tutorial_screen) self.tutorial_full_overlay.cpos = (Window.width / 2, Window.height / 2) self.tutorial_full_overlay.csize = (Window.width, Window.height) self.tutorial_options_overlay.size = (Window.width, self.size_dim + Window.height / 25) self.tutorial_musicbox_overlay.pos = (Window.width // 2, self.size_dim + Window.height / 25) self.tutorial_musicbox_overlay.size = ( Window.width / 2, Window.height - (self.size_dim + Window.height / 25)) self.tutorial_gearbox_overlay.pos = (0, self.size_dim + Window.height / 25) self.tutorial_gearbox_overlay.size = ( Window.width / 2, Window.height - (self.size_dim + Window.height / 25)) self.tutorial_skip_button.pos = ( 0.98 * Window.width - (self.skip_image.width * self.size_dim / 300), 0.98 * Window.height - self.skip_image.height * self.size_dim / 300) self.tutorial_skip_button.size = (self.skip_image.width * self.size_dim / 300, self.skip_image.height * self.size_dim / 300) def reset(self): for gear in self.gears: # reset gear position gear.reset() # stop gear from rotating gear.stop() # stop center gear from rotating self.center_gear.stop() # stop music self.goal_music_seq.stop() if self.gear_music_seq: self.gear_music_seq.stop() # end tutorial if self.use_tutorial: self.tutorial_label.text = '' self.use_tutorial = False self.clear_overlays() while self.tutorial_skip_button in self.canvas.children: self.canvas.remove(self.tutorial_skip_button) def skip_tutorial_pressed(self, touch): if self.use_tutorial: if 0.98 * Window.width - ( self.skip_image.width * self.size_dim / 300 ) < touch.pos[ 0] < 0.98 * Window.width and 0.98 * Window.height - self.skip_image.height * self.size_dim / 300 < touch.pos[ 1] < 0.98 * Window.height: return True return False def on_touch_up(self, touch): # if click is on one of the lower menu buttons, perform the appropriate action self.options.on_touch_up(self.switch_to, self.gear_music_seq, self.check_level_complete(), self.win_ps, self.you_win_label, self.lose_ps, self.you_lose_label, self.reset, touch) for index, gear in enumerate(self.gears): # response is true if you click the current gear response = gear.on_touch_up(touch.pos, self.gear_area.max_x, self._can_add_gear) self.gear_centers[index].on_touch_up(touch.pos, self.gear_area.max_x, self._can_add_gear) if response: if gear not in self.music_gears: self.music_gears.append(gear) # update the gear music based on the gear that is selected function = 'self.gear_music.update_' + gear.type + '(' + str( gear.value) + ')' eval(function) else: if gear in self.music_gears: self.music_gears.remove(gear) self.center_gear.on_touch_up(touch.pos, self.gear_area.max_x, self._can_add_gear) if self.use_tutorial: # if skip button pressed, quit out of tutorial mode if self.skip_tutorial_pressed(touch): self.use_tutorial = False self.remove_widget(self.tutorial_label) self.clear_overlays() while self.tutorial_skip_button in self.canvas.children: self.canvas.remove(self.tutorial_skip_button) elif self.tutorial_screen == 'A': # show screen B (musicbox and gearbox covered) self.tutorial_screen = 'B' self.update_tutorial_screen('B') elif self.tutorial_screen == 'B': # show screen C (musicbox and options covered) self.tutorial_screen = 'C' self.update_tutorial_screen('C') elif self.tutorial_screen == 'C': # show screen D (gearbox and options covered) self.tutorial_screen = 'D' self.update_tutorial_screen('D') elif self.tutorial_screen == 'D': # show screen E (options covered) self.tutorial_screen = 'E' self.update_tutorial_screen('E') elif self.tutorial_screen == 'E' and self._check_music_gears(): # if all gears have been placed, show screen F (gearbox covered) self.tutorial_screen = 'F' self.update_tutorial_screen('F') elif self.tutorial_screen == 'F' and self.gear_play_status == 'finished' and self.goal_play_status == 'finished': # if both tunes have been played show screen G (gearbox and musicbox covered) self.tutorial_screen = 'G' self.update_tutorial_screen('G') elif self.tutorial_screen == 'G': # end tutorial self.use_tutorial = False self.remove_widget(self.tutorial_label) self.clear_overlays() while self.tutorial_skip_button in self.canvas.children: self.canvas.remove(self.tutorial_skip_button) def update_tutorial_screen(self, screen): if not self.use_tutorial: return self.remove_widget(self.tutorial_label) if self.tutorial_screen == 'A': self.activate_overlays(['full']) self.tutorial_label.center_x = Window.width / 2 self.tutorial_label.center_y = Window.height / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]Welcome to the\n[/font] [font=./fonts/options-icons]|[/font] [font=./fonts/PassionOne-Regular]Play It By Gear Tutorial[/font] [font=./fonts/options-icons]|[/font] [font=./fonts/lato-bold]\n\nThe goal of this game is to make the \n goal song match the song you create by \nplacing the correct gears in a music box \n\n[/font] [font=./fonts/lato-light] (click to see the next \nstep of the tutorial)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 40) + 'sp' if self.tutorial_screen == 'B': self.activate_overlays(['musicbox', 'gearbox']) self.tutorial_label.center_x = 1 / 2 * Window.width self.tutorial_label.center_y = Window.height / 2 + (min( Window.width / 6, Window.height / 6) + Window.height / 25) / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]\nAt the bottom of the screen is the menu\nbar which contains some helpful buttons\n\nthe [/font] [font=./fonts/options-icons]^[/font] [font=./fonts/lato-bold] button brings\nyou back to the level select menu\n\nthe [/font] [font=./fonts/options-icons]`[/font] [font=./fonts/lato-bold] button resets the level\n\n[/font] [font=./fonts/lato-light](click to continue)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 50) + 'sp' elif self.tutorial_screen == 'C': self.activate_overlays(['musicbox', 'options']) self.tutorial_label.center_x = 3 / 4 * Window.width self.tutorial_label.center_y = Window.height / 2 + (min( Window.width / 6, Window.height / 6) + Window.height / 25) / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]The left side of the screen\nhas all the gears you can choose\nfrom in order to make the\nmusic box sound correct\n\n[/font] [font=./fonts/lato-light](click to continue)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 60) + 'sp' elif self.tutorial_screen == 'D': self.activate_overlays(['gearbox', 'options']) self.tutorial_label.center_x = 1 / 4 * Window.width self.tutorial_label.center_y = Window.height / 2 + (min( Window.width / 6, Window.height / 6) + Window.height / 25) / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]The right side of the screen\nis the music box. Gears in\nthe music box modify the song.\n\nYou need one gear of each\ntype/color in the music box in\norder for the song to play. \n\n[/font] [font=./fonts/lato-light](click to continue)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 60) + 'sp' elif self.tutorial_screen == 'E': self.activate_overlays(['options']) self.tutorial_label.center_x = Window.width / 2 self.tutorial_label.center_y = (min( Window.width / 6, Window.height / 6) + Window.height / 25) / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]Now drag one gear of each type/color into the music box\n[/font] [font=./fonts/lato-light](when there are 4 gears in the music box, the tutorial will continue)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 60) + 'sp' elif self.tutorial_screen == 'F': self.activate_overlays(['gearbox']) self.tutorial_label.center_x = 1 / 4 * Window.width self.tutorial_label.center_y = Window.height / 2 + (min( Window.width / 6, Window.height / 6) + Window.height / 25) / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]Play the goal sound by pressing\nthe [/font] [font=./fonts/options-icons]_[/font] [font=./fonts/lato-bold] button, then press\nthe [/font] [font=./fonts/options-icons]~[/font] [font=./fonts/lato-bold] in the center gear to\nplay the song you created\nwith the gears\n\n[/font] [font=./fonts/lato-light](after you play both songs,\nclick again to continue)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 60) + 'sp' elif self.tutorial_screen == 'G': self.activate_overlays(['musicbox', 'gearbox']) self.tutorial_label.center_x = 1 / 2 * Window.width self.tutorial_label.center_y = Window.height / 2 + (min( Window.width / 6, Window.height / 6) + Window.height / 25) / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]Did the two songs sound the same?\n\nIf yes, you can press the [/font] [font=./fonts/options-icons]{[/font] [font=./fonts/lato-bold] button\n to see if you're correct\n\n If no, you can switch the gears in the music box\nuntil you think both songs sound the same\n\n[/font] [font=./fonts/lato-light](click to exit the tutorial)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 55) + 'sp' self.add_widget(self.tutorial_label) self.canvas.add(self.tutorial_skip_button) def on_touch_down(self, touch): other_gears = False for index, gear in enumerate(self.gears): cur_gear = gear.on_touch_down(touch.pos) other_gears = other_gears or cur_gear self.gear_centers[index].on_touch_down(touch.pos) if other_gears: if self.gear_music_seq: for gear in self.music_gears: gear.stop() self.center_gear.stop() self.gear_music_seq.stop() self.gear_music_seq = None else: response = self.center_gear.on_touch_down(touch.pos) if response: if self._check_music_gears(): for gear in self.music_gears: gear.toggle_rotate() is_rotating = self.center_gear.toggle_rotate() if is_rotating: self.gear_music_seq = self.gear_music.generate() self.gear_music_seq.start() if self.use_tutorial and self.gear_play_status == None: self.gear_play_status = 'started' else: if self.gear_music_seq: self.gear_music_seq.stop() self.gear_music_seq = None else: if not self.use_tutorial: self.error_msg.text = 'Place all 4 gears' else: self.error_msg.text = ' ' return self.error_msg.text = ' ' def on_touch_move(self, touch): for index, gear in enumerate(self.gears): gear.on_touch_move(touch.pos) self.gear_centers[index].on_touch_move(touch.pos) def on_update(self): self.goal_audio.on_update() self.gear_audio.on_update() self.options.on_update() for gear in self.gears: gear.on_update(1) self.center_gear.on_update(1) if self.gear_music_seq and not self.gear_music_seq.playing: for gear in self.music_gears: gear.stop() self.center_gear.stop() self.gear_music_seq = None if self.use_tutorial and self.gear_play_status == 'started': self.gear_play_status = 'finished' def check_level_complete(self): return self.goal_music.is_equal(self.gear_music)