]> 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?
 
        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
 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
 
        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
 transparency (blocks and entities)
 
        transparent blocks because awesome
@@ -81,9 +88,10 @@ world generator that is not boring
 
 entity/world collision
 
 
 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
 
 
 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.
 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;
 
 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()); }
 
        /// 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 FaceBlock();
        void TurnBlock();
 
+       void ToggleCollision();
+
        void PickBlock();
        void PlaceBlock();
        void RemoveBlock() noexcept;
        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;
 
                        TurnBlock();
                        break;
 
+               case SDLK_n:
+                       ToggleCollision();
+                       break;
+
                case SDLK_b:
                        PrintBlockInfo();
                        break;
                case SDLK_b:
                        PrintBlockInfo();
                        break;
@@ -178,6 +182,11 @@ void Interface::TurnBlock() {
        hud.Display(selection);
 }
 
        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) {
 void Interface::PrintBlockInfo() {
        std::cout << std::endl;
        if (!aim_chunk) {
index 344bec7f6542b1c5ffa049ec08cda2b8dd8135d2..28f814b80d7245adf022f216689822b305c38142 100644 (file)
@@ -22,11 +22,19 @@ struct BlockType {
 
        Block::Type id;
 
 
        Block::Type id;
 
+       // light level that blocks of this type emit
        int luminosity;
 
        int luminosity;
 
+       // whether to draw
        bool visible;
        bool visible;
+       // if true, stops light from propagating and fixes level to luminosity
        bool block_light;
 
        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 {
        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 <iostream>
 #include <limits>
+#include <glm/gtx/io.hpp>
 #include <glm/gtx/transform.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;
        { // 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.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.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);
        }
                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;
        { // 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.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.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);
        }
                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;
        { // 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.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.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);
        }
                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;
        { // 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.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.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);
        }
                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;
                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);
        }
                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 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)) {
        // 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);
 }
 
        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> &);
                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; }
 
 
        BlockTypeRegistry &BlockTypes() { return blockType; }
 
index eb2e5e2871a334bfe02e1bd0be24a5c48572af98..ebf01c17cd0362bfda3f1ba15f674367b8205bc2 100644 (file)
@@ -1,13 +1,14 @@
 #ifndef BLANK_WORLD_WORLDCOLLISION_HPP_
 #define BLANK_WORLD_WORLDCOLLISION_HPP_
 
 #ifndef BLANK_WORLD_WORLDCOLLISION_HPP_
 #define BLANK_WORLD_WORLDCOLLISION_HPP_
 
+#include "BlockType.hpp"
+#include "Chunk.hpp"
+
 #include <glm/glm.hpp>
 
 
 namespace blank {
 
 #include <glm/glm.hpp>
 
 
 namespace blank {
 
-class Chunk;
-
 struct WorldCollision {
 
        const Chunk *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) { }
 
        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)
 , luminosity(0)
 , visible(v)
 , block_light(false)
+, collision(false)
+, collide_block(false)
 , fill({ false, false, false, false, false, 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);
                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)) {
                                        continue;
                                }
                                if (type.shape->Intersects(Mchunk * ToTransform(Pos(x, y, z), idx), box, Mbox, penetration, normal)) {