|
|
|
@ -16,6 +16,8 @@ fn main() {
|
|
|
|
Physics2dPlugin,
|
|
|
|
Physics2dPlugin,
|
|
|
|
))
|
|
|
|
))
|
|
|
|
.insert_resource(Gravity(Vec2::NEG_Y * 9.8 * 100.0))
|
|
|
|
.insert_resource(Gravity(Vec2::NEG_Y * 9.8 * 100.0))
|
|
|
|
|
|
|
|
.init_resource::<PipeComponents>()
|
|
|
|
|
|
|
|
.init_resource::<GroundComponents>()
|
|
|
|
.init_resource::<Score>()
|
|
|
|
.init_resource::<Score>()
|
|
|
|
.init_resource::<RewindFrames>()
|
|
|
|
.init_resource::<RewindFrames>()
|
|
|
|
.init_resource::<Flaps>()
|
|
|
|
.init_resource::<Flaps>()
|
|
|
|
@ -25,7 +27,9 @@ fn main() {
|
|
|
|
Startup,
|
|
|
|
Startup,
|
|
|
|
(
|
|
|
|
(
|
|
|
|
init_bird,
|
|
|
|
init_bird,
|
|
|
|
init_obstacles,
|
|
|
|
// init_obstacles,
|
|
|
|
|
|
|
|
init_obstacle_assets,
|
|
|
|
|
|
|
|
init_first_batches.after(init_obstacle_assets),
|
|
|
|
init_ui,
|
|
|
|
init_ui,
|
|
|
|
tweak_camera.after(create_camera_2d),
|
|
|
|
tweak_camera.after(create_camera_2d),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
@ -81,6 +85,10 @@ fn main() {
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.add_observer(flap)
|
|
|
|
.add_observer(flap)
|
|
|
|
|
|
|
|
.add_observer(populate_batch)
|
|
|
|
|
|
|
|
.add_observer(populate_pipe)
|
|
|
|
|
|
|
|
.add_observer(populate_ground)
|
|
|
|
|
|
|
|
.add_observer(populate_hitbox)
|
|
|
|
.run();
|
|
|
|
.run();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -152,108 +160,135 @@ fn init_bird(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Component, Clone)]
|
|
|
|
#[derive(Component, Clone)]
|
|
|
|
struct Ground;
|
|
|
|
struct Ground(isize);
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Component, Clone)]
|
|
|
|
#[derive(Component, Clone)]
|
|
|
|
struct Pipe;
|
|
|
|
enum Pipe {
|
|
|
|
|
|
|
|
Top,
|
|
|
|
|
|
|
|
Bottom,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Component, Clone)]
|
|
|
|
#[derive(Component, Clone)]
|
|
|
|
struct Hitbox;
|
|
|
|
struct Hitbox;
|
|
|
|
|
|
|
|
|
|
|
|
fn init_obstacles(
|
|
|
|
#[derive(Component, Clone)]
|
|
|
|
|
|
|
|
struct Batch(usize);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn init_first_batches(
|
|
|
|
|
|
|
|
mut commands: Commands
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
commands.spawn(Batch(0));
|
|
|
|
|
|
|
|
commands.spawn(Batch(1));
|
|
|
|
|
|
|
|
commands.spawn(Batch(2));
|
|
|
|
|
|
|
|
commands.spawn(Batch(3));
|
|
|
|
|
|
|
|
commands.spawn(Batch(4));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn populate_batch(
|
|
|
|
|
|
|
|
trigger: Trigger<OnAdd, Batch>,
|
|
|
|
|
|
|
|
batches: Query<&Batch>,
|
|
|
|
mut commands: Commands,
|
|
|
|
mut commands: Commands,
|
|
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
|
|
|
|
|
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
|
|
|
|
|
|
|
server: Res<AssetServer>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
let ground = {
|
|
|
|
let Batch(batch_id) = batches.get(trigger.target()).unwrap();
|
|
|
|
let material = MeshMaterial2d(materials.add(ColorMaterial {
|
|
|
|
commands
|
|
|
|
texture: Some(server.load("kenny.nl/1-bit-platformer-pack/tile_0088.png")),
|
|
|
|
.entity(trigger.target())
|
|
|
|
color: BLACK.into(),
|
|
|
|
.insert((Transform::from_xyz(500.0 * (*batch_id) as f32, 0.0, 0.0), Visibility::Inherited))
|
|
|
|
..default()
|
|
|
|
.with_children(|parent| {
|
|
|
|
}));
|
|
|
|
parent.spawn(Ground(-2));
|
|
|
|
|
|
|
|
parent.spawn(Ground(-1));
|
|
|
|
|
|
|
|
parent.spawn(Ground(0));
|
|
|
|
|
|
|
|
parent.spawn(Ground(1));
|
|
|
|
|
|
|
|
parent.spawn(Ground(2));
|
|
|
|
|
|
|
|
if *batch_id > 0 {
|
|
|
|
|
|
|
|
parent.spawn(Pipe::Top);
|
|
|
|
|
|
|
|
parent.spawn(Pipe::Bottom);
|
|
|
|
|
|
|
|
parent.spawn(Hitbox);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn populate_ground(
|
|
|
|
|
|
|
|
trigger: Trigger<OnAdd, Ground>,
|
|
|
|
|
|
|
|
grounds: Query<&Ground>,
|
|
|
|
|
|
|
|
ground_assets: Res<GroundComponents>,
|
|
|
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
let Ground(idx) = grounds.get(trigger.target()).unwrap();
|
|
|
|
|
|
|
|
commands.entity(trigger.target()).insert((
|
|
|
|
|
|
|
|
ground_assets.material.clone(),
|
|
|
|
|
|
|
|
ground_assets.mesh.clone(),
|
|
|
|
|
|
|
|
Name::new("ground"),
|
|
|
|
|
|
|
|
RigidBody::Static, Collider::rectangle(1.0, 1.0),
|
|
|
|
|
|
|
|
Transform::from_xyz(100.0 * (*idx) as f32, -400.0, -1.0).with_scale(Vec3::splat(100.0))
|
|
|
|
|
|
|
|
));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let mesh = Mesh2d(meshes.add(Rectangle::new(1.0, 1.0)));
|
|
|
|
fn populate_pipe(
|
|
|
|
|
|
|
|
trigger: Trigger<OnAdd, Pipe>,
|
|
|
|
|
|
|
|
pipes: Query<&Pipe>,
|
|
|
|
|
|
|
|
pipe_assets: Res<PipeComponents>,
|
|
|
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
let pipe_t = match pipes.get(trigger.target()).unwrap() {
|
|
|
|
|
|
|
|
Pipe::Top => Transform::from_xyz(0.0, 200.0, -1.0).with_scale(Vec3::splat(100.0)),
|
|
|
|
|
|
|
|
Pipe::Bottom => Transform::from_xyz(0.0, -200.0, -1.0).with_scale(Vec3::splat(100.0)),
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
commands.entity(trigger.target()).insert((
|
|
|
|
|
|
|
|
pipe_t,
|
|
|
|
|
|
|
|
pipe_assets.material.clone(),
|
|
|
|
|
|
|
|
pipe_assets.mesh.clone(),
|
|
|
|
|
|
|
|
RigidBody::Static, Collider::rectangle(1.0, 1.0),
|
|
|
|
|
|
|
|
Name::new("pipe"),
|
|
|
|
|
|
|
|
));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let name = Name::new("ground");
|
|
|
|
fn populate_hitbox(
|
|
|
|
|
|
|
|
trigger: Trigger<OnAdd, Hitbox>,
|
|
|
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
commands.entity(trigger.target()).insert((
|
|
|
|
|
|
|
|
RigidBody::Static,
|
|
|
|
|
|
|
|
Collider::rectangle(1.0, 10.0),
|
|
|
|
|
|
|
|
Sensor,
|
|
|
|
|
|
|
|
CollisionEventsEnabled,
|
|
|
|
|
|
|
|
Name::new("hitbox"),
|
|
|
|
|
|
|
|
Transform::from_xyz(0.0, 0.0, 0.0).with_scale(Vec3::splat(100.0)),
|
|
|
|
|
|
|
|
));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let physics = (RigidBody::Static, Collider::rectangle(1.0, 1.0));
|
|
|
|
#[derive(Resource, Default)]
|
|
|
|
|
|
|
|
struct GroundComponents {
|
|
|
|
|
|
|
|
material: MeshMaterial2d<ColorMaterial>,
|
|
|
|
|
|
|
|
mesh: Mesh2d,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
(name, mesh, material, physics, Ground)
|
|
|
|
#[derive(Resource, Default)]
|
|
|
|
};
|
|
|
|
struct PipeComponents {
|
|
|
|
let pipe = {
|
|
|
|
material: MeshMaterial2d<ColorMaterial>,
|
|
|
|
let material = MeshMaterial2d(materials.add(ColorMaterial {
|
|
|
|
mesh: Mesh2d,
|
|
|
|
texture: Some(server.load("kenny.nl/1-bit-platformer-pack/tile_0247.png")),
|
|
|
|
}
|
|
|
|
color: GREEN.into(),
|
|
|
|
|
|
|
|
..default()
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mesh = Mesh2d(meshes.add(Rectangle::new(1.0, 1.0)));
|
|
|
|
fn init_obstacle_assets(
|
|
|
|
let physics = (RigidBody::Static, Collider::rectangle(1.0, 1.0));
|
|
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
|
|
let name = Name::new("pipe");
|
|
|
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
|
|
|
|
|
|
|
mut pipe_assets: ResMut<PipeComponents>,
|
|
|
|
|
|
|
|
mut ground_assets: ResMut<GroundComponents>,
|
|
|
|
|
|
|
|
server: Res<AssetServer>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
pipe_assets.material = MeshMaterial2d(materials.add(ColorMaterial {
|
|
|
|
|
|
|
|
texture: Some(server.load("kenny.nl/1-bit-platformer-pack/tile_0247.png")),
|
|
|
|
|
|
|
|
color: GREEN.into(),
|
|
|
|
|
|
|
|
..default()
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
pipe_assets.mesh = Mesh2d(meshes.add(Rectangle::new(1.0, 1.0)));
|
|
|
|
|
|
|
|
|
|
|
|
(
|
|
|
|
ground_assets.material = MeshMaterial2d(materials.add(ColorMaterial {
|
|
|
|
name.clone(),
|
|
|
|
texture: Some(server.load("kenny.nl/1-bit-platformer-pack/tile_0088.png")),
|
|
|
|
mesh.clone(),
|
|
|
|
color: BLACK.into(),
|
|
|
|
material.clone(),
|
|
|
|
..default()
|
|
|
|
physics.clone(),
|
|
|
|
}));
|
|
|
|
Pipe,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
let hitbox = {
|
|
|
|
|
|
|
|
let physics = (
|
|
|
|
|
|
|
|
RigidBody::Static,
|
|
|
|
|
|
|
|
Collider::rectangle(1.0, 10.0),
|
|
|
|
|
|
|
|
Sensor,
|
|
|
|
|
|
|
|
CollisionEventsEnabled,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
let name = Name::new("hitbox");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(name.clone(), physics.clone(), Hitbox)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: Instead of spawning infinite floor/pipes, we should instead spawn enough for 1-3 a few
|
|
|
|
ground_assets.mesh = Mesh2d(meshes.add(Rectangle::new(1.0, 1.0)));
|
|
|
|
// screens and then "move" them around.
|
|
|
|
|
|
|
|
// This is considerably more complexity so can be implemented later, but would keep memory
|
|
|
|
|
|
|
|
// overhead fairly static.
|
|
|
|
|
|
|
|
(1..10).for_each(|i| {
|
|
|
|
|
|
|
|
// TODO: Jitter close/far of pipes for challenge
|
|
|
|
|
|
|
|
let jitter: f32 = {
|
|
|
|
|
|
|
|
let h = RandomState::default();
|
|
|
|
|
|
|
|
let x: u64 = h.hash_one(i);
|
|
|
|
|
|
|
|
((x % 10) * 20) as f32 - 100.0
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
info!("Jitter for {i} is {jitter}");
|
|
|
|
|
|
|
|
let above = {
|
|
|
|
|
|
|
|
let x = 300.0 * i as f32;
|
|
|
|
|
|
|
|
let y = f32::min(300.0 + jitter, 400.0);
|
|
|
|
|
|
|
|
Transform::from_xyz(x, y, -1.0).with_scale(Vec3::splat(100.0))
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
commands.spawn((pipe.clone(), above));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let below = {
|
|
|
|
|
|
|
|
let x = 300.0 * i as f32;
|
|
|
|
|
|
|
|
let y = f32::max(-200.0 + jitter, -300.0);
|
|
|
|
|
|
|
|
Transform::from_xyz(x, y, -1.0).with_scale(Vec3::splat(100.0))
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
commands.spawn((pipe.clone(), below));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let hitbox_pos =
|
|
|
|
|
|
|
|
Transform::from_xyz(300.0 * i as f32, 0.0, 10.0).with_scale(Vec3::splat(100.0));
|
|
|
|
|
|
|
|
commands.spawn((hitbox_pos, hitbox.clone()));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let floor1 =
|
|
|
|
|
|
|
|
Transform::from_xyz(300.0 * i as f32 - 100.0, -300.0, 1.0).with_scale(Vec3::splat(100.0));
|
|
|
|
|
|
|
|
commands.spawn((ground.clone(), floor1));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let floor2 =
|
|
|
|
|
|
|
|
Transform::from_xyz(300.0 * i as f32, -300.0, 1.0).with_scale(Vec3::splat(100.0));
|
|
|
|
|
|
|
|
commands.spawn((ground.clone(), floor2));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let floor3 =
|
|
|
|
|
|
|
|
Transform::from_xyz(300.0 * i as f32 + 100.0, -300.0, 1.0).with_scale(Vec3::splat(100.0));
|
|
|
|
|
|
|
|
commands.spawn((ground.clone(), floor3));
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn init_ui(mut commands: Commands) {
|
|
|
|
fn init_ui(mut commands: Commands) {
|
|
|
|
@ -390,7 +425,7 @@ fn flap(
|
|
|
|
mut bird: Query<&mut ExternalImpulse, With<Bird>>,
|
|
|
|
mut bird: Query<&mut ExternalImpulse, With<Bird>>,
|
|
|
|
mut flaps: ResMut<Flaps>,
|
|
|
|
mut flaps: ResMut<Flaps>,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
info!("real flap for {:?}", trigger.target());
|
|
|
|
debug!("real flap for {:?}", trigger.target());
|
|
|
|
// Increment flap stat
|
|
|
|
// Increment flap stat
|
|
|
|
flaps.0 += 1;
|
|
|
|
flaps.0 += 1;
|
|
|
|
|
|
|
|
|
|
|
|
|