Download Documentation API Reference Samples Asset Store Donate




Collision


Adding Colliders



e = Entity(model='sphere', x=2) e.collider = 'box' # add BoxCollider based on entity's bounds. e.collider = 'sphere' # add SphereCollider based on entity's bounds. e.collider = 'mesh' # add MeshCollider based on entity's bounds. e.collider = BoxCollider(e, center=Vec3(0,0,0), size=Vec3(1,1,1)) # add BoxCollider at custom positions and size. e.collider = SphereCollider(e, center=Vec3(0,0,0), radius=.75) # add SphereCollider at custom positions and size. e.collider = MeshCollider(e, mesh=e.model, center=Vec3(0,0,0)) # add MeshCollider with custom shape and center.

Usually you add the collider when you create the Entity, but make sure you set the model
before setting the collider if you want it to fit its bounds.

e = Entity(model='cube', collider='box')


raycast()



raycast(origin, direction=(0,0,1), distance=inf, traverse_target=scene, ignore=list(), debug=False)

Casts a ray from *origin*, in *direction*, with length *distance* and returns
a HitInfo containing information about what it hit. This ray will only hit entities with a collider.

Use optional *traverse_target* to only be able to hit a specific entity and its children/descendants.
Use optional *ignore* list to ignore certain entities.
Setting debug to True will draw the line on screen.

Example where we only move if a wall is not hit:

from ursina import * app = Ursina() class Player(Entity): def update(self): self.direction = Vec3( self.forward * (held_keys['w'] - held_keys['s']) + self.right * (held_keys['d'] - held_keys['a']) ).normalized() # get the direction we're trying to walk in. origin = self.world_position + (self.up*.5) # the ray should start slightly up from the ground so we can walk up slopes or walk over small objects. hit_info = raycast(origin , self.direction, ignore=(self,), distance=.5, debug=False) if not hit_info.hit: self.position += self.direction * 5 * time.dt Player(model='cube', origin_y=-.5, color=color.orange) wall_left = Entity(model='cube', collider='box', scale_y=3, origin_y=-.5, color=color.azure, x=-4) wall_right = duplicate(wall_left, x=4) camera.y = 2 app.run()



boxcast()


boxcast(origin, direction=(0,0,1), distance=9999, thickness=(1,1), traverse_target=scene, ignore=list(), debug=False) # similar to raycast, but with width and height

boxcast is similar to raycast, but the "ray" has thickness, height and width.



intersects()



Check if a entity (with a collider) intersects other entities with colliders.

from ursina import * app = Ursina() player = Entity(model='cube', color=color.orange, collider='box', origin_y=-.5) trigger_box = Entity(model='wireframe_cube', color=color.gray, scale=2, collider='box', position=Vec3(1,0,2), origin_y=-.5) EditorCamera() def update(): player.z += (held_keys['w'] - held_keys['s']) * time.dt * 6 player.x += (held_keys['d'] - held_keys['a']) * time.dt * 6 if player.intersects(trigger_box).hit: trigger_box.color = color.lime print('player is inside trigger box') else: trigger_box.color = color.gray app.run()





HitInfo



All of these functions will return a HitInfo. This contains information about what it hit.

hit = None entity = None point = None world_point = None distance = math.inf normal = None world_normal = None hits = [] entities = []


Distance Check



Sometimes it enough to just check the distance between two entities.
For example if you want a pickup:

from ursina import * from ursina.prefabs.first_person_controller import FirstPersonController app = Ursina() ground = Entity(model='plane', texture='grass', scale=10, collider='box') player = FirstPersonController(model='cube', origin_y=-.5, color=color.orange, has_pickup=False) camera.z = -5 pickup = Entity(model='sphere', position=(1,.5,3)) def update(): if not player.has_pickup and distance(player, pickup) < pickup.scale_x / 2: print('pickup') player.has_pickup = True pickup.animate_scale(0, duration=.1) destroy(pickup, delay=.1) app.run()



Mouse Collision



The mouse does raycast automatically.
Both UI elements(Entities parented to camera.ui) and Entities in 3d space (parented to scene) can
get hit as long as they have a collider. UI elements will however block things behind them.

mouse.hovered_entity returns mouse.normal # returns the normal of the polygon, in local space. mouse.world_normal # returns the normal of the polygon, in world space. mouse.point # returns the point hit, in local space mouse.world_point # returns the point hit, in world space

Handling clicks is very easy, just add a collider and on_click.
The on_click function will then be called when you click on the Entity with the mouse.

def action(): print('Ow! That hurt!') Entity(model='quad', parent=camera.ui, scale=.1, collider='box', on_click=action) # on_click should be a function/callable/Func/Sequence