use anyhow::Result; use chrono::offset::Utc; use gilrs::{Axis, Button, Event, EventType, Gilrs}; use rand::prelude::*; use std::{ io::{self, Write}, thread, time, time::Duration, }; type Segment = [[f32; 2]; 2]; #[derive(Default)] struct Game { platforms: Vec>, player: Vec, joystick_player_delta: [f32; 2], jump_player_delta: f32, } const COLORS: [u32; 12] = [ 0xFF0000, 0xFF8000, 0xFFFF00, 0x80FF00, 0x00FF00, 0x00FF80, 0x00FFFF, 0x0080FF, 0x0000FF, 0x7F00FF, 0xFF00FF, 0xFF007F, ]; fn main() -> Result<()> { let mut gilrs = Gilrs::new().unwrap(); let mut rng = rand::thread_rng(); let mut frame_count: u64 = 0; let mut last_press_frame_count = 0; let mut is_jump = false; let mut double_jump = false; let mut velocity = 1.0; let mut last_is_colide = false; let mut x_pressed = 0; let mut velocity_under_0 = 0; let mut color = 0xFFFFFF; let mut colors_iter = COLORS.iter().cycle(); let mut destroyed_platforms_without_ground = 0; let mut game = Game { player: vec![ [[600.0, 600.0], [650.0, 600.0]], [[650.0, 600.0], [650.0, 650.0]], [[650.0, 650.0], [600.0, 650.0]], // bottom line [[600.0, 650.0], [600.0, 600.0]], ], ..Game::default() }; let mut active_gamepad = None; loop { let mut is_collide = false; if let Some(Event { id, event, time }) = gilrs.next_event() { active_gamepad = Some(id); } if let Some(active_gamepad) = active_gamepad { let gp = gilrs.gamepad(active_gamepad); { let velocity = 0.5; let (sx, sy) = (gp.value(Axis::LeftStickX), gp.value(Axis::LeftStickY)); if sx.abs() > 0.5 || sy.abs() > 0.5 { if sx.abs() > 0.5 { let x = velocity * sx.signum(); if game.joystick_player_delta[0] + x >= -50. && game.joystick_player_delta[0] + x <= 20. { game.joystick_player_delta[0] += x; } } // if sy.abs() > 0.5 { // game.joystick_player_delta[1] -= velocity * sy.signum(); // } } } for l in game.platforms.iter_mut() { if (game.player[2][0][1] + game.joystick_player_delta[1] * 10. + game.jump_player_delta >= l[0][0][1] - 18. && game.player[2][0][1] + game.joystick_player_delta[1] * 10. + game.jump_player_delta <= l[0][0][1] + 18.) && (game.player[2][0][0] + game.joystick_player_delta[0] * 7. >= l[0][0][0] && game.player[2][1][0] + game.joystick_player_delta[0] * 7. <= l[0][1][0]) { is_collide = true; } if !is_collide && last_is_colide && !double_jump { velocity = 0.; } if is_collide && !last_is_colide { double_jump = false; if destroyed_platforms_without_ground % 5 == 0 && destroyed_platforms_without_ground != 0 { color = *colors_iter.next().unwrap(); destroyed_platforms_without_ground += 1; } } } if last_press_frame_count + rng.gen_range(100, 4000) <= frame_count { let height = rng.gen_range(300., 550.); game.platforms .push(vec![[[800., height], [rng.gen_range(810., 900.), height]]]); last_press_frame_count = frame_count; } /*if gp.is_pressed(Button::West) && } else*/ if gp.is_pressed(Button::South) { if game.jump_player_delta == 0. { x_pressed += 1; is_jump = true; velocity = 1.0; } if is_collide || (velocity > 0. && !double_jump) { x_pressed += 1; velocity = 1.0; double_jump = true; } } } if is_collide && game.joystick_player_delta[0] >= -49. && game.joystick_player_delta[0] <= 20. { game.joystick_player_delta[0] -= 1. / 7.; } // if is_jump && !is_collide && !double_jump { // } else { // is_jump = false; // double_jump = false; // game.jump_player_delta = 0.; // } // //eprintln!("Jump: alter_y: {:?}", game.jump_player_delta); // } if is_jump { game.jump_player_delta -= velocity * 30.; is_jump = false; } if (game.player[2][0][1] + game.joystick_player_delta[1] * 10. + game.jump_player_delta) < 650. { if !is_collide || velocity >= 0. { if velocity >= 0. { velocity_under_0 += 1; } game.jump_player_delta -= velocity * 30.; velocity -= 0.05; } } else { color = 0xFFFFFF; destroyed_platforms_without_ground = 0; colors_iter = COLORS.iter().cycle(); game.jump_player_delta = 0.; } let mut frame: Vec<(f32, f32, u32)> = vec![]; let mut to_remove = vec![]; for (k, l) in game.platforms.iter_mut().enumerate() { let mut must_remove = false; for (i, p) in l.iter_mut().enumerate() { frame.push((p[0][0], p[0][1], 0)); frame.push((p[0][0], p[0][1], color)); frame.push((p[1][0], p[1][1], color)); frame.push((p[1][0], p[1][1], 0)); if p[0][0] >= 50. { p[0][0] -= 1.; p[1][0] -= 1.; } else { must_remove = true; } } if must_remove { to_remove.push(k); } } for i in to_remove { game.platforms.remove(i); destroyed_platforms_without_ground += 1; } for p in game.player.iter() { let p = [ ( p[0][0] + game.joystick_player_delta[0] * 7., p[0][1] + game.joystick_player_delta[1] * 10. + game.jump_player_delta, ), ( p[1][0] + game.joystick_player_delta[0] * 7., p[1][1] + game.joystick_player_delta[1] * 10. + game.jump_player_delta, ), ]; frame.push((p[0].0, p[0].1, 0)); frame.push((p[0].0, p[0].1, color)); frame.push((p[1].0, p[1].1, color)); frame.push((p[1].0, p[1].1, 0)); } let out = serde_json::to_string(&frame)?; if !frame.is_empty() { io::stdout().write_all(out.as_bytes())?; io::stdout().write(b"\n")?; io::stdout().flush()?; } eprintln!("score: {:?}", destroyed_platforms_without_ground); // eprintln!( // "{}: // game.player: {:?} // game.platforms: {:?} // game.joystick_player_delta: {:?} // game.jump_player_delta: {:?} // is_collide: {:?} // is_jump: {:?} // double_jump: {:?} // velocity: {:?} // x_pressed: {:?} // velocity_under_0: {:?} // {:?}", // Utc::now().time(), // game.player, // game.platforms, // game.joystick_player_delta, // (game.player[2][0][1] + game.joystick_player_delta[1] * 10. + game.jump_player_delta), // is_collide, // is_jump, // double_jump, // velocity, // x_pressed, // velocity_under_0, // game.player[2][0][1] + game.joystick_player_delta[1] * 10. + game.jump_player_delta // ); thread::sleep(Duration::from_millis(1000 / 60)); frame_count += 1; last_is_colide = is_collide; } Ok(()) }