Commit 2a99971f authored by Luke Jones's avatar Luke Jones

Re-add simple player object and moving view

Signed-off-by: 's avatarLuke Jones <jones_ld@protonmail.com>
parent ac7d051f
Pipeline #69317965 passed with stage
in 3 minutes and 25 seconds
......@@ -13,18 +13,10 @@ use crate::resource::SpriteSheets;
use crate::vec2d::Vec2d;
/// Create a Player entity at the X,Y coords in the World
pub fn player(
world: &mut World,
x: u32,
y: u32,
sprite_id: &str,
sprite_sheets: &SpriteSheets,
) -> usize {
pub fn player(world: &mut World, x: u32, y: u32, sprite_id: &str) -> usize {
if let Ok(ent) = world.entities.get_free_slot() {
let pos = Vec2d::new(f64::from(x), f64::from(y));
let mut player = Particle::new(1.0, 0.85);
player.set_position(pos);
player.set_position(Vec2d::new(f64::from(x), f64::from(y)));
player.set_acceleration(Vec2d::new(0.0, -9.81));
let id = world.physics_world.add_particle(player).unwrap();
let particle_ptr = world
......@@ -35,7 +27,7 @@ pub fn player(
.entities
.add_part::<ParticleID>(ent, ParticleID { id });
let tx = sprite_sheets.get_ref(sprite_id);
let tx = world.sprite_sheets.get_ref(sprite_id);
let rec = Rect::new(0, 0, tx.width(), tx.height());
world
......
......@@ -23,6 +23,7 @@ impl Position {
}
}
#[derive(Debug)]
pub struct ParticleID {
pub id: usize,
}
......@@ -74,7 +75,7 @@ pub enum InputTypes {
Menu(Bindings),
}
///
#[derive(Debug)]
pub struct Sprite {
pub sid: String,
pub frame: Rect,
......
......@@ -18,7 +18,7 @@ use crate::particle2d::world::World as PhysicsWorld;
use crate::resource::{CachedTile, SpriteSheets};
use crate::vec2d::Vec2d;
use crate::FP;
use tiled_json_rs::{Layer, LayerType, TileLayer};
use tiled_json_rs::{Layer, TileLayer};
pub struct World<'a> {
level_change: bool,
......@@ -98,9 +98,9 @@ impl<'a> World<'a> {
physics_world.add_contact_generator(AreaContact::new(min, max));
let viewport =
Rect::new(0, 0, pixel_width / 1, ((pixel_width / 1) / 4) * 3);
Rect::new(0, 0, pixel_width / 2, ((pixel_width / 2) / 4) * 3);
World {
let mut world = World {
// May need to tweak the final pre-allocated amount. Perhaps vary depending
// on game level loads?
// Use arrays because Vectors shift too much
......@@ -116,7 +116,12 @@ impl<'a> World<'a> {
viewport,
msg_bus: MessageBus::new(),
msg_listeners: Vec::new(),
}
};
let player = create::player(&mut world, 50, 50, "QuakeFace");
dbg!(player);
world
}
pub fn set_player(&mut self, player: usize) {
......@@ -134,8 +139,10 @@ impl<'a> World<'a> {
let pr =
self.physics_world.get_particle_position(p.id).unwrap();
// TODO: fix hardcoded tile size
let world_y = (self.dimensions.y() * 16) as i32;
let pr = Vec2d::new(pr.x() as i32, world_y - pr.y() as i32);
let pr = Vec2d::new(
pr.x() as i32,
self.dimensions.y() as i32 - pr.y() as i32,
);
let limit = 32;
let left_limit = self.viewport.center().x() - limit;
let right_limit = self.viewport.center().x() + limit;
......@@ -177,13 +184,11 @@ impl<'a> World<'a> {
};
}
fn render_tile_layer(&self, tile_layer: &TileLayer) -> Surface {
let mut surface = Surface::new(
self.dimensions.x(),
self.dimensions.y(),
PixelFormatEnum::RGBA32,
)
.unwrap();
fn render_tile_layer(
&self,
tile_layer: &TileLayer,
mut surface: &mut Surface,
) {
for (i, id) in tile_layer.data.iter().enumerate() {
if *id != 0 {
let tile_surface = self.tiles[*id as usize].get_surface_ref();
......@@ -200,29 +205,21 @@ impl<'a> World<'a> {
.expect("failed to blit tile to surface");
}
}
surface
}
fn render_layers(&self, layers: &Vec<Layer>) -> Vec<Surface> {
let mut surf_array: Vec<Surface> = Vec::with_capacity(layers.len());
fn render_layers(&self, layers: &Vec<Layer>, mut surface: &mut Surface) {
for layer in layers {
match &layer.layer_type {
tiled::LayerType::TileLayer(tiles) => {
surf_array.push(self.render_tile_layer(tiles));
self.render_tile_layer(tiles, &mut surface);
}
tiled::LayerType::Group { layers } => {
surf_array.append(&mut self.render_layers(layers));
&mut self.render_layers(layers, surface);
}
tiled::LayerType::ImageLayer(image) => {
let sprite = self
.sprite_sheets
.get_ref(image.image.to_str().unwrap());
let mut surface = Surface::new(
self.dimensions.x(),
self.dimensions.y(),
PixelFormatEnum::RGBA32,
)
.unwrap();
let source_rect = Rect::new(
layer.offset_x.abs() as i32,
layer.offset_y.abs() as i32,
......@@ -232,12 +229,10 @@ impl<'a> World<'a> {
sprite
.blit(Some(source_rect), &mut surface, None)
.expect("failed to blit tile to surface");
surf_array.push(surface);
}
tiled::LayerType::ObjectGroup(objects) => {}
}
}
surf_array
}
/// Updates all active entities using the appropriate systems
......@@ -254,6 +249,9 @@ impl<'a> World<'a> {
// set viewport position
self.update_viewport();
self.active_ents.clear();
self.active_ents.push(self.player);
// input - entities with input and velocity. Player specific, will have defined set of actions
// for example, and elevator input might check positions then switch velocity.
for eid in &self.active_ents {
......@@ -278,11 +276,40 @@ impl<'a> World<'a> {
///
/// Fetch all textures and positions, then draw what is visible.
pub fn render(&mut self, _dt: FP, display_surface: &mut Surface) {
let surf_array = self.render_layers(&self.map);
for surface in surf_array {
surface
.blit_scaled(Some(self.viewport), display_surface, None)
.ok();
let mut tmp_surface = Surface::new(
self.dimensions.x(),
self.dimensions.y(),
PixelFormatEnum::RGBA32,
)
.unwrap();
// render tiles first
self.render_layers(&self.map, &mut tmp_surface);
if let Ok(sprites) = self.entities.borrow::<parts::Sprite>() {
if let Ok(particles) = self.entities.borrow::<parts::ParticleID>() {
for (id, sprite) in sprites.get() {
if let Ok(particleID) = particles.get_part_ref(id) {
if let Some(position) = self
.physics_world
.get_particle_position(particleID.id)
{
let mut dst = sprite.frame;
dst.set_x(position.x() as i32);
dst.set_y(
self.dimensions.y() as i32
- position.y() as i32,
);
let surf = self.sprite_sheets.get_ref(&sprite.sid);
surf.blit(None, &mut tmp_surface, Some(dst)).ok();
}
}
}
}
}
// now draw result to display surface
tmp_surface
.blit_scaled(Some(self.viewport), display_surface, None)
.ok();
}
}
......@@ -2,12 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use sdl2::pixels::Color as SdlColour;
use sdl2::surface::Surface as SdlSurface;
use sdl2::{pixels::Color, surface::Surface};
use super::GameState;
use crate::controls::{Bindings, Input};
use crate::FP;
use crate::{
controls::{Bindings, Input},
states::GameState,
FP,
};
pub struct Menu {
id: String,
......@@ -22,8 +23,8 @@ impl Menu {
impl GameState for Menu {
fn update(&mut self, _dt: FP, _input: &Input, _bindings: &mut Bindings) {}
fn render(&mut self, _dt: FP, sdl_surface: &mut SdlSurface) {
let alive = SdlColour::RGB(200, 200, 230);
fn render(&mut self, _dt: FP, sdl_surface: &mut Surface) {
let alive = Color::RGB(200, 200, 230);
sdl_surface.fill_rect(None, alive).unwrap();
}
fn enter(&mut self) {}
......
......@@ -17,15 +17,10 @@ use std::collections::VecDeque;
/// Required traits for proper interaction with each state
pub trait GameState {
/// A game state performs input checking against control bindings, and updates active objects.
///
/// General I/O will happen here
fn update(&mut self, dt: FP, input: &Input, bindings: &mut Bindings);
/// Calls the `draw()` method on all active objects
///
/// The state should call `draw()` for all active objects.
/// A mutable surface needs be passed in to the state for which to blit objects to.
/// The surface is then rendered to screen by the game loop.
/// Rendering is separated from updates so that both can run at different speeds
fn render(&mut self, dt: FP, sdl_surface: &mut SdlSurface);
/// Called when the state is entered
......@@ -33,13 +28,13 @@ pub trait GameState {
/// This is where any set-up methods should live, such as level loading, object loading
fn enter(&mut self);
/// Called on the state below the popped state
fn resume(&mut self);
/// Called on the existing state when a new state is pushed on top
fn pause(&mut self);
/// Called when the state exits
///
/// An example of use here would be to save the current `play` state.
fn exit(&mut self);
/// Returns the state ID, used for checking which state is active
......@@ -58,17 +53,6 @@ impl States {
}
/// Push a new state on to the queue
///
/// ```rust
/// # extern crate framework;
/// # use framework::manager::states::States;
/// # use framework::states::menu::*;
/// # fn main() {
/// let mut states = States::new(1024, 768);
/// states.push(Box::new(Menu::new()));
/// assert_eq!(states.get_state_id().unwrap(), "_MENU")
/// # }
/// ```
pub fn push(&mut self, state: impl GameState + 'static) {
// Call pause on the currently running state
if let Some(state) = self.game_states.back_mut() {
......@@ -81,21 +65,6 @@ impl States {
}
/// Pop the active state from the queue
///
/// ```rust
/// # extern crate framework;
/// # use framework::manager::states::States;
/// # use framework::states::menu::*;
/// # use framework::states::play::*;
/// # fn main() {
/// let mut states = States::new(1024, 768);
/// states.push(Box::new(Menu::new()));
/// states.push(Box::new(Play::new()));
/// # assert_eq!(states.get_state_id().unwrap(), "_PLAY");
/// states.pop();
/// assert_eq!(states.get_state_id().unwrap(), "_MENU")
/// # }
/// ```
pub fn pop(&mut self) {
if let Some(state) = &mut self.game_states.pop_back() {
state.exit();
......@@ -108,19 +77,6 @@ impl States {
/// Change the active state
///
/// Swaps the active state in the Queue for the one requested
///
/// ```rust
/// # extern crate framework;
/// # use framework::manager::states::States;
/// # use framework::states::menu::*;
/// # use framework::states::play::*;
/// # fn main() {
/// let mut states = States::new(1024, 768);
/// states.push(Box::new(Menu::new()));
/// states.change(Box::new(Play::new()));
/// assert_eq!(states.get_state_id().unwrap(), "_PLAY")
/// # }
/// ```
pub fn change(&mut self, state: impl GameState + 'static) {
if let Some(st) = self.game_states.back() {
if st.get_id() == state.get_id() {
......
......@@ -2,12 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use sdl2::pixels::Color as SdlColour;
use sdl2::surface::Surface as SdlSurface;
use sdl2::{pixels::Color, surface::Surface};
use super::GameState;
use crate::controls::{Bindings, Input};
use crate::FP;
use crate::{
controls::{Bindings, Input},
states::GameState,
FP,
};
pub struct Pause {
id: String,
......@@ -22,8 +23,8 @@ impl Pause {
impl GameState for Pause {
fn update(&mut self, _dt: FP, _input: &Input, _bindings: &mut Bindings) {}
fn render(&mut self, _dt: FP, sdl_surface: &mut SdlSurface) {
let alive = SdlColour::RGB(60, 1, 1);
fn render(&mut self, _dt: FP, sdl_surface: &mut Surface) {
let alive = Color::RGB(60, 1, 1);
sdl_surface.fill_rect(None, alive).unwrap();
}
fn enter(&mut self) {}
......
......@@ -2,29 +2,22 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use sdl2::pixels::Color;
use sdl2::surface::Surface;
use sdl2::{pixels::Color, surface::Surface};
use crate::controls::{Bindings, Input};
use crate::manager::world::World;
use crate::{
controls::{Bindings, Input},
manager::world::World,
states::GameState,
FP,
};
use super::GameState;
use crate::FP;
use std::path::PathBuf;
pub struct Play<'a> {
id: String,
world: World<'a>,
}
// Note: test sprite for tiles is 256x128, 16x8 h/w = 16x16
///
/// The `Play` module is used to;
/// * keep track of game entities
/// * update the entities per game tick
/// * handle any input/commands to the game or current player object.
/// * render the results to a surface that `States::update()` gives it
///
impl<'a> Play<'a> {
pub fn new() -> Play<'a> {
Play {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment