Skip to content
This repository has been archived by the owner on Apr 29, 2021. It is now read-only.

Commit

Permalink
Reworked entity hitboxes
Browse files Browse the repository at this point in the history
  • Loading branch information
VictorKoenders committed Jan 21, 2017
1 parent 818d35d commit 9592a77
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 124 deletions.
11 changes: 7 additions & 4 deletions assets/color_shader.vert
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
#version 140

in vec2 position;
in vec2 dimension_affinity;

uniform vec4 color;
out vec4 v_color;

uniform mat3 matrix;
uniform vec2 screen_size;
uniform vec2 offset;
uniform vec2 dimensions;

void main() {
v_color = color;

vec3 actual_position = matrix * vec3(position, 1.0);

vec3 actual_position = vec3(
offset + (dimension_affinity * dimensions)
, 1.0);
gl_Position = vec4((actual_position.x/screen_size.x)*2.0 - 1.0, 1.0 - (actual_position.y/screen_size.y)*2.0, 0.0, 1.0);
}
Binary file added assets/you_lost.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 25 additions & 9 deletions src/engine/entity.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
use super::{Result, Engine, EngineGraphics, KeyboardState};
use rand::{ThreadRng, Rng};
use std::any::Any;

// TODO: Implement something like this:
#[derive(PartialEq)]
pub enum CollisionResult {
}

