Jelajahi Sumber

fix problems with collision detection

Kolja Strohm 1 bulan lalu
induk
melakukan
d6291a5fdc

+ 21 - 4
FactoryCraft/Dimension.cpp

@@ -329,20 +329,35 @@ void Dimension::saveStructure(MultiblockStructure* zStructure) const
 void Dimension::entityTickLoop()
 {
     ZeitMesser zm;
+    double ausgleich = 0.0;
     zm.messungStart();
+    Sleep(16);
     while (!stop)
     {
-        Sleep(32);
         zm.messungEnde();
         double seconds = zm.getSekunden();
         zm.messungStart();
         entityCs.lock();
         chunkCs.lock();
-        for (auto entity : *entities)
+        auto iterator = entities->begin();
+        auto end = entities->end();
+        while (iterator != end)
         {
-            if (!entity->isRemoved())
+            if (!iterator->isRemoved())
+            {
+                iterator->prepareTick(this, seconds);
+                iterator++;
+            }
+            else
             {
-                entity->prepareTick(this, seconds);
+                auto chunk = zChunk(
+                    Game::getChunkCenter((int)iterator->getPosition().x,
+                        (int)iterator->getPosition().y));
+                if (chunk)
+                {
+                    chunk->onEntityLeaves(iterator, 0);
+                }
+                iterator.remove();
             }
         }
         int index = 0;
@@ -356,6 +371,8 @@ void Dimension::entityTickLoop()
         }
         chunkCs.unlock();
         entityCs.unlock();
+        ausgleich += 1.0 / 30 - seconds;
+        if (ausgleich > 0) Sleep((int)(ausgleich * 1000));
     }
 }
 

+ 107 - 52
FactoryCraft/Entity.cpp

@@ -605,42 +605,50 @@ void Entity::calcBlockCollision(int& x, int& y, int& xl, int& yl)
     maxXY += location;
     minXmaxY += location;
     maxXminY += location;
-    x = (int)minXY.x;
-    y = (int)minXY.y;
-    if (x > (int)minXmaxY.x) x = (int)minXmaxY.x;
-    if (x > (int)maxXminY.x) x = (int)maxXminY.x;
-    if (x > (int)maxXY.x) x = (int)maxXY.x;
-    if (y > (int)minXmaxY.y) y = (int)minXmaxY.y;
-    if (y > (int)maxXminY.y) y = (int)maxXminY.y;
-    if (y > (int)maxXY.y) y = (int)maxXY.y;
-    xl = (int)minXY.x;
-    if (xl < (int)minXmaxY.x) xl = (int)minXmaxY.x;
-    if (xl < (int)maxXminY.x) xl = (int)maxXminY.x;
-    if (xl < (int)maxXY.x) xl = (int)maxXY.x;
-    yl = (int)minXY.y;
-    if (yl < (int)minXmaxY.y) yl = (int)minXmaxY.y;
-    if (yl < (int)maxXminY.y) yl = (int)maxXminY.y;
-    if (yl < (int)maxXY.y) yl = (int)maxXY.y;
+    Framework::Vec3<int> minXYI(
+        (int)floor(minXY.x), (int)floor(minXY.y), (int)floor(minXY.z));
+    Framework::Vec3<int> maxXYI(
+        (int)floor(maxXY.x), (int)floor(maxXY.y), (int)floor(maxXY.z));
+    Framework::Vec3<int> minXmaxYI(
+        (int)floor(minXmaxY.x), (int)floor(minXmaxY.y), (int)floor(minXmaxY.z));
+    Framework::Vec3<int> maxXminYI(
+        (int)floor(maxXminY.x), (int)floor(maxXminY.y), (int)floor(maxXminY.z));
+    x = minXYI.x;
+    y = minXYI.y;
+    if (x > minXmaxYI.x) x = minXmaxYI.x;
+    if (x > maxXminYI.x) x = maxXminYI.x;
+    if (x > maxXYI.x) x = maxXYI.x;
+    if (y > minXmaxYI.y) y = minXmaxYI.y;
+    if (y > maxXminYI.y) y = maxXminYI.y;
+    if (y > maxXYI.y) y = maxXYI.y;
+    xl = minXYI.x;
+    if (xl < minXmaxYI.x) xl = minXmaxYI.x;
+    if (xl < maxXminYI.x) xl = maxXminYI.x;
+    if (xl < maxXYI.x) xl = maxXYI.x;
+    yl = minXYI.y;
+    if (yl < minXmaxYI.y) yl = minXmaxYI.y;
+    if (yl < maxXminYI.y) yl = maxXminYI.y;
+    if (yl < maxXYI.y) yl = maxXYI.y;
     xl = xl - x + 1;
     yl = yl - y + 1;
     if (collisionMapLength < xl * yl)
     {
         delete[] collisionMap;
-        collisionMap = new bool[xl, yl];
+        collisionMap = new bool[xl * yl];
         collisionMapLength = xl * yl;
     }
     memset(collisionMap, 0, xl * yl * sizeof(bool));
