]> git.localhorst.tv Git - blank.git/commitdiff
entity/world collision response
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 26 Jun 2015 10:39:31 +0000 (12:39 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 26 Jun 2015 10:50:54 +0000 (12:50 +0200)
TODO
running
src/app/FPSController.hpp
src/ui/Interface.hpp
src/ui/ui.cpp
src/world/BlockType.hpp
src/world/World.cpp
src/world/World.hpp
src/world/WorldCollision.hpp
src/world/block.cpp
src/world/chunk.cpp

diff --git a/TODO b/TODO
index 7b481da14cf911a5362da38245173d55141a5c3f..a0c8c1dee83a343e53e6fd983be20da62aa431f7 100644 (file)
--- a/TODO
+++ b/TODO
@@ -48,6 +48,9 @@ entity ai
        that as the light power for the directional lighting shader and use a
        direction that's fixed relative to the camera?
 
+       there's a bug where a chunk's model is not updated if its neighbor
+       changes border light levels
+
 gravity
 
        maybe like light levels? should also store a direction with it in
@@ -70,6 +73,10 @@ chunk traversal
        profiling indicates that this is not neccessary atm. maybe it will
        when there's some more action in the world
 
+       I got a segfault (sadly in release mode, so no sensible trace, but
+       it was in ChunkLoader::Update). I suspect it has something to do
+       with how chunks are relinked after a near death experience.
+
 transparency (blocks and entities)
 
        transparent blocks because awesome
@@ -81,9 +88,10 @@ world generator that is not boring
 
 entity/world collision
 
-       entities should be stopped from entering solid parts of the world
-
-       also, current ray/obb intersection test sucks
+       first draft of entity/world collision is implemented
+       it jitters and has some surprising behaviour
+       finding a spawn point which doesn't put entities in solids is
+       now a little more crucial. press N if you're in trouble
 
 better noise
 
diff --git a/running b/running
index 7bc9a0e86e8487755aba651386814d71993b3124..6764224d216d40a75ac71eb7f3da998c84906cd6 100644 (file)
--- a/running
+++ b/running
@@ -61,3 +61,5 @@ front, and back) and E changes the turn (none, left, around, and right).
 Pressing B prints details about the block you're pointing at and P prints
 info about the active block. L spits out the player position and light
 level there. C dumps info about the chunk of the pointed at block.
