Compare commits
No commits in common. "main" and "dev" have entirely different histories.
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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(())
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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.
Loading…
x
Reference in New Issue
Block a user