Skip to content
This repository has been archived by the owner on Mar 26, 2024. It is now read-only.

Collision system #114

Open
wants to merge 14 commits into
base: dev
Choose a base branch
from
Open
687 changes: 402 additions & 285 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions rask-engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ lazy_static = "1.4.0"
ouroboros = "0.5"
specs-hierarchy = "0.6"
spin = {version = "0.5", optional = false}
shrev = "1.1"
hibitset = "0.6"
11 changes: 10 additions & 1 deletion rask-engine/src/boxes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use core::ops;

use crate::math::Vec2;
use crate::math::{Mat2, Mat3, Vec2, Vec3};

/// An axis-aligned box.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -156,3 +156,12 @@ impl From<&spine::skeleton::srt::SRT> for RBox {
RBox { pos, v1, v2 }
}
}

impl From<&Mat3> for RBox {
fn from(mat: &Mat3) -> RBox {
let pos = (*mat * Vec3::new(-1.0, -1.0, 1.0)).into();
let v1 = (*mat * Vec3::new(0.0, 2.0, 0.0)).into();
let v2 = (*mat * Vec3::new(2.0, 0.0, 0.0)).into();
RBox { pos, v1, v2 }
}
}
39 changes: 39 additions & 0 deletions rask-engine/src/collide.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ use crate::math::{Vec2, EPSILON};
/// A trait for objects that can collide with other objects.
pub trait Collide<Rhs = Self> {
/// calculate the penetration depth (a scalar ratio of `dv`)
/// as well as the normal of the colliding edge
/// of the collision after applying the velocity,
/// if there was any.
/// `dv` is the difference between the two velocities
fn collide_after(&self, other: &Rhs, dv: Vec2) -> Option<f32>;
}

#[derive(Debug, Clone)]
pub enum Collidable {
Point(Vec2),
AABox(AABox),
Expand All @@ -37,6 +39,23 @@ impl Collide for Collidable {
}
}

impl Collidable {
pub fn shift(&mut self, dv: Vec2) {
*self = match self {
Collidable::AABox(a) => Collidable::AABox(AABox {
pos: a.pos + dv,
size: a.size,
}),
Collidable::RBox(r) => Collidable::RBox(RBox {
pos: r.pos + dv,
v1: r.v1,
v2: r.v2,
}),
Collidable::Point(p) => Collidable::Point(*p + dv),
}
}
}

// Given a fraction of the dv vectors length,
// return the amount to set the objects back
// in case of a collision
Expand All @@ -60,6 +79,26 @@ macro_rules! impl_collide {
Self::$C(other)
}
}

impl Collide<$A> for Collidable {
fn collide_after(&self, other: &$A, dv: Vec2) -> Option<f32> {
match self {
Collidable::Point(s) => s.collide_after(other, dv),
Collidable::AABox(s) => s.collide_after(other, dv),
Collidable::RBox(s) => s.collide_after(other, dv),
}
}
}