-    int xi = (int)minXY.x - x;
-    int yi = (int)minXY.y - y;
+    int xi = minXYI.x - x;
+    int yi = minXYI.y - y;
     collisionMap[xi + yi * xl] = 1;
-    xi = (int)maxXY.x - x;
-    yi = (int)maxXY.y - y;
+    xi = maxXYI.x - x;
+    yi = maxXYI.y - y;
     collisionMap[xi + yi * xl] = 1;
-    xi = (int)minXmaxY.x - x;
-    yi = (int)minXmaxY.y - y;
+    xi = minXmaxYI.x - x;
+    yi = minXmaxYI.y - y;
     collisionMap[xi + yi * xl] = 1;
-    xi = (int)maxXminY.x - x;
-    yi = (int)maxXminY.y - y;
+    xi = maxXminYI.x - x;
+    yi = maxXminYI.y - y;
     collisionMap[xi + yi * xl] = 1;
     auto dir = minXmaxY - minXY;
     float m = 0;
@@ -651,10 +659,14 @@ void Entity::calcBlockCollision(int& x, int& y, int& xl, int& yl)
             m = dir.y / dir.x;
         }
         float yy = minXY.y;
-        for (int xx = (int)minXY.x; xx < (int)minXmaxY.x; xx++)
+        for (int xx = (int)floor(minXY.x); xx < (int)floor(minXmaxY.x); xx++)
         {
             int xi = xx - x;
-            int yi = (int)yy - y;
+            int yi = (int)floor(yy) - y;
+            if (xi >= xl || yi >= yl)
+            {
+                continue;
+            }
             collisionMap[xi + yi * xl] = 1;
             yy += m;
         }
@@ -666,10 +678,14 @@ void Entity::calcBlockCollision(int& x, int& y, int& xl, int& yl)
             m = dir.x / dir.y;
         }
         float xx = minXY.x;
-        for (int yy = (int)minXY.y; yy < (int)minXmaxY.y; yy++)
+        for (int yy = (int)floor(minXY.y); yy < (int)floor(minXmaxY.y); yy++)
         {
-            int xi = (int)xx - x;
+            int xi = (int)floor(xx) - x;
             int yi = yy - y;
+            if (xi >= xl || yi >= yl)
+            {
+                continue;
+            }
             collisionMap[xi + yi * xl] = 1;
             xx += m;
         }
@@ -683,10 +699,14 @@ void Entity::calcBlockCollision(int& x, int& y, int& xl, int& yl)
             m = dir.y / dir.x;
         }
         float yy = minXY.y;
-        for (int xx = (int)minXY.x; xx < (int)maxXminY.x; xx++)
+        for (int xx = (int)floor(minXY.x); xx < (int)floor(maxXminY.x); xx++)
         {
             int xi = xx - x;
-            int yi = (int)yy - y;
+            int yi = (int)floor(yy) - y;
+            if (xi >= xl || yi >= yl)
+            {
+                continue;
+            }
             collisionMap[xi + yi * xl] = 1;
             yy += m;
         }
@@ -698,10 +718,14 @@ void Entity::calcBlockCollision(int& x, int& y, int& xl, int& yl)
             m = dir.x / dir.y;
         }
         float xx = minXY.x;
-        for (int yy = (int)minXY.y; yy < (int)maxXminY.y; yy++)
+        for (int yy = (int)floor(minXY.y); yy < (int)floor(maxXminY.y); yy++)
         {
-            int xi = (int)xx - x;
+            int xi = (int)floor(xx) - x;
             int yi = yy - y;
+            if (xi >= xl || yi >= yl)
+            {
+                continue;
+            }
             collisionMap[xi + yi * xl] = 1;
             xx += m;
         }
@@ -715,10 +739,14 @@ void Entity::calcBlockCollision(int& x, int& y, int& xl, int& yl)
             m = dir.y / dir.x;
         }
         float yy = maxXminY.y;
