Starting to do physics
This commit is contained in:
parent
4da27c5777
commit
3e8ae2d496
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
|
@ -1,82 +1,199 @@
|
||||||
use std::time::Duration;
|
use std::time::{
|
||||||
|
Instant,
|
||||||
|
Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use sfml::system::Vector2;
|
use sfml::system::Vector2;
|
||||||
use sfml::window::Event;
|
use sfml::window::Event;
|
||||||
use sfml::graphics::{
|
use sfml::graphics::IntRect;
|
||||||
Drawable,
|
use sfml::window::Key;
|
||||||
RenderStates,
|
|
||||||
RenderTarget,
|
|
||||||
Sprite,
|
|
||||||
Color,
|
|
||||||
};
|
|
||||||
|
|
||||||
use engine::scene::Updatable;
|
use engine::scene::Updatable;
|
||||||
use engine::controls::Controls;
|
use engine::controls::Controls;
|
||||||
|
use engine::renderer::Drawable;
|
||||||
|
use engine::texture::Texture;
|
||||||
|
use engine::physics;
|
||||||
|
use engine::math::{
|
||||||
|
duration_as_f32,
|
||||||
|
duration_as_frame,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The different sides a character can face.
|
||||||
|
pub enum Side {
|
||||||
|
/// The character looks to the left.
|
||||||
|
Left,
|
||||||
|
|
||||||
|
/// The character looks to the right.
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Side {
|
||||||
|
/// Returns the side corresponding to the force.
|
||||||
|
///
|
||||||
|
/// Returns None if the force is null.
|
||||||
|
pub fn from_force(force: Vector2<f32>) -> Option<Side> {
|
||||||
|
if force.x > 0.0 {
|
||||||
|
Some(Side::Right)
|
||||||
|
} else if force.x < 0.0 {
|
||||||
|
Some(Side::Left)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the offset in the texture.
|
||||||
|
pub fn offset(&self) -> i32 {
|
||||||
|
match *self {
|
||||||
|
Side::Left => 0,
|
||||||
|
Side::Right => 32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A character, enemy or controllable.
|
/// A character, enemy or controllable.
|
||||||
pub struct Character {
|
pub struct Character {
|
||||||
|
|
||||||
/// The position of the character.
|
/// The position of the character.
|
||||||
position: Vector2<f32>,
|
pub position: Vector2<f32>,
|
||||||
|
|
||||||
/// The speed of the character.
|
/// The speed of the character.
|
||||||
speed: Vector2<f32>,
|
pub speed: Vector2<f32>,
|
||||||
|
|
||||||
/// If the player is controlling a character.
|
/// If the player is controlling a character.
|
||||||
controls: Option<Controls>,
|
controls: Option<Controls>,
|
||||||
|
|
||||||
|
/// The side of the character.
|
||||||
|
side: Side,
|
||||||
|
|
||||||
|
/// The counter of jumps.
|
||||||
|
///
|
||||||
|
/// When it's 0, the character can no longer jump.
|
||||||
|
jump_counter: usize,
|
||||||
|
|
||||||
|
/// The maximum number of jumps a character can do.
|
||||||
|
///
|
||||||
|
/// It's reset when the character hits the ground.
|
||||||
|
max_jump: usize,
|
||||||
|
|
||||||
|
/// The timer of the character's animation.
|
||||||
|
animation_timer: Option<Instant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Character {
|
impl Character {
|
||||||
/// Creates a character in (0, 0).
|
|
||||||
pub fn new() -> Character {
|
fn generic(controls: Option<Controls>) -> Character {
|
||||||
Character {
|
Character {
|
||||||
position: Vector2::new(0.0, 0.0),
|
position: Vector2::new(0.0, 0.0),
|
||||||
speed: Vector2::new(0.0, 0.0),
|
speed: Vector2::new(0.0, 0.0),
|
||||||
controls: None,
|
controls: controls,
|
||||||
|
side: Side::Right,
|
||||||
|
jump_counter: 1,
|
||||||
|
max_jump: 1,
|
||||||
|
animation_timer: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a character in (0, 0).
|
||||||
|
pub fn new() -> Character {
|
||||||
|
Character::generic(None)
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a character with the specified controls.
|
/// Creates a character with the specified controls.
|
||||||
pub fn with_controls(controls: Controls) -> Character {
|
pub fn with_controls(controls: Controls) -> Character {
|
||||||
Character {
|
Character::generic(Some(controls))
|
||||||
position: Vector2::new(0.0, 0.0),
|
|
||||||
speed: Vector2::new(0.0, 0.0),
|
|
||||||
controls: Some(controls),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the position of the character.
|
/// Sets the position of the character.
|
||||||
pub fn set_position<S: Into<Vector2<f32>>>(&mut self, position: S) {
|
pub fn set_position<S: Into<Vector2<f32>>>(&mut self, position: S) {
|
||||||
self.position = position.into();
|
self.position = position.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes the character jump.
|
||||||
|
pub fn jump(&mut self) {
|
||||||
|
if self.jump_counter > 0 {
|
||||||
|
self.jump_counter -= 1;
|
||||||
|
self.speed.y = physics::JUMP_SPEED.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resets the jump counter.
|
||||||
|
pub fn ground_collision(&mut self) {
|
||||||
|
self.jump_counter = self.max_jump;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Updatable for Character {
|
impl Updatable for Character {
|
||||||
fn update(&mut self, duration: &Duration) {
|
fn update(&mut self, duration: &Duration) {
|
||||||
|
|
||||||
|
let mut force: Vector2<f32> = Vector2::new(0.0, 0.0);
|
||||||
|
|
||||||
|
// Manage the input of the player
|
||||||
|
if Key::Left.is_pressed() {
|
||||||
|
force.x -= 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if Key::Right.is_pressed() {
|
||||||
|
force.x += 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(side) = Side::from_force(force) {
|
||||||
|
|
||||||
|
self.side = side;
|
||||||
|
|
||||||
|
if self.animation_timer.is_none() {
|
||||||
|
self.animation_timer = Some(Instant::now());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
self.animation_timer = None;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let duration = duration_as_f32(duration);
|
||||||
|
|
||||||
|
// Compute acceleration
|
||||||
|
let accel = physics::G;
|
||||||
|
|
||||||
|
// Compute speed
|
||||||
|
self.speed.x *= physics::GROUND_FRICTION.x;
|
||||||
|
self.speed += accel * duration + force * 64.0;
|
||||||
|
|
||||||
|
// Compute position
|
||||||
|
self.position += self.speed * duration;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn manage_event(&mut self, event: &Event) {
|
fn manage_event(&mut self, event: &Event) {
|
||||||
|
match event {
|
||||||
|
|
||||||
|
Event::KeyPressed {
|
||||||
|
code: Key::Return, ..
|
||||||
|
} => self.jump(),
|
||||||
|
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drawable for Character {
|
impl Drawable for Character {
|
||||||
fn draw<'a: 'shader, 'texture, 'shader, 'shader_texture>(
|
fn texture(&self) -> Texture {
|
||||||
&'a self,
|
Texture::Mario
|
||||||
target: &mut RenderTarget,
|
}
|
||||||
states: RenderStates<'texture, 'shader, 'shader_texture>
|
|
||||||
) {
|
|
||||||
|
|
||||||
use sfml::graphics::Transformable;
|
fn texture_rect(&self) -> IntRect {
|
||||||
let mut sprite = Sprite::new();
|
let frame = if let Some(started) = self.animation_timer {
|
||||||
sprite.set_origin((32.0, 0.0));
|
duration_as_frame(&Instant::now().duration_since(started), 2)
|
||||||
sprite.set_position(self.position);
|
|
||||||
sprite.set_color(&if self.controls.is_some() {
|
|
||||||
Color::rgb(255, 0, 0)
|
|
||||||
} else {
|
} else {
|
||||||
Color::rgb(255, 255, 255)
|
0
|
||||||
});
|
};
|
||||||
sprite.draw(target, states);
|
|
||||||
|
IntRect::new(self.side.offset(), frame * 32, 32, 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position(&self) -> Vector2<f32> {
|
||||||
|
self.position
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use std::ops::{
|
use std::ops::{
|
||||||
Index,
|
Index,
|
||||||
IndexMut
|
IndexMut
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Converts a duration into an animation frame number.
|
||||||
|
pub fn duration_as_frame(duration: &Duration, total: usize) -> i32 {
|
||||||
|
let secs = duration_as_f32(duration);
|
||||||
|
|
||||||
|
(secs * 4.0) as i32 % total as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a duration into its number of seconds.
|
||||||
|
pub fn duration_as_f32(duration: &Duration) -> f32 {
|
||||||
|
duration.as_secs() as f32 + duration.subsec_nanos() as f32 / 1_000_000_000.0
|
||||||
|
}
|
||||||
|
|
||||||
/// A generic matrix type, useful for levels.
|
/// A generic matrix type, useful for levels.
|
||||||
pub struct Matrix<T> {
|
pub struct Matrix<T> {
|
||||||
|
|
||||||
|
|
|
@ -13,3 +13,9 @@ pub mod texture;
|
||||||
|
|
||||||
/// This module contains the math tools that will be used.
|
/// This module contains the math tools that will be used.
|
||||||
pub mod math;
|
pub mod math;
|
||||||
|
|
||||||
|
/// This module contains our wrapper of SFML window.
|
||||||
|
pub mod renderer;
|
||||||
|
|
||||||
|
/// This module contains everything related to physics.
|
||||||
|
pub mod physics;
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
use sfml::system::Vector2;
|
||||||
|
|
||||||
|
/// The gravity force.
|
||||||
|
pub const G: Vector2<f32> = Vector2 { x: 0.0, y: 50.0 * 32.0 };
|
||||||
|
|
||||||
|
/// The friction with the ground.
|
||||||
|
pub const GROUND_FRICTION: Vector2<f32> = Vector2 { x: 0.5, y: 1.0 };
|
||||||
|
|
||||||
|
/// The speed of a jump.
|
||||||
|
pub const JUMP_SPEED: Vector2<f32> = Vector2 { x: 0.0, y: -600.0 };
|
|
@ -0,0 +1,110 @@
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use sfml::graphics::{
|
||||||
|
RenderWindow,
|
||||||
|
RenderTarget,
|
||||||
|
Sprite,
|
||||||
|
Color,
|
||||||
|
IntRect,
|
||||||
|
};
|
||||||
|
|
||||||
|
use sfml::window::{
|
||||||
|
Style,
|
||||||
|
Event,
|
||||||
|
};
|
||||||
|
|
||||||
|
use sfml::system::{
|
||||||
|
Vector2,
|
||||||
|
};
|
||||||
|
|
||||||
|
use engine::texture::{Texture, TextureManager};
|
||||||
|
use engine::scene::Scene;
|
||||||
|
|
||||||
|
/// Our custom drawable trait.
|
||||||
|
pub trait Drawable {
|
||||||
|
/// Returns the texture of the drawable.
|
||||||
|
fn texture(&self) -> Texture;
|
||||||
|
|
||||||
|
/// Returns the coordinates to use on the texture.
|
||||||
|
fn texture_rect(&self) -> IntRect;
|
||||||
|
|
||||||
|
/// Returns the position on which the drawable should be drawn.
|
||||||
|
fn position(&self) -> Vector2<f32>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The game window.
|
||||||
|
pub struct Renderer {
|
||||||
|
|
||||||
|
/// The window on which the rendering will be done.
|
||||||
|
window: RenderWindow,
|
||||||
|
|
||||||
|
/// The texture manager needed by the renderer.
|
||||||
|
texture_manager: TextureManager,
|
||||||
|
|
||||||
|
/// The global timer of the renderer.
|
||||||
|
started: Instant,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderer {
|
||||||
|
/// Creates a new renderer.
|
||||||
|
pub fn new(width: u32, height: u32) -> Renderer {
|
||||||
|
|
||||||
|
let mut window = RenderWindow::new(
|
||||||
|
(width, height),
|
||||||
|
"Bomberman",
|
||||||
|
Style::CLOSE,
|
||||||
|
&Default::default(),
|
||||||
|
);
|
||||||
|
window.set_vertical_sync_enabled(true);
|
||||||
|
window.set_framerate_limit(60);
|
||||||
|
|
||||||
|
Renderer {
|
||||||
|
window: window,
|
||||||
|
texture_manager: TextureManager::new(),
|
||||||
|
started: Instant::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the animation state of the renderer, between 0 and 3.
|
||||||
|
pub fn animation_state(&self) -> i32 {
|
||||||
|
let duration = Instant::now().duration_since(self.started);
|
||||||
|
let ns = 1_000_000_000 * duration.as_secs() + duration.subsec_nanos() as u64;
|
||||||
|
let result = (ns as usize / 250_000_000) % 4;
|
||||||
|
result as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the window.
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.window.clear(&Color::rgb(0, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draws a drawable.
|
||||||
|
pub fn draw<D: Drawable>(&mut self, drawable: &D) {
|
||||||
|
let texture = self.texture_manager.get(drawable.texture());
|
||||||
|
let mut sprite = Sprite::with_texture(&texture);
|
||||||
|
sprite.set_texture_rect(&drawable.texture_rect());
|
||||||
|
|
||||||
|
use sfml::graphics::Transformable;
|
||||||
|
sprite.set_position(drawable.position());
|
||||||
|
|
||||||
|
self.window.draw(&sprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draws a scene on the window.
|
||||||
|
pub fn draw_scene(&mut self, scene: &Scene) {
|
||||||
|
for c in scene.characters() {
|
||||||
|
self.draw(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Triggers the display.
|
||||||
|
pub fn display(&mut self) {
|
||||||
|
self.window.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if there are new events, returns the top of the stack.
|
||||||
|
pub fn poll_event(&mut self) -> Option<Event> {
|
||||||
|
self.window.poll_event()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,6 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use sfml::window::Event;
|
use sfml::window::Event;
|
||||||
use sfml::graphics::{
|
|
||||||
RenderTarget,
|
|
||||||
RenderStates,
|
|
||||||
Drawable,
|
|
||||||
};
|
|
||||||
|
|
||||||
use engine::character::Character;
|
use engine::character::Character;
|
||||||
|
|
||||||
|
@ -14,6 +9,7 @@ pub struct Scene {
|
||||||
|
|
||||||
/// The characters contained in the scene.
|
/// The characters contained in the scene.
|
||||||
characters: Vec<Character>,
|
characters: Vec<Character>,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scene {
|
impl Scene {
|
||||||
|
@ -32,8 +28,15 @@ impl Scene {
|
||||||
|
|
||||||
/// Updates the whole scene.
|
/// Updates the whole scene.
|
||||||
pub fn update(&mut self, duration: &Duration) {
|
pub fn update(&mut self, duration: &Duration) {
|
||||||
|
|
||||||
for c in &mut self.characters {
|
for c in &mut self.characters {
|
||||||
c.update(duration);
|
c.update(duration);
|
||||||
|
|
||||||
|
if c.position.y > 500.0 {
|
||||||
|
c.position.y = 500.0;
|
||||||
|
c.speed.y = 0.0;
|
||||||
|
c.ground_collision();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,22 +46,12 @@ impl Scene {
|
||||||
c.manage_event(event);
|
c.manage_event(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Drawable for Scene {
|
/// Returns a reference to the characters of the scene.
|
||||||
fn draw<'a: 'shader, 'texture, 'shader, 'shader_texture>(
|
pub fn characters(&self) -> &Vec<Character> {
|
||||||
&'a self,
|
&self.characters
|
||||||
target: &mut RenderTarget,
|
}
|
||||||
states: RenderStates<'texture, 'shader, 'shader_texture>
|
|
||||||
) {
|
|
||||||
|
|
||||||
for c in &self.characters {
|
|
||||||
let mut s = RenderStates::default();
|
|
||||||
s.transform = states.transform.clone();
|
|
||||||
s.blend_mode = states.blend_mode;
|
|
||||||
c.draw(target, s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait that needs to be implemented for everything that can be updatable.
|
/// Trait that needs to be implemented for everything that can be updatable.
|
||||||
|
|
|
@ -57,12 +57,13 @@ macro_rules! make_textures {
|
||||||
}
|
}
|
||||||
|
|
||||||
make_textures!(
|
make_textures!(
|
||||||
|
Mario, mario, make_mario_texture, "../../../assets/textures/mario.png",
|
||||||
);
|
);
|
||||||
|
|
||||||
impl TextureManager {
|
impl TextureManager {
|
||||||
/// Creates a textures from an array of bytes.
|
/// Creates a textures from an array of bytes.
|
||||||
fn make_texture_from_bytes(bytes: Vec<u8>) -> SfTexture {
|
fn make_texture_from_bytes(bytes: Vec<u8>) -> SfTexture {
|
||||||
SfTexture::from_memory(&bytes, &IntRect::new(0, 0, 500, 500))
|
SfTexture::from_memory(&bytes, &IntRect::new(0, 0, 256, 256))
|
||||||
.expect("Failed to create texture")
|
.expect("Failed to create texture")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,21 +7,14 @@ use std::time::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use sfml::window::{
|
use sfml::window::{
|
||||||
ContextSettings,
|
|
||||||
Style,
|
|
||||||
Event,
|
Event,
|
||||||
Key,
|
Key,
|
||||||
};
|
};
|
||||||
|
|
||||||
use sfml::graphics::{
|
|
||||||
RenderWindow,
|
|
||||||
RenderTarget,
|
|
||||||
Color,
|
|
||||||
};
|
|
||||||
|
|
||||||
use rusty::engine::scene::Scene;
|
use rusty::engine::scene::Scene;
|
||||||
use rusty::engine::character::Character;
|
use rusty::engine::character::Character;
|
||||||
use rusty::engine::controls::Controls;
|
use rusty::engine::controls::Controls;
|
||||||
|
use rusty::engine::renderer::Renderer;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let game_width = 800;
|
let game_width = 800;
|
||||||
|
@ -32,27 +25,16 @@ fn main() {
|
||||||
|
|
||||||
let mut scene = Scene::new();
|
let mut scene = Scene::new();
|
||||||
scene.add(character);
|
scene.add(character);
|
||||||
scene.add(Character::new());
|
|
||||||
|
|
||||||
let context_settings = ContextSettings {
|
let mut renderer = Renderer::new(game_width, game_height);
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut window = RenderWindow::new(
|
|
||||||
(game_width, game_height),
|
|
||||||
"Free Rusty Maker",
|
|
||||||
Style::CLOSE,
|
|
||||||
&context_settings,
|
|
||||||
);
|
|
||||||
|
|
||||||
window.set_framerate_limit(60);
|
|
||||||
|
|
||||||
|
let mut after_loop = None;
|
||||||
let mut running = true;
|
let mut running = true;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|
||||||
// Manage the events
|
// Manage the events
|
||||||
while let Some(event) = window.poll_event() {
|
while let Some(event) = renderer.poll_event() {
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
// Quit the game if window is closed
|
// Quit the game if window is closed
|
||||||
|
@ -71,15 +53,23 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manage the physics
|
// Manage the physics
|
||||||
// ...
|
let duration = if let Some(instant) = after_loop {
|
||||||
|
Instant::now().duration_since(instant)
|
||||||
|
} else {
|
||||||
|
Duration::from_millis(20)
|
||||||
|
};
|
||||||
|
|
||||||
|
after_loop = Some(Instant::now());
|
||||||
|
|
||||||
|
scene.update(&duration);
|
||||||
|
|
||||||
// Do the rendering
|
// Do the rendering
|
||||||
window.clear(&Color::rgb(50, 200, 50));
|
renderer.clear();
|
||||||
window.draw(&scene);
|
renderer.draw_scene(&scene);
|
||||||
|
|
||||||
// Display and manage the frame rate
|
// Display and manage the frame rate
|
||||||
window.display();
|
renderer.display();
|
||||||
|
|
||||||
|
|
||||||
if ! running {
|
if ! running {
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue