171 lines
5.8 KiB
C++
171 lines
5.8 KiB
C++
#pragma once
|
|
|
|
#include <iostream>
|
|
#include <memory>
|
|
|
|
#include <SDL/SDL.h>
|
|
#include <moggle/xxx/mesh.hpp>
|
|
#include <motor/basic/body.hpp>
|
|
#include <motor/basic/scene.hpp>
|
|
#include <motor/core/fbo.hpp>
|
|
|
|
#include <astrant-extensions/algorithm.hpp>
|
|
|
|
#include "globals.hpp"
|
|
|
|
//! Returns (f(ax, bx) && f(ay, by)) || (f(ax, by) && f(ay, bx))
|
|
//! Useful for instance when you want to compare two pairs if they contain the same elements, but don't care about the order
|
|
//! (and we provide an overload for that of course)
|
|
template <typename First, typename Second, typename Third, typename Fourth, typename CompareFunction>
|
|
bool order_agnostic_compare(First const& ax, Second const& ay, Third const& bx, Fourth const& by, CompareFunction const& f){
|
|
return
|
|
(f(ax, bx) && f(ay, by))
|
|
||
|
|
(f(ax, by) && f(ay, bx));
|
|
}
|
|
|
|
//TODO: Figure out what the syntax of this was, then express equal, less{,or equal}, greater{, or equal}.
|
|
//using order_agnostic_equalness<First, Second, Third, Fourth> = order_agnostic_compare<First, Second, Third, Fourth, std::eq>;
|
|
|
|
template <typename First, typename Second, typename Third, typename Fourth>
|
|
bool order_agnostic_equal(First const& ax, Second const& ay, Third const& bx, Fourth const& by){
|
|
return ((ax == bx && ay == by) || (ax == by && ay == bx));
|
|
}
|
|
|
|
template <typename First, typename Second, typename Third, typename Fourth>
|
|
bool order_agnostic_equal(std::pair<First, Second> const& a, std::pair<Third, Fourth> const& b){
|
|
return order_agnostic_equalness(a.first, a.second, b.first, b.second);
|
|
}
|
|
|
|
|
|
namespace games {
|
|
using namespace motor;
|
|
|
|
struct Base {
|
|
static ResourceCache resource_cache;
|
|
std::shared_ptr<Scene> scene = std::make_shared<Scene>();
|
|
|
|
int window_width;
|
|
int window_height;
|
|
Fbo fbo{window_width, window_height};
|
|
|
|
float time = 0.0;
|
|
|
|
// So all this is needed to set up Bullet!
|
|
// You pay for modularity with a lot of code, but perhaps we can wrap this in our own motor::world or something.
|
|
std::unique_ptr<btDefaultCollisionConfiguration> collison_configuration{new btDefaultCollisionConfiguration()};
|
|
std::unique_ptr<btCollisionDispatcher> collision_dispatcher{new btCollisionDispatcher(collison_configuration.get())};
|
|
btVector3 const world_minimum = btVector3(-1000,-1000,-1000);
|
|
btVector3 const world_maximum = btVector3(1000,1000,1000);
|
|
std::unique_ptr<btBroadphaseInterface> overlapping_pair_cache{new btAxisSweep3(world_minimum, world_maximum)};
|
|
std::unique_ptr<btConstraintSolver> constraint_solver{new btSequentialImpulseConstraintSolver()};
|
|
std::unique_ptr<btDynamicsWorld> dynamics_world{new btDiscreteDynamicsWorld(collision_dispatcher.get(), overlapping_pair_cache.get(), constraint_solver.get(), collison_configuration.get())};
|
|
|
|
Base(int window_width, int window_height);
|
|
virtual ~Base();
|
|
|
|
virtual bool has_ended();
|
|
|
|
private:
|
|
// Contains objects that were colliding in the previous update
|
|
std::vector<std::pair<btCollisionObject const*, btCollisionObject const*>> bullet_objects_in_collision_previous_frame{};
|
|
|
|
public:
|
|
virtual void update(float const dt, std::map<SDLKey, bool> keys_went_down, std::map<SDLKey, bool> is_pressed, std::map<SDLKey, bool> keys_went_up);
|
|
|
|
void update_bullet(float const dt);
|
|
|
|
void check_collisions();
|
|
|
|
//! A callback for when a collision between two objects occurs.
|
|
//! TODO: Expand to N-objects?
|
|
//! The pointers aren't const here so we can call f with the two arguments
|
|
struct dual_collision_callback {
|
|
//! The constructor.
|
|
//! CallbackFunctor must be a valid ctor-parameter for @member f
|
|
template <typename CallbackFunctor>
|
|
dual_collision_callback(std::shared_ptr<Body> first_, std::shared_ptr<Body> second_, CallbackFunctor&& c)
|
|
: first(first_)
|
|
, second(second_)
|
|
, f(c)
|
|
{}
|
|
|
|
std::shared_ptr<Body> first;
|
|
std::shared_ptr<Body> second;
|
|
std::function<void(decltype(first), decltype(second))> f;
|
|
|
|
void operator()() {
|
|
f(first, second);
|
|
}
|
|
};
|
|
|
|
struct single_collision_callback {
|
|
template <typename CallbackFunctor>
|
|
single_collision_callback(std::shared_ptr<Body> b_, CallbackFunctor&& c)
|
|
: b(b_)
|
|
, f(c)
|
|
{}
|
|
|
|
std::shared_ptr<Body> b;
|
|
std::function<void(decltype(b))> f;
|
|
|
|
void operator()() {
|
|
f(b);
|
|
}
|
|
};
|
|
|
|
void register_on_enter_collision_callback(dual_collision_callback&& c){
|
|
on_enter_dual_collision_callback.emplace_back(std::move(c));
|
|
}
|
|
|
|
void register_on_exit_collision_callback(dual_collision_callback&& c){
|
|
on_exit_dual_collision_callback.emplace_back(std::move(c));
|
|
}
|
|
|
|
void register_on_enter_collision_callback(single_collision_callback&& c){
|
|
on_enter_single_collision_callback.emplace_back(std::move(c));
|
|
}
|
|
|
|
void register_on_exit_collision_callback(single_collision_callback&& c){
|
|
on_exit_single_collision_callback.emplace_back(std::move(c));
|
|
}
|
|
|
|
private:
|
|
std::vector<dual_collision_callback> on_enter_dual_collision_callback{};
|
|
std::vector<dual_collision_callback> on_exit_dual_collision_callback{};
|
|
std::vector<single_collision_callback> on_enter_single_collision_callback{};
|
|
std::vector<single_collision_callback> on_exit_single_collision_callback{};
|
|
|
|
void bullet_objects_entered_collision(btCollisionObject const* x, btCollisionObject const* y){
|
|
for(auto& c : on_enter_dual_collision_callback){
|
|
if(order_agnostic_equal(c.first->get_physical_body(), c.second->get_physical_body(), x, y)){
|
|
c();
|
|
}
|
|
}
|
|
|
|
for(auto& c : on_enter_single_collision_callback){
|
|
if(c.b->get_physical_body() == x || c.b->get_physical_body() == y){
|
|
c();
|
|
}
|
|
}
|
|
}
|
|
|
|
void bullet_objects_exited_collision(btCollisionObject const* x, btCollisionObject const* y){
|
|
for(auto& c : on_exit_dual_collision_callback){
|
|
if(order_agnostic_equal(c.first->get_physical_body(), c.second->get_physical_body(), x, y)){
|
|
c();
|
|
}
|
|
}
|
|
|
|
for(auto& c : on_exit_single_collision_callback){
|
|
if(c.b->get_physical_body() == x || c.b->get_physical_body() == y){
|
|
c();
|
|
}
|
|
}
|
|
}
|
|
|
|
public:
|
|
virtual void draw();
|
|
};
|
|
|
|
} // namespace games
|