ARYAN KINO
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
4415
Cargo.lock
generated
Normal file
4415
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "birdgame"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bevy = { version = "0.14", features = ["dynamic_linking"] } # 0.14 is current as of Nov 2025
|
||||
bevy_flycam = "0.14" # optional: for free camera while testing
|
||||
rand = "0.8"
|
||||
|
||||
[target.x86_64-pc-windows-msvc]
|
||||
linker = "rust-lld"
|
||||
BIN
assets/models/bird.glb
Normal file
BIN
assets/models/bird.glb
Normal file
Binary file not shown.
234
src/main.rs
Normal file
234
src/main.rs
Normal file
@@ -0,0 +1,234 @@
|
||||
use bevy::prelude::*;
|
||||
use rand::Rng;
|
||||
|
||||
const GRAVITY: f32 = -20.0;
|
||||
const FLAP_STRENGTH: f32 = 12.0;
|
||||
const MOVE_SPEED: f32 = 10.0;
|
||||
const ARENA_HALF: f32 = 22.0;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins.set(WindowPlugin {
|
||||
primary_window: Some(Window {
|
||||
title: "Bird PvP".into(),
|
||||
resolution: (1280., 720.).into(),
|
||||
..default()
|
||||
}),
|
||||
..default()
|
||||
}))
|
||||
.insert_resource(Scoreboard::default())
|
||||
.insert_resource(ClearColor(Color::srgb(0.2, 0.6, 1.0)))
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
player_input,
|
||||
bird_physics,
|
||||
bird_vs_bird_collision,
|
||||
arena_collision,
|
||||
ui_update,
|
||||
),
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
struct Scoreboard {
|
||||
p1: u32,
|
||||
p2: u32,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct Bird {
|
||||
velocity: Vec3,
|
||||
player_id: usize,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct ScoreText;
|
||||
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
// LIGHT
|
||||
commands.spawn(PointLightBundle {
|
||||
point_light: PointLight {
|
||||
intensity: 4000.0,
|
||||
range: 200.,
|
||||
shadows_enabled: true,
|
||||
..default()
|
||||
},
|
||||
transform: Transform::from_xyz(20.0, 30.0, 20.0),
|
||||
..default()
|
||||
});
|
||||
|
||||
// GROUND
|
||||
commands.spawn(PbrBundle {
|
||||
mesh: meshes.add(Plane3d::default().mesh().size(60.0, 60.0)),
|
||||
material: materials.add(Color::srgb(0.1, 0.7, 0.1)),
|
||||
transform: Transform::from_xyz(0.0, -1.0, 0.0),
|
||||
..default()
|
||||
});
|
||||
|
||||
// PLAYER 1 — red bird
|
||||
commands.spawn((
|
||||
SceneBundle {
|
||||
scene: asset_server.load("models/bird.glb#Scene0"),
|
||||
transform: Transform::from_xyz(-5.0, 2.0, 0.0).with_scale(Vec3::splat(0.15)),
|
||||
..default()
|
||||
},
|
||||
Bird {
|
||||
velocity: Vec3::ZERO,
|
||||
player_id: 1,
|
||||
},
|
||||
));
|
||||
|
||||
// PLAYER 2 — blue bird
|
||||
commands.spawn((
|
||||
SceneBundle {
|
||||
scene: asset_server.load("models/bird.glb#Scene0"),
|
||||
transform: Transform::from_xyz(5.0, 2.0, 0.0).with_scale(Vec3::splat(0.15)),
|
||||
..default()
|
||||
},
|
||||
Bird {
|
||||
velocity: Vec3::ZERO,
|
||||
player_id: 2,
|
||||
},
|
||||
));
|
||||
|
||||
// CAMERA
|
||||
commands.spawn(Camera3dBundle {
|
||||
transform: Transform::from_xyz(0.0, 30.0, 30.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||
..default()
|
||||
});
|
||||
|
||||
// UI
|
||||
commands.spawn((
|
||||
TextBundle::from_section(
|
||||
"P1: 0 P2: 0",
|
||||
TextStyle {
|
||||
font_size: 40.0,
|
||||
color: Color::WHITE,
|
||||
..default()
|
||||
},
|
||||
),
|
||||
ScoreText,
|
||||
));
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
// PLAYER INPUT
|
||||
// ----------------------------------------------
|
||||
|
||||
fn player_input(input: Res<ButtonInput<KeyCode>>, mut birds: Query<(&mut Bird, &mut Transform)>) {
|
||||
for (mut bird, mut tf) in &mut birds {
|
||||
let mut move_x = 0.0;
|
||||
let mut flap = false;
|
||||
|
||||
match bird.player_id {
|
||||
1 => {
|
||||
if input.pressed(KeyCode::KeyA) {
|
||||
move_x -= 1.0;
|
||||
}
|
||||
if input.pressed(KeyCode::KeyD) {
|
||||
move_x += 1.0;
|
||||
}
|
||||
if input.just_pressed(KeyCode::KeyW) {
|
||||
flap = true;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
if input.pressed(KeyCode::ArrowLeft) {
|
||||
move_x -= 1.0;
|
||||
}
|
||||
if input.pressed(KeyCode::ArrowRight) {
|
||||
move_x += 1.0;
|
||||
}
|
||||
if input.just_pressed(KeyCode::ArrowUp) {
|
||||
flap = true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if flap {
|
||||
bird.velocity.y = FLAP_STRENGTH;
|
||||
}
|
||||
|
||||
tf.translation.x += move_x * MOVE_SPEED * 0.016;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
// PHYSICS
|
||||
// ----------------------------------------------
|
||||
|
||||
fn bird_physics(time: Res<Time>, mut q: Query<(&mut Bird, &mut Transform)>) {
|
||||
for (mut bird, mut tf) in &mut q {
|
||||
bird.velocity.y += GRAVITY * time.delta_seconds();
|
||||
tf.translation += bird.velocity * time.delta_seconds();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
// BIRD VS BIRD COLLISION
|
||||
// ----------------------------------------------
|
||||
|
||||
fn bird_vs_bird_collision(mut birds: Query<(&mut Bird, &Transform)>) {
|
||||
let mut iter = birds.iter_mut();
|
||||
|
||||
let Some((mut a, tf_a)) = iter.next() else {
|
||||
return;
|
||||
};
|
||||
let Some((mut b, tf_b)) = iter.next() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let diff = tf_b.translation - tf_a.translation;
|
||||
let dist = diff.length();
|
||||
|
||||
if dist < 1.5 {
|
||||
let push = diff.normalize() * 10.0;
|
||||
a.velocity -= push;
|
||||
b.velocity += push;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
// WALL COLLISION + SCORING
|
||||
// ----------------------------------------------
|
||||
|
||||
fn arena_collision(
|
||||
mut birds: Query<(&mut Transform, &mut Bird)>,
|
||||
mut scoreboard: ResMut<Scoreboard>,
|
||||
) {
|
||||
for (mut tf, mut bird) in &mut birds {
|
||||
if tf.translation.x.abs() > ARENA_HALF
|
||||
|| tf.translation.z.abs() > ARENA_HALF
|
||||
|| tf.translation.y < -2.0
|
||||
|| tf.translation.y > 15.0
|
||||
{
|
||||
match bird.player_id {
|
||||
1 => scoreboard.p2 += 1,
|
||||
2 => scoreboard.p1 += 1,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Respawn
|
||||
tf.translation = Vec3::new(rand::thread_rng().gen_range(-5.0..5.0), 2.0, 0.0);
|
||||
bird.velocity = Vec3::ZERO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
// UI UPDATE
|
||||
// ----------------------------------------------
|
||||
|
||||
fn ui_update(scoreboard: Res<Scoreboard>, mut text: Query<&mut Text, With<ScoreText>>) {
|
||||
let mut ui = text.single_mut();
|
||||
ui.sections[0].value = format!("P1: {} P2: {}", scoreboard.p1, scoreboard.p2);
|
||||
}
|
||||
Reference in New Issue
Block a user