#include #include "Entity.h" #include "Globals.h" #include "Game.h" Entity::Entity(const EntityType* zType, Framework::Model3DData* model, Framework::Model3DTextur* texture, int id, Framework::Vec3 position, float maxMovementSpeed) : Model3D(), id(id), zType(zType), playerControlled(0), maxMovementSpeed(maxMovementSpeed), lastFlags(0), timeSinceSync(0), speed(0, 0, 0) { pos = position; setModelDaten(model); setModelTextur(texture); lastDirection = World::INSTANCE->zKamera()->getDirection(); currentFrame.duration = 0; rend = 1; } Entity::~Entity() {} void Entity::api(char* message) { switch (message[0]) { case 0: { // add movement frame if (!playerControlled) { MovementFrame frame; frame.direction.x = *(float*)(message += 1); frame.direction.y = *(float*)(message += 4); frame.direction.z = *(float*)(message += 4); frame.targetPosition.x = *(float*)(message += 4); frame.targetPosition.y = *(float*)(message += 4); frame.targetPosition.z = *(float*)(message += 4); frame.movementFlags = *(int*)(message += 4); frame.duration = *(double*)(message += 4); cs.lock(); movements.add(frame); cs.unlock(); } break; } case 1: { // position correction if (playerControlled) { timeSinceSync = 0; pos.x = *(float*)(message += 1); pos.y = *(float*)(message += 4); pos.z = *(float*)(message += 4); lastDirection = World::INSTANCE->zKamera()->getDirection(); lastFlags = 0; } break; } } } bool Entity::tick(double time) { if (playerControlled && GetForegroundWindow() == window->getFensterHandle()) { Vec3 direction = World::INSTANCE->zKamera()->getDirection(); Vec3 lastPos = pos; int flags = 0; speed = { 0, 0, speed.z }; if (GetKeyState('w') & 0x8000 || GetKeyState('W') & 0x8000) { flags |= 1; speed += {direction.x, direction.y, 0}; } if (GetKeyState('a') & 0x8000 || GetKeyState('A') & 0x8000) { flags |= 2; Vec2 norm = { direction.x, direction.y }; norm.CCW90().normalize(); speed += {norm.x, norm.y, 0}; } if (GetKeyState('s') & 0x8000 || GetKeyState('S') & 0x8000) { flags |= 4; speed += {-direction.x, -direction.y, 0}; } if (GetKeyState('d') & 0x8000 || GetKeyState('D') & 0x8000) { flags |= 8; Vec2 norm = { direction.x, direction.y }; norm.CW90().normalize(); speed += {norm.x, norm.y, 0}; } if (GetKeyState(T_Shift) & 0x8000) { flags |= 16; speed.z = -maxMovementSpeed; } else if (GetKeyState(T_Space) & 0x8000) { flags |= 32; speed.z = maxMovementSpeed; } else { speed.z = 0.f; } Vec2 norm = { speed.x, speed.y }; if (norm.getLengthSq() != 0) { norm.normalize(); speed.x = norm.x * maxMovementSpeed; speed.y = norm.y * maxMovementSpeed; } // collision checking Vec3 minP = model->getMinPos(); Vec3 maxP = model->getMaxPos(); Vec3 worldBoundingBox[8]; worldBoundingBox[0] = applyWorldTransformation(minP); worldBoundingBox[1] = applyWorldTransformation({ minP.x, minP.y, maxP.z }); worldBoundingBox[2] = applyWorldTransformation({ minP.x, maxP.y, minP.z }); worldBoundingBox[3] = applyWorldTransformation({ maxP.x, minP.y, minP.z }); worldBoundingBox[4] = applyWorldTransformation({ maxP.x, minP.y, maxP.z }); worldBoundingBox[5] = applyWorldTransformation({ maxP.x, maxP.y, minP.z }); worldBoundingBox[6] = applyWorldTransformation({ minP.x, maxP.y, maxP.z }); worldBoundingBox[7] = applyWorldTransformation(maxP); Vec3 worldBoundingBoxFloor[8]; for (int i = 0; i < 8; i++) { worldBoundingBoxFloor[i] = Vec3(floor(worldBoundingBox[i].x), floor(worldBoundingBox[i].y), floor(worldBoundingBox[i].z)); } Vec3 frameSpeed = speed * (float)time; bool hasCollided = 0; while (true) { float tf = 1.f; int collType = 0; int updateType = 0; int updateI = 0; if (frameSpeed.x > 0) { for (int i = 0; i < 8; i++) { if (abs(frameSpeed.x) >= abs(worldBoundingBoxFloor[i].x + 1.f - worldBoundingBox[i].x)) { float xt = (worldBoundingBoxFloor[i].x + 1.f - worldBoundingBox[i].x) / frameSpeed.x; Vec3 tmp = worldBoundingBox[i] + frameSpeed * xt; if (tmp.y >= worldBoundingBoxFloor[i].y && tmp.y < worldBoundingBoxFloor[i].y + 1.f && tmp.z >= worldBoundingBoxFloor[i].z && tmp.z < worldBoundingBoxFloor[i].z + 1.f) { Block* b = World::INSTANCE->zBlockAt(Vec3{ (int)worldBoundingBoxFloor[i].x + 1, (int)worldBoundingBoxFloor[i].y, (int)worldBoundingBoxFloor[i].z }); if (b) // TODO: ignore passable blocks { if (xt < tf) { tf = xt; collType = 1; updateType = 0; } hasCollided = 1; } else { if (xt < tf) { tf = xt; collType = 0; updateType = 1; updateI = i; } } } } } } if (frameSpeed.x < 0) { for (int i = 0; i < 8; i++) { if (abs(frameSpeed.x) >= abs(worldBoundingBoxFloor[i].x - worldBoundingBox[i].x)) { float xt = (worldBoundingBoxFloor[i].x - worldBoundingBox[i].x) / frameSpeed.x; Vec3 tmp = worldBoundingBox[i] + frameSpeed * xt; if (tmp.y >= worldBoundingBoxFloor[i].y && tmp.y < worldBoundingBoxFloor[i].y + 1.f && tmp.z >= worldBoundingBoxFloor[i].z && tmp.z < worldBoundingBoxFloor[i].z + 1.f) { Block* b = World::INSTANCE->zBlockAt(Vec3{ (int)worldBoundingBoxFloor[i].x - 1, (int)worldBoundingBoxFloor[i].y, (int)worldBoundingBoxFloor[i].z }); if (b) // TODO: ignore passable blocks { if (xt < tf) { tf = xt; collType = 1; updateType = 0; } hasCollided = 1; } else { if (xt < tf) { tf = xt; collType = 0; updateType = 1; updateI = i; } } } } } } if (frameSpeed.y > 0) { for (int i = 0; i < 8; i++) { if (abs(frameSpeed.y) >= abs(worldBoundingBoxFloor[i].y + 1.f - worldBoundingBox[i].y)) { float yt = (worldBoundingBoxFloor[i].y + 1.f - worldBoundingBox[i].y) / frameSpeed.y; Vec3 tmp = worldBoundingBox[i] + frameSpeed * yt; if (tmp.x >= worldBoundingBoxFloor[i].x && tmp.x < worldBoundingBoxFloor[i].x + 1.f && tmp.z >= worldBoundingBoxFloor[i].z && tmp.z < worldBoundingBoxFloor[i].z + 1.f) { Block* b = World::INSTANCE->zBlockAt(Vec3{ (int)worldBoundingBoxFloor[i].x, (int)worldBoundingBoxFloor[i].y + 1, (int)worldBoundingBoxFloor[i].z }); if (b) // TODO: ignore passable blocks { if (yt < tf) { tf = yt; collType = 2; updateType = 0; } hasCollided = 1; } else { if (yt < tf) { tf = yt; collType = 0; updateType = 2; updateI = i; } } } } } } if (frameSpeed.y < 0) { for (int i = 0; i < 8; i++) { if (abs(frameSpeed.y) >= abs(worldBoundingBoxFloor[i].y - worldBoundingBox[i].y)) { float yt = (worldBoundingBoxFloor[i].y - worldBoundingBox[i].y) / frameSpeed.y; Vec3 tmp = worldBoundingBox[i] + frameSpeed * yt; if (tmp.x >= worldBoundingBoxFloor[i].x && tmp.x < worldBoundingBoxFloor[i].x + 1.f && tmp.z >= worldBoundingBoxFloor[i].z && tmp.z < worldBoundingBoxFloor[i].z + 1.f) { Block* b = World::INSTANCE->zBlockAt(Vec3{ (int)worldBoundingBoxFloor[i].x, (int)worldBoundingBoxFloor[i].y - 1, (int)worldBoundingBoxFloor[i].z }); if (b) // TODO: ignore passable blocks { if (yt < tf) { tf = yt; collType = 2; updateType = 0; } hasCollided = 1; } else { if (yt < tf) { tf = yt; collType = 0; updateType = 2; updateI = i; } } } } } } if (frameSpeed.z > 0) { for (int i = 0; i < 8; i++) { if (abs(frameSpeed.z) >= abs(worldBoundingBoxFloor[i].z + 1.f - worldBoundingBox[i].z)) { float zt = (worldBoundingBoxFloor[i].z + 1.f - worldBoundingBox[i].z) / frameSpeed.z; Vec3 tmp = worldBoundingBox[i] + frameSpeed * zt; if (zt <= 1.f && tmp.x >= worldBoundingBoxFloor[i].x && tmp.x < worldBoundingBoxFloor[i].x + 1.f && tmp.y >= worldBoundingBoxFloor[i].y && tmp.y < worldBoundingBoxFloor[i].y + 1.f) { Block* b = World::INSTANCE->zBlockAt(Vec3{ (int)worldBoundingBoxFloor[i].x, (int)worldBoundingBoxFloor[i].y, (int)worldBoundingBoxFloor[i].z + 1 }); if (b) // TODO: ignore passable blocks { if (zt < tf) { tf = zt; collType = 3; } hasCollided = 1; } else { if (zt < tf) { tf = zt; collType = 0; updateType = 3; updateI = i; } } } } } } if (frameSpeed.z < 0) { for (int i = 0; i < 8; i++) { if (abs(frameSpeed.z) >= abs(worldBoundingBoxFloor[i].z - worldBoundingBox[i].z)) { float zt = (worldBoundingBoxFloor[i].z - worldBoundingBox[i].z) / frameSpeed.z; Vec3 tmp = worldBoundingBox[i] + frameSpeed * zt; if (tmp.x >= worldBoundingBoxFloor[i].x && tmp.x < worldBoundingBoxFloor[i].x + 1.f && tmp.y >= worldBoundingBoxFloor[i].y && tmp.y < worldBoundingBoxFloor[i].y + 1) { Block* b = World::INSTANCE->zBlockAt(Vec3{ (int)worldBoundingBoxFloor[i].x, (int)worldBoundingBoxFloor[i].y, (int)worldBoundingBoxFloor[i].z - 1 }); if (b) // TODO: ignore passable blocks { if (zt < tf) { tf = zt; collType = 3; updateType = 0; } hasCollided = 1; } else { if (zt < tf) { tf = zt; collType = 0; updateType = 3; updateI = i; } } } } } } if (collType == 1) frameSpeed.x = tf > 0.1f ? frameSpeed.x * (tf - 0.1f) : 0.f; if (collType == 2) frameSpeed.y = tf > 0.1f ? frameSpeed.y * (tf - 0.1f) : 0.f; if (collType == 3) frameSpeed.z = tf > 0.1f ? frameSpeed.z * (tf - 0.1f) : 0.f; if (updateType == 1) { if ((int)worldBoundingBoxFloor[updateI].x < (int)floor(worldBoundingBox[updateI].x + frameSpeed.x)) worldBoundingBoxFloor[updateI].x++; if ((int)worldBoundingBoxFloor[updateI].x > (int)floor(worldBoundingBox[updateI].x + frameSpeed.x)) worldBoundingBoxFloor[updateI].x--; } if (updateType == 2) { if ((int)worldBoundingBoxFloor[updateI].y < (int)floor(worldBoundingBox[updateI].y + frameSpeed.y)) worldBoundingBoxFloor[updateI].y++; if ((int)worldBoundingBoxFloor[updateI].y > (int)floor(worldBoundingBox[updateI].y + frameSpeed.y)) worldBoundingBoxFloor[updateI].y--; } if (updateType == 3) { if ((int)worldBoundingBoxFloor[updateI].z < (int)floor(worldBoundingBox[updateI].z + frameSpeed.z)) worldBoundingBoxFloor[updateI].z++; if ((int)worldBoundingBoxFloor[updateI].z > (int)floor(worldBoundingBox[updateI].z + frameSpeed.z)) worldBoundingBoxFloor[updateI].z--; } if (updateType || collType) continue; break; } pos += frameSpeed; World::INSTANCE->zKamera()->setPosition(pos + Vec3(0.f, 0.f, 1.5f)); Model3D* target = World::INSTANCE->getCurrentTarget(); Block* b = target ? dynamic_cast(target) : 0; ((Game*)(Menu*)menuRegister->get("game"))->updatePosition(pos, b != 0, b ? b->getLocation() : Vec3(0, 0, 0)); if(target) target->release(); if (flags != lastFlags || direction != lastDirection || timeSinceSync >= 1 || hasCollided) { if (timeSinceSync > 0) { MovementFrame frame; frame.direction = lastDirection; frame.targetPosition = lastPos; frame.movementFlags = lastFlags; frame.duration = timeSinceSync; World::INSTANCE->zClient()->sendPlayerMovement(frame); } lastFlags = flags; lastDirection = direction; timeSinceSync = 0; } timeSinceSync += time; rend = 1; } else { double totalTime = time; while (totalTime > 0) { if (currentFrame.duration <= 0) { if (movements.getEintragAnzahl() > 0) { currentFrame = movements.get(0); cs.lock(); movements.remove(0); cs.unlock(); } else { break; } } double t = min(currentFrame.duration, totalTime); pos += (currentFrame.targetPosition - pos) * (float)(t / currentFrame.duration); currentFrame.duration -= t; totalTime -= t; if (currentFrame.duration <= 0) { pos = currentFrame.targetPosition; } rend = 1; } } return Model3D::tick(time); } int Entity::getId() const { return id; } const EntityType* Entity::zEntityType() const { return zType; } void Entity::lock() { cs.lock(); } void Entity::unlock() { cs.unlock(); } void Entity::setPlayerControlled() { playerControlled = 1; World::INSTANCE->zKamera()->setPosition(pos + Vec3(0.f, 0.f, 1.5f)); }