Compare commits

..

No commits in common. "main" and "dev" have entirely different histories.
main ... dev

7 changed files with 95 additions and 247 deletions

View File

@ -28,12 +28,4 @@ impl Bbox {
size,
}
}
/// Returns true is the two bboxes overlap.
pub fn overlap(self, rhs: Bbox) -> bool {
rhs.position.x < self.position.x + self.size.x
&& rhs.position.x + rhs.size.x > self.position.x
&& rhs.position.y < self.position.y + self.size.y
&& rhs.position.y + rhs.size.y > self.position.y
}
}

View File

@ -302,10 +302,4 @@ impl Inputs {
let mut inner = self.0.borrow_mut();
inner.events.pop_front()
}
/// Deletes all the events and resets all the values.
pub fn clear(&mut self) {
let mut inner = self.0.borrow_mut();
inner.events.clear();
}
}

View File

@ -94,32 +94,6 @@ impl CollisionAxis {
_ => true,
}
}
/// Adds another collision axis.
pub fn and(self, other: CollisionAxis) -> CollisionAxis {
match (self, other) {
(CollisionAxis::X, CollisionAxis::X) => CollisionAxis::X,
(CollisionAxis::X, CollisionAxis::Y) => CollisionAxis::Both,
(CollisionAxis::Y, CollisionAxis::X) => CollisionAxis::Both,
(CollisionAxis::Y, CollisionAxis::Y) => CollisionAxis::Y,
(CollisionAxis::Both, _) => CollisionAxis::Both,
(_, CollisionAxis::Both) => CollisionAxis::Both,
}
}
/// Adds another collision axis to options.
pub fn and_option(first: Option<CollisionAxis>, other: CollisionAxis) -> Option<CollisionAxis> {
Some(match (first, other) {
(None, CollisionAxis::X) => CollisionAxis::X,
(None, CollisionAxis::Y) => CollisionAxis::Y,
(Some(CollisionAxis::X), CollisionAxis::X) => CollisionAxis::X,
(Some(CollisionAxis::X), CollisionAxis::Y) => CollisionAxis::Both,
(Some(CollisionAxis::Y), CollisionAxis::X) => CollisionAxis::Both,
(Some(CollisionAxis::Y), CollisionAxis::Y) => CollisionAxis::Y,
(Some(CollisionAxis::Both), _) => CollisionAxis::Both,
(_, CollisionAxis::Both) => CollisionAxis::Both,
})
}
}
/// This struct represents the different sides from which a collision can occur.
@ -172,7 +146,7 @@ impl CollisionTile {
/// This struct represents a renderable tile linking to its part in the tileset texture.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct GraphicTile(pub Option<i32>);
pub struct GraphicTile(Option<i32>);
impl GraphicTile {
/// Creates the correct graphic tile depending on the neighbours.
@ -256,82 +230,6 @@ pub struct PositionedTile {
pub position: Vector,
}
impl PositionedTile {
/// Returns the collision information between a collision tile and a moving object.
pub fn collides(self, old: Bbox, new: Bbox) -> Option<(CollisionAxis, Vector)> {
let mut collision_x = false;
let mut collision_y = false;
let mut new = new;
let tile = Bbox::new(self.position.x, self.position.y, SPRITE_SIZE, SPRITE_SIZE);
loop {
// I know, this loop is ugly, but I don't care
if !new.overlap(tile) {
break;
}
// Collisions between feet and ground
if self.collision.from_top
&& old.position.y + old.size.y <= tile.position.y
&& new.position.y + new.size.y >= tile.position.y
{
collision_y = true;
new.position.y = tile.position.y - new.size.y;
}
if !new.overlap(tile) {
break;
}
// Collisions between right and right wall
if self.collision.from_left
&& old.position.x + old.size.x <= tile.position.x
&& new.position.x + new.size.x >= tile.position.x
{
collision_x = true;
new.position.x = tile.position.x - new.size.x;
}
if !new.overlap(tile) {
break;
}
// Collisions between left and left wall
if self.collision.from_right
&& old.position.x >= tile.position.x + SPRITE_SIZE
&& new.position.x <= tile.position.x + SPRITE_SIZE
{
collision_x = true;
new.position.x = tile.position.x + SPRITE_SIZE;
}
if !new.overlap(tile) {
break;
}
// Collisions between head and roof
if self.collision.from_bottom
&& old.position.y >= tile.position.y + SPRITE_SIZE
&& new.position.y <= tile.position.y + SPRITE_SIZE
{
collision_y = true;
new.position.y = tile.position.y + SPRITE_SIZE;
}
break;
}
match (collision_x, collision_y) {
(true, true) => Some((CollisionAxis::Both, new.position)),
(true, false) => Some((CollisionAxis::X, new.position)),
(false, true) => Some((CollisionAxis::Y, new.position)),
(false, false) => None,
}
}
}
impl Drawable for PositionedTile {
fn texture(&self) -> Texture {
Texture::Overworld
@ -574,15 +472,67 @@ impl Map {
rows as f64,
) as usize;
let mut collision_axis: Option<CollisionAxis> = None;
let mut collision_x = false;
let mut collision_y = false;
let mut new = new;
for col in min_col..=max_col {
for row in min_row..=max_row {
if let Some((axis, new_pos)) = self.at(row, col).collides(old, new) {
new.position = new_pos;
collision_axis = CollisionAxis::and_option(collision_axis, axis);
let tile_left = col as f64 * SPRITE_SIZE;
let tile_top = row as f64 * SPRITE_SIZE;
let tile = Bbox::new(tile_left, tile_top, SPRITE_SIZE, SPRITE_SIZE);
if !overlap(new, tile) {
continue;
}
// Collisions between feet and ground
if self.collision_tiles[(row, col)].from_top
&& old.position.y + old.size.y <= tile_top
&& new.position.y + new.size.y >= tile_top
{
collision_y = true;
new.position.y = tile_top - new.size.y;
}
if !overlap(new, tile) {
continue;
}
// Collisions between right and right wall
if self.collision_tiles[(row, col)].from_left
&& old.position.x + old.size.x <= tile_left
&& new.position.x + new.size.x >= tile_left
{
collision_x = true;
new.position.x = tile_left - new.size.x;
}
if !overlap(new, tile) {
continue;
}
// Collisions between left and left wall
if self.collision_tiles[(row, col)].from_right
&& old.position.x >= tile_left + SPRITE_SIZE
&& new.position.x <= tile_left + SPRITE_SIZE
{
collision_x = true;
new.position.x = tile_left + SPRITE_SIZE;
}
if !overlap(new, tile) {
continue;
}
// Collisions between head and roof
if self.collision_tiles[(row, col)].from_bottom
&& old.position.y >= tile_top + SPRITE_SIZE
&& new.position.y <= tile_top + SPRITE_SIZE
{
collision_y = true;
new.position.y = tile_top + SPRITE_SIZE;
}
}
}
@ -590,25 +540,35 @@ impl Map {
// Collision between the player and left border of the level
if new.position.x < 0.0 {
new.position.x = 0.0;
collision_axis = CollisionAxis::and_option(collision_axis, CollisionAxis::X);
collision_x = true;
}
// Collision between the player and right border of the level
if new.position.x > cols as f64 * SPRITE_SIZE {
new.position.x = cols as f64 * SPRITE_SIZE;
collision_axis = CollisionAxis::and_option(collision_axis, CollisionAxis::Y);
collision_x = true;
}
// Collision between the player and the void
if new.position.y > self.collision_tiles.rows() as f64 * SPRITE_SIZE {
new.position.y = self.collision_tiles.rows() as f64 * SPRITE_SIZE;
collision_y = true;
death = true;
}
if let Some(collision_axis) = collision_axis {
Some((collision_axis, new.position, death))
} else {
None
match (collision_x, collision_y) {
(true, true) => Some((CollisionAxis::Both, new.position, death)),
(true, false) => Some((CollisionAxis::X, new.position, death)),
(false, true) => Some((CollisionAxis::Y, new.position, death)),
(false, false) => None,
}
}
}
/// Checks if two boxes overlap.
pub fn overlap(box1: Bbox, box2: Bbox) -> bool {
box2.position.x < box1.position.x + box1.size.x
&& box2.position.x + box2.size.x > box1.position.x
&& box2.position.y < box1.position.y + box1.size.y
&& box2.position.y + box2.size.y > box1.position.y
}

View File

@ -6,7 +6,6 @@ pub mod controls;
pub mod input;
pub mod map;
pub mod math;
pub mod object;
pub mod physics;
pub mod scene;
pub mod texture;
@ -56,6 +55,17 @@ impl Game {
/// Creates a new game.
pub fn new() -> Result<Game> {
Ok(Game(Rc::new(RefCell::new(Engine::new()?))))
// let clone = inner.clone();
// let cb = Closure::<dyn FnMut(_)>::new(move |event: web_sys::GamepadEvent| {
// let mut inner = clone.borrow_mut();
// inner.add_gamepad(&event);
// });
// (*window)
// .add_event_listener_with_callback("gamepadconnected", cb.as_ref().unchecked_ref())?;
// cb.forget();
}
/// Starts the game.
@ -125,11 +135,6 @@ pub struct Engine {
/// The web page document.
pub document: web_sys::Document,
/// The canvas.
///
/// We keep it to easily know the size.
pub canvas: web_sys::HtmlCanvasElement,
/// The canvas rendering context.
///
/// We keep a reference so that we can easily render things.
@ -167,7 +172,6 @@ impl Engine {
inputs: Inputs::new(&window)?,
window,
document,
canvas,
context,
performance,
})
@ -220,9 +224,6 @@ impl Engine {
self.scene = scene;
}
} else {
// Clear the events received while document was out of focus
self.inputs.clear();
}
Ok(())
@ -230,30 +231,13 @@ impl Engine {
/// Performs the rendering of the engine.
pub fn render(&self) -> Result<()> {
let window_width = unwrap!(self.window.inner_width()?.as_f64());
let window_height = unwrap!(self.window.inner_height()?.as_f64());
let window_width_u32 = window_width as u32;
let window_height_u32 = window_height as u32;
if window_width_u32 != self.canvas.width() {
self.canvas.set_width(window_width_u32);
}
if window_height_u32 != self.canvas.height() {
self.canvas.set_height(window_height_u32);
}
let window_size = Vector::new(window_width, window_height);
let view = self.scene.view().unwrap(); // TODO remove this unwrap
// Clear render
self.context
.clear_rect(0.0, 0.0, window_width, window_height);
self.context.clear_rect(0.0, 0.0, 1920.0, 1080.0);
self.context
.set_fill_style(&JsValue::from_str("rgb(135, 206, 235)"));
self.context
.fill_rect(0.0, 0.0, window_width, window_height);
self.context.fill_rect(0.0, 0.0, 1920.0, 1080.0);
// Draw the scene
let map = self.scene.map();
@ -264,20 +248,15 @@ impl Engine {
for j in 0..cols {
let tile = map.at(i, j);
if tile.graphic.is_visible() {
self.draw(&tile, view, window_size)?;
self.draw(&tile, view)?;
}
}
}
// Draw the objects
for o in self.scene.objects() {
self.draw(o, view, window_size)?;
}
// Draw characters
for c in self.scene.characters() {
if true {
self.draw(c, view, window_size)?;
self.draw(c, view)?;
}
}
@ -285,20 +264,16 @@ impl Engine {
}
/// Draw a drawable.
pub fn draw<D: Drawable>(&self, drawable: &D, view: Bbox, window: Vector) -> Result<()> {
pub fn draw<D: Drawable>(&self, drawable: &D, view: Bbox) -> Result<()> {
let image = self.textures.get(drawable.texture());
let source = drawable.texture_rect(self.after_loop);
let mut dest = source.clone();
// Without view
// dest.position = drawable.position();
// With view
dest.position = drawable.position() - view.position;
dest.position.x *= window.x / view.size.x;
dest.position.y *= window.y / view.size.y;
dest.size.x *= window.x / view.size.x;
dest.size.y *= window.y / view.size.y;
dest.position.x *= 1920.0 / view.size.x;
dest.position.y *= 1080.0 / view.size.y;
dest.size.x *= 1920.0 / view.size.x;
dest.size.y *= 1080.0 / view.size.y;
image.render(source, dest, &self.context)?;
Ok(())

View File

@ -1,35 +0,0 @@
//! This module contains objects that are not characters.
use std::time::SystemTime;
use crate::engine::bbox::Bbox;
use crate::engine::texture::{Texture, SPRITE_SIZE};
use crate::engine::vector::Vector;
use crate::engine::Drawable;
/// An object that can collide with the character.
pub struct Object {
/// The initial position of the object.
pub position: Vector,
}
impl Object {
/// Creates a new object.
pub fn new(position: Vector) -> Object {
Object { position }
}
}
impl Drawable for Object {
fn texture(&self) -> Texture {
Texture::Overworld
}
fn texture_rect(&self, _now: SystemTime) -> Bbox {
Bbox::new(46.0 * SPRITE_SIZE, 0.0, SPRITE_SIZE, SPRITE_SIZE)
}
fn position(&self) -> Vector {
self.position
}
}

View File

@ -6,19 +6,14 @@ use crate::engine::bbox::Bbox;
use crate::engine::character::Character;
use crate::engine::input::Action;
use crate::engine::input::InputManager;
use crate::engine::map::{CollisionTile, GraphicTile, Map, PositionedTile};
use crate::engine::object::Object;
use crate::engine::map::Map;
use crate::engine::texture::SPRITE_SIZE;
use crate::engine::vector::Vector;
/// Contains everything needed to play.
pub struct Scene {
/// The characters contained in the scene.
characters: Vec<Character>,
/// The objects contained in the scene.
objects: Vec<Object>,
/// The map of the scene.
map: Map,
}
@ -36,10 +31,8 @@ pub enum State {
impl Scene {
/// Creates a scene from a map level.
pub fn from_map(map: Map) -> Scene {
let object = Object::new(Vector::new(100.0, 300.0));
Scene {
characters: vec![],
objects: vec![object],
map,
}
}
@ -53,11 +46,6 @@ impl Scene {
self.characters.push(character);
}
/// Adds an object to the scene.
pub fn add_object(&mut self, object: Object) {
self.objects.push(object);
}
/// Returns the controlable.
pub fn controlable(&self) -> Option<&Character> {
for character in &self.characters {
@ -127,7 +115,6 @@ impl Scene {
if axis.is_x() {
c.speed.x = 0.0;
}
if axis.is_y() {
c.speed.y = 0.0;
c.ground_collision();
@ -140,26 +127,6 @@ impl Scene {
} else {
c.fall_off();
}
for object in &self.objects {
let positioned = PositionedTile {
graphic: GraphicTile(None),
collision: CollisionTile::full(),
position: object.position,
};
if let Some((axis, position)) = positioned.collides(old, c.bbox()) {
c.position = position - offset;
if axis.is_x() {
c.speed.x = 0.0;
}
if axis.is_y() {
c.speed.y = 0.0;
c.ground_collision();
}
}
}
}
}
@ -182,11 +149,6 @@ impl Scene {
pub fn map(&self) -> &Map {
&self.map
}
/// Returns a reference to the objects of the scene.
pub fn objects(&self) -> &Vec<Object> {
&self.objects
}
}
/// Trait that needs to be implemented for everything that can be updatable.

Binary file not shown.