def position(self): return Vec3(self.getX(), self.getZ(), self.getY())
def world_scale_z(self, value): self.setScale(base.render, Vec3(self.world_scale_x, value, self.world_scale_z))
def bounds(self): return Vec3(self.model_bounds[0] * self.scale_x, self.model_bounds[1] * self.scale_y, self.model_bounds[2] * self.scale_z)
def rotation_y(self, value): self.rotation = Vec3(self.rotation[0], value, self.rotation[2])
def world_scale(self): return Vec3(*self.getScale(base.render))
def world_rotation_y(self, value): self.world_rotation = Vec3(self.world_rotation[0], value, self.world_rotation[2])
def rotation(self): rotation = self.getHpr() return Vec3(rotation[1], rotation[0], rotation[2]) * Entity.rotation_directions
def right(self): vec = render.getRelativeVector(self, (1, 0, 0)) return Vec3(vec[0], vec[2], vec[1])
def up(self): vec = render.getRelativeVector(self, (0, 0, 1)) return Vec3(vec[0], vec[2], vec[1])
def world_scale_x(self, value): self.setScale(base.render, Vec3(value, self.world_scale_z, self.world_scale_y))
def forward(self): vec = render.getRelativeVector(self, (0, 1, 0)) return Vec3(vec[0], vec[2], vec[1])
def world_scale(self): scale = self.getScale(base.render) return Vec3(scale[0], scale[2], scale[1])
def rotation(self): rotation = self.getHpr() return Vec3(-rotation[1], -rotation[0], rotation[2])
def world_rotation(self): rotation = self.getHpr(base.render) return Vec3(-rotation[1], -rotation[0], rotation[2])
def world_rotation(self, value): rotation = self.setHpr( Vec3(value[1], value[0], value[2]) * Entity.rotation_directions, base.render)
def get_position(self, relative_to=scene): pos = self.getPos(relative_to) return Vec3(pos[0], pos[2], pos[1])
def world_rotation_x(self, value): self.world_rotation = Vec3(value, self.world_rotation[1], self.world_rotation[2])
def animate_scale(self, value, duration=.1, **kwargs): if isinstance(value, (int, float, complex)): value = Vec3(value, value, value) return self.animate('scale', value, duration, **kwargs)
def world_rotation_z(self, value): self.world_rotation = Vec3(self.world_rotation[0], self.world_rotation[1], value)
def intersects(self, traverse_target=scene, ignore=(), debug=False): from ursina.hit_info import HitInfo if not self.collision or not self.collider: self.hit = HitInfo(hit=False) return self.hit from ursina import distance if not hasattr(self, '_picker'): from panda3d.core import CollisionTraverser, CollisionNode, CollisionHandlerQueue from panda3d.core import CollisionRay, CollisionSegment, CollisionBox self._picker = CollisionTraverser() # Make a traverser self._pq = CollisionHandlerQueue() # Make a handler self._pickerNode = CollisionNode('raycaster') self._pickerNode.set_into_collide_mask(0) self._pickerNP = self.attach_new_node(self._pickerNode) self._picker.addCollider(self._pickerNP, self._pq) self._pickerNP.show() self._pickerNode.addSolid(self._collider.shape) if debug: self._pickerNP.show() else: self._pickerNP.hide() self._picker.traverse(traverse_target) if self._pq.get_num_entries() == 0: self.hit = HitInfo(hit=False) return self.hit ignore += (self, ) 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 = HitInfo(hit=False, distance=0) return self.hit collision = self.entries[0] nP = collision.get_into_node_path().parent point = collision.get_surface_point(nP) point = Vec3(*point) world_point = collision.get_surface_point(render) world_point = Vec3(*world_point) hit_dist = distance(self.world_position, world_point) self.hit = HitInfo(hit=True) self.hit.entity = next(e for e in scene.entities if e == nP) self.hit.point = point self.hit.world_point = world_point self.hit.distance = hit_dist normal = collision.get_surface_normal( collision.get_into_node_path().parent).normalized() self.hit.normal = Vec3(*normal) normal = collision.get_surface_normal(render).normalized() self.hit.world_normal = Vec3(*normal) self.hit.entities = [] for collision in self.entries: self.hit.entities.append( next(e for e in scene.entities if e == collision.get_into_node_path().parent)) return self.hit
def rotation_x(self, value): self.rotation = Vec3(value, self.rotation[1], self.rotation[2])
def world_position(self): return Vec3(self.get_position(render))
def rotation_z(self, value): self.rotation = Vec3(self.rotation[0], self.rotation[1], value)
def __init__(self, add_to_scene_entities=True, **kwargs): super().__init__(self.__class__.__name__) self.name = camel_to_snake(self.type) self._enabled = True self.enabled = True # disabled entities wil not be visible nor run code. self.visible = True self.ignore = False # if True, will not try to run code. self.eternal = False # eternal entities does not get destroyed on scene.clear() self.ignore_paused = False # if True, will still run when application is paused. useful when making a pause menu for example. self.ignore_input = False self.parent = scene # default parent is scene, which means it's in 3d space. to use UI space, set the parent to camera.ui instead. self.add_to_scene_entities = add_to_scene_entities # set to False to be ignored by the engine, but still get rendered. if add_to_scene_entities: scene.entities.append(self) self.model = None # set model with model='model_name' (without file type extention) self.color = color.white self.texture = None # set model with texture='texture_name'. requires a model to be set beforehand. self.render_queue = 0 self.double_sided = False if Entity.default_shader: self.shader = Entity.default_shader self.collision = False # toggle collision without changing collider. self.collider = None # set to 'box'/'sphere'/'mesh' for auto fitted collider. self.scripts = list( ) # add with add_script(class_instance). will assign an 'entity' variable to the script. self.animations = list() self.hovered = False # will return True if mouse hovers entity. self.origin = Vec3(0, 0, 0) self.position = Vec3( 0, 0, 0) # right, up, forward. can also set self.x, self.y, self.z self.rotation = Vec3( 0, 0, 0 ) # can also set self.rotation_x, self.rotation_y, self.rotation_z self.scale = Vec3( 1, 1, 1) # can also set self.scale_x, self.scale_y, self.scale_z self.line_definition = None # returns a Traceback(filename, lineno, function, code_context, index). if application.trace_entity_definition and add_to_scene_entities: from inspect import getframeinfo, stack _stack = stack() caller = getframeinfo(_stack[1][0]) if len(_stack) > 2 and _stack[ 1].code_context and 'super().__init__()' in _stack[ 1].code_context[0]: caller = getframeinfo(_stack[2][0]) self.line_definition = caller if caller.code_context: self.code_context = caller.code_context[0] if (self.code_context.count('(') == self.code_context.count(')') and ' = ' in self.code_context and not 'name=' in self.code_context and not 'Ursina()' in self.code_context): self.name = self.code_context.split( ' = ')[0].strip().replace('self.', '') # print('set name to:', self.code_context.split(' = ')[0].strip().replace('self.', '')) if application.print_entity_definition: print( f'{Path(caller.filename).name} -> {caller.lineno} -> {caller.code_context}' ) for key, value in kwargs.items(): setattr(self, key, value)
def world_scale(self, value): if isinstance(value, (int, float, complex)): value = Vec3(value, value, value) self.setScale(base.render, value)
def position(self): return Vec3(*self.getPos())
def scale(self): scale = self.getScale() return Vec3(scale[0], scale[1], scale[2])
def world_rotation(self): rotation = self.getHpr(base.render) return Vec3(rotation[1], rotation[0], rotation[2]) * Entity.rotation_directions
def set_position(self, value, relative_to=scene): self.setPos(relative_to, Vec3(value[0], value[1], value[2]))
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)) ray.setDirection(Vec3(0, 0, 1)) else: # ray = CollisionSegment(Vec3(0,0,0), Vec3(0,distance,0)) ray = CollisionSegment(Vec3(0, 0, 0), Vec3(0, 0, distance)) 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 = HitInfo(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 = HitInfo(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]) point = Vec3(point[0], point[1], point[2]) world_point = self.collision.get_surface_point(render) # world_point = Vec3(world_point[0], world_point[2], world_point[1]) world_point = Vec3(world_point[0], world_point[1], world_point[2]) hit_dist = self.distance(self.world_position, world_point) if nP.name.endswith('.egg'): nP = nP.parent self.hit = HitInfo(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]) self.hit.normal = (normal[0], normal[1], normal[2]) normal = self.collision.get_surface_normal(render) # self.hit.world_normal = (normal[0], normal[2], normal[1]) self.hit.world_normal = (normal[0], normal[1], normal[2]) return self.hit self.hit = HitInfo(hit=False) return self.hit