Compare commits

...

7 Commits

Author SHA1 Message Date
JP Stringham
92c83c7b30 Merge branch 'main' of ssh://192.168.7.152:3001/jp/sailing 2025-12-07 11:45:15 -05:00
JP Stringham
711250d87a Sailing direction against wind update 2025-12-07 11:44:56 -05:00
JP Stringham
122e09a6a9 macos gitignore thing 2025-12-02 12:58:23 -05:00
JP Stringham
8a3b485ece Wind! 2025-11-28 16:42:22 -05:00
JP Stringham
cf4beb0b9a Playing with sails and rudders 2025-11-28 16:25:37 -05:00
JP Stringham
b564b42ade tiny sail 2025-11-28 16:06:03 -05:00
JP Stringham
612b76a45c tiny sail 2025-11-28 16:05:52 -05:00
4 changed files with 105 additions and 28 deletions

2
.gitignore vendored
View File

@@ -1 +1,3 @@
*.DS_Store
/target

View File

@@ -10,4 +10,4 @@ bevy = { version = "0.17.3", features = ["dynamic_linking"] }
opt-level = 1
[profile.dev.package."*"]
opt-level = 3
opt-level = 3

BIN
assets/sail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

View File

@@ -1,4 +1,4 @@
use bevy::prelude::*;
use bevy::{prelude::*, sprite_render::Wireframe2dPlugin};
const MAX_SAILING_SPEED: f32 = 0.9;
const MAX_TURN_SPEED: f32 = 0.1;
@@ -18,10 +18,26 @@ struct InputState {
y: f32,
}
#[derive(Component, Default)]
struct SailboatState {
sail_extension: f32,
rudder_dir: f32,
}
#[derive(Default, Resource)]
struct WindConditions {
direction: f32,
strength: f32,
}
fn main() {
let mut app = App::new();
app.add_plugins(DefaultPlugins)
app.add_plugins((DefaultPlugins, Wireframe2dPlugin::default()))
.insert_resource(WindConditions {
strength: 1.0,
..default()
})
.add_systems(Startup, (hello_world, camera_setup, sprite_setup).chain())
.add_systems(Update, (handle_keys, player_physics).chain());
@@ -39,16 +55,33 @@ fn camera_setup(mut clear_color: ResMut<ClearColor>, mut commands: Commands) {
}
fn sprite_setup(assets: Res<AssetServer>, mut commands: Commands) {
let sprite_handle = assets.load("sprite-0001.png");
let ship_sprite = assets.load("sprite-0001.png");
let sail_sprite = assets.load("sail.png");
commands.spawn((
Sprite {
image: sprite_handle,
..default()
},
EntityPhysics::default(),
InputState::default(),
));
commands
.spawn((
Sprite {
image: ship_sprite,
..default()
},
EntityPhysics::default(),
InputState::default(),
SailboatState::default(),
))
.with_child((
Sprite {
image: sail_sprite,
..default()
},
Transform {
translation: Vec3 {
x: 8.0,
y: 1.0,
z: 0.,
},
..default()
},
));
}
fn handle_keys(mut q_player: Query<&mut InputState>, keys: Res<ButtonInput<KeyCode>>) {
@@ -77,32 +110,74 @@ fn handle_keys(mut q_player: Query<&mut InputState>, keys: Res<ButtonInput<KeyCo
}
}
fn player_physics(mut q_player: Query<(&InputState, &mut EntityPhysics, &mut Transform)>) {
let Ok((input, mut physics, mut transform)) = q_player.single_mut() else {
fn player_physics(
mut q_player: Query<(
&InputState,
&mut SailboatState,
&mut EntityPhysics,
&mut Transform,
)>,
wind_conditions: Res<WindConditions>,
) {
let Ok((input, mut boat_state, mut physics, mut transform)) = q_player.single_mut() else {
return;
};
if input.x < 0. {
physics.turn_speed -= 0.1;
} else if input.x > 0. {
physics.turn_speed += 0.1;
} else {
physics.turn_speed *= 0.99;
if input.y > 0. {
boat_state.sail_extension = (1.0 + boat_state.sail_extension) * 0.5;
} else if input.y < 0. {
boat_state.sail_extension *= 0.5;
}
physics.turn_speed = physics.turn_speed.clamp(-MAX_TURN_SPEED, MAX_TURN_SPEED);
physics.heading += physics.turn_speed * 0.1;
boat_state.sail_extension = boat_state.sail_extension.clamp(0., 1.);
if input.y > 0. {
physics.speed += 0.1;
} else if input.y < 0. {
physics.speed -= 0.1;
} else {
physics.speed *= 0.999;
physics.speed *= 0.99;
// using just the heading is incorrect, as the sail adjusts based on heading vs wind
let sail_dir_x = physics.heading.sin();
let sail_dir_y = physics.heading.cos();
let wind_dir_x = wind_conditions.direction.sin();
let wind_dir_y = wind_conditions.direction.cos();
let sail_dir_vec = Vec2 {
x: sail_dir_x,
y: sail_dir_y,
};
let wind_dir_vec = Vec2 {
x: wind_dir_x,
y: wind_dir_y,
};
// technically you could put your sail out and try to go backwards but..
// let's not tackle that (Yet?)
let sail_strength = sail_dir_vec
.dot(wind_dir_vec)
.clamp(-0.8, 1.)
.remap(-0.8, 1., 0., 1.)
* wind_conditions.strength;
if boat_state.sail_extension > 0. {
physics.speed += 0.01 * boat_state.sail_extension * sail_strength;
}
physics.speed = physics.speed.clamp(-MAX_SAILING_SPEED, MAX_SAILING_SPEED);
if input.x < 0. {
boat_state.rudder_dir = (-1.0 + boat_state.rudder_dir) * 0.5;
} else if input.x > 0. {
boat_state.rudder_dir = (1.0 + boat_state.rudder_dir) * 0.5;
} else {
boat_state.rudder_dir *= 0.5;
}
physics.turn_speed *= 0.1;
physics.turn_speed += boat_state.rudder_dir * (physics.speed.abs() / MAX_SAILING_SPEED);
physics.turn_speed = physics.turn_speed.clamp(-MAX_TURN_SPEED, MAX_TURN_SPEED);
physics.heading += physics.turn_speed * 0.1;
let x_speed = physics.heading.sin() * physics.speed;
let y_speed = physics.heading.cos() * physics.speed;