-        for (int xx = (int)maxXminY.x; xx < (int)maxXY.x; xx++)
+        for (int xx = (int)floor(maxXminY.x); xx < (int)floor(maxXY.x); xx++)
         {
             int xi = xx - x;
-            int yi = (int)yy - y;
+            int yi = (int)floor(yy) - y;
+            if (xi >= xl || yi >= yl)
+            {
+                continue;
+            }
             collisionMap[xi + yi * xl] = 1;
             yy += m;
         }
@@ -730,10 +758,14 @@ void Entity::calcBlockCollision(int& x, int& y, int& xl, int& yl)
             m = dir.x / dir.y;
         }
         float xx = maxXminY.x;
-        for (int yy = (int)maxXminY.y; yy < (int)maxXY.y; yy++)
+        for (int yy = (int)floor(maxXminY.y); yy < (int)floor(maxXY.y); yy++)
         {
-            int xi = (int)xx - x;
+            int xi = (int)floor(xx) - x;
             int yi = yy - y;
+            if (xi >= xl || yi >= yl)
+            {
+                continue;
+            }
             collisionMap[xi + yi * xl] = 1;
             xx += m;
         }
@@ -747,10 +779,14 @@ void Entity::calcBlockCollision(int& x, int& y, int& xl, int& yl)
             m = dir.y / dir.x;
         }
         float yy = minXmaxY.y;
-        for (int xx = (int)minXmaxY.x; xx < (int)maxXY.x; xx++)
+        for (int xx = (int)floor(minXmaxY.x); xx < (int)floor(maxXY.x); xx++)
         {
             int xi = xx - x;
-            int yi = (int)yy - y;
+            int yi = (int)floor(yy) - y;
+            if (xi >= xl || yi >= yl)
+            {
+                continue;
+            }
             collisionMap[xi + yi * xl] = 1;
             yy += m;
         }
@@ -762,10 +798,14 @@ void Entity::calcBlockCollision(int& x, int& y, int& xl, int& yl)
             m = dir.x / dir.y;
         }
         float xx = minXmaxY.x;
-        for (int yy = (int)minXmaxY.y; yy < (int)maxXY.y; yy++)
+        for (int yy = (int)floor(minXmaxY.y); yy < (int)floor(maxXY.y); yy++)
         {
-            int xi = (int)xx - x;
+            int xi = (int)floor(xx) - x;
             int yi = yy - y;
+            if (xi >= xl || yi >= yl)
+            {
+                continue;
+            }
             collisionMap[xi + yi * xl] = 1;
             xx += m;
         }
@@ -846,26 +886,38 @@ void Entity::tick(const Dimension* zDimension, double seconds)
     {
         float rot = Framework::Vec2<float>(0, -1).angle({faceDir.x, faceDir.y});
         rotSpeed = rot - rotation;
-    }
-    if (rotSpeed != 0.f)
-    {
-        rotation += rotSpeed;
-        if (isCollidingWithBlock(zDimension))
+        while (rotSpeed >= 2.f * (float)PI)
         {
-            rotation -= rotSpeed;
+            rotSpeed -= 2.f * (float)PI;
         }
-        else
+        while (rotSpeed <= -2.f * (float)PI)
         {
-            changed = 1;
+            rotSpeed += 2.f * (float)PI;
         }
-        while (rotation > 2.f * (float)PI)
+    }
+    if (rotSpeed != 0.f)
+    {
+        float last = rotation;
+        rotation += rotSpeed;
+        while (rotation >= 2.f * (float)PI)
         {
             rotation -= 2.f * (float)PI;
         }
-        while (rotation < 0.f)
+        while (rotation <= -2.f * (float)PI)
         {
             rotation += 2.f * (float)PI;
         }
+        if (last != rotation)
+        {
+            if (isCollidingWithBlock(zDimension))
+            {
+                rotation -= rotSpeed;
+            }
+            else
+            {
+                changed = 1;
+            }
+        }
     }
     Framework::Vec3<float> moveDir(0.f, 0.f, 0.f);
     if (movementFlags & MovementFlags::WALK_FORWARD)
@@ -931,7 +983,10 @@ void Entity::tick(const Dimension* zDimension, double seconds)
             movementFlags &= ~MovementFlags::GROUND_CONTACT;
         }
     }
