def sweep_collision(self, collidee, v, debug=False): """ self (collider) moving by v, collidee stationery based on http://bit.ly/3grWzs """ u_0 = [2, 2, 2] u_1 = [1, 1, 1] for i in xrange(3): if fops.lte(self.maxs[i], collidee.mins[i]) and fops.gt(v[i], 0): d = collidee.mins[i] - self.maxs[i] u_0[i] = d / v[i] elif fops.lte(collidee.maxs[i], self.mins[i]) and fops.lt(v[i], 0): d = collidee.maxs[i] - self.mins[i] u_0[i] = d / v[i] elif not(fops.lte(self.maxs[i], collidee.mins[i]) or fops.gte(self.mins[i], collidee.maxs[i])): u_0[i] = 0 if fops.gte(collidee.maxs[i], self.mins[i]) and fops.gt(v[i], 0): d = collidee.maxs[i] - self.mins[i] u_1[i] = d / v[i] elif fops.gte(self.maxs[i], collidee.mins[i]) and fops.lt(v[i], 0): d = collidee.mins[i] - self.maxs[i] u_1[i] = d / v[i] u0 = max(u_0) if u0 == 2 or fops.gte(u0, 1.0): col = False else: col = fops.lte(u0, min(u_1)) return col, u0
def action(self): b_obj = self.blackboard.bot_object self.status = self._check_status(b_obj) if self.status != Status.running: return on_ladder = self.blackboard.bot_is_on_ladder(b_obj) in_water = self.blackboard.bot_is_in_water(b_obj) if on_ladder or in_water: elev = self.target_state.platform_y - b_obj.y if fops.gt(elev, 0): self.jump(b_obj) self.move(b_obj) elif fops.lt(elev, 0): self.move(b_obj) else: if on_ladder: self.sneak(b_obj) self.move(b_obj) elif self.blackboard.bot_is_standing(b_obj): elev = self.target_state.platform_y - b_obj.y if fops.lte(elev, 0): self.move(b_obj) elif fops.gt(elev, 0): if self.start_state.base_in(b_obj.aabb): self.jump(b_obj) self.move(b_obj) else: self.move(b_obj)
def _tick(self): if self.cancelled: self.status = Status.failure return b_obj = self.bot.bot_object self.status = self.check_status(b_obj) if self.status != Status.running: return on_ladder = self.bot.is_on_ladder(b_obj) in_water = self.bot.is_in_water(b_obj) if on_ladder or in_water: elev = self.target_state.platform_y - b_obj.y if fops.gt(elev, 0): self.jump(b_obj) self.move(b_obj) elif fops.lt(elev, 0): self.move(b_obj) else: if on_ladder: self.sneak(b_obj) self.move(b_obj) elif self.bot.is_standing(b_obj): elev = self.target_state.platform_y - b_obj.y if fops.lte(elev, 0): self.move(b_obj) elif fops.gt(elev, 0): if self.start_state.base_in(b_obj.aabb): self.jump(b_obj) self.move(b_obj) else: self.move(b_obj)
def sweep_collision(self, collidee, v, debug=False): """ self (collider) moving by v, collidee stationery based on http://bit.ly/3grWzs """ u_0 = [2, 2, 2] u_1 = [1, 1, 1] for i in xrange(3): if fops.lte(self.maxs[i], collidee.mins[i]) and fops.gt(v[i], 0): d = collidee.mins[i] - self.maxs[i] u_0[i] = d / v[i] elif fops.lte(collidee.maxs[i], self.mins[i]) and fops.lt(v[i], 0): d = collidee.maxs[i] - self.mins[i] u_0[i] = d / v[i] elif not (fops.lte(self.maxs[i], collidee.mins[i]) or fops.gte(self.mins[i], collidee.maxs[i])): u_0[i] = 0 if fops.gte(collidee.maxs[i], self.mins[i]) and fops.gt(v[i], 0): d = collidee.maxs[i] - self.mins[i] u_1[i] = d / v[i] elif fops.gte(self.maxs[i], collidee.mins[i]) and fops.lt(v[i], 0): d = collidee.mins[i] - self.maxs[i] u_1[i] = d / v[i] u0 = max(u_0) if u0 == 2 or fops.gte(u0, 1.0): col = False else: col = fops.lte(u0, min(u_1)) return col, u0
def check_aabbs(self): out = [] self.add_grid_bounding_boxes_to(out) check = [0, 0, 0, 0] if len(out) == 3: bb = out[2] if fops.gt(bb.min_x, self.x): check[2] = -1 elif fops.lt(bb.max_x, self.x + 1): check[2] = 1 if fops.gt(bb.min_z, self.z): check[3] = -1 elif fops.lt(bb.max_z, self.z + 1): check[3] = 1 bb = out[1] if fops.gt(bb.min_x, self.x): check[0] = -1 elif fops.lt(bb.max_x, self.x + 1): check[0] = 1 if fops.gt(bb.min_z, self.z): check[1] = -1 elif fops.lt(bb.max_z, self.z + 1): check[1] = 1 if check[2] != 0 or check[3] != 0: if check[0] != 0: check[2] = check[0] if check[1] != 0: check[3] = check[1] yield AABB.from_block_coords(self.x + check[2] * config.PLAYER_RADIUS, self.y + 0.5, self.z + check[3] * config.PLAYER_RADIUS) else: if check[0] != 0: yield AABB.from_block_coords(self.x + check[0] * config.PLAYER_RADIUS, self.y + 0.5, self.z) if check[1] != 0: yield AABB.from_block_coords(self.x, self.y + 0.5, self.z + check[1] * config.PLAYER_RADIUS)
def move_collisions(self, b_obj, vx, vy, vz): if self.is_in_web(b_obj): vx *= 0.25 vy *= 0.05000000074505806 vz *= 0.25 b_obj.velocities.x = 0 b_obj.velocities.y = 0 b_obj.velocities.z = 0 aabbs = self.world.grid.collision_aabbs_in( b_obj.aabb.extend_to(vx, vy, vz)) b_bb = b_obj.aabb dy = vy if not fops.eq(vy, 0): for bb in aabbs: dy = b_bb.calculate_axis_offset(bb, dy, 1) b_bb = b_bb.offset(dy=dy) dx = vx if not fops.eq(vx, 0): for bb in aabbs: dx = b_bb.calculate_axis_offset(bb, dx, 0) b_bb = b_bb.offset(dx=dx) dz = vz if not fops.eq(vz, 0): for bb in aabbs: dz = b_bb.calculate_axis_offset(bb, dz, 2) b_bb = b_bb.offset(dz=dz) if vy != dy and vy < 0 and (dx != vx or dz != vz): st = config.MAX_STEP_HEIGHT aabbs = self.world.grid.collision_aabbs_in( b_obj.aabb.extend_to(vx, st, vz)) b_bbs = b_obj.aabb dys = st for bb in aabbs: dys = b_bbs.calculate_axis_offset(bb, dys, 1) b_bbs = b_bbs.offset(dy=dys) dxs = vx for bb in aabbs: dxs = b_bbs.calculate_axis_offset(bb, dxs, 0) b_bbs = b_bbs.offset(dx=dxs) dzs = vz for bb in aabbs: dzs = b_bbs.calculate_axis_offset(bb, dzs, 2) b_bbs = b_bbs.offset(dz=dzs) if fops.gt(dxs * dxs + dzs * dzs, dx * dx + dz * dz): dx = dxs dy = dys dz = dzs b_bb = b_bbs b_obj.on_ground = vy != dy and vy < 0 b_obj.is_collided_horizontally = dx != vx or dz != vz b_obj.horizontally_blocked = not fops.eq(dx, vx) and not fops.eq( dz, vz) if not fops.eq(vx, dx): b_obj.velocities.x = 0 if not fops.eq(vy, dy): b_obj.velocities.y = 0 if not fops.eq(vz, dz): b_obj.velocities.z = 0 b_obj.set_xyz(b_bb.posx, b_bb.min_y, b_bb.posz) self.do_block_collision(b_obj)
def move_collisions(self, b_obj, vx, vy, vz): if self.is_in_web(b_obj): vx *= 0.25 vy *= 0.05000000074505806 vz *= 0.25 b_obj.velocities.x = 0 b_obj.velocities.y = 0 b_obj.velocities.z = 0 aabbs = self.world.grid.collision_aabbs_in(b_obj.aabb.extend_to(vx, vy, vz)) b_bb = b_obj.aabb dy = vy if not fops.eq(vy, 0): for bb in aabbs: dy = b_bb.calculate_axis_offset(bb, dy, 1) b_bb = b_bb.offset(dy=dy) dx = vx if not fops.eq(vx, 0): for bb in aabbs: dx = b_bb.calculate_axis_offset(bb, dx, 0) b_bb = b_bb.offset(dx=dx) dz = vz if not fops.eq(vz, 0): for bb in aabbs: dz = b_bb.calculate_axis_offset(bb, dz, 2) b_bb = b_bb.offset(dz=dz) if vy != dy and vy < 0 and (dx != vx or dz != vz): st = config.MAX_STEP_HEIGHT aabbs = self.world.grid.collision_aabbs_in(b_obj.aabb.extend_to(vx, st, vz)) b_bbs = b_obj.aabb dys = st for bb in aabbs: dys = b_bbs.calculate_axis_offset(bb, dys, 1) b_bbs = b_bbs.offset(dy=dys) dxs = vx for bb in aabbs: dxs = b_bbs.calculate_axis_offset(bb, dxs, 0) b_bbs = b_bbs.offset(dx=dxs) dzs = vz for bb in aabbs: dzs = b_bbs.calculate_axis_offset(bb, dzs, 2) b_bbs = b_bbs.offset(dz=dzs) if fops.gt(dxs * dxs + dzs * dzs, dx * dx + dz * dz): dx = dxs dy = dys dz = dzs b_bb = b_bbs b_obj.on_ground = vy != dy and vy < 0 b_obj.is_collided_horizontally = dx != vx or dz != vz b_obj.horizontally_blocked = not fops.eq(dx, vx) and not fops.eq(dz, vz) if not fops.eq(vx, dx): b_obj.velocities.x = 0 if not fops.eq(vy, dy): b_obj.velocities.y = 0 if not fops.eq(vz, dz): b_obj.velocities.z = 0 b_obj.set_xyz(b_bb.posx, b_bb.min_y, b_bb.posz) self.do_block_collision(b_obj)
def collision_distance(self, collidee, axis=None, direction=None): for i in xrange(3): if i == axis: continue if fops.lte(self.maxs[i], collidee.mins[i]) or \ fops.gte(self.mins[i], collidee.maxs[i]): return None p = None if direction < 0: if fops.eq(self.mins[axis], collidee.maxs[axis]): p = 0 elif fops.gt(self.mins[axis], collidee.maxs[axis]): p = self.mins[axis] - collidee.maxs[axis] else: if fops.eq(collidee.mins[axis], self.maxs[axis]): p = 0 elif fops.gt(collidee.mins[axis], self.maxs[axis]): p = collidee.mins[axis] - self.maxs[axis] return p
def sweep_collision(self, collidee, v, debug=False): """ self moving by v, collidee stationery based on http://bit.ly/3grWzs """ u_0 = [2, 2, 2] u_1 = [1, 1, 1] dists = [None, None, None] for i in xrange(3): if fops.lte(self.maxs[i], collidee.mins[i]) and fops.gt(v[i], 0): d = collidee.mins[i] - self.maxs[i] dists[i] = d u_0[i] = d / v[i] elif fops.lte(collidee.maxs[i], self.mins[i]) and fops.lt(v[i], 0): d = collidee.maxs[i] - self.mins[i] dists[i] = d u_0[i] = d / v[i] elif fops.eq(v[i], 0) and \ not(fops.lte(self.maxs[i], collidee.mins[i]) or fops.gte(self.mins[i], collidee.maxs[i])): u_0[i] = 0 elif not(fops.lte(self.maxs[i], collidee.mins[i]) or fops.gte(self.mins[i], collidee.maxs[i])): u_0[i] = 0 if fops.gte(collidee.maxs[i], self.mins[i]) and fops.gt(v[i], 0): d = collidee.maxs[i] - self.mins[i] u_1[i] = d / v[i] elif fops.gte(self.maxs[i], collidee.mins[i]) and fops.lt(v[i], 0): d = collidee.mins[i] - self.maxs[i] u_1[i] = d / v[i] if max(u_0) == 2: u0 = None col = False else: u0 = max(u_0) u1 = min(u_1) if fops.gte(u0, 1.0): col = False else: col = fops.lte(u0, u1) return col, u0
def check_aabbs(self): out = [] self.add_grid_bounding_boxes_to(out) check = [0, 0, 0, 0] if len(out) == 3: bb = out[2] if fops.gt(bb.min_x, self.x): check[2] = -1 elif fops.lt(bb.max_x, self.x + 1): check[2] = 1 if fops.gt(bb.min_z, self.z): check[3] = -1 elif fops.lt(bb.max_z, self.z + 1): check[3] = 1 bb = out[1] if fops.gt(bb.min_x, self.x): check[0] = -1 elif fops.lt(bb.max_x, self.x + 1): check[0] = 1 if fops.gt(bb.min_z, self.z): check[1] = -1 elif fops.lt(bb.max_z, self.z + 1): check[1] = 1 if check[2] != 0 or check[3] != 0: if check[0] != 0: check[2] = check[0] if check[1] != 0: check[3] = check[1] yield AABB.from_block_coords( self.x + check[2] * config.PLAYER_RADIUS, self.y + 0.5, self.z + check[3] * config.PLAYER_RADIUS) else: if check[0] != 0: yield AABB.from_block_coords( self.x + check[0] * config.PLAYER_RADIUS, self.y + 0.5, self.z) if check[1] != 0: yield AABB.from_block_coords( self.x, self.y + 0.5, self.z + check[1] * config.PLAYER_RADIUS)
def _tick(self): b_obj = self.bot.bot_object self.status = self.check_status(b_obj) if self.status != Status.running: return col_distance, col_bb = self.world.grid.min_collision_between(b_obj.aabb, self.target_space.bb_stand, horizontal=True, max_height=True) if self.bot.is_on_ladder(b_obj) or self.bot.is_in_water(b_obj): elev = self.target_space.bb_stand.min_y - b_obj.aabb.min_y if fops.gt(elev, 0): self.jump(b_obj) self.move(b_obj) elif fops.lt(elev, 0): if col_distance is None: self.move(b_obj) else: self.move(b_obj) elif self.bot.is_standing(b_obj): if col_distance is None: self.move(b_obj) else: elev = self.target_space.bb_stand.min_y - b_obj.aabb.min_y if fops.lte(elev, 0): self.move(b_obj) elif fops.gt(elev, 0) and fops.lte(elev, config.MAX_STEP_HEIGHT): self.move(b_obj) elif fops.gt(elev, config.MAX_STEP_HEIGHT) and fops.lt(elev, config.MAX_JUMP_HEIGHT): ticks_to_col = col_distance / self.bot.current_motion(b_obj) ticks_to_jump = math.sqrt(2 * elev / config.G) * 20 if ticks_to_col < ticks_to_jump: self.jump(b_obj) self.move(b_obj) else: raise Exception("move elevation error %s with collision %s" % (elev, col_distance)) else: self.move(b_obj)
def calculate_axis_offset(self, collidee, d, axis): for i in xrange(3): if i == axis: continue if fops.lte(self.maxs[i], collidee.mins[i]) or \ fops.gte(self.mins[i], collidee.maxs[i]): return d if d < 0 and fops.lte(collidee.maxs[axis], self.mins[axis]): dout = collidee.maxs[axis] - self.mins[axis] if fops.gt(dout, d): d = dout elif d > 0 and fops.gte(collidee.mins[axis], self.maxs[axis]): dout = collidee.mins[axis] - self.maxs[axis] if fops.lt(dout, d): d = dout return d
def can_stand_between(self, gs, debug=False): if self.block.is_ladder_vine or gs.block.is_ladder_vine: return True if self.block.is_water or gs.block.is_water: return True if fops.gt(abs(self.platform.min_y - gs.platform.min_y), config.MAX_STEP_HEIGHT): return True stand_platform = self.platform.expand(config.PLAYER_BODY_DIAMETER - 0.09, 0, config.PLAYER_BODY_DIAMETER - 0.09) self.intersection = gs.stand_block.intersection_on_axes( stand_platform, x=True, z=True, debug=debug) if self.intersection is None: return False if self.stand_block.x != gs.stand_block.x and self.stand_block.z != gs.stand_block.z: if fops.lt(gs.platform.get_side('min', x=True, z=True), 0.5): return False else: return True else: return True
def can_go_between(self, gs, update_to_bb_stand=False, debug=False): edge_cost = 0 bb_stand = self.bb_stand other_bb_stand = gs.bb_stand if bb_stand.horizontal_distance(other_bb_stand) > config.HORIZONTAL_MOVE_DISTANCE_LIMIT: if debug: print 'horizontal distance too far', bb_stand.horizontal_distance(other_bb_stand) return False if fops.gt(bb_stand.min_y, other_bb_stand.min_y): if (bb_stand.min_y - other_bb_stand.min_y) > 3: return False elev = bb_stand.min_y - other_bb_stand.min_y elev_bb = other_bb_stand.extend_to(dy=elev) bb_from = bb_stand bb_to = other_bb_stand.offset(dy=elev) elif fops.lt(bb_stand.min_y, other_bb_stand.min_y): if fops.lte(bb_stand.grid_y + 2, other_bb_stand.min_y): if debug: print 'over 2 high difference' return False elev = other_bb_stand.min_y - bb_stand.min_y in_water = self.grid.aabb_in_water(bb_stand) if in_water and \ other_bb_stand.grid_y > bb_stand.grid_y and \ fops.gt(other_bb_stand.min_y, other_bb_stand.grid_y) and \ not self.grid.aabb_in_water(bb_stand.shift(min_y=other_bb_stand.min_y)) and \ fops.gte(other_bb_stand.min_y - (bb_stand.grid_y + 1), config.MAX_WATER_JUMP_HEIGHT - 0.15): if debug: print 'water cannot go' return False if self.grid.aabb_on_ladder(bb_stand) and \ other_bb_stand.grid_y > bb_stand.grid_y and \ fops.gt(other_bb_stand.min_y, other_bb_stand.grid_y) and \ not self.grid.aabb_on_ladder(bb_stand.shift(min_y=other_bb_stand.min_y)) and \ fops.gte(other_bb_stand.min_y - (bb_stand.grid_y + 1), config.MAX_VINE_JUMP_HEIGHT - 0.2): if debug: print 'ladder cannot go' return False if fops.gt(elev, config.MAX_JUMP_HEIGHT) and not in_water: if debug: print 'too high' return False if fops.lte(elev, config.MAX_STEP_HEIGHT): elev = config.MAX_STEP_HEIGHT aabbs = self.grid.aabbs_in(bb_stand.extend_to(0, elev, 0)) for bb in aabbs: elev = bb_stand.calculate_axis_offset(bb, elev, 1) if fops.lt(bb_stand.min_y + elev, other_bb_stand.min_y): if debug: print 'cannot make step' return False elev_bb = bb_stand.extend_to(dy=elev) bb_from = bb_stand.offset(dy=elev) bb_to = other_bb_stand else: elev = 0 elev_bb = None bb_from = bb_stand bb_to = other_bb_stand if elev_bb is not None: if self.grid.aabb_collides(elev_bb): if debug: print 'elevation collision' return False if self.blocks_to_avoid(self.grid.blocks_in_aabb(elev_bb)): if debug: print 'elevation hitting avoid block' return False if self.grid.collision_between(bb_from, bb_to, debug=debug): if debug: print 'horizontal collision' return False if self.blocks_to_avoid(self.grid.passing_blocks_between(bb_from, bb_to)): if debug: print 'hitting avoid block' return False edge_cost += config.COST_DIRECT * bb_from.horizontal_distance(bb_to) if not (fops.lte(elev, config.MAX_STEP_HEIGHT) and fops.gte(elev, -config.MAX_STEP_HEIGHT)): edge_cost += config.COST_FALL * \ bb_from.horizontal_distance(bb_to) if elev < 0: edge_cost += config.COST_FALL * elev else: edge_cost += config.COST_JUMP self.edge_cost = edge_cost if update_to_bb_stand: gs.bb_stand = other_bb_stand return True
def move(self, b_obj): self.clip_abs_velocities(b_obj) is_in_water = self.handle_water_movement(b_obj) is_in_lava = self.handle_lava_movement(b_obj) if b_obj.is_jumping: if is_in_water or is_in_lava: b_obj.velocities[1] += config.SPEED_LIQUID_JUMP elif b_obj.on_ground: b_obj.velocities[1] = config.SPEED_JUMP elif self.is_on_ladder(b_obj): b_obj.velocities[1] = config.SPEED_CLIMB b_obj.is_jumping = False if is_in_water: if b_obj.floating_flag: if self.head_inside_water(b_obj): b_obj.velocities[1] += config.SPEED_LIQUID_JUMP else: x, y, z = b_obj.aabb.grid_bottom_center b_up = self.world.grid.get_block(x, y + 1, z) b_down = self.world.grid.get_block(x, y - 1, z) b_cent = self.world.grid.get_block(x, y, z) no_up = not b_up.is_water and b_down.collidable and fops.eq(b_down.max_y, y) if (not no_up and b_cent.is_water and fops.gt(b_cent.y + 0.5, b_obj.aabb.min_y)) or isinstance(b_up, blocks.StillWater): b_obj.velocities[1] += config.SPEED_LIQUID_JUMP orig_y = b_obj.y self.update_directional_speed(b_obj, 0.02, balance=True) self.move_collisions(b_obj, b_obj.velocities[0], b_obj.velocities[1], b_obj.velocities[2]) b_obj.velocities[0] *= 0.800000011920929 b_obj.velocities[1] *= 0.800000011920929 b_obj.velocities[2] *= 0.800000011920929 b_obj.velocities[1] -= 0.02 if b_obj.is_collided_horizontally and \ self.is_offset_in_liquid(b_obj, b_obj.velocities[0], b_obj.velocities[1] + 0.6 - b_obj.y + orig_y, b_obj.velocities[2]): b_obj.velocities[1] = 0.30000001192092896 elif is_in_lava: orig_y = self.y self.update_directional_speed(b_obj, 0.02) self.move_collisions(b_obj, b_obj.velocities[0], b_obj.velocities[1], b_obj.velocities[2]) b_obj.velocities[0] *= 0.5 b_obj.velocities[1] *= 0.5 b_obj.velocities[2] *= 0.5 b_obj.velocities[1] -= 0.02 if b_obj.is_collided_horizontally and \ self.is_offset_in_liquid(b_obj, self.velocities[0], self.velocities[1] + 0.6 - self.y + orig_y, self.velocities[2]): self.velocities[1] = 0.30000001192092896 else: slowdown = self.current_slowdown(b_obj) self.update_directional_speed(b_obj, self.current_speed_factor(b_obj)) self.clip_ladder_velocities(b_obj) self.move_collisions(b_obj, b_obj.velocities[0], b_obj.velocities[1], b_obj.velocities[2]) if b_obj.is_collided_horizontally and self.is_on_ladder(b_obj): b_obj.velocities[1] = 0.2 b_obj.velocities[1] -= config.BLOCK_FALL b_obj.velocities[1] *= config.DRAG b_obj.velocities[0] *= slowdown b_obj.velocities[2] *= slowdown