use rusting_engine::prelude::*;
const MAX_PUTT_SPEED: f32 = 12.0;
const CHARGE_TICKS: i32 = 60;
const ROLL_DRAG: f32 = 0.2;
const ROLL_FRICTION: f32 = 0.35;
const REST_SPEED: f32 = 0.1;
const CUP_SPEED: f32 = 4.0;
const TEE: [f32; 3] = [0.0, 0.15, 8.0];
fn power(charge: i32) -> i32 {
let phase = charge % (2 * CHARGE_TICKS);
let rising = if phase <= CHARGE_TICKS {
phase
} else {
2 * CHARGE_TICKS - phase
};
rising * 100 / CHARGE_TICKS
}
fn aim_direction(
scene: &mut GameScene<'_>,
ball: [f32; 3],
) -> Option<[f32; 2]> {
let (origin, direction) = scene.pointer_ray()?;
let hit = scene.raycast(origin, direction, 100.0)?;
let (dx, dz) = (hit.point[0] - ball[0], hit.point[2] - ball[2]);
let length = dx.hypot(dz);
(length > 0.2).then(|| [dx / length, dz / length])
}
fn update(scene: &mut GameScene<'_>, time: &FrameTime) {
if scene.pressed("restart") {
scene.restart();
return;
}
if scene.counter_complete("sunk") {
return;
}
let step = time.delta.as_secs_f32();
let ball = scene.object("Ball").position();
let [vx, vy, vz] = scene.linear_velocity("Ball").unwrap_or([0.0; 3]);
let speed = vx.hypot(vz);
if ball[1] < -2.0 {
scene.set_linear_velocity("Ball", [0.0; 3]);
scene.object("Ball").set_position(TEE);
scene.add_to_counter("strokes", 1);
return;
}
if speed < CUP_SPEED
&& scene.touching("Ball").iter().any(|name| name == "Cup")
{
scene.set_counter("sunk", 1);
scene.set_body_kind("Ball", RigidBodyKind::Kinematic);
scene.set_linear_velocity("Ball", [0.0; 3]);
scene.set_visible("Ball", false);
scene.set_visible("Aim", false);
return;
}
let at_rest = speed < REST_SPEED;
if !at_rest {
let slowed =
(speed * (1.0 - ROLL_DRAG * step) - ROLL_FRICTION * step).max(0.0);
let scale = slowed / speed;
scene.set_linear_velocity("Ball", [vx * scale, vy, vz * scale]);
scene.set_visible("Aim", false);
return;
}
if speed > 0.0 {
scene.set_linear_velocity("Ball", [0.0, vy, 0.0]);
}
let Some([dx, dz]) = aim_direction(scene, ball) else {
scene.set_visible("Aim", false);
return;
};
let charge = scene.counter_value("charge");
if scene.held("putt") {
scene.add_to_counter("charge", 1);
} else if charge > 0 {
let putt = power(charge) as f32 / 100.0 * MAX_PUTT_SPEED;
scene.set_linear_velocity("Ball", [dx * putt, vy, dz * putt]);
scene.add_to_counter("strokes", 1);
scene.set_counter("charge", 0);
}
let percent = power(scene.counter_value("charge"));
scene.set_counter("power", percent);
let length = 0.5 + 2.0 * percent as f32 / 100.0;
scene.set_visible("Aim", true);
let mut aim = scene.object("Aim");
aim.set_position([
ball[0] + dx * (0.25 + length * 0.5),
0.05,
ball[2] + dz * (0.25 + length * 0.5),
]);
aim.set_rotation([0.0, (-dx).atan2(-dz), 0.0]);
aim.set_scale([0.08, 0.03, length]);
}
rusting_game!(update);