impl Collide<Collidable> for $A {
fn collide_after(&self, other: &Collidable, dv: Vec2) -> Option<f32> {
match other {
Collidable::Point(s) => self.collide_after(s, dv),
Collidable::AABox(s) => self.collide_after(s, dv),
Collidable::RBox(s) => self.collide_after(s, dv),
}
}
}
};
(for {$A:ident, $B:ident} $item:item) => {
impl Collide<$B> for $A {
Expand Down
75 changes: 68 additions & 7 deletions rask-engine/src/engine/components.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use crate::collide::Collidable;
use crate::io;
use crate::math::Vec2;
use crate::math::{Mat3, Vec2};
use crate::resources::{
self,
registry::{CharacterInfo, ResourceInfo},
};
use specs::{prelude::*, Component};
use specs_hierarchy::Parent as PParent;
use specs_hierarchy::{Hierarchy, Parent as PParent};
use std::collections::HashMap;

#[derive(Debug, Default)]
pub struct Gravitation(pub Vec2);
Expand Down Expand Up @@ -42,11 +44,15 @@ impl PParent for Parent {
}
}

#[derive(Debug, Clone, Copy, Component)]
#[derive(Debug, Clone, Copy, Default, Component)]
#[storage(VecStorage)]
pub struct Vel(pub Vec2);

#[derive(Debug, Clone, Copy, Component)]
#[derive(Debug, Clone, Copy, Default, Component)]
#[storage(VecStorage)]
pub struct DeltaVel(pub Vec2);

#[derive(Debug, Clone, Copy, Default, Component)]
#[storage(VecStorage)]
pub struct Pos(pub Vec2);

Expand All @@ -55,12 +61,58 @@ pub struct Pos(pub Vec2);
pub struct Speed(pub f32);

#[derive(Debug, Clone, Component)]
#[storage(DenseVecStorage)]
pub struct Health {
pub value: u32,
pub max_value: u32,
}

#[derive(Debug, Clone, Component)]
pub struct Damaging {
pub damage: f32,
}

#[derive(Debug, Clone, Component)]
pub struct Vulnerable {
pub armor: f32,
}

#[derive(Debug, Default, Clone, Component)]
#[storage(NullStorage)]
pub struct Terrain;

#[derive(Debug, Clone)]
pub struct SubCollider {
pub collider: Collidable,
}

impl Component for SubCollider {
type Storage = FlaggedStorage<Self, DenseVecStorage<Self>>;
}

#[derive(Debug, Clone)]
pub enum HitboxType {
Damaging,
Vulnerable,
Repulsion,
}

#[derive(Debug, Clone, Component)]
pub struct Collider {
pub mapping: HashMap<u32, HitboxType>,
pub default: HitboxType,
}

#[derive(Debug, Clone)]
pub struct Animation {
pub id: u32,
pub animation: String,
pub start: f32,
}

impl Component for Animation {
type Storage = FlaggedStorage<Self, DenseVecStorage<Self>>;
}

#[derive(Debug, Clone, Component)]
#[storage(VecStorage)]
pub struct Scale(pub Vec2);
Expand All @@ -69,11 +121,20 @@ pub struct Scale(pub Vec2);
#[storage(VecStorage)]
pub struct Sprite {
pub id: u32,
pub sub_id: u64,
}

#[derive(Debug, Default, Clone, Component)]
pub struct Transform(pub Mat3);

impl Transform {
pub fn shift(&mut self, vec: Vec2) {
self.0 = Mat3::translation(vec.x(), vec.y()) * self.0
}
}

#[derive(Debug, Default, Clone, Copy, Component)]
#[storage(NullStorage)]
pub struct Static;
pub struct Mass(pub f32);

#[derive(Debug, Default, Clone, Copy, Component)]
#[storage(NullStorage)]
Expand Down
68 changes: 62 additions & 6 deletions rask-engine/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use core::time::Duration;
use specs::prelude::*;
use specs::WorldExt;
use specs_hierarchy::{Hierarchy, HierarchySystem};
use std::collections::HashMap;

mod components;
mod systems;
Expand Down Expand Up @@ -56,32 +57,87 @@ impl GameEngine for RaskEngine {
.with(UpdateAnimationSystem, "update_anim", &["check_present"])
.with(MovementSystem, "movement", &["events"])
.with(GravitationSystem, "gravitation", &["movement"])
.with(VelocitySystem, "velocity", &["gravitation"])
.with(UpdateAnimationSystem, "update_anim", &["movement"])
.with(
SimpleVelocitySystem,
"simple_velocity",
&["gravitation", "update_anim"],
)
.with(VelocitySystem, "velocity", &["gravitation", "update_anim"])
.with_thread_local(RenderSystem)
.build();

tick_dispatcher.setup(&mut world);
let _backround = world

let _background = world
.create_entity()
.with(Pos(Vec2::new(0.0, 0.0)))
.with(Sprite {
id: registry::EMPTY.id,
sub_id: 0,
})
.with(Terrain)
.with(Collider {
mapping: HashMap::new(),
default: HitboxType::Repulsion,
})
.with(Scale(Vec2::new(1.0, 1.0)))
.with(Static)
.build();
let _ground = world
.create_entity()
.with(Pos(Vec2::new(-2.0, -1.0)))
.with(Scale(Vec2::new(6.0, 0.15)))
.with(Sprite {
id: registry::EMPTY.id,
sub_id: 0,
})
.with(SubCollider {
collider: crate::boxes::AABox {
pos: Vec2::new(-2.0, -1.0),
size: Vec2::new(6.0, 0.15),
}
.into(),
})
.with(Parent {
entity: _background,
})
.build();
let _ground = world
.create_entity()
.with(Sprite {
id: registry::EMPTY.id,
sub_id: 0,
})
.with(Pos(Vec2::new(1.0, -1.0)))
.with(Scale(Vec2::new(1.0, 0.5)))
.with(SubCollider {
collider: crate::boxes::AABox {
pos: Vec2::new(0.0, -1.0),
size: Vec2::new(2.0, 0.5),
}
.into(),
})
.with(Parent {
entity: _background,
})
.build();
let _char = world
.create_entity()
.with(Pos(Vec2::new(0.0, -0.8)))
.with(Pos(Vec2::new(0.3, 0.0)))
.with(Vel(Vec2::new(0.0, 0.0)))
.with(Speed(0.2))
.with(DeltaVel(Vec2::zero()))
.with(Speed(0.4))
.with(Mass(1.0))
.with(Animation {
id: registry::CHAR.id,
animation: "walking".to_string(),
start: 0.0,
})
.with(Collider {
mapping: HashMap::new(),
default: HitboxType::Vulnerable,
})
.with(Scale(Vec2::new(1.0, 1.0)))
.with(Static)
.build();
Self {
world,
Expand Down
Loading