pub enum UpdateResult {
/*
// TODO: Add collision layers where entities are on a layer and can determine what layers they collide with
pub enum CollisionLayer {
None,
Player,
Enemy,
}
*/
pub enum EntityEvent {
ClearAllEntities,
SpawnEntity(Box<EntityTrait>),
}

/*
// TODO: This always returns Option::None
pub trait EntityCastTrait {
fn as_type<T: Any>(&self) -> Option<&Box<&T>>;
}
Expand All @@ -20,8 +28,13 @@ impl EntityCastTrait for Box<EntityTrait> {
any.downcast_ref::<Box<&T>>()
}
}
*/


pub trait EntityTrait {
fn identifying_string(&self) -> String;
//fn collision_layers(&self) -> Vec<CollisionLayer> { Vec::new() }
//fn collides_with_layers(&self) -> Vec<CollisionLayer> { Vec::new() }
fn draw(&self, _state: &EntityState, _graphics: &mut EngineGraphics) -> Result<()> {
Ok(())
}
Expand All @@ -31,14 +44,15 @@ pub trait EntityTrait {
fn update(&mut self,
_game_state: &mut GameState,
_entity_state: &mut EntityState)
-> Vec<UpdateResult> {
-> Vec<EntityEvent> {
Vec::new()
}
fn collided(&self,
_self_state: &EntityState,
fn collided(&mut self,
_self_state: &mut EntityState,
_other: &Box<EntityTrait>,
_other_state: &EntityState)
-> Vec<CollisionResult> {
_other_state: &mut EntityState,
_graphics: &EngineGraphics)
-> Vec<EntityEvent> {
Vec::new()
}

Expand Down Expand Up @@ -86,6 +100,7 @@ impl<'a> GameState<'a> {
pub struct EntityWrapper {
pub entity: Box<EntityTrait>,
pub state: EntityState,
pub name: String,
}

pub struct EntityState {
Expand All @@ -110,6 +125,7 @@ impl EntityWrapper {
pub fn new(entity: Box<EntityTrait>, engine: &Engine) -> EntityWrapper {
EntityWrapper {
state: entity.get_initial_state(engine),
name: entity.identifying_string(),
entity: entity,
}
}
Expand Down
209 changes: 117 additions & 92 deletions src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,49 +28,17 @@ pub struct Engine {
pub rng: ::rand::ThreadRng,
}

pub struct EngineGraphics {
pub display: GlutinFacade,
pub textured_program: Program,
pub color_program: Program,
pub frame: Option<Frame>,
pub width: f32,
pub height: f32,
}

impl Engine {
pub fn new(width: f32, height: f32) -> Result<Engine> {
let display = WindowBuilder::new().with_dimensions(width as u32, height as u32)
.with_min_dimensions(width as u32, height as u32)
.with_max_dimensions(width as u32, height as u32)
.with_vsync()
.build_glium()?;
let textured_program =
Program::from_source(&display,
include_str!("../../assets/textured_shader.vert"),
include_str!("../../assets/textured_shader.frag"),
None)?;
let color_program = Program::from_source(&display,
include_str!("../../assets/color_shader.vert"),
include_str!("../../assets/color_shader.frag"),
None)?;

println!("{:?}", display.get_opengl_version());

Ok(Engine {
graphics: EngineGraphics {
display: display,
textured_program: textured_program,
color_program: color_program,
frame: None,
width: width,
height: height,
},
let engine = Engine {
graphics: EngineGraphics::new(width, height)?,
keyboard: KeyboardState::default(),
running: true,
last_update_time: self::time::get(),
entities: Vec::new(),
rng: ::rand::thread_rng(),
})
};
Ok(engine)
}

pub fn register_entity<T: EntityTrait + 'static>(&mut self, entity: T) {
Expand All @@ -96,9 +64,48 @@ impl Engine {
Ok(())
}

fn handle_event(&mut self, events: Vec<EntityEvent>) {
for result in events.into_iter() {
match result {
EntityEvent::SpawnEntity(entity) => {
let wrapper = EntityWrapper::new(entity, self);
self.entities.push(wrapper);
},
EntityEvent::ClearAllEntities => {
self.entities.clear();
}
}
}
}

fn check_collisions(&mut self) {
let events = {
let mut events = Vec::new();
let ref mut slice = self.entities[..];
for i in 1..slice.len() {
let (ref mut first, ref mut remaining) = slice.split_at_mut(i);
let ref mut first = first.last_mut().unwrap();
for ref mut second in remaining.iter_mut() {
if first.entity.intersects_with(&first.state, &second.entity, &second.state) {
let results = first.entity.collided(&mut first.state, &second.entity, &mut second.state, &self.graphics);
events.extend(results.into_iter());
}
if second.entity.intersects_with(&second.state, &first.entity, &first.state) {
let results = second.entity.collided(&mut second.state, &first.entity, &mut first.state, &self.graphics);
events.extend(results.into_iter());
}
}
}
events
};

self.handle_event(events);
}

pub fn update_entities(&mut self) {
let delta_time = self::time::since(&mut self.last_update_time) as f32;
let mut spawned_entities: Vec<Box<EntityTrait>> = Vec::new();

let mut events = Vec::new();

for entity in &mut self.entities {
let mut state = GameState {
Expand All @@ -109,32 +116,14 @@ impl Engine {
rng: &mut self.rng,
};
let update_result = entity.entity.update(&mut state, &mut entity.state);
for result in update_result.into_iter() {
match result {
UpdateResult::SpawnEntity(e) => spawned_entities.push(e),
}
}
events.extend(update_result.into_iter());
}

for i in 0..self.entities.len() {
for j in i + 1..self.entities.len() {
let ref first = self.entities[i];
let ref second = self.entities[j];
if first.entity.intersects_with(&first.state, &second.entity, &second.state) {
let _result = first.entity.collided(&first.state, &second.entity, &second.state);
}
if second.entity.intersects_with(&second.state, &first.entity, &first.state) {
let _result = second.entity.collided(&second.state, &first.entity, &first.state);
}
}
}
self.handle_event(events);

self.entities.retain(|e| e.state.active);
self.check_collisions();

for entity in spawned_entities.into_iter() {
let wrapper = EntityWrapper::new(entity, self);
self.entities.push(wrapper);
}
self.entities.retain(|e| e.state.active);
}

pub fn run(&mut self) {
Expand Down Expand Up @@ -182,39 +171,75 @@ impl Engine {

#[derive(Copy, Clone)]
pub struct Vertex {
pub position: [f32; 2],
pub dimension_affinity: [f32; 2],
}

implement_vertex!(Vertex, dimension_affinity);

pub struct EngineGraphics {
pub display: GlutinFacade,
pub textured_program: Program,
pub color_program: Program,
pub frame: Option<Frame>,
pub width: f32,
pub height: f32,

rectangle_vertex_buffer: VertexBuffer<Vertex>,
rectangle_index_buffer: IndexBuffer<u8>,
}

implement_vertex!(Vertex, position);

#[allow(dead_code)]
pub fn draw_rectangle(engine: &Engine,
frame: &mut Frame,
x: f32,
y: f32,
width: f32,
height: f32,
color: (f32, f32, f32, f32))
-> Result<()> {
let vertex_buffer = VertexBuffer::new(&engine.graphics.display,
&[Vertex { position: [x, y] },
Vertex { position: [x + width, y] },
Vertex { position: [x, y + height] },
Vertex { position: [x + width, y + height] }])?;

let index_buffer = IndexBuffer::<u8>::new(&engine.graphics.display,
PrimitiveType::TriangleStrip,
&[0, 1, 2, 3])?;

let matrix = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0f32]];
let uniform = UniformsStorage::new("matrix", matrix);
let uniform = uniform.add("color", color);
let uniform = uniform.add("screen_size",
[engine.graphics.width as f32, engine.graphics.height as f32]);
frame.draw(&vertex_buffer,
&index_buffer,
&engine.graphics.color_program,
&uniform,
&DrawParameters::default())?;
Ok(())
impl EngineGraphics {
pub fn new(width: f32, height: f32) -> Result<EngineGraphics> {
let display = WindowBuilder::new().with_dimensions(width as u32, height as u32)
.with_min_dimensions(width as u32, height as u32)
.with_max_dimensions(width as u32, height as u32)
.with_vsync()
.build_glium()?;
let textured_program =
Program::from_source(&display,
include_str!("../../assets/textured_shader.vert"),
include_str!("../../assets/textured_shader.frag"),
None)?;
let color_program = Program::from_source(&display,
include_str!("../../assets/color_shader.vert"),
include_str!("../../assets/color_shader.frag"),
None)?;

println!("{:?}", display.get_opengl_version());

let rectangle_vertex_buffer = VertexBuffer::new(&display,
&[Vertex { dimension_affinity: [0f32, 0f32] },
Vertex { dimension_affinity: [1f32, 0f32] },
Vertex { dimension_affinity: [0f32, 1f32] },
Vertex { dimension_affinity: [1f32, 1f32] }])?;

let rectangle_index_buffer = IndexBuffer::<u8>::new(&display,
PrimitiveType::TriangleStrip,
&[0, 1, 2, 3])?;

Ok(EngineGraphics {
display: display,
textured_program: textured_program,
color_program: color_program,
frame: None,
width: width,
height: height,
rectangle_vertex_buffer: rectangle_vertex_buffer,
rectangle_index_buffer: rectangle_index_buffer
})
}
pub fn draw_rectangle(&mut self, x: f32, y: f32, width: f32, height: f32, color: (f32, f32, f32, f32)) -> Result<()> {
if let Some(ref mut frame) = self.frame {
let uniform = UniformsStorage::new("offset", [x, y]);
let uniform = uniform.add("dimensions", [width, height]);
let uniform = uniform.add("color", color);
let uniform = uniform.add("screen_size", [self.width as f32, self.height as f32]);
frame.draw(&self.rectangle_vertex_buffer,
&self.rectangle_index_buffer,
&self.color_program,
&uniform,
&DrawParameters::default())?;
}
Ok(())
}
}
7 changes: 5 additions & 2 deletions src/entities/bullet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ pub struct Bullet {
drawable: Rc<DrawHelper>,
start_x: f32,
start_y: f32,
id: u64,
}

impl Bullet {
pub fn new(drawable: Rc<DrawHelper>, x: f32, y: f32) -> Bullet {
pub fn new(drawable: Rc<DrawHelper>, x: f32, y: f32, id: u64) -> Bullet {
Bullet {
drawable: drawable,
start_x: x,
start_y: y,
id: id,
}
}
}

impl EntityTrait for Bullet {
fn identifying_string(&self) -> String { format!("Bullet {}", self.id) }
fn get_initial_state(&self, _: &Engine) -> EntityState {
let hitbox = Hitbox {
left: 6f32,
Expand All @@ -32,7 +35,7 @@ impl EntityTrait for Bullet {
}
}

fn update(&mut self, game_state: &mut GameState, state: &mut EntityState) -> Vec<UpdateResult> {
fn update(&mut self, game_state: &mut GameState, state: &mut EntityState) -> Vec<EntityEvent> {
state.x -= 0.1f32 * game_state.delta_time;

if state.x + state.hitbox.right < 0f32 {
Expand Down
Loading

0 comments on commit 9592a77

Please sign in to comment.