import math
from pybevy.input import AccumulatedMouseMotion, MouseInput
from pybevy.prelude import *
@resource
class CameraSettings(Resource):
def __init__(self):
pitch_limit = math.pi / 2 - 0.01
self.orbit_distance = 20.0
self.pitch_speed = 0.003
self.pitch_range_start = -pitch_limit
self.pitch_range_end = pitch_limit
self.roll_speed = 1.0
self.yaw_speed = 0.004
def setup(
commands: Commands,
meshes: ResMut[Assets[Mesh]],
materials: ResMut[Assets[StandardMaterial]],
) -> None:
camera_transform = Transform.from_xyz(5.0, 5.0, 5.0).looking_at(Vec3.ZERO, Vec3.Y)
commands.spawn(
Camera3d(),
camera_transform,
)
plane_mesh = Plane3d().mesh().size(5.0, 5.0)
plane_material = StandardMaterial(
base_color=Color.srgb(0.3, 0.5, 0.3),
cull_mode=None, )
commands.spawn(
Mesh3d(meshes.add(plane_mesh)),
MeshMaterial3d(materials.add(plane_material)),
)
cube_mesh = Cuboid().mesh()
cube_material = StandardMaterial(base_color=Color.srgb(0.8, 0.7, 0.6))
commands.spawn(
Mesh3d(meshes.add(cube_mesh)),
MeshMaterial3d(materials.add(cube_material)),
Transform.from_xyz(1.5, 0.51, 1.5),
)
commands.spawn(
PointLight(),
Transform.from_xyz(3.0, 8.0, 5.0),
)
def orbit(
camera_query: Single[Mut[Transform], With[Camera3d]],
camera_settings: Res[CameraSettings],
mouse_buttons: Res[MouseInput],
mouse_motion: Res[AccumulatedMouseMotion],
time: Res[Time],
) -> None:
for camera in camera_query:
delta = Vec2(mouse_motion.delta.x, mouse_motion.delta.y)
delta_roll = 0.0
if mouse_buttons.pressed(MouseButton.Left()):
delta_roll -= 1.0
if mouse_buttons.pressed(MouseButton.Right()):
delta_roll += 1.0
delta_pitch = delta.y * camera_settings.pitch_speed
delta_yaw = delta.x * camera_settings.yaw_speed
delta_roll *= camera_settings.roll_speed * time.delta_secs()
yaw, pitch, roll = camera.rotation.to_euler(EulerRot.YXZ)
pitch = max(camera_settings.pitch_range_start,
min(pitch + delta_pitch, camera_settings.pitch_range_end))
roll = roll + delta_roll
yaw = yaw + delta_yaw
camera.rotation = Quat.from_euler(EulerRot.YXZ, yaw, pitch, roll)
target = Vec3.ZERO
camera.translation = target - camera.forward() * camera_settings.orbit_distance
@entrypoint
def main(app: App) -> App:
return (
app.add_plugins(DefaultPlugins)
.insert_resource(CameraSettings())
.add_systems(Startup, setup)
.add_systems(Update, orbit)
)
if __name__ == "__main__":
main().run()