def _init_lose(self): # If the player is stuck, wait a little while, then signal the activity # to display the stuck dialog. start_time = time.time() def update_func(): delta = time.time() - start_time return (delta <= _STUCK_DELAY) def end_anim_func(anim_stopped): if not anim_stopped: self.emit('show-stuck', 1) self._anim = Anim(update_func, end_anim_func) self._anim.start()
def action(stage): # Caveat: This has the potential to get a little messed up if it is an # early action in a stage or if the screen changes size as the cursor # is moving... Best to keep a pause before it in the sequence. (old_x, old_y) = stage.preview.get_cursor_pos() (new_x, new_y) = coord_func(stage) delta_x = new_x - old_x delta_y = new_y - old_y dist = math.sqrt(delta_x * delta_x + delta_y * delta_y) move_time = dist * _MOUSE_SPEED start_time = time.time() def update_func(): delta = time.time() - start_time if delta >= move_time or move_time == 0.0: return False t = max(0.0, min(1.0, delta / move_time)) # Use the first half of cosine wave to ease in/out. w = 1.0 - (0.5 * math.cos(t * math.pi) + 0.5) inv_w = 1.0 - w move_x = old_x * inv_w + new_x * w move_y = old_y * inv_w + new_y * w stage.preview.set_cursor_pos(move_x, move_y) return True def end_anim_func(anim_stopped): if not anim_stopped: stage.next_action() stage.anim = Anim(update_func, end_anim_func) stage.anim.start()
def action(stage): contiguous = stage.board.get_contiguous(x, y) removal_drawer = stage.preview.removal_drawer stage.preview.set_drawer(removal_drawer) removal_drawer.init(stage.board, contiguous) removal_drawer.set_anim_time(0.0) start_time = time.time() def update_func(start_time_ref=[start_time]): delta = time.time() - start_time_ref[0] length = removal_drawer.get_anim_length() if delta > length: if not removal_drawer.next_stage(): return False start_time_ref[0] = time.time() delta = 0.0 removal_drawer.set_anim_time(delta) return True def local_end_anim_func(anim_stopped): stage.preview.set_drawer(stage.preview.board_drawer) stage.undo_stack.append(stage.board) board = stage.board.clone() board.clear_pieces(contiguous) board.drop_pieces() board.remove_empty_columns() stage.set_board(board) if not anim_stopped: stage.next_action() stage.anim = Anim(update_func, local_end_anim_func) stage.anim.start()
def action(stage): start_time = time.time() def update_func(): delta = time.time() - start_time return delta < delay def end_anim_func(anim_stopped): if not anim_stopped: stage.next_action() stage.anim = Anim(update_func, end_anim_func) stage.anim.start()
def action(stage): start_time = time.time() stage.preview.set_click_visible(True) def update_func(): delta = time.time() - start_time return (delta < _CLICK_SPEED) def end_anim_func(anim_stopped): stage.preview.set_click_visible(False) if not anim_stopped: stage.next_action() stage.anim = Anim(update_func, end_anim_func) stage.anim.start()
def undo_to_solvable_state(self): # Undoes the player's moves until the puzzle is in a solvable state. # # Actually, we undo moves until the player's moves so far match the # beginning of a list of moves known to solve the puzzle, as given by # the puzzle generator. Since each puzzle can potentially be solved # through many different sequences of moves, we will almost certainly # be undoing more moves than we need to. One possible improvement # would be to write a generic puzzle solver that can test some of the # player's later board states for solvability, so that we don't need to # undo as many moves. self._hide_stuck() self._stop_animation() if len(self._undo_stack) == 0: return start_time = time.time() def update_func(start_time_ref=[start_time]): delta = time.time() - start_time_ref[0] if delta > _UNDO_DELAY: self._undo_last_move() moves = self._get_moves_so_far() if moves == self._winning_moves[:len(moves)]: return False start_time_ref[0] = time.time() return True def end_anim_func(anim_stopped): moves = self._get_moves_so_far() while moves != self._winning_moves[:len(moves)]: self._undo_last_move() moves = self._get_moves_so_far() self._anim = Anim(update_func, end_anim_func) self._anim.start()
def get_win_anim(self, end_anim_func): self._set_current_drawer(self._win_drawer) self._win_drawer.init() length = self._win_drawer.get_anim_length() start_time = time.time() def update_func(): delta = time.time() - start_time self._win_drawer.set_anim_time(min(delta, length)) return (delta <= length) def local_end_anim_func(anim_stopped): self._win_drawer.set_anim_time(length) end_anim_func(anim_stopped) return Anim(update_func, local_end_anim_func)
def action(stage): win_drawer = stage.preview.win_drawer stage.preview.set_drawer(win_drawer) win_drawer.set_win_state(True, color) length = win_drawer.get_anim_length() start_time = time.time() def update_func(): delta = time.time() - start_time win_drawer.set_anim_time(min(delta, length)) return (delta <= length) def local_end_anim_func(anim_stopped): win_drawer.set_anim_time(length) if not anim_stopped: stage.next_action() stage.anim = Anim(update_func, local_end_anim_func) stage.anim.start()
def get_removal_anim(self, board, contiguous, end_anim_func): self._set_current_drawer(self._removal_drawer) self._removal_drawer.init(board, contiguous) self._removal_drawer.set_anim_time(0.0) start_time = time.time() def update_func(start_time_ref=[start_time]): delta = time.time() - start_time_ref[0] length = self._removal_drawer.get_anim_length() if delta > length: if not self._removal_drawer.next_stage(): return False start_time_ref[0] = time.time() delta = 0.0 self._removal_drawer.set_anim_time(delta) return True def local_end_anim_func(anim_stopped): self._set_current_drawer(self._board_drawer) end_anim_func(anim_stopped) return Anim(update_func, local_end_anim_func)
def __init__(self, sprite): super(Entity, self).__init__() self.sprite = sprite self.sprite.isobs = False self.x__ = self.sprite.x self.y__ = self.sprite.y self.w = self.sprite.hotwidth self.h = self.sprite.hotheight self.state__ = None self.vx = 0 self.vy = 0 self.left_wall = 0 self.right_wall = 0 self.ceiling = 0 self.floor = 0 self.check_obs = True self.hurtable = False self.anim = Anim() self.state = self.null_state self.touchable = False self.destroy = False self.active = True self.platform = False
def undo_to_solvable_state(self): # Undoes the player's moves until the puzzle is in a solvable state. # # Actually, we undo moves until the player's moves so far match the # beginning of a list of moves known to solve the puzzle, as given by # the puzzle generator. Since each puzzle can potentially be solved # through many different sequences of moves, we will almost certainly # be undoing more moves than we need to. One possible improvement # would be to write a generic puzzle solver that can test some of the # player's later board states for solvability, so that we don't need to # undo as many moves. self._hide_stuck() self._stop_animation() if len(self._undo_stack) == 0: return start_time = time.time() def update_func(start_time_ref = [start_time]): delta = time.time() - start_time_ref[0] if delta > _UNDO_DELAY: self._undo_last_move() moves = self._get_moves_so_far() if moves == self._winning_moves[:len(moves)]: return False start_time_ref[0] = time.time() return True def end_anim_func(anim_stopped): moves = self._get_moves_so_far() while moves != self._winning_moves[:len(moves)]: self._undo_last_move() moves = self._get_moves_so_far() self._anim = Anim(update_func, end_anim_func) self._anim.start()
class ImplodeGame(Gtk.EventBox): """Gtk widget for playing the implode game.""" __gsignals__ = { 'show-stuck': (GObject.SignalFlags.RUN_LAST, None, (int, )), } def __init__(self, *args, **kwargs): super(ImplodeGame, self).__init__(*args, **kwargs) self._animate = True self._anim = None self._board = None # Undo and redo stacks are pairs of (board state, subsequent move). self._undo_stack = [] self._redo_stack = [] self._winning_moves = [] self._random = random.Random() # self._random.seed(0) self._difficulty = 0 self._size = (8, 6) self._seed = 0 self._fragmentation = 0 self._grid = gridwidget.GridWidget() self._grid.connect('piece-selected', self._piece_selected_cb) self._grid.connect('undo-key-pressed', self._undo_key_pressed_cb) self._grid.connect('redo-key-pressed', self._redo_key_pressed_cb) self._grid.connect('new-key-pressed', self._new_key_pressed_cb) self.add(self._grid) self.new_game() def grab_focus(self): self._grid.grab_focus() # self._grid.select_center_cell() def new_game(self): self._hide_stuck() self._stop_animation() self._seed = self._random.randint(0, 99999) size_frag_dict = { 0: ((8, 6), 0), 1: ((12, 10), 0), 2: ((20, 15), 2), } (self._size, self._fragmentation) = size_frag_dict[self._difficulty] self._reset_board() def replay_game(self): self._hide_stuck() self._stop_animation() self._reset_board() def undo(self): self._hide_stuck() self._stop_animation() if len(self._undo_stack) == 0: return self._undo_last_move() def undo_to_solvable_state(self): # Undoes the player's moves until the puzzle is in a solvable state. # # Actually, we undo moves until the player's moves so far match the # beginning of a list of moves known to solve the puzzle, as given by # the puzzle generator. Since each puzzle can potentially be solved # through many different sequences of moves, we will almost certainly # be undoing more moves than we need to. One possible improvement # would be to write a generic puzzle solver that can test some of the # player's later board states for solvability, so that we don't need to # undo as many moves. self._hide_stuck() self._stop_animation() if len(self._undo_stack) == 0: return start_time = time.time() def update_func(start_time_ref=[start_time]): delta = time.time() - start_time_ref[0] if delta > _UNDO_DELAY: self._undo_last_move() moves = self._get_moves_so_far() if moves == self._winning_moves[:len(moves)]: return False start_time_ref[0] = time.time() return True def end_anim_func(anim_stopped): moves = self._get_moves_so_far() while moves != self._winning_moves[:len(moves)]: self._undo_last_move() moves = self._get_moves_so_far() self._anim = Anim(update_func, end_anim_func) self._anim.start() def _get_moves_so_far(self): # Returns a list of the moves so far. return [move for (board, move) in self._undo_stack] def _undo_last_move(self): # Undoes the most recent move and stores the state on the undo stack. (board, move) = self._undo_stack.pop() self._redo_stack.append((self._board, move)) self._board = board # Force board refresh. self._grid.set_board(self._board) self._grid.set_win_draw_flag(False) def redo(self): self._hide_stuck() self._stop_animation() if len(self._redo_stack) == 0: return (board, move) = self._redo_stack.pop() self._undo_stack.append((self._board, move)) self._board = board # Force board refresh. self._grid.set_board(self._board) self._check_for_lose_state() def set_level(self, level): self._difficulty = level def get_game_state(self): # Returns a dictionary containing the game state, in atomic subobjects. def encode_board(board, move): # Encodes the given board and move to a state array. (w, h) = (board.width, board.height) data = [] for i in range(h): for j in range(w): data.append(board.get_value(j, i)) if move is not None: return [w, h] + data + list(move) else: return [w, h] + data return { 'difficulty': self._difficulty, 'seed': self._seed, 'size': self._size, 'fragmentation': self._fragmentation, 'board': encode_board(self._board, None), 'undo_stack': [encode_board(b, m) for b, m in self._undo_stack], 'redo_stack': [encode_board(b, m) for b, m in self._redo_stack], 'win_draw_flag': self._grid.get_win_draw_flag(), 'win_color': self._grid.get_win_color(), 'winning_moves': self._winning_moves } def set_game_state(self, state): # Sets the game state using a dictionary of atomic subobjects. self._hide_stuck() self._stop_animation() def decode_board(state): # Decodes a board (and maybe an appended move) from the given state # array. b = board.Board() (w, h) = (state[0], state[1]) data = state[2:] for i in range(h): for j in range(w): b.set_value(j, i, data.pop(0)) if len(data) == 2: # Return appended move. return b, tuple(data) else: return b, None self._difficulty = state['difficulty'] self._seed = state['seed'] self._size = state['size'] self._fragmentation = state['fragmentation'] (self._board, dummy) = decode_board(state['board']) self._undo_stack = [decode_board(x) for x in state['undo_stack']] self._redo_stack = [decode_board(x) for x in state['redo_stack']] self._grid.set_board(self._board) self._grid.set_win_state(state['win_draw_flag'], state['win_color']) if 'winning_moves' in state: # Prior to version 8, we didn't store the list of winning moves. self._winning_moves = [tuple(x) for x in state['winning_moves']] else: self._winning_moves = [] self._check_for_lose_state() def _reset_board(self): # Regenerates the board with the current seed. (self._board, self._winning_moves) = \ boardgen.generate_board( seed=self._seed, fragmentation=self._fragmentation, max_size=self._size) self._grid.set_board(self._board) self._grid.set_win_draw_flag(False) self._undo_stack = [] self._redo_stack = [] def _piece_selected_cb(self, widget, x, y): # Handles piece selection. # We check contiguous before stopping the animation because we don't # want a click on the game board in a losing state to stop the "stuck" # animation. if len(self._board.get_contiguous(x, y)) < 3: return self._hide_stuck() self._stop_animation() # We recalc contiguous here because _stop_animation may modify board # contents (e.g. the undo-many animation). contiguous = self._board.get_contiguous(x, y) if len(contiguous) >= 3: def remove_func(anim_stopped=False): self._remove_contiguous(contiguous, anim_stopped) if self._animate: self._anim = self._grid.get_removal_anim( self._board, contiguous, remove_func) self._anim.start() else: remove_func() def _undo_key_pressed_cb(self, widget, dummy): self.undo() def _redo_key_pressed_cb(self, widget, dummy): self.redo() def _new_key_pressed_cb(self, widget, dummy): # Only invoke new command via game pad if board is clear, to prevent # terrible accidents. if self._board.is_empty(): self.new_game() def _stop_animation(self): if self._anim is not None: self._anim.stop() def _remove_contiguous(self, contiguous, anim_stopped=False): # Removes the given set of contiguous blocks from the board. self._redo_stack = [] # We save the player's move as the lexographically smallest coordinate # of the piece. move = min(contiguous) self._undo_stack.append((self._board.clone(), move)) self._board.clear_pieces(contiguous) self._board.drop_pieces() self._board.remove_empty_columns() # Force board refresh. self._grid.set_board(self._board) if self._board.is_empty(): if self._animate and not anim_stopped: self._anim = self._grid.get_win_anim(self._init_win) self._anim.start() else: self._init_win() else: self._check_for_lose_state() def _check_for_lose_state(self): if not self._board.is_empty(): all_contiguous = self._board.get_all_contiguous() if len(all_contiguous) == 0: self._init_lose() def _init_win(self, anim_stopped=False): self._grid.set_win_draw_flag(True) # Clear the undo stack so that the undo/redo buttons do nothing after # winning. self._undo_stack = [] def _init_lose(self): # If the player is stuck, wait a little while, then signal the activity # to display the stuck dialog. start_time = time.time() def update_func(): delta = time.time() - start_time return (delta <= _STUCK_DELAY) def end_anim_func(anim_stopped): if not anim_stopped: self.emit('show-stuck', 1) self._anim = Anim(update_func, end_anim_func) self._anim.start() def _hide_stuck(self): self.emit('show-stuck', 0)
class ImplodeGame(Gtk.EventBox): """Gtk widget for playing the implode game.""" __gsignals__ = { 'show-stuck': (GObject.SignalFlags.RUN_LAST, None, (int,)), } def __init__(self, *args, **kwargs): super(ImplodeGame, self).__init__(*args, **kwargs) self._animate = True self._anim = None self._board = None # Undo and redo stacks are pairs of (board state, subsequent move). self._undo_stack = [] self._redo_stack = [] self._winning_moves = [] self._random = random.Random() #self._random.seed(0) self._difficulty = 0 self._size = (8, 6) self._seed = 0 self._fragmentation = 0 self._grid = gridwidget.GridWidget() self._grid.connect('piece-selected', self._piece_selected_cb) self._grid.connect('undo-key-pressed', self._undo_key_pressed_cb) self._grid.connect('redo-key-pressed', self._redo_key_pressed_cb) self._grid.connect('new-key-pressed', self._new_key_pressed_cb) self.add(self._grid) self.new_game() def grab_focus(self): self._grid.grab_focus() #self._grid.select_center_cell() def new_game(self): self._hide_stuck() self._stop_animation() self._seed = self._random.randint(0, 99999) size_frag_dict = { 0: (( 8, 6), 0), 1: ((12, 10), 0), 2: ((20, 15), 2), } (self._size, self._fragmentation) = size_frag_dict[self._difficulty] self._reset_board() def replay_game(self): self._hide_stuck() self._stop_animation() self._reset_board() def undo(self): self._hide_stuck() self._stop_animation() if len(self._undo_stack) == 0: return self._undo_last_move() def undo_to_solvable_state(self): # Undoes the player's moves until the puzzle is in a solvable state. # # Actually, we undo moves until the player's moves so far match the # beginning of a list of moves known to solve the puzzle, as given by # the puzzle generator. Since each puzzle can potentially be solved # through many different sequences of moves, we will almost certainly # be undoing more moves than we need to. One possible improvement # would be to write a generic puzzle solver that can test some of the # player's later board states for solvability, so that we don't need to # undo as many moves. self._hide_stuck() self._stop_animation() if len(self._undo_stack) == 0: return start_time = time.time() def update_func(start_time_ref = [start_time]): delta = time.time() - start_time_ref[0] if delta > _UNDO_DELAY: self._undo_last_move() moves = self._get_moves_so_far() if moves == self._winning_moves[:len(moves)]: return False start_time_ref[0] = time.time() return True def end_anim_func(anim_stopped): moves = self._get_moves_so_far() while moves != self._winning_moves[:len(moves)]: self._undo_last_move() moves = self._get_moves_so_far() self._anim = Anim(update_func, end_anim_func) self._anim.start() def _get_moves_so_far(self): # Returns a list of the moves so far. return [move for (board, move) in self._undo_stack] def _undo_last_move(self): # Undoes the most recent move and stores the state on the undo stack. (board, move) = self._undo_stack.pop() self._redo_stack.append((self._board, move)) self._board = board # Force board refresh. self._grid.set_board(self._board) self._grid.set_win_draw_flag(False) def redo(self): self._hide_stuck() self._stop_animation() if len(self._redo_stack) == 0: return (board, move) = self._redo_stack.pop() self._undo_stack.append((self._board, move)) self._board = board # Force board refresh. self._grid.set_board(self._board) self._check_for_lose_state() def set_level(self, level): self._difficulty = level def get_game_state(self): # Returns a dictionary containing the game state, in atomic subobjects. def encode_board(board, move): # Encodes the given board and move to a state array. (w, h) = (board.width, board.height) data = [] for i in range(h): for j in range(w): data.append(board.get_value(j, i)) if move is not None: return [w, h] + data + list(move) else: return [w, h] + data return { 'difficulty' : self._difficulty, 'seed' : self._seed, 'size' : self._size, 'fragmentation' : self._fragmentation, 'board' : encode_board(self._board, None), 'undo_stack': [encode_board(b,m) for b,m in self._undo_stack], 'redo_stack': [encode_board(b,m) for b,m in self._redo_stack], 'win_draw_flag': self._grid.get_win_draw_flag(), 'win_color': self._grid.get_win_color(), 'winning_moves' : self._winning_moves } def set_game_state(self, state): # Sets the game state using a dictionary of atomic subobjects. self._hide_stuck() self._stop_animation() def decode_board(state): # Decodes a board (and maybe an appended move) from the given state # array. b = board.Board() (w, h) = (state[0], state[1]) data = state[2:] for i in range(h): for j in range(w): b.set_value(j, i, data.pop(0)) if len(data) == 2: # Return appended move. return b, tuple(data) else: return b, None self._difficulty = state['difficulty'] self._seed = state['seed'] self._size = state['size'] self._fragmentation = state['fragmentation'] (self._board, dummy) = decode_board(state['board']) self._undo_stack = [decode_board(x) for x in state['undo_stack']] self._redo_stack = [decode_board(x) for x in state['redo_stack']] self._grid.set_board(self._board) self._grid.set_win_state(state['win_draw_flag'], state['win_color']) if 'winning_moves' in state: # Prior to version 8, we didn't store the list of winning moves. self._winning_moves = [tuple(x) for x in state['winning_moves']] else: self._winning_moves = [] self._check_for_lose_state() def _reset_board(self): # Regenerates the board with the current seed. (self._board, self._winning_moves) = \ boardgen.generate_board(seed=self._seed, fragmentation=self._fragmentation, max_size=self._size) self._grid.set_board(self._board) self._grid.set_win_draw_flag(False) self._undo_stack = [] self._redo_stack = [] def _piece_selected_cb(self, widget, x, y): # Handles piece selection. # We check contiguous before stopping the animation because we don't # want a click on the game board in a losing state to stop the "stuck" # animation. if len(self._board.get_contiguous(x, y)) < 3: return self._hide_stuck() self._stop_animation() # We recalc contiguous here because _stop_animation may modify board # contents (e.g. the undo-many animation). contiguous = self._board.get_contiguous(x, y) if len(contiguous) >= 3: def remove_func(anim_stopped=False): self._remove_contiguous(contiguous, anim_stopped) if self._animate: self._anim = self._grid.get_removal_anim(self._board, contiguous, remove_func) self._anim.start() else: remove_func() def _undo_key_pressed_cb(self, widget, dummy): self.undo() def _redo_key_pressed_cb(self, widget, dummy): self.redo() def _new_key_pressed_cb(self, widget, dummy): # Only invoke new command via game pad if board is clear, to prevent # terrible accidents. if self._board.is_empty(): self.new_game() def _stop_animation(self): if self._anim is not None: self._anim.stop() def _remove_contiguous(self, contiguous, anim_stopped=False): # Removes the given set of contiguous blocks from the board. self._redo_stack = [] # We save the player's move as the lexographically smallest coordinate # of the piece. move = min(contiguous) self._undo_stack.append((self._board.clone(), move)) self._board.clear_pieces(contiguous) self._board.drop_pieces() self._board.remove_empty_columns() # Force board refresh. self._grid.set_board(self._board) if self._board.is_empty(): if self._animate and not anim_stopped: self._anim = self._grid.get_win_anim(self._init_win) self._anim.start() else: self._init_win() else: self._check_for_lose_state() def _check_for_lose_state(self): if not self._board.is_empty(): all_contiguous = self._board.get_all_contiguous() if len(all_contiguous) == 0: self._init_lose() def _init_win(self, anim_stopped=False): self._grid.set_win_draw_flag(True) # Clear the undo stack so that the undo/redo buttons do nothing after # winning. self._undo_stack = [] def _init_lose(self): # If the player is stuck, wait a little while, then signal the activity # to display the stuck dialog. start_time = time.time() def update_func(): delta = time.time() - start_time return (delta <= _STUCK_DELAY) def end_anim_func(anim_stopped): if not anim_stopped: self.emit('show-stuck', 1) self._anim = Anim(update_func, end_anim_func) self._anim.start() def _hide_stuck(self): self.emit('show-stuck', 0)
class Entity(object): #sprite is an ika Sprite def __init__(self, sprite): super(Entity, self).__init__() self.sprite = sprite self.sprite.isobs = False self.x__ = self.sprite.x self.y__ = self.sprite.y self.w = self.sprite.hotwidth self.h = self.sprite.hotheight self.state__ = None self.vx = 0 self.vy = 0 self.left_wall = 0 self.right_wall = 0 self.ceiling = 0 self.floor = 0 self.check_obs = True self.hurtable = False self.anim = Anim() self.state = self.null_state self.touchable = False self.destroy = False self.active = True self.platform = False # Hack so that ika can detect entity collisions for us. #ika.Map.entities[id(self.sprite)] = self.sprite def draw(self): pass def touch(self, entity): pass def set_animation_state(self, first, last, delay, loop=True, reset=True): # Reverse order. if first > last: strand = range(last, first + 1) strand.reverse() self.anim.set_anim(make_anim(strand, delay), loop, reset) else: self.anim.set_anim(make_anim(range(first, last + 1), delay), loop, reset) def animation(self): self.anim.update(1) self.sprite.specframe = self.anim.cur_frame def update(self): # Because it could have been destroyed already. if self.sprite is None: return self.state__() self.animation() self.x += self.vx self.y += self.vy self.sprite.x = int(self.x) self.sprite.y = int(self.y) if self.check_obs: self.check_obstructions() if self.destroy: # Must put this at the end of the update. self._destroy() def null_state(self): """Default entity state. The entity does nothing at all in this state. """ while True: yield None def _destroy(self): self.visible = False self.active = False #self.sprite = None e.engine.RemoveEntity(self) def check_obstructions(self): x = int(self.x) y = int(self.y) layer = 1 self.left_wall = self.check_v_line(x + self.vx - 2, y, y + self.sprite.hotheight - 2) self.right_wall = self.check_v_line(x + self.sprite.hotwidth + self.vx + 1, y, y + self.sprite.hotheight - 2) self.ceiling = self.check_h_line(x + 1, y + self.vy, x + self.sprite.hotwidth - 1) self.floor = self.check_h_line(x, y + self.sprite.hotheight + self.vy, x + self.sprite.hotwidth - 1) def detect_collision(self): #entity collisions, not currently used in default entity code result = [] for entity in e.engine.entities: top = bottom = left = right = False etop = entity.y ebottom = entity.y + entity.sprite.hotheight eleft = entity.x eright = entity.x + entity.sprite.hotwidth if entity is not self and entity.sprite and \ ebottom > self.y and etop < self.y + self.sprite.hotheight and \ eright > self.x and eleft < self.x + self.sprite.hotwidth: #within bounding box. Check if it's the top, bottom, left, or right side being collided with. if ebottom > self.y and ebottom < self.y + (self.sprite.hotheight/2): top = True #entity touching top side if etop < self.y + self.sprite.hotheight and top > self.y + (self.sprite.hotheight/2): bottom = True if eright > self.x and eright < self.x + (self.sprite.hotwidth/2): left = True if eleft < self.x + self.sprite.hotwidth and eleft < self.x + (self.sprite.hotheight/2): right = True result.append((entity, top, bottom, left, right)) return result def check_v_line(self, x1, y1, y2): x1 = int(x1) y1 = int(y1) y2 = int(y2) for y in range(y1, y2, 4): if self.get_obstruction(x1, y, self.layer): return True return self.get_obstruction(x1, y2, self.layer) def check_h_line(self, x1, y1, x2): x1 = int(x1) y1 = int(y1) x2 = int(x2) for x in range(x1, x2, 4): if self.get_obstruction(x, y1, self.layer): return True return self.get_obstruction(x2, y1, self.layer) def get_obstruction(self, x, y, layer): return ika.Map.GetObs(int(x / ika.Map.tilewidth), int(y / ika.Map.tileheight), layer) def _set_state(self, new_state): self.state__ = new_state().next def _set_x(self, value): self.sprite.x = self.x__ = value def _set_y(self, value): self.sprite.y = self.y__ = value def _set_layer(self, value): self.sprite.layer = value def _set_position(self, (x, y)): self.x, self.y = x, y