def __init__(self, **kwargs): super(LevelSelectScreen, self).__init__(**kwargs) Window.clearcolor = colors['grey'].rgba self.anim_group = AnimGroup() self.canvas.add(self.anim_group) self.label = Label(text='Play it by Gear', font_name='./fonts/PassionOne-Regular', color=(.165, .718, .792, 1)) self.add_widget(self.label) self.buttons = [] self.id_counter = 0 self.audio = Audio(2) self.mixer = Mixer() self.audio.set_generator(self.mixer) self.start_time = None self.switch_level = None self.border_color = colors['dark_grey'] self.border = Line(rectangle=(0, 0, Window.width, Window.height), width=Window.width * 0.03) self.anim_group.add(self.border_color) self.anim_group.add(self.border) self.on_layout((Window.width, Window.height))
def __init__(self, **kwargs): super(MainScreen, self).__init__(**kwargs) mode = 'mac' if (len(sys.argv) == 2) and (sys.argv[1] == 'mac') else 'pc' self.norm = Normalizer(mode) self.info = topleft_label() self.add_widget(self.info) self.writer = AudioWriter('recordings/song') self.audio = Audio(2, self.writer.add_audio) self.mixer = Mixer() self.mixer.set_gain(1.0) self.audio.set_generator(self.mixer) self.sandbox = Sandbox(canvas=self.canvas, pos=self.norm.nt((580, 50)), size=self.norm.nt((1000, 1000))) # since putting all our sound module code in MainScreen would be a nightmare, we've # modularized our modules into separate files. each module has two classes, the sound # module itself and its handler class. the handler class is essentially a wrapper of # many of MainScreen's important event functions (e.g. on_touch_down) that keeps track # of all variables related to that sound module for every connected client. self.module_dict = { 'PhysicsBubble': PhysicsBubble, 'SoundBlock': SoundBlock, 'TempoCursor': TempoCursor } block = SoundBlockHandler(self.norm, self.sandbox, self.mixer, client, client_id) self.module_handlers = { 'SoundBlock': block, 'PhysicsBubble': PhysicsBubbleHandler(self.norm, self.sandbox, self.mixer, client, client_id, block), 'TempoCursor': TempoCursorHandler(self.norm, self.sandbox, self.mixer, client, client_id, block) } # name a default starting module and handler self.module = PhysicsBubble self.module_handler = self.module_handlers[self.module.name] self.sandbox.add(self.module_handler.gui) # sync with existing server state client.emit('sync_module_state', {'module': 'PhysicsBubble'}) client.emit('sync_module_state', {'module': 'SoundBlock'}) client.emit('sync_module_state', {'module': 'TempoCursor'}) client.emit('update_norm', {'norm': {client_id: self.norm.mode}})
def __init__(self, level=0, prev_room=None, on_finished_puzzle=None): super().__init__() self.create_objects() self.place_objects() self.blocks_placed = 0 self.create_treasure_popup((Window.width, Window.height)) self.audio = Audio(2) self.mixer = Mixer() self.mixer.set_gain(0.2) self.audio.set_generator(self.mixer) self.wave_file_gen = WaveGenerator( WaveFile("./data/treasure_music.wav"))
def __init__(self): super(GameObject, self).__init__() self._graphics = Graphics() self._transform = Transform(self._graphics) self._mixer = Mixer() self._parent = None self._game_objects = set() self._widgets = set() self._event_listeners = defaultdict(lambda: []) self.updating = False self.to_add = []
def __init__(self, level, goal_music_seq, duration, edit_goal_play_status=None): super(LevelOptions, self).__init__() self.level = level # level number self.audio = Audio(2) self.mixer = Mixer() self.audio.set_generator(self.mixer) self.options_bar = Rectangle(pos=(0, 0)) self.home_button = Rectangle( texture=CoreImage('images/home.png').texture) self.play_button = Rectangle( texture=CoreImage('images/play.png').texture) self.reset_button = Rectangle( texture=CoreImage('images/reset.png').texture) self.check_button = Rectangle( texture=CoreImage('images/check.png').texture) self.on_layout((Window.width, Window.height)) self.add(colors['grey']) self.add(self.options_bar) self.add(colors['green']) self.add(self.home_button) self.add(self.play_button) self.add(self.reset_button) self.add(self.check_button) self.is_playing = False self.start_time = None self.duration = 0 self.goal_music_seq = None self.duration_circle = Line() self.add(self.duration_circle) # true iff you recently lost or won the game self.win_or_lose = False self.win_gen = WaveGenerator(WaveFile("./data/win_sound.wav")) self.lose_gen = WaveGenerator(WaveFile("./data/lose_sound.wav")) self.goal_music_seq = goal_music_seq self.duration = duration self.button_press_time = None self.edit_goal_play_status = edit_goal_play_status
def __init__(self): super(MainWidget, self).__init__() self.audio = Audio(2, input_func=self.receive_audio, num_input_channels=1) self.mixer = Mixer() self.audio.set_generator(self.mixer) self.pitch = PitchDetector() self.recorder = VoiceAudioWriter('data') self.info = topleft_label() self.add_widget(self.info) self.anim_group = AnimGroup() self.mic_meter = MeterDisplay((50, 25), 150, (-96, 0), (.1, .9, .3)) self.mic_graph = GraphDisplay((110, 25), 150, 300, (-96, 0), (.1, .9, .3)) self.pitch_meter = MeterDisplay((50, 200), 150, (30, 90), (.9, .1, .3)) self.pitch_graph = GraphDisplay((110, 200), 150, 300, (30, 90), (.9, .1, .3)) self.canvas.add(self.mic_meter) self.canvas.add(self.mic_graph) self.canvas.add(self.pitch_meter) self.canvas.add(self.pitch_graph) # Record button self.record_button = InteractiveImage() self.record_button.source = "../data/mic.png" self.record_button.x = 400 self.record_button.y = 400 self.record_button.size = (100, 100) self.record_button.set_callback(self.init_recording) self.add_widget(self.record_button) # Play button self.play_button = InteractiveImage() self.play_button.source = "../data/play.png" self.play_button.x = 600 self.play_button.y = 400 self.play_button.size = (100, 100) self.play_button.set_callback(self.play_recording) self.add_widget(self.play_button) self.canvas.add(self.anim_group) self.onset_disp = None self.onset_x = 0 self.cur_pitch = 0 # Note Scheduler self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.mixer.add(self.sched) self.sched.set_generator(self.synth) # Note Sequencers self.seq = [] # live Generator self.live_wave = None
class MainWidget(BaseWidget): def __init__(self): super(MainWidget, self).__init__() self.audio = Audio(2, input_func=self.receive_audio, num_input_channels=1) self.mixer = Mixer() self.audio.set_generator(self.mixer) self.pitch = PitchDetector() self.recorder = VoiceAudioWriter('data') self.info = topleft_label() self.add_widget(self.info) self.anim_group = AnimGroup() self.mic_meter = MeterDisplay((50, 25), 150, (-96, 0), (.1, .9, .3)) self.mic_graph = GraphDisplay((110, 25), 150, 300, (-96, 0), (.1, .9, .3)) self.pitch_meter = MeterDisplay((50, 200), 150, (30, 90), (.9, .1, .3)) self.pitch_graph = GraphDisplay((110, 200), 150, 300, (30, 90), (.9, .1, .3)) self.canvas.add(self.mic_meter) self.canvas.add(self.mic_graph) self.canvas.add(self.pitch_meter) self.canvas.add(self.pitch_graph) # Record button self.record_button = InteractiveImage() self.record_button.source = "../data/mic.png" self.record_button.x = 400 self.record_button.y = 400 self.record_button.size = (100, 100) self.record_button.set_callback(self.init_recording) self.add_widget(self.record_button) # Play button self.play_button = InteractiveImage() self.play_button.source = "../data/play.png" self.play_button.x = 600 self.play_button.y = 400 self.play_button.size = (100, 100) self.play_button.set_callback(self.play_recording) self.add_widget(self.play_button) self.canvas.add(self.anim_group) self.onset_disp = None self.onset_x = 0 self.cur_pitch = 0 # Note Scheduler self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.mixer.add(self.sched) self.sched.set_generator(self.synth) # Note Sequencers self.seq = [] # live Generator self.live_wave = None def on_update(self): self.audio.on_update() self.anim_group.on_update() self.info.text = 'fps:%d\n' % kivyClock.get_fps() self.info.text += 'load:%.2f\n' % self.audio.get_cpu_load() self.info.text += "pitch: %.1f\n" % self.cur_pitch self.info.text += 'max delta: %.3f\n' % self.onset_detector.get_max_delta( ) self.info.text += 'onset delta thresh (up/down): %.3f\n' % self.onset_detector.onset_thresh if self.recorder.active: self.info.text += 'RECORDING' def receive_audio(self, frames, num_channels): assert (num_channels == 1) # Microphone volume level, take RMS, convert to dB. # display on meter and graph rms = np.sqrt(np.mean(frames**2)) rms = np.clip(rms, 1e-10, 1) # don't want log(0) db = 20 * np.log10(rms) # convert from amplitude to decibels self.mic_meter.set(db) self.mic_graph.add_point(db) # pitch detection: get pitch and display on meter and graph self.cur_pitch = self.pitch.write(frames) self.pitch_meter.set(self.cur_pitch) self.pitch_graph.add_point(self.cur_pitch) # record audio self.recorder.add_audio(frames, num_channels) # onset detection and classification self.onset_detector.write(frames) def init_recording(self): data = self.recorder.toggle() if data: print(data) wave_gen, filename, duration_midi = data for i in range(len(duration_midi)): if duration_midi[i][0] < 0.12: duration_midi[i] = (duration_midi[i][0], 0) duration_midi = harmony.harmonize(duration_midi) self.live_wave = wave_gen print([[i[1] for i in j] for j in duration_midi]) tempo = 120 multiplier = 1 / 60 * tempo * 480 converted_midi_duration = [[(i * multiplier, j) for i, j in k] for k in duration_midi] for i in converted_midi_duration: self.seq.append( NoteSequencer(self.sched, self.synth, 1, (0, 0), i, True)) def play_recording(self): print("hello") for i in self.seq: i.start() if self.live_wave: self.mixer.add(self.live_wave) def on_key_down(self, keycode, modifiers): t = lookup(keycode[1], ['up', 'down'], [.001, -.001]) if t is not None: self.onset_detector.onset_thresh += t if keycode[1] == "w": self.init_recording() if keycode[1] == "s" and self.seq: self.play_recording()
class TreasureRoom(Puzzle): def __init__(self, level=0, prev_room=None, on_finished_puzzle=None): super().__init__() self.create_objects() self.place_objects() self.blocks_placed = 0 self.create_treasure_popup((Window.width, Window.height)) self.audio = Audio(2) self.mixer = Mixer() self.mixer.set_gain(0.2) self.audio.set_generator(self.mixer) self.wave_file_gen = WaveGenerator( WaveFile("./data/treasure_music.wav")) """ Mandatory Puzzle methods """ def is_game_over(self): pass def create_objects(self): self.objects = {} size = (self.grid.tile_side_len, self.grid.tile_side_len) icons = [ "./data/guitar.png", "./data/bass.png", "./data/drums.png", "./data/piano.png", ] init_positions = [(1, 1), (1, 7), (7, 1), (7, 7)] final_positions = [(2, 4), (3, 4), (5, 4), (6, 4)] colors = [ Color(hsv=(0, 0.5, 1)), # Green Color(hsv=(0.15, 0.5, 1)), # Red Color(hsv=(0.25, 0.5, 1)), # Yellow Color(hsv=(0.5, 0.5, 1)), # Blue ] for i in range(len(icons)): self.objects[init_positions[i]] = MovingBlock( size, self.grid.grid_to_pixel(init_positions[i]), ((1, 1), (8, 8)), colors[i], icons[i], final_positions[i], ) self.grid.get_tile(final_positions[i]).set_color(colors[i]) def place_objects(self): self.create_objects() self.add(PushMatrix()) self.add(Translate(*self.grid.pos)) for pos, obj in self.objects.items(): self.add(obj) self.add(PopMatrix()) def valid_block_move(self, pos, move_range): return (move_range[0][0] <= pos[0] < move_range[1][0] and move_range[0][1] <= pos[1] < move_range[1][1]) def move_block(self, new_location, x, y): obj_loc = (new_location[0] + x, new_location[1] + y) if self.is_valid_pos(obj_loc) and self.valid_block_move( obj_loc, self.objects[new_location].move_range): self.remove(self.objects[new_location]) obj = MovingBlock( self.objects[new_location].size, self.grid.grid_to_pixel(obj_loc), self.objects[new_location].move_range, self.objects[new_location].color, self.objects[new_location].icon_source, self.objects[new_location].final_position, ) del self.objects[new_location] self.add(PushMatrix()) self.add(Translate(*self.grid.pos)) self.add(obj) self.add(PopMatrix()) self.objects[obj_loc] = obj self.blocks_placed += self.objects[obj_loc].on_block_placement( obj_loc) return True else: return False def on_player_input(self, button): if button in [Button.UP, Button.DOWN, Button.LEFT, Button.RIGHT]: move_possible = True x, y = button.value cur_location = self.character.grid_pos new_location = (cur_location[0] + x, cur_location[1] + y) self.character.change_direction(button.value) if new_location in self.objects: if self.objects[new_location].moveable: move_possible = self.move_block(new_location, x, y) if move_possible: self.character.move_player(new_location) if self.character.grid_pos in self.objects: if isinstance(self.objects[self.character.grid_pos], DoorTile): if not isinstance( self.objects[self.character.grid_pos].other_room, Puzzle): # instantiate class when we enter the door self.objects[ self.character.grid_pos].other_room = self.objects[ self.character.grid_pos].other_room( self, self.level + 1) return self.objects[self.character.grid_pos].other_room if self.blocks_placed == 4: self.on_game_over() self.mixer.add(self.wave_file_gen) def create_treasure_popup(self, win_size): self.game_over_window_color = Color(rgba=(1, 1, 1, 1)) self.game_over_window = CRectangle( cpos=(win_size[0] // 2, win_size[1] // 2), csize=(win_size[0] // 2, win_size[1] // 5), ) self.game_over_text_color = Color(rgba=(0, 0, 0, 1)) self.game_over_text = CLabelRect( (win_size[0] // 2, win_size[1] // 2), "You unlocked the pharaoh's treasure!\nYou WIN!", 40) self.treasure = CRectangle(cpos=(win_size[0] // 2, win_size[1] // 4), csize=(win_size[0] // 4, win_size[1] // 4), source='./data/treasure.png') def on_game_over(self): self.game_over = True self.add(self.game_over_window_color) self.add(self.game_over_window) self.add(self.game_over_text_color) self.add(self.game_over_text) self.add(self.game_over_window_color) self.add(self.treasure) def on_update(self): self.audio.on_update() def on_layout(self, win_size): self.remove(self.character) self.remove(self.grid) self.grid.on_layout(win_size) for pos, obj in self.objects.items(): self.remove(obj) self.add(self.grid) self.place_objects() self.character.on_layout(win_size) self.add(self.character) self.create_treasure_popup(win_size) if self.game_over: self.remove(self.game_over_window_color) self.remove(self.game_over_window) self.remove(self.game_over_text_color) self.remove(self.game_over_text) self.remove(self.treasure) self.on_game_over()
class GameObject(object): ''' Game Objects can contain each other (like HTML divs, or something) ''' def __init__(self): super(GameObject, self).__init__() self._graphics = Graphics() self._transform = Transform(self._graphics) self._mixer = Mixer() self._parent = None self._game_objects = set() self._widgets = set() self._event_listeners = defaultdict(lambda: []) self.updating = False self.to_add = [] @property def game_objects(self): return self._game_objects @property def client(self): return self.base_widget.client_obj if self.base_widget else None @property def base_widget(self): if self._parent: return self._parent.base_widget return None @property def widgets(self): widgets = self._widgets.copy() for go in self._game_objects: widgets.update(go.widgets) return widgets def add_widget(self, widget): self._widgets.add(widget) # self._add_widget(widget) def get_abs_pos(self): x = self.position.x y = self.position.y x *= self.scale.x y *= self.scale.y parent = self._parent while parent is not None: xp = parent.position.x yp = parent.position.y x += xp * parent.scale.x y += yp * parent.scale.y parent = parent._parent return x, y def on_add(self): pass @property def position(self): return self._transform.position @position.setter def position(self, new_pos): self._transform.position.xy = new_pos for widget in self._widgets: widget.pos = new_pos @property def rotation(self): return self._transform.rotation @rotation.setter def rotation(self, new_rotation): self._transform.rotation.angle = new_rotation @property def scale(self): return self._transform.scale @scale.setter def scale(self, new_scale): self._transform.scale.x = new_scale self._transform.scale.y = new_scale def add_graphic(self, graphic): self._graphics.add(graphic) def remove_graphic(self, graphic): self._graphics.remove(graphic) def add_generator(self, generator): self._mixer.add(generator) def remove_generator(self, generator): self._mixer.remove(generator) def add(self, *game_objects): for go in game_objects: if self.updating: self.to_add.append(go) else: self.add_game_object(go) go.on_add() def add_game_object(self, game_object): # self.add_widget(game_object) # assert game_object._parent == None, 'game object already has parent' if game_object._parent: game_object._parent.remove(game_object) game_object._parent = self self._game_objects.add(game_object) self._graphics.add(game_object._transform) self._mixer.add(game_object._mixer) def remove(self, *game_objects): for go in game_objects: self.remove_game_object(go) def remove_game_object(self, game_object): # pass if game_object._parent != self: return game_object._parent = None self._game_objects.remove(game_object) self._graphics.remove(game_object._transform) self._mixer.remove(game_object._mixer) def add_event_listener(self, event, callback): self._event_listeners[event].append(callback) def trigger_event(self, event_type, **kwargs): assert self._parent != None, 'Game Object needs to be attached to a scene. Event Lost to the void' self._parent.trigger_event(event_type, **kwargs) def _handle_event(self, event): if hasattr(self, event.type): getattr(self, event.type)(event) for callback in self._event_listeners[event.type]: callback(self, event) for go in self._game_objects: go._handle_event(event) def _on_update(self): self.updating = True self.on_update() dt = kivyClock.frametime self._graphics.on_update(dt) for go in self._game_objects: go._on_update() self.updating = False for go in self.to_add: self.add(go) self.to_add = [] def on_update(self): pass def on_add(self): pass
class MainScreen(Screen): def __init__(self, **kwargs): super(MainScreen, self).__init__(**kwargs) mode = 'mac' if (len(sys.argv) == 2) and (sys.argv[1] == 'mac') else 'pc' self.norm = Normalizer(mode) self.info = topleft_label() self.add_widget(self.info) self.writer = AudioWriter('recordings/song') self.audio = Audio(2, self.writer.add_audio) self.mixer = Mixer() self.mixer.set_gain(1.0) self.audio.set_generator(self.mixer) self.sandbox = Sandbox(canvas=self.canvas, pos=self.norm.nt((580, 50)), size=self.norm.nt((1000, 1000))) # since putting all our sound module code in MainScreen would be a nightmare, we've # modularized our modules into separate files. each module has two classes, the sound # module itself and its handler class. the handler class is essentially a wrapper of # many of MainScreen's important event functions (e.g. on_touch_down) that keeps track # of all variables related to that sound module for every connected client. self.module_dict = { 'PhysicsBubble': PhysicsBubble, 'SoundBlock': SoundBlock, 'TempoCursor': TempoCursor } block = SoundBlockHandler(self.norm, self.sandbox, self.mixer, client, client_id) self.module_handlers = { 'SoundBlock': block, 'PhysicsBubble': PhysicsBubbleHandler(self.norm, self.sandbox, self.mixer, client, client_id, block), 'TempoCursor': TempoCursorHandler(self.norm, self.sandbox, self.mixer, client, client_id, block) } # name a default starting module and handler self.module = PhysicsBubble self.module_handler = self.module_handlers[self.module.name] self.sandbox.add(self.module_handler.gui) # sync with existing server state client.emit('sync_module_state', {'module': 'PhysicsBubble'}) client.emit('sync_module_state', {'module': 'SoundBlock'}) client.emit('sync_module_state', {'module': 'TempoCursor'}) client.emit('update_norm', {'norm': {client_id: self.norm.mode}}) def on_touch_down(self, touch): if touch.button != 'left': return global client, client_id data = {'cid': client_id, 'module': self.module.name, 'pos': touch.pos} client.emit('touch_down', data) def on_touch_move(self, touch): if touch.button != 'left': return global client, client_id data = {'cid': client_id, 'module': self.module.name, 'pos': touch.pos} client.emit('touch_move', data) def on_touch_up(self, touch): if touch.button != 'left': return global client, client_id data = {'cid': client_id, 'module': self.module.name, 'pos': touch.pos} client.emit('touch_up', data) def on_key_down(self, keycode, modifiers): global client, client_id key = keycode[1] # switch module using keys (for now) module_name = lookup(key, 'zxc', ['PhysicsBubble', 'SoundBlock', 'TempoCursor']) if module_name is not None: old_handler = self.module_handler new_handler = self.module_handlers[module_name] if old_handler.module_name != new_handler.module_name: self.sandbox.remove(old_handler.gui) self.sandbox.add(new_handler.gui) self.module = self.module_dict[module_name] self.module_handler = new_handler elif key == 'spacebar': print('boop') self.writer.toggle() else: data = {'cid': client_id, 'module': self.module.name, 'key': key} client.emit('key_down', data) def on_update(self): self.audio.on_update() for _, handler in self.module_handlers.items(): handler.on_update() self.info.text = 'module: {}\n\n'.format(self.module.name) self.info.text += self.module_handler.display_controls() def on_layout(self, win_size): resize_topleft_label(self.info) def update_count(self, count): self.count = count
class LevelSelectScreen(Screen): def __init__(self, **kwargs): super(LevelSelectScreen, self).__init__(**kwargs) Window.clearcolor = colors['grey'].rgba self.anim_group = AnimGroup() self.canvas.add(self.anim_group) self.label = Label(text='Play it by Gear', font_name='./fonts/PassionOne-Regular', color=(.165, .718, .792, 1)) self.add_widget(self.label) self.buttons = [] self.id_counter = 0 self.audio = Audio(2) self.mixer = Mixer() self.audio.set_generator(self.mixer) self.start_time = None self.switch_level = None self.border_color = colors['dark_grey'] self.border = Line(rectangle=(0, 0, Window.width, Window.height), width=Window.width * 0.03) self.anim_group.add(self.border_color) self.anim_group.add(self.border) self.on_layout((Window.width, Window.height)) def generate_buttons(self, row_pos, num_buttons, max_num_buttons, num_rows, margin): for i in range(num_buttons): self.id_counter += 1 square_dim = min(Window.width / (max_num_buttons + 2), Window.height / (num_rows + 1)) button = LevelButton(pos=(i / 6 * (Window.width) + margin, row_pos), size=(square_dim, square_dim), id=self.id_counter) self.buttons.append(button) self.anim_group.add(button) def on_touch_up(self, touch): for b in self.buttons: if b.is_clicked(touch): self.mixer.add( WaveGenerator(WaveFile("./data/button_press.wav"))) self.start_time = time.time() edit_progress_file(b.id, 'y') self.switch_level = 'Level ' + str(b.id) def on_enter(self): # update button colors by regenerating buttons self.on_layout((Window.width, Window.height)) def on_layout(self, winsize): # update level buttons self.anim_group.remove_all() self.id_counter = 0 self.buttons = [] self.generate_buttons(row_pos=(3 * Window.height / 5 - Window.height / 10), num_buttons=4, max_num_buttons=5, num_rows=3, margin=Window.width / 6) self.generate_buttons(row_pos=(2 * Window.height / 5 - Window.height / 10), num_buttons=5, max_num_buttons=5, num_rows=3, margin=Window.width / 12) self.generate_buttons(row_pos=(1 * Window.height / 5 - Window.height / 10), num_buttons=4, max_num_buttons=5, num_rows=3, margin=Window.width / 6) # update title label self.label.center_x = Window.width / 2 self.label.center_y = 5 * Window.height / 6 self.label.font_size = str(Window.width // 15) + 'sp' # update border self.border_color = colors['dark_grey'] self.border = Line(rectangle=(0, 0, Window.width, Window.height), width=Window.width * 0.03) self.anim_group.add(self.border_color) self.anim_group.add(self.border) def on_update(self): self.audio.on_update() if self.start_time and time.time() - self.start_time > 0.13: self.start_time = None self.switch_to(self.switch_level)
class LevelOptions(InstructionGroup): def __init__(self, level, goal_music_seq, duration, edit_goal_play_status=None): super(LevelOptions, self).__init__() self.level = level # level number self.audio = Audio(2) self.mixer = Mixer() self.audio.set_generator(self.mixer) self.options_bar = Rectangle(pos=(0, 0)) self.home_button = Rectangle( texture=CoreImage('images/home.png').texture) self.play_button = Rectangle( texture=CoreImage('images/play.png').texture) self.reset_button = Rectangle( texture=CoreImage('images/reset.png').texture) self.check_button = Rectangle( texture=CoreImage('images/check.png').texture) self.on_layout((Window.width, Window.height)) self.add(colors['grey']) self.add(self.options_bar) self.add(colors['green']) self.add(self.home_button) self.add(self.play_button) self.add(self.reset_button) self.add(self.check_button) self.is_playing = False self.start_time = None self.duration = 0 self.goal_music_seq = None self.duration_circle = Line() self.add(self.duration_circle) # true iff you recently lost or won the game self.win_or_lose = False self.win_gen = WaveGenerator(WaveFile("./data/win_sound.wav")) self.lose_gen = WaveGenerator(WaveFile("./data/lose_sound.wav")) self.goal_music_seq = goal_music_seq self.duration = duration self.button_press_time = None self.edit_goal_play_status = edit_goal_play_status def on_layout(self, winsize): size_dim = min(Window.width / 6, Window.height / 6) self.options_bar.size = (Window.width, size_dim + Window.height / 25) self.home_button.pos = (Window.width - 5 * size_dim, Window.height / 50) self.home_button.size = (size_dim, size_dim) self.play_button.pos = (Window.width - 3.75 * size_dim, Window.height / 50) self.play_button.size = (size_dim, size_dim) self.reset_button.pos = (Window.width - 2.5 * size_dim, Window.height / 50) self.reset_button.size = (size_dim, size_dim) self.check_button.pos = (Window.width - 1.25 * size_dim, Window.height / 50) self.check_button.size = (size_dim, size_dim) def on_touch_up(self, switch_screen, gear_music_seq, level_complete, win_particle, you_win_label, lose_particle, you_lose_label, reset_fn, touch): self.switch_screen = switch_screen def reset(): reset_fn() win_particle.stop() you_win_label.text = ' ' lose_particle.stop() you_lose_label.text = ' ' if self.win_gen in self.mixer.generators: self.mixer.remove(self.win_gen) elif self.lose_gen in self.mixer.generators: self.mixer.remove(self.lose_gen) # When you win/you lose is displayed, clicking anywhere on the # screen should bring you back to the home screen if self.win_or_lose: reset() switch_screen('level_select') self.win_or_lose = False elif self.is_clicked(self.home_button, touch): # play button press sound self.mixer.add(WaveGenerator(WaveFile("./data/button_press.wav"))) self.button_press_time = time.time() # go back to level select screen reset() elif self.is_clicked(self.play_button, touch): # play button press sound self.mixer.add(WaveGenerator(WaveFile("./data/button_press.wav"))) if self.edit_goal_play_status: self.edit_goal_play_status('started') # play/stop goal music self.is_playing = not self.is_playing if self.is_playing: self.goal_music_seq.start() self.start_time = time.time() self.play_button.texture = CoreImage('images/stop.png').texture else: self.goal_music_seq.stop() self.start_time = None self.play_button.texture = CoreImage('images/play.png').texture elif self.is_clicked(self.reset_button, touch): # play button press sound self.mixer.add(WaveGenerator(WaveFile("./data/button_press.wav"))) # reset gear positions reset() elif self.is_clicked(self.check_button, touch): # play button press sound self.mixer.add(WaveGenerator(WaveFile("./data/button_press.wav"))) # if gear placement is correct self.win_or_lose = True self.goal_music_seq.stop() if gear_music_seq: gear_music_seq.stop() if level_complete: # show particle effect, you win label, and play sound win_particle.start() you_win_label.text = 'YOU WIN' edit_progress_file(self.level, 'g') # generate and play winning music self.win_gen = WaveGenerator(WaveFile("./data/win_sound.wav")) self.mixer.add(self.win_gen) else: lose_particle.start() you_lose_label.text = 'YOU LOSE' edit_progress_file(self.level, 'r') self.lose_gen = WaveGenerator( WaveFile("./data/lose_sound.wav")) self.mixer.add(self.lose_gen) def on_update(self): self.audio.on_update() if self.button_press_time and time.time( ) - self.button_press_time > 0.13: self.button_press_time = None self.switch_screen('level_select') # if goal sound played completely, switch back to play icon if self.start_time and time.time() - self.start_time >= self.duration: self.goal_music_seq.stop() self.is_playing = False self.play_button.texture = CoreImage('images/play.png').texture self.duration_circle.width = 0.01 if self.edit_goal_play_status: self.edit_goal_play_status('finished') elif self.start_time and self.is_playing: size_dim = min(Window.width / 6, Window.height / 6) self.duration_circle.width = 10 self.duration_circle.circle = ( Window.width - 3.25 * size_dim, Window.height / 50 + size_dim / 2, size_dim / 2, 0, (self.start_time and time.time() - self.start_time) / self.duration * 360) else: self.duration_circle.width = 0.01 def is_clicked(self, button, touch): return button.pos[0] < touch.x < button.pos[0] + button.size[0] \ and button.pos[1] < touch.y < button.pos[1] + button.size[1]