-    if (!(movementFlags & MovementFlags::FLYING))
+    if ((!(movementFlags & MovementFlags::FLYING)
+            && (speed.x != 0.f || speed.y != 0.f || speed.z != 0.f
+                || moveDir.x != 0.f || moveDir.y != 0.f || moveDir.z != 0.f))
+        || !(movementFlags & MovementFlags::GROUND_CONTACT))
     {
         speed.z
             -= zDimension->getGravity() * gravityMultiplier * (float)seconds;

+ 4 - 1
FactoryCraft/EntityType.cpp

@@ -97,7 +97,10 @@ void EntityType::saveSuperEntity(
 
 void EntityType::createSuperEntity(Entity* zEntity) const
 {
-    zEntity->boundingBox = model->getBoundingBox();
+    if (model)
+    {
+        zEntity->boundingBox = model->getBoundingBox();
+    }
 }
 
 bool EntityType::initialize(Game* zGame)

+ 9 - 0
FactoryCraft/Game.cpp

@@ -864,9 +864,18 @@ void Game::spawnItem(
 void Game::spawnItem(
     Framework::Vec3<float> location, int dimensionId, ItemStack* stack)
 {
+    if (stack->getSize() == 0)
+    {
+        Logging::error() << "spawn item was called with empty stack";
+        return;
+    }
     ItemEntity* itemEntity = (ItemEntity*)zEntityType(EntityTypeEnum::ITEM)
                                  ->createEntityAt(location, dimensionId);
     itemEntity->unsaveAddItem(stack, NO_DIRECTION, 0);
+    if (stack->getSize() > 0)
+    {
+        Logging::error() << "could not add item to item entity";
+    }
     stack->release();
     Dimension* dim = zDimension(dimensionId);
     if (dim)

+ 27 - 20
FactoryCraft/ItemEntity.cpp

@@ -26,34 +26,41 @@ ItemEntity::ItemEntity(
     setThirst(10);
     targetDistanceLimit = 4;
     maxMovementSpeed = 1;
-    movementFlags |= MovementFlags::ROTATE_TO_FACE;
+    movementFlags |= MovementFlags::ROTATE_TO_FACE | MovementFlags::FLYING;
 }
 
 void ItemEntity::prepareTick(const Dimension* zDimension, double seconds)
 {
     if (slot->zStack() == 0 && !removed) throw "Illegal State exception";
-    // TODO: implement movement towards other item entities
-    /* if (movements.getEintragAnzahl() <= 1)
+    Entity* zOther = Game::INSTANCE->zNearestEntity(
+        dimensionId, location, [this](Entity* zOther) {
+            return zOther != this
+                && zOther->numberOfAddableItems(
+                    slot->zStack()->zItem(), NO_DIRECTION)
+                && (!this->slot->isFull()
+                    || zOther->zType()->getId() != EntityTypeEnum::ITEM);
+        });
+    if (zOther)
     {
-        Entity* zOther = Game::INSTANCE->zNearestEntity(
-            dimensionId, location, [this](Entity* zOther) {
-                return zOther != this
-                    && zOther->numberOfAddableItems(
-                        slot->zStack()->zItem(), NO_DIRECTION)
-                    && (!this->slot->isFull()
-                        || zOther->zType()->getId() != EntityTypeEnum::ITEM);
-            });
-        if (zOther)
+        faceDir = zOther->getPosition() - getPosition();
+        movementFlags |= MovementFlags::WALK_FORWARD;
+        if (getPosition().z < zOther->getPosition().z)
+        {
+            movementFlags |= MovementFlags::JUMPING;
+            movementFlags &= ~MovementFlags::SNEAKING;
+        }
+        else if (getPosition().z > zOther->getPosition().z)
         {
-            MovementFrame frame;
-            frame.direction = zOther->getPosition() - getPosition();
-            frame.duration = 0.25;
-            frame.movementFlags = 0x1; // TODO: torn on flight mode
-            frame.targetPosition
-                = getPosition() + frame.direction * (0.5f * maxMovementSpeed);
-            addMovementFrame(frame);
+            movementFlags |= MovementFlags::SNEAKING;
+            movementFlags &= ~MovementFlags::JUMPING;
         }
-    }*/
+    }
+    else
+    {
+        movementFlags &= ~MovementFlags::WALK_FORWARD;
+        movementFlags &= ~MovementFlags::JUMPING;
+        movementFlags &= ~MovementFlags::SNEAKING;
+    }
     Entity::prepareTick(zDimension, seconds);
 }
 

+ 64 - 37
FactoryCraft/TypeRegistry.h

@@ -30,9 +30,21 @@ public:
  */
 template<typename T> class ObjectTypeFactory : public SimpleTypeFactory<T*>
 {
+protected:
+    mutable Framework::Validator::DataValidator* validator;
+
 public:
     ObjectTypeFactory()
-        : SimpleTypeFactory<T*>() {};
+        : SimpleTypeFactory<T*>(),
+          validator(0) {};
+
+    ~ObjectTypeFactory()
+    {
+        if (validator)
+        {
+            validator->release();
+        }
+    }
 
     T* fromJson(Framework::JSON::JSONValue* zJson) const final override
     {
@@ -46,9 +58,14 @@ public:
 
     virtual Framework::Validator::DataValidator* getValidator() const override
     {
-        return addToValidator(
-            Framework::Validator::DataValidator::buildForObject())
-            ->finishObject();
+        if (!this->validator)
+        {
+            this->validator = addToValidator(
+                Framework::Validator::DataValidator::buildForObject())
+                                  ->finishObject();
+        }
+        return dynamic_cast<Framework::Validator::DataValidator*>(
+            this->validator->getThis());
     };
 
     virtual JSONObjectValidationBuilder* addToValidator(
@@ -77,16 +94,21 @@ public:
     virtual Framework::Validator::DataValidator*
     getValidator() const final override
     {
-        Framework::Text referenceId = "_type_";
-        referenceId.append() << typeid(T).name() << "_" << getTypeToken();
-        return this
-            ->addToValidator(
-                Framework::Validator::DataValidator::buildForObject()
-                    ->withRequiredString("type")
-                    ->withExactMatch(getTypeToken())
-                    ->finishString()
-                    ->setReferenceId(referenceId))
-            ->finishObject();
+        if (!this->validator)
+        {
+            Framework::Text referenceId = "_type_";
+            referenceId.append() << typeid(T).name() << "_" << getTypeToken();
+            this->validator
+                = this->addToValidator(
+                          Framework::Validator::DataValidator::buildForObject()
+                              ->withRequiredString("type")
+                              ->withExactMatch(getTypeToken())
+                              ->finishString()
+                              ->setReferenceId(referenceId))
+                      ->finishObject();
+        }
+        return dynamic_cast<Framework::Validator::DataValidator*>(
+            this->validator->getThis());
     };
 
     virtual const char* getTypeToken() const = 0;
@@ -210,35 +232,40 @@ public:
 
     Framework::Validator::DataValidator* getValidator() const override
     {
-        Framework::Validator::DataValidator* result;
-        if (!insideGetValidator)
+        if (!this->validator)
         {
-            insideGetValidator = true;
-            auto validator
-                = Framework::Validator::DataValidator::buildForOneOf()
-                      ->typeSpecifiedByAttribute("type");
-            for (SubTypeFactoryRef<T>* factory : factories)
+            if (!insideGetValidator)
             {
-                validator = validator->addAcceptedType(factory->getValidator());
+                insideGetValidator = true;
+                auto validator
+                    = Framework::Validator::DataValidator::buildForOneOf()
+                          ->typeSpecifiedByAttribute("type");
+                for (SubTypeFactoryRef<T>* factory : factories)
+                {
+                    validator
+                        = validator->addAcceptedType(factory->getValidator());
+                }
+                this->validator = validator->finishOneOf();
+                insideGetValidator = false;
             }
-            result = validator->finishOneOf();
-            insideGetValidator = false;
-        }
-        else
-        {
-            auto validator
-                = Framework::Validator::DataValidator::buildForOneOf()
-                      ->typeSpecifiedByAttribute("type");
-            for (SubTypeFactoryRef<T>* factory : factories)
+            else
             {
-                validator = validator->addAcceptedType(
-                    Framework::Validator::DataValidator::buildForReference(
-                        ((Framework::Text("_type_") += typeid(T).name()) += "_")
-                        += factory->getTypeToken()));
+                auto validator
+                    = Framework::Validator::DataValidator::buildForOneOf()
+                          ->typeSpecifiedByAttribute("type");
+                for (SubTypeFactoryRef<T>* factory : factories)
+                {
+                    validator = validator->addAcceptedType(
+                        Framework::Validator::DataValidator::buildForReference(
+                            ((Framework::Text("_type_") += typeid(T).name())
+                                += "_")
+                            += factory->getTypeToken()));
+                }
+                this->validator = validator->finishOneOf();
             }
-            result = validator->finishOneOf();
         }
-        return result;
+        return dynamic_cast<Framework::Validator::DataValidator*>(
+            this->validator->getThis());
     }
 
     template<typename S,