void MCObjectTest::testVelocityAndPreventSleeping() { MCWorld world; MCObject object("TestObject"); object.addToWorld(); object.physicsComponent().setVelocity(MCVector3dF(1, 1, 1)); QVERIFY(object.physicsComponent().isSleeping() == false); QVERIFY(object.index() >= 0); vector3dCompare(object.physicsComponent().velocity(), MCVector3dF(1, 1, 1)); object.physicsComponent().preventSleeping(true); object.physicsComponent().setVelocity(MCVector3dF(0, 0, 0)); vector3dCompare(object.physicsComponent().velocity(), MCVector3dF(0, 0, 0)); world.stepTime(1); QVERIFY(object.physicsComponent().isSleeping() == false); QVERIFY(object.index() >= 0); object.physicsComponent().preventSleeping(false); world.stepTime(1); QVERIFY(object.physicsComponent().isSleeping() == true); QVERIFY(object.index() == -1); }
void MCObjectTest::testChildTranslate() { MCWorld world; world.setDimensions(0, 1024, 0, 768, 0, 100, 1); MCObject root("root"); MCObjectPtr child1(new MCObject("child1")); MCObjectPtr child2(new MCObject("child2")); root.addChildObject(child1, MCVector3dF(1, 1, 1)); root.addChildObject(child2, MCVector3dF(2, 2, 2)); root.addToWorld(); // Root at (0, 0, 0) vector3dCompare(root.location(), MCVector3dF(0, 0, 0)); vector3dCompare(child1->location(), MCVector3dF(0, 0, 0)); vector3dCompare(child2->location(), MCVector3dF(0, 0, 0)); // Now move the root root.translate(MCVector3dF(1, 2, 3)); // Translate children only when root translates vector3dCompare(root.location(), MCVector3dF(1, 2, 3)); vector3dCompare(child1->location(), MCVector3dF(2, 3, 4)); vector3dCompare(child2->location(), MCVector3dF(3, 4, 5)); }
void MCObjectTest::testTranslate() { MCWorld world; MCObject object("TestObject"); object.addToWorld(); vector3dCompare(object.location(), MCVector3dF(0, 0, 0)); object.translate(MCVector3dF(1, 2, 3)); vector3dCompare(object.location(), MCVector3dF(1, 2, 3)); }
void MCObjectTest::testInitialLocation() { MCObject object("TestObject"); vector3dCompare(object.initialLocation(), MCVector3dF(0, 0, 0)); const MCVector3dF initialLocation(1, 2, 3); object.setInitialLocation(initialLocation); vector3dCompare(object.initialLocation(), initialLocation); }
void MCObjectTest::testChildRotate() { MCWorld world; world.setDimensions(0, 1024, 0, 768, 0, 100, 1); MCObject root("root"); MCObjectPtr child1(new MCObject("child1")); MCObjectPtr child2(new MCObject("child2")); float child1Angle = 45; root.addChildObject(child1, MCVector3dF(1, 1, 1), child1Angle); const float child2Angle = 90; root.addChildObject(child2, MCVector3dF(2, 2, 2), 90); root.addToWorld(); // Root at (0, 0, 0) const float rootAngle = 69; root.rotate(rootAngle); // Rotate children only when root rotates QVERIFY(root.angle() == rootAngle); QVERIFY(child1->angle() == child1Angle + rootAngle); QVERIFY(child2->angle() == child2Angle + rootAngle); vector3dCompare(child1->location(), MCVector3dF(MCTrigonom::rotatedVector(MCVector2dF(1.0, 1.0), rootAngle), 1.0f)); vector3dCompare(child2->location(), MCVector3dF(MCTrigonom::rotatedVector(MCVector2dF(2.0, 2.0), rootAngle), 2.0f)); // Now move the root const MCVector3dF rootLocation(3, 4, 5); root.translate(rootLocation); QVERIFY(root.angle() == rootAngle); QVERIFY(child1->angle() == child1Angle + rootAngle); QVERIFY(child2->angle() == child2Angle + rootAngle); vector3dCompare(child1->location(), rootLocation + MCVector3dF(MCTrigonom::rotatedVector(MCVector2dF(1.0, 1.0), rootAngle), 1.0f)); vector3dCompare(child2->location(), rootLocation + MCVector3dF(MCTrigonom::rotatedVector(MCVector2dF(2.0, 2.0), rootAngle), 2.0f)); // Rotate child relatively child1Angle = 47; child1->rotateRelative(child1Angle); root.translate(rootLocation); vector3dCompare(child1->location(), rootLocation + MCVector3dF(MCTrigonom::rotatedVector(MCVector2dF(1.0, 1.0), rootAngle), 1.0f)); QVERIFY(child1->angle() == rootAngle + child1Angle); }
void MCObjectTest::testVelocityIntegration() { MCWorld world; world.setDimensions(0, 1024, 0, 768, 0, 100, 1); MCObject object("TestObject"); object.addToWorld(); vector3dCompare(object.location(), MCVector3dF(0, 0, 0)); vector3dCompare(object.physicsComponent().velocity(), MCVector3dF(0, 0, 0)); MCVector3dF velocity(1, 2, 3); object.physicsComponent().setVelocity(velocity); world.stepTime(1); vector3dCompare(object.location(), velocity * DAMPING); const MCVector3dF location = object.location(); world.stepTime(1); velocity *= DAMPING; vector3dCompare(object.location(), location + velocity * DAMPING); }
void StartlightsOverlay::renderLights(int rows, int litRows, float glowScale, bool glowAlways) const { const int cols = 8; const float x = m_model.pos().i() - (cols - 1) * m_startLightOn.width() / 2; const float y = m_model.pos().j() - (rows - 1) * m_startLightOn.height() / 2; const float h = rows * m_startLightOn.height(); // Body for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { const MCVector3dF pos( x + col * m_startLightOff.width(), y + h - row * m_startLightOff.height()); if (row < litRows) { if (row == 0 && col == 0) { m_startLightOnCorner.render(nullptr, pos, 0); } else if (row == rows - 1 && col == 0) { m_startLightOnCorner.render(nullptr, pos, 90); } else if (row == rows - 1 && col == cols - 1) { m_startLightOnCorner.render(nullptr, pos, 180); } else if (row == 0 && col == cols - 1) { m_startLightOnCorner.render(nullptr, pos, 270); } else { m_startLightOn.render(nullptr, pos, 0); } } else { if (row == 0 && col == 0) { m_startLightOffCorner.render(nullptr, pos, 0); } else if (row == rows - 1 && col == 0) { m_startLightOffCorner.render(nullptr, pos, 90); } else if (row == rows - 1 && col == cols - 1) { m_startLightOffCorner.render(nullptr, pos, 180); } else if (row == 0 && col == cols - 1) { m_startLightOffCorner.render(nullptr, pos, 270); } else { m_startLightOff.render(nullptr, pos, 0); } } } } // Glow for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { if (row < litRows || glowAlways) { m_startLightGlow.setScale(MCVector3dF(glowScale, glowScale, 1.0f)); m_startLightGlow.render( nullptr, MCVector3dF( x + col * m_startLightOn.width(), y + h - row * m_startLightOn.height()), 0); } } } }
void Minimap::initialize(Car & carToFollow, const MapBase & trackMap, int x, int y, int size) { m_carToFollow = &carToFollow; m_center = MCVector3dF(x, y); // Set m_tileW and m_tileH so that they are squares m_tileW = size / trackMap.cols(); m_tileH = size / trackMap.rows(); if (m_tileW > m_tileH) { m_tileW = m_tileH; } else { m_tileH = m_tileW; } float initX, initY; // Center the map if (trackMap.cols() % 2 == 0) { initX = x - trackMap.cols() * m_tileW / 2 + m_tileW / 4; } else { initX = x - trackMap.cols() * m_tileW / 2; } initY = y - trackMap.rows() * m_tileH / 2; m_map.clear(); // Loop through the visible tile matrix and store relevant tiles float tileX, tileY; tileY = initY; for (unsigned int j = 0; j < trackMap.rows(); j++) { tileX = initX; for (unsigned int i = 0; i < trackMap.cols(); i++) { auto tile = std::static_pointer_cast<TrackTile>(trackMap.getTile(i, j)); auto surface = tile->previewSurface(); if (surface && !tile->excludeFromMinimap()) { surface->setShaderProgram(Renderer::instance().program("menu")); surface->setColor(MCGLColor(1.0, 1.0, 1.0)); surface->setSize(m_tileH, m_tileW); MinimapTile minimapTile; minimapTile.pos = MCVector3dF(tileX + m_tileW / 2, tileY + m_tileH / 2); minimapTile.rotation = tile->rotation(); m_map[surface].push_back(minimapTile); } tileX += m_tileW; } tileY += m_tileH; } m_sceneW = trackMap.cols() * TrackTile::TILE_W; m_sceneH = trackMap.rows() * TrackTile::TILE_H; m_size = MCVector3dF(trackMap.cols() * m_tileW, trackMap.rows() * m_tileH); }
TrackObject * TrackObjectFactory::build( QString category, QString role, MCVector2dF location, int angle) { MCObjectPtr object; if (role == "brake" || role == "left" || role == "right") { MCSurfaceObjectData data(role.toStdString()); data.setInitialLocation(location); data.setInitialAngle(angle); data.setBatchMode(true); data.setXYFriction(1.0); data.setRestitution(0.5); data.setMass(1000); data.setSurfaceId(role.toStdString()); data.setRenderLayer(static_cast<int>(Layers::Render::Objects)); object = m_objectFactory.build(data); object->shape()->view()->setShaderProgram(Renderer::instance().program("defaultSpecular")); // Wrap the MCObject in a TrackObject return new TrackObject(category, role, object); } else if (role == "bushArea") { MCSurfaceObjectData data(role.toStdString()); data.setInitialLocation(location); data.setInitialAngle(angle); data.setBatchMode(true); data.setIsStationary(true); data.setSurfaceId(role.toStdString()); data.setRenderLayer(static_cast<int>(Layers::Render::Objects)); object = m_objectFactory.build(data); object->setIsPhysicsObject(false); } else if (role == "crate") { MCMeshObjectData data(role.toStdString()); data.setInitialLocation(MCVector3dF(location.i(), location.j(), 12)); data.setInitialAngle(angle); data.setBatchMode(true); data.setXYFriction(1.0); data.setMass(1000); data.setMeshId(role.toStdString()); data.setSurfaceId(role.toStdString()); data.setRestitution(0.9); data.setRenderLayer(static_cast<int>(Layers::Render::Objects)); object = m_objectFactory.build(data); } else if (role == "dustRacing2DBanner") { MCSurfaceObjectData data(role.toStdString()); data.setInitialLocation(location); data.setInitialAngle(angle); data.setBatchMode(true); data.setXYFriction(1.0); data.setRestitution(0.5); data.setIsStationary(true); data.setSurfaceId(role.toStdString()); data.setRenderLayer(static_cast<int>(Layers::Render::Objects)); object = m_objectFactory.build(data); object->shape()->view()->setShaderProgram(Renderer::instance().program("defaultSpecular")); // Wrap the MCObject in a TrackObject return new TrackObject(category, role, object); } else if (role == "grandstand") { MCSurfaceObjectData data(role.toStdString()); data.setInitialLocation(location); data.setInitialAngle(angle); data.setBatchMode(true); data.setXYFriction(1.0); data.setRestitution(0.5); data.setIsStationary(true); data.setSurfaceId(role.toStdString()); data.setRenderLayer(static_cast<int>(Layers::Render::Objects)); object = m_objectFactory.build(data); } else if (role == "plant") { const MCFloat plantBodyRadius = 4; MCSurfaceObjectData data(role.toStdString()); data.setInitialLocation(location); data.setInitialAngle(angle); data.setBatchMode(true); data.setXYFriction(1.0); data.setIsStationary(true); data.setSurfaceId(role.toStdString()); data.setRestitution(0.25); data.setShapeWidth(plantBodyRadius); data.setShapeHeight(plantBodyRadius); data.setRenderLayer(static_cast<int>(Layers::Render::Objects)); object = m_objectFactory.build(data); } else if (role == "rock") { MCSurfaceObjectData data(role.toStdString()); data.setInitialLocation(location); data.setInitialAngle(angle); data.setBatchMode(true); data.setXYFriction(1.0); data.setMass(5000); data.setSurfaceId(role.toStdString()); data.setRestitution(0.9); data.setRenderLayer(static_cast<int>(Layers::Render::Objects)); object = m_objectFactory.build(data); } else if ( role == "grid" || role == "sandAreaCurve" || role == "sandAreaBig") { MCSurfaceObjectData data(role.toStdString()); data.setInitialLocation(location); data.setInitialAngle(angle); data.setBatchMode(true); data.setIsStationary(true); data.setSurfaceId(role.toStdString()); data.setRenderLayer(static_cast<int>(Layers::Render::Ground)); object = m_objectFactory.build(data); object->setIsPhysicsObject(false); object->shape()->view()->setHasShadow(false); } else if (role == "pit") { object = MCObjectPtr(new Pit(MCAssetManager::surfaceManager().surface("pit"))); object->setInitialLocation(location); object->setInitialAngle(angle); object->physicsComponent().setMass(1, true); // Stationary object->setRenderLayer(static_cast<int>(Layers::Render::Ground)); object->setIsPhysicsObject(false); object->setIsTriggerObject(true); object->shape()->view()->setHasShadow(false); object->shape()->view()->setBatchMode(true); } else if (role == "tire") { MCSurfaceObjectData data(role.toStdString()); data.setDefaultCircleShape(true); data.setInitialLocation(location); data.setInitialAngle(angle); data.setBatchMode(true); data.setXYFriction(1.0); data.setRestitution(0.5); data.setMass(500); // Exaggerate the mass on purpose data.setSurfaceId(role.toStdString()); data.setXYFriction(0.25); data.setRenderLayer(static_cast<int>(Layers::Render::Objects)); object = m_objectFactory.build(data); object->shape()->view()->setShaderProgram(Renderer::instance().program("defaultSpecular")); // Wrap the MCObject in a TrackObject return new TrackObject(category, role, object); } else if (role == "tree") { const MCFloat treeViewRadius = 48; const MCFloat treeBodyRadius = 8; MCSurfaceObjectData data(role.toStdString()); data.setInitialLocation(location); data.setInitialAngle(angle); data.setBatchMode(true); data.setXYFriction(1.0); data.setIsStationary(true); data.setRestitution(0.25); data.setShapeWidth(treeBodyRadius); data.setShapeHeight(treeBodyRadius); data.setRenderLayer(static_cast<int>(Layers::Render::Objects)); // Create a custom view. MCShapeViewPtr view(new TreeView( MCAssetManager::surfaceManager().surface("tree"), treeViewRadius, 2, 120, 5)); MCObjectPtr object = m_objectFactory.build(data, view); // Wrap the MCObject in a TrackObject return new TrackObject(category, role, object); } else if (role == "wall" || role == "wallLong") { MCSurfaceObjectData data(role.toStdString()); data.setInitialLocation(location); data.setInitialAngle(angle); data.setBatchMode(true); data.setXYFriction(1.0); data.setIsStationary(true); data.setSurfaceId(role.toStdString()); data.setRestitution(0.9); data.setRenderLayer(static_cast<int>(Layers::Render::Objects)); data.setInitialLocation(MCVector3dF(location.i(), location.j(), 8)); object = m_objectFactory.build(data); object->shape()->view()->setShaderProgram(Renderer::instance().program("defaultSpecular")); // Wrap the MCObject in a TrackObject return new TrackObject(category, role, object); } if (!object) { MCLogger().warning() << "Unknown or deprecated object '" << role.toStdString() << "'"; return nullptr; } else { // Wrap the MCObject in a TrackObject return new TrackObject(category, role, object); } }