def __init__(self, norm, sandbox, pos, vel, pitch, timbre, color, bounces, handler, gravity=False, callback=None): """ :param norm: normalizer :param sandbox: client's sandbox :param pos: initial position :param vel: initial velocity :param pitch: MIDI pitch value, where 60 is middle C :param timbre: type of waveform, e.g. 'sine' or 'sawtooth' :param color: 3-tuple of RGB color :param bounces: number of times the bubble bounces before fading away :param gravity: whether or not the bubble is subjected to downwards gravity :param callback: the sound function that is called when the bubble bounces """ super(PhysicsBubble, self).__init__() self.norm = norm self.sandbox = sandbox self.r = self.norm.nv(40) self.pos = np.array(pos, dtype=np.float) self.vel = 2 * np.array(vel, dtype=np.float) self.pitch = pitch self.timbre = timbre self.color = Color(*color) self.text_color = Color(0, 0, 0) self.bounces = bounces self.gravity = gravity self.callback = callback self.handler = handler self.text = CLabelRect(cpos=pos, text=str(self.bounces)) self.bubble = self.timbre_to_shape(self.timbre, pos) self.add(self.color) self.add(self.bubble) self.add(self.text_color) self.add(self.text) # have the bubble fade away when self.bounces = 0 self.fade_anim = KFAnim((0, 1), (0.25, 0)) self.time = 0 self.on_update(0)
def create_instructions(self, win_size): self.instructions_text_color = Color(rgba=(1, 1, 1, 1)) self.instructions_text = CLabelRect( (win_size[0] // 8, win_size[1] * 4 / 7), "Press + to hear your note sequence.\nPress - to hear the sequence\nyou are trying to match.", 20, )
def create_instructions(self): margin = self.grid.tile_side_len // 2 self.instructions_window_color = Color(rgba=(1, 1, 1, 1)) self.instructions_window = Rectangle( pos=(margin, margin), size=( self.grid.grid_side_len - 2 * margin - 2 * self.grid.tile_side_len, 3 * self.grid.tile_side_len - 2 * margin, ), ) self.instructions_text_color = Color(rgba=(0, 0, 0, 1)) self.instructions_text = CLabelRect( (self.win_size[0] // 2, self.win_size[1] // 4.3), "Move around the room with the arrow keys\n" + "Press 'a' to interact with objects", 34, ) self.add(PushMatrix()) self.add(Translate(*self.grid.pos)) self.add(self.instructions_window_color) self.add(self.instructions_window) self.add(PopMatrix()) self.add(self.instructions_text_color) self.add(self.instructions_text)
def __init__(self, norm, pos, beat_callback): super(CursorGUI, self).__init__() self.norm = norm self.pos = pos self.margin = self.norm.nv(20) self.size = self.norm.nt((300, 350)) self.white = (239 / 255, 226 / 255, 222 / 255) self.title_height = self.norm.nv(50) # height of the word 'instrument' self.title = 'beat select' x, y = self.pos title_pos = (x + self.size[0] / 2, y + self.size[1] - self.title_height / 2 - self.margin / 2) self.title = CLabelRect(cpos=title_pos, text=self.title, font_size='18') self.add(Color(*self.white)) self.add(self.title) self.add(Color(1, 1, 1)) self.add(Line(rectangle=(*self.pos, *self.size), width=2)) bs_pos = (self.pos[0] + self.norm.nv(20), self.pos[1] + self.norm.nv(20)) self.bs = BeatSelect(self.norm, bs_pos, beat_callback) self.add(self.bs)
def create_game_over_text(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 Win!", 70 )
def __init__(self, prev_room, level=0, on_finished_puzzle=None): super().__init__() self.door_sources = { (4, 9): "./data/Door_up.png", # UP (4, -1): "./data/door_down.png", # DOWN (-1, 4): "./data/door_left.png", # LEFT (9, 4): "./data/Door_right.png", # RIGHT } self.prev_room = prev_room self.on_finished_puzzle = on_finished_puzzle self.animations = AnimGroup() self.level = level self.notes, self.actual_key = levels[level] duration = choice(durations) pitch_shift = choice(range(-3, 4)) self.user_notes = [ Note(duration, n.get_pitch() + pitch_shift) for n in self.notes ] render_user_notes = self.level < 2 self.actual_sound = PuzzleSound(self.notes) self.user_sound = PuzzleSound(self.user_notes) self.music_bar = MusicBar(self.notes, self.user_notes, render_user_notes, self.actual_sound) self.animations.add(self.music_bar) self.add(self.animations) self.user_key = "C" self.place_objects() self.key_label = CLabelRect( (Window.width // 30, 23 * Window.height // 32), f"Key: {self.user_key}", 34) self.add(Color(rgba=(1, 1, 1, 1))) self.add(self.key_label) self.create_instructions((Window.width, Window.height)) self.add(self.instructions_text_color) self.add(self.instructions_text) self.objects = {}
def __init__(self, mode): super(HelpDisplay, self).__init__() self.mode = mode # Start levels self.start_box_color = Color(0, 1, 0, 0.2) self.start_box = Rectangle(pos=(0.1 * w, 0.7 * h), size=(0.8 * w, 0.2 * h)) self.start_text_color = Color(0, 1, 0, 0.8) if mode == 'lmode': start_text = "Start off with these levels" cpos = (0.75 * w, 0.88 * h) elif mode == 'gmode': start_text = "Complete the learning mode to unlock the first level" cpos = (0.6 * w, 0.88 * h) self.start_text = CLabelRect(text=start_text, font_size=font_sz / 4, font_name=font_name, cpos=cpos) self.add(self.start_box_color) self.add(self.start_box) self.add(self.start_text_color) self.add(self.start_text) # Locked levels self.locked_box_color = Color(1, 1, 0, 0.2) self.locked_box = Rectangle(pos=(0.1 * w, 0.2 * h), size=(0.8 * w, 0.5 * h)) self.locked_text_color = Color(1, 1, 0, 0.8) if mode == 'lmode': locked_text = "Complete the easier levels to unlock new ones" elif mode == 'gmode': locked_text = "Pass the easier level to unlock the next one" self.locked_text = CLabelRect(text=locked_text, font_size=font_sz / 4, font_name=font_name, cpos=(0.65 * w, 0.25 * h)) self.add(self.locked_box_color) self.add(self.locked_box) self.add(self.locked_text_color) self.add(self.locked_text)
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 __init__(self): super(TimerDisplay, self).__init__() self.duration = 30. self.start_x = Window.width * 0.2 self.end_x = Window.width * .85 self.start_y = Window.height * .2 self.end_y = Window.height * .25 # Initialize moving timer self.color = Color(0, 1, 0) # start off green self.bar = Rectangle(pos=(self.start_x, self.start_y), size=(self.end_x - self.start_x, self.end_y - self.start_y)) self.add(self.color) self.add(self.bar) self.remaining_time = CLabelRect( cpos=(self.end_x + 50, self.start_y), text=str(int(self.duration)), font_size=(self.end_y - self.start_y) / 2, font_name="assets/AtlantisInternational") self.add(self.remaining_time) # Vertical borders self.border_left = Line(width=2) self.border_mid = Line(width=2) self.border_right = Line(width=2) self.add(self.border_left) self.add(self.border_right) self.add(self.border_mid) # Horizontal borders self.border_bot = Line(width=2) self.border_top = Line(width=2) self.add(self.border_bot) self.add(self.border_top) self.on_layout(Window.size)
def on_layout(self, win_size): self.remove(self.character) self.remove(self.grid) self.remove(self.instructions_text_color) self.remove(self.instructions_text) self.grid.on_layout((win_size[0], 0.75 * win_size[1])) for pos, obj in self.objects.items(): self.remove(obj) self.add(self.grid) if not self.objects: self.create_objects() self.place_objects() self.character.on_layout(win_size) self.add(self.character) self.music_bar.on_layout(win_size) self.remove(self.key_label) self.key_label = CLabelRect( (win_size[0] // 30, 23 * win_size[1] // 32), f"Key: {self.user_key}", 34) self.add(Color(rgba=(1, 1, 1, 1))) self.add(self.key_label) self.create_instructions(win_size) self.add(self.instructions_text_color) self.add(self.instructions_text) self.create_game_over_text(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.on_game_over()
def on_touch_down(self, cid, pos): if cid == self.cid: self.gui.on_touch_down(pos) if not self.sandbox.in_bounds(pos): return # start drawing drag line and preview of the PhysicsBubble self.hold_point[cid] = pos self.hold_shape[cid] = self.timbre_to_shape(self.timbre[cid], pos) self.hold_line[cid] = Line(points=(*pos, *pos), width=3) self.text[cid] = CLabelRect(cpos=pos, text=str(self.bounces[cid])) # if self.skip.get(cid) == True: # self.skip[cid] = False # return self.sandbox.add(Color(*self.color[cid])) self.sandbox.add(self.hold_shape[cid]) self.sandbox.add(self.hold_line[cid]) self.sandbox.add(self.text_color) self.sandbox.add(self.text[cid])
def __init__(self, norm, pos, callback): super(GravitySelect, self).__init__() self.norm = norm self.callback = callback self.pos = pos self.margin = self.norm.nv(20) self.check_size = self.norm.nt((50, 50)) self.size = ( self.norm.nv(210), 2*self.margin + self.check_size[1] ) self.border_color = Color(50/255, 147/255, 140/255) # bluegreen self.border = Line(rectangle=(*self.pos, *self.size), width=2) self.add(self.border_color) self.add(self.border) self.check_color = Color(1, 1, 1) self.off = Rectangle( pos=(self.pos[0] + self.margin, self.pos[1] + self.margin), size=self.check_size, texture=Image('ui/buttons/unchecked.png').texture ) self.on = Rectangle( pos=(self.pos[0] + self.margin, self.pos[1] + self.margin), size=self.check_size, texture=Image('ui/buttons/checked.png').texture ) self.add(self.check_color) self.add(self.off) title_pos = ( self.pos[0] + self.norm.nv(140), self.pos[1] + self.check_size[1]/2 + self.margin ) self.title = CLabelRect(cpos=title_pos, text='gravity', font_size='18') self.add(Color(1, 1, 1)) self.add(self.title)
def __init__(self, norm, pos, callback): super(TimbreSelect, self).__init__() self.norm = norm self.selected = 'sine' # the actual important variable: which timbre is selected! self.callback = callback self.pos = pos self.margin = self.norm.nv(20) self.button_length = self.norm.nv(64) self.title_height = self.norm.nv(50) # height of the word 'timbre' self.size = ( (4 * self.button_length) + (5 * self.margin), self.button_length + (2 * self.margin) + self.title_height ) self.white = (239/255, 226/255, 222/255) self.red = (201/255, 108/255, 130/255) self.border_color = Color(147/255, 127/255, 159/255) # purple self.border = Line(rectangle=(*self.pos, *self.size), width=2) self.add(self.border_color) self.add(self.border) button_size = (self.button_length, self.button_length) self.timbres = { 'sine': Rectangle(size=button_size, texture=Image('images/sine.png').texture), 'square': Rectangle(size=button_size, texture=Image('images/square.png').texture), 'triangle': Rectangle(size=button_size, texture=Image('images/triangle.png').texture), 'sawtooth': Rectangle(size=button_size, texture=Image('images/sawtooth.png').texture) } self.timbre_bgs = { 'sine': Rectangle(size=button_size), 'square': Rectangle(size=button_size), 'triangle': Rectangle(size=button_size), 'sawtooth': Rectangle(size=button_size) } self.timbre_colors = { 'sine': Color(*self.red), # default selected timbre 'square': Color(*self.white), 'triangle': Color(*self.white), 'sawtooth': Color(*self.white) } x, y = self.pos sine_pos = (x + self.margin, y + self.margin) square_pos = (x + 2*self.margin + self.button_length, y + self.margin) triangle_pos = (x + 3*self.margin + 2*self.button_length, y + self.margin) sawtooth_pos = (x + 4*self.margin + 3*self.button_length, y + self.margin) for timbre, timbre_pos in zip( ('sine', 'square', 'triangle', 'sawtooth'), (sine_pos, square_pos, triangle_pos, sawtooth_pos) ): self.timbres[timbre].pos = self.timbre_bgs[timbre].pos = timbre_pos self.add(self.timbre_colors[timbre]) self.add(self.timbre_bgs[timbre]) self.add(self.timbres[timbre]) title_pos = (x + self.size[0]/2, y + self.size[1] - self.title_height/2 - self.margin/2) self.title = CLabelRect(cpos=title_pos, text='timbre', font_size='18') self.add(Color(*self.white)) self.add(self.title)
class TimerDisplay(InstructionGroup): def __init__(self): super(TimerDisplay, self).__init__() self.duration = 30. self.start_x = Window.width * 0.2 self.end_x = Window.width * .85 self.start_y = Window.height * .2 self.end_y = Window.height * .25 # Initialize moving timer self.color = Color(0, 1, 0) # start off green self.bar = Rectangle(pos=(self.start_x, self.start_y), size=(self.end_x - self.start_x, self.end_y - self.start_y)) self.add(self.color) self.add(self.bar) self.remaining_time = CLabelRect( cpos=(self.end_x + 50, self.start_y), text=str(int(self.duration)), font_size=(self.end_y - self.start_y) / 2, font_name="assets/AtlantisInternational") self.add(self.remaining_time) # Vertical borders self.border_left = Line(width=2) self.border_mid = Line(width=2) self.border_right = Line(width=2) self.add(self.border_left) self.add(self.border_right) self.add(self.border_mid) # Horizontal borders self.border_bot = Line(width=2) self.border_top = Line(width=2) self.add(self.border_bot) self.add(self.border_top) self.on_layout(Window.size) def reset(self, duration=30.): self.duration = duration self.color.rgb = (0, 1, 0) self.bar.size = (self.end_x - self.start_x, self.end_y - self.start_y) self.remaining_time.set_text(str(int(self.duration))) def get_width(self, time): t = (self.end_x - self.start_x) * (1 - time / self.duration) return t def on_update(self, time_elapsed): if time_elapsed > self.duration: return 'end of game' if time_elapsed >= 0: self.bar.size = (self.get_width(time_elapsed), self.end_y - self.start_y) # update remaining time self.remaining_time.set_text(str(int(self.duration - time_elapsed))) # update bar timer color self.color.rgb = (min(time_elapsed / self.duration * 2, 1), min(1, (1 - time_elapsed / self.duration) * 2), 0) def on_layout(self, win_size): self.start_x = win_size[0] * 0.2 self.end_x = win_size[0] * .85 self.start_y = win_size[1] * .2 self.end_y = win_size[1] * .25 self.bar.pos = (self.start_x, self.start_y) self.border_left.points = [(self.start_x, self.start_y), (self.start_x, self.end_y)] self.border_mid.points = [ ((self.start_x + self.end_x) / 2, self.start_y), ((self.start_x + self.end_x) / 2, self.end_y) ] self.border_right.points = [(self.end_x, self.start_y), (self.end_x, self.end_y)] self.border_bot.points = [(self.start_x, self.start_y), (self.end_x, self.start_y)] self.border_top.points = [( self.start_x, self.end_y, ), (self.end_x, self.end_y)] self.remaining_time.set_cpos((self.end_x + 50, self.start_y))
class HelpDisplay(InstructionGroup): ''' Help Overlay. |---------------------| |mode | | (O O O O) | | O O O O | | O O O O | |return help| |---------------------| ''' def __init__(self, mode): super(HelpDisplay, self).__init__() self.mode = mode # Start levels self.start_box_color = Color(0, 1, 0, 0.2) self.start_box = Rectangle(pos=(0.1 * w, 0.7 * h), size=(0.8 * w, 0.2 * h)) self.start_text_color = Color(0, 1, 0, 0.8) if mode == 'lmode': start_text = "Start off with these levels" cpos = (0.75 * w, 0.88 * h) elif mode == 'gmode': start_text = "Complete the learning mode to unlock the first level" cpos = (0.6 * w, 0.88 * h) self.start_text = CLabelRect(text=start_text, font_size=font_sz / 4, font_name=font_name, cpos=cpos) self.add(self.start_box_color) self.add(self.start_box) self.add(self.start_text_color) self.add(self.start_text) # Locked levels self.locked_box_color = Color(1, 1, 0, 0.2) self.locked_box = Rectangle(pos=(0.1 * w, 0.2 * h), size=(0.8 * w, 0.5 * h)) self.locked_text_color = Color(1, 1, 0, 0.8) if mode == 'lmode': locked_text = "Complete the easier levels to unlock new ones" elif mode == 'gmode': locked_text = "Pass the easier level to unlock the next one" self.locked_text = CLabelRect(text=locked_text, font_size=font_sz / 4, font_name=font_name, cpos=(0.65 * w, 0.25 * h)) self.add(self.locked_box_color) self.add(self.locked_box) self.add(self.locked_text_color) self.add(self.locked_text) def on_layout(self, win_size): w, h = win_size self.start_box.pos = (0.1 * w, 0.7 * h) self.start_box.size = (0.8 * w, 0.2 * h) if self.mode == 'lmode': self.start_text.set_cpos((0.75 * w, 0.88 * h)) elif self.mode == 'gmode': self.start_text.set_cpos((0.6 * w, 0.88 * h)) self.locked_box.pos = (0.1 * w, 0.2 * h) self.locked_box.size = (0.8 * w, 0.5 * h) self.locked_text.set_cpos((0.65 * w, 0.25 * h))
class PianoPuzzle(Puzzle): def __init__(self, prev_room, level=0, on_finished_puzzle=None): super().__init__() self.door_sources = { (4, 9): "./data/Door_up.png", # UP (4, -1): "./data/door_down.png", # DOWN (-1, 4): "./data/door_left.png", # LEFT (9, 4): "./data/Door_right.png", # RIGHT } self.prev_room = prev_room self.on_finished_puzzle = on_finished_puzzle self.animations = AnimGroup() self.level = level self.notes, self.actual_key = levels[level] duration = choice(durations) pitch_shift = choice(range(-3, 4)) self.user_notes = [ Note(duration, n.get_pitch() + pitch_shift) for n in self.notes ] render_user_notes = self.level < 2 self.actual_sound = PuzzleSound(self.notes) self.user_sound = PuzzleSound(self.user_notes) self.music_bar = MusicBar(self.notes, self.user_notes, render_user_notes, self.actual_sound) self.animations.add(self.music_bar) self.add(self.animations) self.user_key = "C" self.place_objects() self.key_label = CLabelRect( (Window.width // 30, 23 * Window.height // 32), f"Key: {self.user_key}", 34) self.add(Color(rgba=(1, 1, 1, 1))) self.add(self.key_label) self.create_instructions((Window.width, Window.height)) self.add(self.instructions_text_color) self.add(self.instructions_text) self.objects = {} def play(self, actual=False): if actual: print("Should be setting the cb_ons") self.actual_sound.set_cb_ons([self.music_bar.play]) self.actual_sound.toggle() else: self.user_sound.set_cb_ons([self.music_bar.play]) self.user_sound.toggle() def create_instructions(self, win_size): self.instructions_text_color = Color(rgba=(1, 1, 1, 1)) self.instructions_text = CLabelRect( (win_size[0] // 8, win_size[1] * 4 / 7), "Press + to hear your note sequence.\nPress - to hear the sequence\nyou are trying to match.", 20, ) def on_pitch_change(self, pitch_index): offset = 1 if self.character.direction == Button.RIGHT.value else -1 for note in self.user_notes: pitch = note.get_pitch() note.set_note(pitch + offset) self.user_sound.set_notes(self.user_notes) def on_duration_change(self, dur_index): for note in self.user_notes: note.set_dur(durations[dur_index]) self.user_sound.set_notes(self.user_notes) def on_key_change(self, key_index): self.user_key = key_names[key_index] self.update_key() self.user_sound.set_notes(self.user_notes) def update_key(self): key_sig = keys[self.user_key] for note in self.user_notes: base_letter = note.get_letter()[0] letter_before = names[names.index(base_letter) - 1] if base_letter not in key_sig["#"]: note.remove_sharp() if base_letter not in key_sig["b"]: note.remove_flat() if base_letter in key_sig["#"] and not (note.get_letter()[:-1] == base_letter + "#"): note.add_sharp() if base_letter in key_sig["b"] and not (note.get_letter()[:-1] == letter_before + "#"): note.add_flat() """ Mandatory Puzzle methods """ def is_game_over(self): same_key = self.user_key == self.actual_key same_dur = (self.music_bar.user_notes[0].get_dur() == self.music_bar.actual_notes[0].get_dur()) same_pitch = (self.music_bar.user_notes[0].get_pitch() == self.music_bar.actual_notes[0].get_pitch()) return same_key and same_dur and same_pitch def create_objects(self): size = (self.grid.tile_side_len, self.grid.tile_side_len) # PITCH self.objects[(4, 7)] = MovingBlock( size, self.grid.grid_to_pixel((4, 7)), ((1, 7), (8, 7)), "./data/pitch_slider.png", self.on_pitch_change, ) # RHYTHM duration = self.user_notes[0].get_dur() self.objects[(durations.index(duration) + 3, 2)] = MovingBlock( size, self.grid.grid_to_pixel((durations.index(duration) + 3, 2)), ((3, 2), (7, 2)), "./data/rhythm_slider.png", self.on_duration_change, ) # KEY self.objects[(key_names.index(self.user_key) + 1, 5)] = MovingBlock( size, self.grid.grid_to_pixel((key_names.index(self.user_key) + 1, 5)), ((1, 5), (7, 5)), "./data/key_slider.png", self.on_key_change, ) self.objects[(9, 4)] = DoorTile( size, self.grid.grid_to_pixel((9, 4)), self.prev_room, source=self.door_sources[(9, 4)], ) def place_objects(self): # rhythm_color = Color(rgba=(0, 0.5, 0.5, 1)) for i in range(len(durations)): # rhythm self.grid.get_tile( (i + 3, 2)).set_color(color=Tile.base_color, source="./data/trackv2.png") # pitch_color = Color(rgba=(0.2, 0.5, 1, 1)) for i in range(7): # rhythm self.grid.get_tile( (i + 1, 7)).set_color(color=Tile.base_color, source="./data/trackv2.png") # key_color = Color(rgba=(0.2, 0.5, 0, 1)) for i in range(len(key_names)): self.grid.get_tile( (i + 1, 5)).set_color(color=Tile.base_color, source="./data/trackv2.png") self.add(PushMatrix()) self.add(Translate(*self.grid.pos)) for pos, obj in self.objects.items(): self.add(obj) self.add(PopMatrix()) 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].icon_source, self.objects[new_location].callback, ) 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.objects[obj_loc].on_block_placement(obj_loc) return True else: return False 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 on_player_input(self, button): player_pos = self.character.grid_pos if button in [Button.UP, Button.DOWN, Button.LEFT, Button.RIGHT]: move_possible = True x, y = button.value new_pos = (player_pos[0] + x, player_pos[1] + y) if new_pos in self.objects: if isinstance(self.objects[new_pos], DoorTile): if not isinstance(self.objects[new_pos].other_room, Puzzle): # instantiate class when we enter the door self.objects[new_pos].other_room = self.objects[ new_pos].other_room(self, self.level + 1, self.on_finished_puzzle) next_room_pos = (8 - new_pos[0] + x, 8 - new_pos[1] + y) self.objects[ new_pos].other_room.character.change_direction( button.value) self.objects[new_pos].other_room.character.move_player( next_room_pos) return self.objects[new_pos].other_room self.character.change_direction(button.value) if new_pos in self.objects: if self.objects[new_pos].moveable: move_possible = self.move_block(new_pos, x, y) if move_possible: self.character.move_player(new_pos) player_pos = self.character.grid_pos if button == Button.MINUS: self.play(actual=True) elif button == Button.PLUS: self.play(actual=False) def on_update(self): self.animations.on_update() self.actual_sound.on_update() self.user_sound.on_update() self.key_label.set_text(f"Key: {self.user_key}") if not self.game_over and self.is_game_over(): for pos, obj in self.objects.items(): if isinstance(obj, MovingBlock): obj.moveable = False if self.level == max(levels.keys()): self.on_finished_puzzle() self.on_game_over() else: if (-1, 4) not in self.objects: size = (self.grid.tile_side_len, self.grid.tile_side_len) self.objects[(-1, 4)] = DoorTile( size, self.grid.grid_to_pixel((-1, 4)), PianoPuzzle, source=self.door_sources[(-1, 4)], ) self.add(PushMatrix()) self.add(Translate(*self.grid.pos)) self.add(self.objects[(-1, 4)]) self.add(PopMatrix()) def on_layout(self, win_size): self.remove(self.character) self.remove(self.grid) self.remove(self.instructions_text_color) self.remove(self.instructions_text) self.grid.on_layout((win_size[0], 0.75 * win_size[1])) for pos, obj in self.objects.items(): self.remove(obj) self.add(self.grid) if not self.objects: self.create_objects() self.place_objects() self.character.on_layout(win_size) self.add(self.character) self.music_bar.on_layout(win_size) self.remove(self.key_label) self.key_label = CLabelRect( (win_size[0] // 30, 23 * win_size[1] // 32), f"Key: {self.user_key}", 34) self.add(Color(rgba=(1, 1, 1, 1))) self.add(self.key_label) self.create_instructions(win_size) self.add(self.instructions_text_color) self.add(self.instructions_text) self.create_game_over_text(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.on_game_over()
def __init__(self, norm, pos, callback): super(PitchSelect, self).__init__() self.norm = norm self.selected_key = 0 self.root_pitch = 60 self.pitch = 60 # default pitch self.green = (144 / 255, 238 / 255, 144 / 255) self.white = (239 / 255, 226 / 255, 222 / 255) self.black = (.2, .2, .2) self.color_names = [ 'red', 'orange', 'yellow', 'green', 'teal', 'blue', 'indigo', 'violet', 'turquoise', 'pink', 'peach', 'magenta', 'grey' ] self.callback = callback self.pos = pos self.margin = self.norm.nv(20) self.white_key_size = self.norm.nt((50, 150)) self.black_key_size = self.norm.nt((40, 100)) self.key_margin = self.norm.nv(2) # pixels of space between keys self.size = (8 * self.white_key_size[0] + 7 * self.key_margin + 2 * self.margin, self.white_key_size[1] + 2 * self.margin + self.norm.nv(60)) self.border_color = Color(238 / 255, 234 / 255, 202 / 255) # yellow self.border = Line(rectangle=(*self.pos, *self.size), width=2) self.add(self.border_color) self.add(self.border) self.keys = [None] * 13 self.white_keys = [0, 2, 4, 5, 7, 9, 11, 12] self.black_keys = [1, 3, 6, 8, 10] key_start = (self.pos[0] + self.margin, self.pos[1] + self.margin) unit = self.white_key_size[0] + self.key_margin black_key_units = [1, 2, 4, 5, 6] for i, m in zip(self.white_keys, range(8)): self.keys[i] = Rectangle(size=self.white_key_size, pos=(key_start[0] + m * unit, key_start[1])) for i, m in zip(self.black_keys, black_key_units): self.keys[i] = CRectangle(csize=self.black_key_size, cpos=(key_start[0] + m * unit, key_start[1] + self.norm.nv(100))) self.key_colors = [None] * 13 for i in self.white_keys: self.key_colors[i] = Color(*self.white) self.add(self.key_colors[i]) self.add(self.keys[i]) for i in self.black_keys: self.key_colors[i] = Color(*self.black) self.add(self.key_colors[i]) self.add(self.keys[i]) self.key_colors[0].rgb = self.green self.arrow_size = self.norm.nt((50, 50)) self.left_pos = (self.pos[0] + self.margin, self.pos[1] + self.size[1] - self.arrow_size[1] - self.norm.nv(10)) self.left_off = Rectangle( pos=self.left_pos, size=self.arrow_size, texture=Image('ui/buttons/left_arrow.png').texture) self.left_on = Rectangle( pos=self.left_pos, size=self.arrow_size, texture=Image('ui/buttons/left_arrow_clicked.png').texture) self.right_pos = (self.pos[0] + self.size[0] - self.margin - self.arrow_size[0], self.pos[1] + self.size[1] - self.arrow_size[1] - self.norm.nv(10)) self.right_off = Rectangle( pos=self.right_pos, size=self.arrow_size, texture=Image('ui/buttons/right_arrow.png').texture) self.right_on = Rectangle( pos=self.right_pos, size=self.arrow_size, texture=Image('ui/buttons/right_arrow_clicked.png').texture) # left_off and right_off are always drawn, but when user mouses over an arrow, # left_on and right_on are drawn over left_off and right_off self.add(Color(1, 1, 1)) self.add(self.left_off) self.add(self.right_off) title_pos = (self.pos[0] + self.size[0] / 2, self.pos[1] + self.size[1] - self.margin - self.norm.nv(20)) self.title = CLabelRect(cpos=title_pos, text='pitch: {}'.format( midi_pitch_to_note_name(self.pitch)), font_size='18') self.add(Color(1, 1, 1)) self.add(self.title)
class PitchSelect(InstructionGroup): """ Submodule to select the instrument pitch of SoundBlock in the form of a graphical piano. """ def __init__(self, norm, pos, callback): super(PitchSelect, self).__init__() self.norm = norm self.selected_key = 0 self.root_pitch = 60 self.pitch = 60 # default pitch self.green = (144 / 255, 238 / 255, 144 / 255) self.white = (239 / 255, 226 / 255, 222 / 255) self.black = (.2, .2, .2) self.color_names = [ 'red', 'orange', 'yellow', 'green', 'teal', 'blue', 'indigo', 'violet', 'turquoise', 'pink', 'peach', 'magenta', 'grey' ] self.callback = callback self.pos = pos self.margin = self.norm.nv(20) self.white_key_size = self.norm.nt((50, 150)) self.black_key_size = self.norm.nt((40, 100)) self.key_margin = self.norm.nv(2) # pixels of space between keys self.size = (8 * self.white_key_size[0] + 7 * self.key_margin + 2 * self.margin, self.white_key_size[1] + 2 * self.margin + self.norm.nv(60)) self.border_color = Color(238 / 255, 234 / 255, 202 / 255) # yellow self.border = Line(rectangle=(*self.pos, *self.size), width=2) self.add(self.border_color) self.add(self.border) self.keys = [None] * 13 self.white_keys = [0, 2, 4, 5, 7, 9, 11, 12] self.black_keys = [1, 3, 6, 8, 10] key_start = (self.pos[0] + self.margin, self.pos[1] + self.margin) unit = self.white_key_size[0] + self.key_margin black_key_units = [1, 2, 4, 5, 6] for i, m in zip(self.white_keys, range(8)): self.keys[i] = Rectangle(size=self.white_key_size, pos=(key_start[0] + m * unit, key_start[1])) for i, m in zip(self.black_keys, black_key_units): self.keys[i] = CRectangle(csize=self.black_key_size, cpos=(key_start[0] + m * unit, key_start[1] + self.norm.nv(100))) self.key_colors = [None] * 13 for i in self.white_keys: self.key_colors[i] = Color(*self.white) self.add(self.key_colors[i]) self.add(self.keys[i]) for i in self.black_keys: self.key_colors[i] = Color(*self.black) self.add(self.key_colors[i]) self.add(self.keys[i]) self.key_colors[0].rgb = self.green self.arrow_size = self.norm.nt((50, 50)) self.left_pos = (self.pos[0] + self.margin, self.pos[1] + self.size[1] - self.arrow_size[1] - self.norm.nv(10)) self.left_off = Rectangle( pos=self.left_pos, size=self.arrow_size, texture=Image('ui/buttons/left_arrow.png').texture) self.left_on = Rectangle( pos=self.left_pos, size=self.arrow_size, texture=Image('ui/buttons/left_arrow_clicked.png').texture) self.right_pos = (self.pos[0] + self.size[0] - self.margin - self.arrow_size[0], self.pos[1] + self.size[1] - self.arrow_size[1] - self.norm.nv(10)) self.right_off = Rectangle( pos=self.right_pos, size=self.arrow_size, texture=Image('ui/buttons/right_arrow.png').texture) self.right_on = Rectangle( pos=self.right_pos, size=self.arrow_size, texture=Image('ui/buttons/right_arrow_clicked.png').texture) # left_off and right_off are always drawn, but when user mouses over an arrow, # left_on and right_on are drawn over left_off and right_off self.add(Color(1, 1, 1)) self.add(self.left_off) self.add(self.right_off) title_pos = (self.pos[0] + self.size[0] / 2, self.pos[1] + self.size[1] - self.margin - self.norm.nv(20)) self.title = CLabelRect(cpos=title_pos, text='pitch: {}'.format( midi_pitch_to_note_name(self.pitch)), font_size='18') self.add(Color(1, 1, 1)) self.add(self.title) def on_touch_down(self, pos): for i in self.black_keys: if in_bounds(pos, self.keys[i].pos, self.black_key_size): self.select(i) return # don't also check for white keys for i in self.white_keys: if in_bounds(pos, self.keys[i].pos, self.white_key_size): self.select(i) if in_bounds(pos, self.left_off.pos, self.arrow_size): self.left_press() if in_bounds(pos, self.right_off.pos, self.arrow_size): self.right_press() def left_press(self): if self.root_pitch - 12 < 24: # don't go below C1 in pitch return index = self.pitch - self.root_pitch self.root_pitch -= 12 self.pitch -= 12 self.title.set_text('pitch: {}'.format( midi_pitch_to_note_name(self.pitch))) self.callback(self.color_names[index], self.pitch) def right_press(self): if self.root_pitch + 12 >= 96: # don't go above C7 in pitch return index = self.pitch - self.root_pitch self.root_pitch += 12 self.pitch += 12 self.title.set_text('pitch: {}'.format( midi_pitch_to_note_name(self.pitch))) self.callback(self.color_names[index], self.pitch) def left_anim(self, pos): if in_bounds(pos, self.left_off.pos, self.arrow_size): if self.left_on not in self.children: self.add(self.left_on) else: if self.left_on in self.children: self.remove(self.left_on) def right_anim(self, pos): if in_bounds(pos, self.right_off.pos, self.arrow_size): if self.right_on not in self.children: self.add(self.right_on) else: if self.right_on in self.children: self.remove(self.right_on) def select(self, key): if key == self.selected_key: return previous_select = self.selected_key self.key_colors[key].rgb = self.green color = self.white if previous_select in self.white_keys else self.black self.key_colors[previous_select].rgb = color pitch = self.root_pitch + key self.title.set_text('pitch: {}'.format(midi_pitch_to_note_name(pitch))) self.pitch = pitch self.selected_key = key self.callback(self.color_names[key], self.pitch) def on_update(self, pos): self.left_anim(pos) self.right_anim(pos)
def __init__(self, norm, pos, callback): super(InstrumentSelect, self).__init__() self.norm = norm self.selected = 'piano' self.callback = callback self.pos = pos self.margin = self.norm.nv(20) self.button_length = self.norm.nv(64) self.title_height = self.norm.nv(50) # height of the word 'instrument' self.size = ((5 * self.button_length) + (6 * self.margin), self.button_length + (2 * self.margin) + self.title_height) self.white = (239 / 255, 226 / 255, 222 / 255) self.red = (201 / 255, 108 / 255, 130 / 255) self.border_color = Color(147 / 255, 127 / 255, 159 / 255) # purple self.border = Line(rectangle=(*self.pos, *self.size), width=2) self.add(self.border_color) self.add(self.border) button_size = (self.button_length, self.button_length) self.instruments = { 'piano': Rectangle(size=button_size, texture=Image('images/piano.png').texture), 'violin': Rectangle(size=button_size, texture=Image('images/violin.png').texture), 'trumpet': Rectangle(size=button_size, texture=Image('images/trumpet.png').texture), 'ocarina': Rectangle(size=button_size, texture=Image('images/ocarina.png').texture), 'choir': Rectangle(size=button_size, texture=Image('images/choir.png').texture) } self.instrument_bgs = { 'piano': Rectangle(size=button_size), 'violin': Rectangle(size=button_size), 'trumpet': Rectangle(size=button_size), 'ocarina': Rectangle(size=button_size), 'choir': Rectangle(size=button_size) } self.instrument_colors = { 'piano': Color(*self.red), # default selected timbre 'violin': Color(*self.white), 'trumpet': Color(*self.white), 'ocarina': Color(*self.white), 'choir': Color(*self.white) } x, y = self.pos piano_pos = (x + self.margin, y + self.margin) violin_pos = (x + 2 * self.margin + self.button_length, y + self.margin) trumpet_pos = (x + 3 * self.margin + 2 * self.button_length, y + self.margin) ocarina_pos = (x + 4 * self.margin + 3 * self.button_length, y + self.margin) choir_pos = (x + 5 * self.margin + 4 * self.button_length, y + self.margin) for instrument, instrument_pos in zip( ('piano', 'violin', 'trumpet', 'ocarina', 'choir'), (piano_pos, violin_pos, trumpet_pos, ocarina_pos, choir_pos)): self.instruments[instrument].pos = self.instrument_bgs[ instrument].pos = instrument_pos self.add(self.instrument_colors[instrument]) self.add(self.instrument_bgs[instrument]) self.add(self.instruments[instrument]) title_pos = (x + self.size[0] / 2, y + self.size[1] - self.title_height / 2 - self.margin / 2) self.title = CLabelRect(cpos=title_pos, text='instrument', font_size='18') self.add(Color(*self.white)) self.add(self.title)
class BounceSelect(InstructionGroup): """ Submodule to toggle bounces of PhysicsBubble. """ def __init__(self, norm, pos, callback): super(BounceSelect, self).__init__() self.norm = norm self.bounces = 5 self.callback = callback self.pos = pos self.margin = self.norm.nv(20) self.size = self.norm.nt((210, 130)) self.border_color = Color(170/255, 220/255, 206/255) # green self.border = Line(rectangle=(*self.pos, *self.size), width=2) self.add(self.border_color) self.add(self.border) self.arrow_size = self.norm.nt((50, 50)) self.left_pos = ( self.pos[0] + self.margin, self.pos[1] + self.margin ) self.left_off = Rectangle( pos=self.left_pos, size=self.arrow_size, texture=Image('ui/buttons/left_arrow.png').texture ) self.left_on = Rectangle( pos=self.left_pos, size=self.arrow_size, texture=Image('ui/buttons/left_arrow_clicked.png').texture ) self.right_pos = ( self.pos[0] + self.size[0] - self.margin - self.arrow_size[0], self.pos[1] + self.margin ) self.right_off = Rectangle( pos=self.right_pos, size=self.arrow_size, texture=Image('ui/buttons/right_arrow.png').texture ) self.right_on = Rectangle( pos=self.right_pos, size=self.arrow_size, texture=Image('ui/buttons/right_arrow_clicked.png').texture ) # left_off and right_off are always drawn, but when user mouses over an arrow, # left_on and right_on are drawn over left_off and right_off self.add(Color(1, 1, 1)) self.add(self.left_off) self.add(self.right_off) title_pos = (self.pos[0] + self.size[0]/2, self.pos[1] + self.size[1] - self.norm.nv(30)) self.title = CLabelRect(cpos=title_pos, text='bounces', font_size='18') self.add(self.title) bounce_text_pos = ( self.pos[0] + self.size[0]/2, self.pos[1] + self.margin + self.arrow_size[1]/2 ) self.bounce_text = CLabelRect(cpos=bounce_text_pos, text=str(self.bounces), font_size='18') self.add(self.bounce_text) def on_touch_down(self, pos): if in_bounds(pos, self.left_off.pos, self.arrow_size): self.left_press() elif in_bounds(pos, self.right_off.pos, self.arrow_size): self.right_press() def left_press(self): self.bounces -= 1 self.bounce_text.set_text(str(self.bounces)) self.callback(self.bounces) def right_press(self): self.bounces += 1 self.bounce_text.set_text(str(self.bounces)) self.callback(self.bounces) def left_anim(self, pos): if in_bounds(pos, self.left_off.pos, self.arrow_size): if self.left_on not in self.children: self.add(self.left_on) else: if self.left_on in self.children: self.remove(self.left_on) def right_anim(self, pos): if in_bounds(pos, self.right_off.pos, self.arrow_size): if self.right_on not in self.children: self.add(self.right_on) else: if self.right_on in self.children: self.remove(self.right_on) def update_bounces(self, bounces): self.bounces = bounces self.bounce_text.set_text(str(bounces)) def on_update(self, pos): self.left_anim(pos) self.right_anim(pos)
def __init__(self, norm, pos, callback): super(BounceSelect, self).__init__() self.norm = norm self.bounces = 5 self.callback = callback self.pos = pos self.margin = self.norm.nv(20) self.size = self.norm.nt((210, 130)) self.border_color = Color(170/255, 220/255, 206/255) # green self.border = Line(rectangle=(*self.pos, *self.size), width=2) self.add(self.border_color) self.add(self.border) self.arrow_size = self.norm.nt((50, 50)) self.left_pos = ( self.pos[0] + self.margin, self.pos[1] + self.margin ) self.left_off = Rectangle( pos=self.left_pos, size=self.arrow_size, texture=Image('ui/buttons/left_arrow.png').texture ) self.left_on = Rectangle( pos=self.left_pos, size=self.arrow_size, texture=Image('ui/buttons/left_arrow_clicked.png').texture ) self.right_pos = ( self.pos[0] + self.size[0] - self.margin - self.arrow_size[0], self.pos[1] + self.margin ) self.right_off = Rectangle( pos=self.right_pos, size=self.arrow_size, texture=Image('ui/buttons/right_arrow.png').texture ) self.right_on = Rectangle( pos=self.right_pos, size=self.arrow_size, texture=Image('ui/buttons/right_arrow_clicked.png').texture ) # left_off and right_off are always drawn, but when user mouses over an arrow, # left_on and right_on are drawn over left_off and right_off self.add(Color(1, 1, 1)) self.add(self.left_off) self.add(self.right_off) title_pos = (self.pos[0] + self.size[0]/2, self.pos[1] + self.size[1] - self.norm.nv(30)) self.title = CLabelRect(cpos=title_pos, text='bounces', font_size='18') self.add(self.title) bounce_text_pos = ( self.pos[0] + self.size[0]/2, self.pos[1] + self.margin + self.arrow_size[1]/2 ) self.bounce_text = CLabelRect(cpos=bounce_text_pos, text=str(self.bounces), font_size='18') self.add(self.bounce_text)
def __init__(self, norm, pos, callback): super(DrumSelect, self).__init__() self.norm = norm self.selected = 'snare' self.callback = callback self.pos = pos self.margin = self.norm.nv(20) self.button_length = self.norm.nv(64) self.title_height = self.norm.nv(50) # height of the word 'drumset' self.size = ((5 * self.button_length) + (6 * self.margin), self.button_length + (2 * self.margin) + self.title_height) self.white = (239 / 255, 226 / 255, 222 / 255) self.red = (201 / 255, 108 / 255, 130 / 255) self.border_color = Color(214 / 255, 152 / 255, 142 / 255) #orange self.border = Line(rectangle=(*self.pos, *self.size), width=2) self.add(self.border_color) self.add(self.border) button_size = (self.button_length, self.button_length) self.instruments = { 'snare': Rectangle(size=button_size, texture=Image('images/snare.png').texture), 'crash': Rectangle(size=button_size, texture=Image('images/crash.png').texture), 'bass': Rectangle(size=button_size, texture=Image('images/bass.png').texture), 'hihat': Rectangle(size=button_size, texture=Image('images/hihat.png').texture), 'triangle': Rectangle(size=button_size, texture=Image('images/triangle_instr.png').texture) } self.instrument_bgs = { 'snare': Rectangle(size=button_size), 'crash': Rectangle(size=button_size), 'bass': Rectangle(size=button_size), 'hihat': Rectangle(size=button_size), 'triangle': Rectangle(size=button_size) } self.instrument_colors = { 'snare': Color(*self.red), # default selected timbre 'crash': Color(*self.white), 'bass': Color(*self.white), 'hihat': Color(*self.white), 'triangle': Color(*self.white) } x, y = self.pos snare_pos = (x + self.margin, y + self.margin) crash_pos = (x + 2 * self.margin + self.button_length, y + self.margin) bass_pos = (x + 3 * self.margin + 2 * self.button_length, y + self.margin) hihat_pos = (x + 4 * self.margin + 3 * self.button_length, y + self.margin) triangle_pos = (x + 5 * self.margin + 4 * self.button_length, y + self.margin) for instrument, instrument_pos in zip( ('snare', 'crash', 'bass', 'hihat', 'triangle'), (snare_pos, crash_pos, bass_pos, hihat_pos, triangle_pos)): self.instruments[instrument].pos = self.instrument_bgs[ instrument].pos = instrument_pos self.add(self.instrument_colors[instrument]) self.add(self.instrument_bgs[instrument]) self.add(self.instruments[instrument]) title_pos = (x + self.size[0] / 2, y + self.size[1] - self.title_height / 2 - self.margin / 2) self.title = CLabelRect(cpos=title_pos, text='drumkit', font_size='18') self.add(Color(*self.white)) self.add(self.title)
class PhysicsBubble(InstructionGroup): """ This module is a drag-and-release physics-based bubble that plays a sound upon colliding with another collidable object, including the sandbox edges. """ name = 'PhysicsBubble' def __init__(self, norm, sandbox, pos, vel, pitch, timbre, color, bounces, handler, gravity=False, callback=None): """ :param norm: normalizer :param sandbox: client's sandbox :param pos: initial position :param vel: initial velocity :param pitch: MIDI pitch value, where 60 is middle C :param timbre: type of waveform, e.g. 'sine' or 'sawtooth' :param color: 3-tuple of RGB color :param bounces: number of times the bubble bounces before fading away :param gravity: whether or not the bubble is subjected to downwards gravity :param callback: the sound function that is called when the bubble bounces """ super(PhysicsBubble, self).__init__() self.norm = norm self.sandbox = sandbox self.r = self.norm.nv(40) self.pos = np.array(pos, dtype=np.float) self.vel = 2 * np.array(vel, dtype=np.float) self.pitch = pitch self.timbre = timbre self.color = Color(*color) self.text_color = Color(0, 0, 0) self.bounces = bounces self.gravity = gravity self.callback = callback self.handler = handler self.text = CLabelRect(cpos=pos, text=str(self.bounces)) self.bubble = self.timbre_to_shape(self.timbre, pos) self.add(self.color) self.add(self.bubble) self.add(self.text_color) self.add(self.text) # have the bubble fade away when self.bounces = 0 self.fade_anim = KFAnim((0, 1), (0.25, 0)) self.time = 0 self.on_update(0) def timbre_to_shape(self, timbre, pos): if timbre == 'sine': return CEllipse(cpos=pos, size=self.norm.nt((80, 80)), segments=20) elif timbre == 'triangle': return CEllipse(cpos=pos, size=self.norm.nt((90, 90)), segments=3) elif timbre == 'square': return CRectangle(cpos=pos, size=self.norm.nt((80, 80))) elif timbre == 'sawtooth': # square rotated 45 degrees return CEllipse(cpos=pos, size=self.norm.nt((90, 90)), segments=4) def on_update(self, dt): if self.gravity: self.vel += downwards_gravity * dt self.pos += self.vel * dt else: self.pos += self.vel * dt if self.bounces > 0: if self.check_for_block_collisions() and self.callback is not None: self.callback(self.pitch, self.timbre) if self.check_for_collisions() and self.callback is not None: self.callback(self.pitch, self.timbre) # second condition checks if bubble hasn't been moving but there's no gravity -- # since bubble would be on the screen forever without making sound, fade it away if self.bounces <= 0 or (not self.gravity and np.linalg.norm(self.vel) == 0): self.color.a = self.fade_anim.eval(self.time) self.time += dt self.bubble.set_cpos(self.pos) self.text.set_cpos(self.pos) return self.fade_anim.is_active(self.time) def check_for_collisions(self): bottom = self.sandbox.pos[1] top = self.sandbox.pos[1] + self.sandbox.height left = self.sandbox.pos[0] right = self.sandbox.pos[0] + self.sandbox.width # collision with bottom if self.pos[1] - self.r < bottom: self.vel[1] = -self.vel[ 1] * damping_factor if self.gravity else -self.vel[1] self.pos[1] = bottom + self.r self.bounces -= 1 self.text.set_text(str(self.bounces)) return True # collision with top if self.pos[1] + self.r > top: self.vel[1] = -self.vel[1] self.pos[1] = top - self.r self.bounces -= 1 self.text.set_text(str(self.bounces)) return True # collision with left if self.pos[0] - self.r < left: self.vel[0] = -self.vel[0] self.pos[0] = left + self.r self.bounces -= 1 self.text.set_text(str(self.bounces)) return True # collision with right if self.pos[0] + self.r > right: self.vel[0] = -self.vel[0] self.pos[0] = right - self.r self.bounces -= 1 self.text.set_text(str(self.bounces)) return True def check_for_block_collisions(self): """Check to see if this bubble collided with any SoundBlocks.""" collide = False blocks = self.handler.block_handler.blocks.objects for block in blocks: left_x = block.pos[0] right_x = block.pos[0] + block.size[0] bottom_y = block.pos[1] top_y = block.pos[1] + block.size[1] # going left if self.pos[0] + self.r >= left_x and \ self.pos[0]+self.r <= right_x and \ self.pos[1] >= bottom_y and self.pos[1] <= top_y: self.vel[0] *= -1 self.pos[0] = left_x - self.r self.bounces -= 1 self.text.set_text(str(self.bounces)) block.flash() collide = True # going right if self.pos[0] - self.r <= right_x and \ self.pos[0]-self.r >= left_x and \ self.pos[1] >= bottom_y and self.pos[1] <= top_y: self.vel[0] *= -1 self.pos[0] = right_x + self.r self.bounces -= 1 self.text.set_text(str(self.bounces)) block.flash() collide = True # going up if self.pos[1] + self.r >= bottom_y and \ self.pos[1] + self.r <= top_y and \ self.pos[0] >= left_x and self.pos[0] <= right_x: self.vel[1] *= -1 self.pos[1] = bottom_y - self.r self.bounces -= 1 self.text.set_text(str(self.bounces)) block.flash() collide = True # going down if self.pos[1] - self.r <= top_y and \ self.pos[1]-self.r >= bottom_y and \ self.pos[0] >= left_x and self.pos[0] <= right_x: self.vel[1] *= -1 self.pos[1] = top_y + self.r self.bounces -= 1 self.text.set_text(str(self.bounces)) block.flash() collide = True return collide