#include "Entity.h" #include #include #include "Game.h" #include "Globals.h" Entity::Entity(const EntityType* zType, Framework::Model3DData* model, Framework::Model3DTextur* texture, int id, Framework::Vec3 position, float maxMovementSpeed, float gravityMultiplier, float jumpSpeed, float size) : FactoryCraftModel(), id(id), zType(zType), playerControlled(0), maxMovementSpeed(maxMovementSpeed), lastFlags(0), timeSinceSync(0), gravityMultiplier(gravityMultiplier), jumpSpeed(jumpSpeed), speed(0, 0, 0) { pos = position; setModelDaten(model); setModelTextur(texture); lastDirection = World::INSTANCE->zKamera()->getDirection(); currentFrame.duration = 0; rend = 1; lastFlags = 0; setSize(size); } Entity::~Entity() {} void Entity::api(char* message) { switch (message[0]) { case 0: { // add movement frame 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); Vec2 norm = {0, -1}; this->setDrehungZ((frame.direction.x < 0 ? -1 : 1) * norm.angle(Vec2( frame.direction.x, frame.direction.y))); if (!playerControlled) { 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 (!World::INSTANCE || !World::INSTANCE->zKamera()) return 0; if (playerControlled && GetForegroundWindow() == window->getFensterHandle()) { Vec3 direction = World::INSTANCE->zKamera()->getDirection(); Vec3 lastPos = pos; int flags = 0; if ((lastFlags | MOVEMENT_FLAG_JUMP) != lastFlags && (speed.z == 0.f || (lastFlags | MOVEMENT_FLAG_FLY) == lastFlags)) { // not jumping and not falling speed = {0, 0, speed.z}; if (GetKeyState('w') & 0x8000 || GetKeyState('W') & 0x8000) { flags |= MOVEMENT_FLAG_FORWARD; speed += {direction.x, direction.y, 0}; } if (GetKeyState('a') & 0x8000 || GetKeyState('A') & 0x8000) { flags |= MOVEMENT_FLAG_LEFT; Vec2 norm = {direction.x, direction.y}; norm.CCW90().normalize(); speed += {norm.x, norm.y, 0}; } if (GetKeyState('s') & 0x8000 || GetKeyState('S') & 0x8000) { flags |= MOVEMENT_FLAG_BACKWARD; speed += {-direction.x, -direction.y, 0}; } if (GetKeyState('d') & 0x8000 || GetKeyState('D') & 0x8000) { flags |= MOVEMENT_FLAG_RIGHT; Vec2 norm = {direction.x, direction.y}; norm.CW90().normalize(); speed += {norm.x, norm.y, 0}; } } else { speed = {speed.x, speed.y, speed.z}; } if ((lastFlags | MOVEMENT_FLAG_FLY) == lastFlags) { // fly mode flags |= MOVEMENT_FLAG_FLY; if (GetKeyState(T_Shift) & 0x8000) { if (getTastenStand(T_Strg)) { // end fly flags &= ~MOVEMENT_FLAG_FLY; speed.z = 0; } else { flags |= MOVEMENT_FLAG_DOWN; speed.z = -maxMovementSpeed; } } else if (GetKeyState(T_Space) & 0x8000) { flags |= MOVEMENT_FLAG_UP; speed.z = maxMovementSpeed; } else { speed.z = 0; } } else { // walk mode if (GetKeyState(T_Space) & 0x8000) { if (getTastenStand(T_Strg)) { // begin fly flags |= MOVEMENT_FLAG_FLY; speed.z = 0; } else if ((flags | MOVEMENT_FLAG_JUMP) != lastFlags && speed.z == 0.f) { // begin jump flags |= MOVEMENT_FLAG_JUMP; speed.z = jumpSpeed; } } if ((flags | MOVEMENT_FLAG_JUMP) == lastFlags && (flags | MOVEMENT_FLAG_FLY) != flags) { flags |= MOVEMENT_FLAG_JUMP; // keep jumping } } Vec2 norm = {speed.x, speed.y}; if (norm.getLengthSq() != 0) { norm.normalize(); speed.x = norm.x * maxMovementSpeed; speed.y = norm.y * maxMovementSpeed; } if ((flags | MOVEMENT_FLAG_FLY) != flags) { speed.z -= World::INSTANCE->zDimension()->getGravity() * gravityMultiplier * (float)time; } // 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; for (int m = 0; m < 20; m++) { 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 (speed.z < 0) { flags &= ~MOVEMENT_FLAG_JUMP; if (-speed.z > 2) { char message[5]; message[0] = 10; *(float*)(message + 1) = -speed.z; World::INSTANCE->zClient()->sendPlayerAction( message, 5); } } speed.z = 0; } 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)); }