def raycast(self, origin, direction=(0,0,1), dist=math.inf, traverse_target=scene, ignore=list(), debug=False): self.position = origin self.look_at(self.position + direction) # need to do this for it to work for some reason self._collision_ray.set_origin(Vec3(0,0,0)) self._collision_ray.set_direction(Vec3(0,1,0)) if debug: self._pickerNP.show() else: self._pickerNP.hide() self._picker.traverse(traverse_target) if self._pq.get_num_entries() == 0: self.hit = Hit(hit=False) return self.hit self._pq.sort_entries() self.entries = [ # filter out ignored entities e for e in self._pq.getEntries() if e.get_into_node_path().parent not in ignore ] if len(self.entries) == 0: self.hit = Hit(hit=False) return self.hit self.collision = self.entries[0] nP = self.collision.get_into_node_path().parent point = self.collision.get_surface_point(nP) point = Vec3(point[0], point[2], point[1]) world_point = self.collision.get_surface_point(render) world_point = Vec3(world_point[0], world_point[2], world_point[1]) hit_dist = self.distance(self.world_position, world_point) if hit_dist <= dist: if nP.name.endswith('.egg'): nP = nP.parent self.hit = Hit(hit=True) for e in scene.entities: if e == nP: # print('cast nP to Entity') self.hit.entity = e self.hit.point = point self.hit.world_point = world_point self.hit.distance = hit_dist normal = self.collision.get_surface_normal(self.collision.get_into_node_path().parent) self.hit.normal = (normal[0], normal[2], normal[1]) normal = self.collision.get_surface_normal(render) self.hit.world_normal = (normal[0], normal[2], normal[1]) return self.hit self.hit = Hit(hit=False) return self.hit
def boxcast(self, origin, direction=(0, 0, 1), distance=math.inf, thickness=(1, 1), traverse_target=scene, ignore=list(), debug=False): if isinstance(thickness, (int, float, complex)): thickness = (thickness, thickness) resolution = 3 rays = list() debugs = list() for y in range(3): for x in range(3): pos = origin + Vec3( lerp(-(thickness[0] / 2), thickness[0] / 2, x / (3 - 1)), lerp(-(thickness[1] / 2), thickness[1] / 2, y / (3 - 1)), 0) ray = self.raycast(pos, direction, distance, traverse_target, ignore, False) rays.append(ray) if debug and ray.hit: d = Entity(model='cube', origin_z=-.5, position=pos, scale=(.02, .02, distance), ignore=True) d.look_at(pos + Vec3(direction)) debugs.append(d) # print(pos, hit.point) if ray.hit and ray.distance > 0: d.scale_z = ray.distance d.color = color.green from ursina import destroy # [destroy(e, 1/60) for e in debugs] rays.sort(key=lambda x: x.distance) closest = rays[0] return Hit( hit=sum([int(e.hit) for e in rays]) > 0, entity=closest.entity, point=closest.point, world_point=closest.world_point, distance=closest.distance, normal=closest.normal, world_normal=closest.world_normal, hits=[e.hit for e in rays], entities=list(set([e.entity for e in rays])), # get unique entities hit )
def find_collision(self): if not self.raycast: return self._pq.sortEntries() if len(self._pq.get_entries()) == 0: self.collision = None return self.collisions = list() for entry in self._pq.getEntries(): # print(entry.getIntoNodePath().parent) for entity in scene.entities: if entry.getIntoNodePath().parent == entity: if entity.collision: self.collisions.append( Hit( hit=entry.collided(), entity=entity, distance=0, point=entry.getSurfacePoint(entity), world_point=entry.getSurfacePoint(scene), normal=entry.getSurfaceNormal(entity), world_normal=entry.getSurfaceNormal(scene), )) break self.collision = self._pq.getEntry(0) nP = self.collision.getIntoNodePath().parent for entity in scene.entities: if not hasattr(entity, 'collision' ) or not entity.collision or not entity.collider: continue # if hit entity is not hovered, call on_mouse_enter() if entity == nP: if not entity.hovered: entity.hovered = True self.hovered_entity = entity # print(entity.name) if hasattr(entity, 'on_mouse_enter'): entity.on_mouse_enter() for s in entity.scripts: if hasattr(s, 'on_mouse_enter'): s.on_mouse_enter() # unhover the rest else: if entity.hovered: entity.hovered = False if hasattr(entity, 'on_mouse_exit'): entity.on_mouse_exit() for s in entity.scripts: if hasattr(s, 'on_mouse_exit'): s.on_mouse_exit()
def find_collision(self): self.collisions = list() self.collision = None if not self.raycast or self._pq.get_num_entries() == 0: self.unhover_everything_not_hit() return False self._pq.sortEntries() for entry in self._pq.getEntries(): for entity in scene.entities: if entry.getIntoNodePath( ).parent == entity and entity.collision: if entity.collision: hit = Hit( hit=entry.collided(), entity=entity, distance=distance(entry.getSurfacePoint(scene), camera.getPos()), point=entry.getSurfacePoint(entity), world_point=entry.getSurfacePoint(scene), normal=entry.getSurfaceNormal(entity), world_normal=entry.getSurfaceNormal(scene), ) hit.point = Vec3(hit.point[0], hit.point[2], hit.point[1]) hit.world_point = Vec3(hit.world_point[0], hit.world_point[2], hit.world_point[1]) hit.normal = Vec3(hit.normal[0], hit.normal[2], hit.normal[1]) hit.world_normal = Vec3(hit.world_normal[0], hit.world_normal[2], hit.world_normal[1]) self.collisions.append(hit) break if self.collisions: self.collision = self.collisions[0] self.hovered_entity = self.collision.entity if not self.hovered_entity.hovered: self.hovered_entity.hovered = True if hasattr(self.hovered_entity, 'on_mouse_enter'): self.hovered_entity.on_mouse_enter() for s in self.hovered_entity.scripts: if hasattr(s, 'on_mouse_enter'): s.on_mouse_enter() self.unhover_everything_not_hit()
def raycast(self, origin, direction=(0, 0, 1), distance=math.inf, traverse_target=scene, ignore=list(), debug=False): self.position = origin self.look_at(self.position + direction) self._pickerNode.clearSolids() # if thickness == (0,0): if distance == math.inf: ray = CollisionRay() ray.setOrigin(Vec3(0, 0, 0)) ray.setDirection(Vec3(0, 1, 0)) else: ray = CollisionSegment(Vec3(0, 0, 0), Vec3(0, distance, 0)) self._pickerNode.addSolid(ray) if debug: self._pickerNP.show() else: self._pickerNP.hide() self._picker.traverse(traverse_target) if self._pq.get_num_entries() == 0: self.hit = Hit(hit=False) return self.hit ignore += tuple([e for e in scene.entities if not e.collision]) self._pq.sort_entries() self.entries = [ # filter out ignored entities e for e in self._pq.getEntries() if e.get_into_node_path().parent not in ignore ] if len(self.entries) == 0: self.hit = Hit(hit=False) return self.hit self.collision = self.entries[0] nP = self.collision.get_into_node_path().parent point = self.collision.get_surface_point(nP) point = Vec3(point[0], point[2], point[1]) world_point = self.collision.get_surface_point(render) world_point = Vec3(world_point[0], world_point[2], world_point[1]) hit_dist = self.distance(self.world_position, world_point) if nP.name.endswith('.egg'): nP = nP.parent self.hit = Hit(hit=True) for e in scene.entities: if e == nP: # print('cast nP to Entity') self.hit.entity = e self.hit.point = point self.hit.world_point = world_point self.hit.distance = hit_dist normal = self.collision.get_surface_normal( self.collision.get_into_node_path().parent) self.hit.normal = (normal[0], normal[2], normal[1]) normal = self.collision.get_surface_normal(render) self.hit.world_normal = (normal[0], normal[2], normal[1]) return self.hit self.hit = Hit(hit=False) return self.hit