+
+Press N to toggle player/world collision.
index 01c745120d579aa209efc550987be912facc3e10..a7b11a417eff960fb31a6504e12c592439a48b1f 100644 (file)
@@ -18,6 +18,9 @@ class FPSController {
 public:
        explicit FPSController(Entity &) noexcept;
 
+       Entity &Controlled() noexcept { return entity; }
+       const Entity &Controlled() const noexcept { return entity; }
+
        /// get position and face direction of controlled entity
        Ray Aim() const noexcept { return entity.Aim(entity.ChunkCoords()); }
 
index 0c140fb88ff40ad18357cd3b42cfce17fbfda5e2..a08a0bf5c6a3add3518ea571333bce3e44d6c212 100644 (file)
@@ -44,6 +44,8 @@ public:
        void FaceBlock();
        void TurnBlock();
 
+       void ToggleCollision();
+
        void PickBlock();
        void PlaceBlock();
        void RemoveBlock() noexcept;
index c71b7c105a0f0c357a359e5cd8ac34779856d166..ea9786b0382952c4aea69a5ac29b1cd0e7d8ed00 100644 (file)
@@ -128,6 +128,10 @@ void Interface::HandlePress(const SDL_KeyboardEvent &event) {
                        TurnBlock();
                        break;
 
+               case SDLK_n:
+                       ToggleCollision();
+                       break;
+
                case SDLK_b:
                        PrintBlockInfo();
                        break;
@@ -178,6 +182,11 @@ void Interface::TurnBlock() {
        hud.Display(selection);
 }
 
+void Interface::ToggleCollision() {
+       ctrl.Controlled().WorldCollidable(!ctrl.Controlled().WorldCollidable());
+       std::cout << "collision " << (ctrl.Controlled().WorldCollidable() ? "on" : "off") << std::endl;
+}
+
 void Interface::PrintBlockInfo() {
        std::cout << std::endl;
        if (!aim_chunk) {
index 344bec7f6542b1c5ffa049ec08cda2b8dd8135d2..28f814b80d7245adf022f216689822b305c38142 100644 (file)
@@ -22,11 +22,19 @@ struct BlockType {
 
        Block::Type id;
 
+       // light level that blocks of this type emit
        int luminosity;
 
+       // whether to draw
        bool visible;
+       // if true, stops light from propagating and fixes level to luminosity
        bool block_light;
 
+       // whether to check for collisions at all
+       bool collision;
+       // if the block should be impenetrable
+       bool collide_block;
+
        struct Faces {
                bool face[Block::FACE_COUNT];
                Faces &operator =(const Faces &other) noexcept {
index cb8186d5f1f10ce27e337030215d060fbe1ee931..d51520ef5b2828c1d22902e1e00902bccb504884 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <iostream>
 #include <limits>
+#include <glm/gtx/io.hpp>
 #include <glm/gtx/transform.hpp>
 
 
@@ -29,18 +30,24 @@ World::World(const Config &config)
        { // white block
                BlockType type(true, { 1.0f, 1.0f, 1.0f }, &blockShape);
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = block_fill;
                blockType.Add(type);
        }
        { // white slab
                BlockType type(true, { 1.0f, 1.0f, 1.0f }, &slabShape);
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = slab_fill;
                blockType.Add(type);
        }
        { // white stair
                BlockType type(true, { 1.0f, 1.0f, 1.0f }, &stairShape);
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = stair_fill;
                blockType.Add(type);
        }
@@ -48,18 +55,24 @@ World::World(const Config &config)
        { // red block
                BlockType type(true, { 1.0f, 0.0f, 0.0f }, &blockShape);
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = block_fill;
                blockType.Add(type);
        }
        { // red slab
                BlockType type(true, { 1.0f, 0.0f, 0.0f }, &slabShape);
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = slab_fill;
                blockType.Add(type);
        }
        { // red stair
                BlockType type(true, { 1.0f, 0.0f, 0.0f }, &stairShape);
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = stair_fill;
                blockType.Add(type);
        }
@@ -67,18 +80,24 @@ World::World(const Config &config)
        { // green block
                BlockType type(true, { 0.0f, 1.0f, 0.0f }, &blockShape);
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = block_fill;
                blockType.Add(type);
        }
        { // green slab
                BlockType type(true, { 0.0f, 1.0f, 0.0f }, &slabShape);
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = slab_fill;
                blockType.Add(type);
        }
        { // green stair
                BlockType type(true, { 0.0f, 1.0f, 0.0f }, &stairShape);
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = stair_fill;
                blockType.Add(type);
        }
@@ -86,18 +105,24 @@ World::World(const Config &config)
        { // blue block
                BlockType type(true, { 0.0f, 0.0f, 1.0f }, &blockShape);
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = block_fill;
                blockType.Add(type);
        }
        { // blue slab
                BlockType type(true, { 0.0f, 0.0f, 1.0f }, &slabShape);
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = slab_fill;
                blockType.Add(type);
        }
        { // blue stair
                BlockType type(true, { 0.0f, 0.0f, 1.0f }, &stairShape);
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = stair_fill;
                blockType.Add(type);
        }
@@ -106,6 +131,8 @@ World::World(const Config &config)
                BlockType type(true, { 1.0f, 1.0f, 0.0f }, &blockShape);
                type.luminosity = 15;
                type.block_light = true;
+               type.collision = true;
+               type.collide_block = true;
                type.fill = block_fill;
                blockType.Add(type);
        }
@@ -179,14 +206,15 @@ bool World::Intersection(
 bool World::Intersection(const Entity &e, std::vector<WorldCollision> &col) {
        AABB box = e.Bounds();
        glm::mat4 M = e.Transform(player->ChunkCoords());
+       bool any = false;
        // TODO: this only needs to check the chunks surrounding the entity's chunk position
        //       need find out if that is quicker than the rough chunk bounds test
        for (Chunk &cur_chunk : chunks.Loaded()) {
                if (cur_chunk.Intersection(box, M, cur_chunk.Transform(player->ChunkCoords()), col)) {
-                       return true;
+                       any = true;
                }
        }
-       return false;
+       return any;
 }
 
 
@@ -221,8 +249,36 @@ void World::Update(int dt) {
        chunks.Update(dt);
 }
 
-void World::Resolve(const Entity &e, std::vector<WorldCollision> &col) {
-       std::cout << e.Name() << " entity intersects world at " << col.size() << " blocks" << std::endl;
+void World::Resolve(Entity &e, std::vector<WorldCollision> &col) {
+       // determine displacement for each cardinal axis and move entity accordingly
+       glm::vec3 min_disp(0.0f);
+       glm::vec3 max_disp(0.0f);
+       for (const WorldCollision &c : col) {
+               if (!c.Blocks()) continue;
+               glm::vec3 local_disp(c.normal * c.depth);
+               // swap if neccessary (normal may point away from the entity)
+               if (dot(c.normal, e.Position() - c.BlockCoords()) < 0) {
+                       local_disp *= -1;
+               }
+               min_disp = min(min_disp, local_disp);
+               max_disp = max(max_disp, local_disp);
+       }
+       // for each axis
+       // if only one direction is set, use that as the final
+       // if both directions are set, use average
+       glm::vec3 final_disp(0.0f);
+       for (int axis = 0; axis < 3; ++axis) {
+               if (std::abs(min_disp[axis]) > std::numeric_limits<float>::epsilon()) {
+                       if (std::abs(max_disp[axis]) > std::numeric_limits<float>::epsilon()) {
+                               final_disp[axis] = (min_disp[axis] + max_disp[axis]) * 0.5f;
+                       } else {
+                               final_disp[axis] = min_disp[axis];
+                       }
+               } else if (std::abs(max_disp[axis]) > std::numeric_limits<float>::epsilon()) {
+                       final_disp[axis] = max_disp[axis];
+               }
+       }
+       e.Move(final_disp);
 }
 
 
index 183fa603209af587d23d18f8f2b0e40c0a98d177..9ec4cb2faf7fae204c53672e0b1f6e800a09e9dc 100644 (file)
@@ -47,7 +47,7 @@ public:
                glm::vec3 &normal);
 
        bool Intersection(const Entity &e, std::vector<WorldCollision> &);
-       void Resolve(const Entity &e, std::vector<WorldCollision> &);
+       void Resolve(Entity &e, std::vector<WorldCollision> &);
 
        BlockTypeRegistry &BlockTypes() { return blockType; }
 
index eb2e5e2871a334bfe02e1bd0be24a5c48572af98..ebf01c17cd0362bfda3f1ba15f674367b8205bc2 100644 (file)
@@ -1,13 +1,14 @@
 #ifndef BLANK_WORLD_WORLDCOLLISION_HPP_
 #define BLANK_WORLD_WORLDCOLLISION_HPP_
 
+#include "BlockType.hpp"
+#include "Chunk.hpp"
+
 #include <glm/glm.hpp>
 
 
 namespace blank {
 
-class Chunk;
-
 struct WorldCollision {
 
        const Chunk *chunk;
@@ -19,6 +20,10 @@ struct WorldCollision {
        WorldCollision(const Chunk *c, int b, float d, const glm::vec3 &n)
        : chunk(c), block(b), depth(d), normal(n) { }
 
+       bool Blocks() const noexcept { return chunk->Type(block).collide_block; }
+
+       glm::vec3 BlockCoords() const noexcept { return Chunk::ToCoords(block); }
+
 };
 
 }
index aabb2b19a9fe47551282f615986a4007deb2726c..78aa9d8a30bdfe765983332247fc6bfddae92f7e 100644 (file)
@@ -81,6 +81,8 @@ BlockType::BlockType(bool v, const glm::vec3 &col, const Shape *s) noexcept
 , luminosity(0)
 , visible(v)
 , block_light(false)
+, collision(false)
+, collide_block(false)
 , fill({ false, false, false, false, false, false }) {
 
 }
index 2c5e7ec4ebad297570c5ef71fd2799822e5e30cc..a65f5c31d9b1d0081ab3204903b87cbe10bd562d 100644 (file)
@@ -500,7 +500,7 @@ bool Chunk::Intersection(
                for (int y = 0; y < height; ++y) {
                        for (int x = 0; x < width; ++x, ++idx) {
                                const BlockType &type = Type(idx);
-                               if (!type.visible) {
+                               if (!type.collision) {
                                        continue;
                                }
                                if (type.shape->Intersects(Mchunk * ToTransform(Pos(x, y, z), idx), box, Mbox, penetration, normal)) {