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, dela
y=.
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