// ok, need thing to step down through bodies and find closest approach // modify targpos directly to aim short of dangerous bodies static bool ParentSafetyAdjust(Ship *ship, Frame *targframe, const vector3d &posoff, vector3d &targpos) { Body *body = 0; Frame *frame = targframe->IsRotatingFrame() ? targframe->m_parent : targframe; while (frame) { double sdist = ship->GetPositionRelTo(frame).Length(); // ship position in that frame if (sdist < frame->GetRadius()) break; while (frame && !(body = frame->GetBodyFor())) frame = frame->m_parent; if (!frame) return false; frame = body->GetFrame()->m_parent; if (body->HasDoubleFrame()) frame = frame->m_parent; } if (!body) return false; // ok, so if body != 0, aim for zero velocity at distance to surface of that body // still along path to target vector3d targpos2 = targpos - ship->GetPosition(); double targdist = targpos2.Length(); double bodydist = body->GetPositionRelTo(ship).Length() - MaxEffectRad(body, ship)*1.5; if (targdist < bodydist) return false; targpos -= (targdist - bodydist) * targpos2 / targdist; // printf("Adjusted targpos for safety from %s: old = %.1f, new = %.1f\n", // body->GetLabel().c_str(), targdist, (targpos-ship->GetPosition()).Length()); return true; }
Game::Game(const SystemPath &path, const vector3d &pos, double time) : m_time(time), m_state(STATE_NORMAL), m_wantHyperspace(false), m_timeAccel(TIMEACCEL_1X), m_requestedTimeAccel(TIMEACCEL_1X), m_forceTimeAccel(false) { Pi::FlushCaches(); m_space.reset(new Space(this, path)); Body *b = m_space->FindBodyForPath(&path); assert(b); m_player.reset(new Player("kanara")); m_space->AddBody(m_player.get()); m_player->SetFrame(b->GetFrame()); m_player->SetPosition(pos); m_player->SetVelocity(vector3d(0,0,0)); Polit::Init(); CreateViews(); }
/* * Method: GetGroundPosition * * Get latitude, longitude and altitude of a dynamic body close to the ground or nil the body is not a dynamic body * or is not close to the ground. * * > latitude, longitude, altitude = body:GetGroundPosition() * * Returns: * * latitude - the latitude of the body in radians * longitude - the longitude of the body in radians * altitude - altitude above the ground in meters * * Examples: * * > -- Get ground position of the player * > local lat, long, alt = Game.player:GetGroundPosition() * > lat = math.rad2deg(lat) * > long = math.rad2deg(long) * * Availability: * * July 2013 * * Status: * * experimental */ static int l_body_get_ground_position(lua_State *l) { Body *b = LuaObject<Body>::CheckFromLua(1); if (!b->IsType(Object::DYNAMICBODY)) { lua_pushnil(l); return 1; } Frame *f = b->GetFrame(); if (!f->IsRotFrame()) return 0; vector3d pos = b->GetPosition(); double latitude = atan2(pos.y, sqrt(pos.x * pos.x + pos.z * pos.z)); double longitude = atan2(pos.x, pos.z); lua_pushnumber(l, latitude); lua_pushnumber(l, longitude); Body *astro = f->GetBody(); if (astro->IsType(Object::TERRAINBODY)) { double radius = static_cast<TerrainBody *>(astro)->GetTerrainHeight(pos.Normalized()); double altitude = pos.Length() - radius; lua_pushnumber(l, altitude); } else { lua_pushnil(l); } return 3; }
void Camera::Update() { if (!m_frame) return; // make temporary camera frame m_camFrame = new Frame(m_frame, "camera", Frame::FLAG_ROTATING); // move and orient it to the camera position m_camFrame->SetOrient(m_orient); m_camFrame->SetPosition(m_pos); // make sure old orient and interpolated orient (rendering orient) are not rubbish m_camFrame->ClearMovement(); m_camFrame->UpdateInterpTransform(1.0); // update root-relative pos/orient // evaluate each body and determine if/where/how to draw it m_sortedBodies.clear(); for (Space::BodyIterator i = Pi::game->GetSpace()->BodiesBegin(); i != Pi::game->GetSpace()->BodiesEnd(); ++i) { Body *b = *i; // prepare attrs for sorting and drawing BodyAttrs attrs; attrs.body = b; Frame::GetFrameRenderTransform(b->GetFrame(), m_camFrame, attrs.viewTransform); attrs.viewCoords = attrs.viewTransform * b->GetInterpPosition(); attrs.camDist = attrs.viewCoords.Length(); attrs.bodyFlags = b->GetFlags(); m_sortedBodies.push_back(attrs); } // depth sort m_sortedBodies.sort(); }
void Camera::Update() { if (!m_body) return; // make temporary camera frame at the body m_camFrame = new Frame(m_body->GetFrame(), "camera", Frame::TEMP_VIEWING | Frame::FLAG_ROTATING); // interpolate between last physics tick position and current one, // to remove temporal aliasing const matrix3x3d &m = m_body->GetInterpOrient(); m_camFrame->SetOrient(m * m_orient); m_camFrame->SetPosition(m * m_pos + m_body->GetInterpPosition()); // make sure old orient and interpolated orient (rendering orient) are not rubbish m_camFrame->ClearMovement(); m_camFrame->UpdateInterpTransform(1.0); // update root-relative pos/orient // evaluate each body and determine if/where/how to draw it m_sortedBodies.clear(); for (Space::BodyIterator i = Pi::game->GetSpace()->BodiesBegin(); i != Pi::game->GetSpace()->BodiesEnd(); ++i) { Body *b = *i; // prepare attrs for sorting and drawing BodyAttrs attrs; attrs.body = b; Frame::GetFrameRenderTransform(b->GetFrame(), m_camFrame, attrs.viewTransform); attrs.viewCoords = attrs.viewTransform * b->GetInterpPosition(); attrs.camDist = attrs.viewCoords.Length(); attrs.bodyFlags = b->GetFlags(); m_sortedBodies.push_back(attrs); } // depth sort m_sortedBodies.sort(); }
/* * Attribute: frameRotating * * Whether the frame this dynamic body is in is a rotating frame. * * Only valid for dynamic <Bodies>. For non-dynamic bodies <frameRotating> * will be nil. * * Availability: * * alpha 12 * * Status: * * experimental */ static int l_body_attr_frame_rotating(lua_State *l) { Body *b = LuaObject<Body>::CheckFromLua(1); if (!b->IsType(Object::DYNAMICBODY)) { lua_pushnil(l); return 1; } Frame *f = b->GetFrame(); lua_pushboolean(l, f->IsRotFrame()); return 1; }
/* * Attribute: frameBody * * The non-dynamic body attached to the frame this dynamic body is in. * * Only valid for dynamic <Bodies>. For non-dynamic bodies <frameBody> will be * nil. * * <frameBody> can also be nil if this dynamic body is in a frame with no * non-dynamic body. This most commonly occurs when the player is in * hyperspace. * * Availability: * * alpha 12 * * Status: * * experimental */ static int l_body_attr_frame_body(lua_State *l) { Body *b = LuaObject<Body>::CheckFromLua(1); if (!b->IsType(Object::DYNAMICBODY)) { lua_pushnil(l); return 1; } Frame *f = b->GetFrame(); LuaObject<Body>::PushToLua(f->GetBody()); return 1; }
Game::Game(const SystemPath &path, double time) : m_galaxy(GalaxyGenerator::Create()), m_time(time), m_state(STATE_NORMAL), m_wantHyperspace(false), m_timeAccel(TIMEACCEL_1X), m_requestedTimeAccel(TIMEACCEL_1X), m_forceTimeAccel(false) { // Now that we have a Galaxy, check the starting location if (!path.IsBodyPath()) throw InvalidGameStartLocation("SystemPath is not a body path"); RefCountedPtr<const Sector> s = m_galaxy->GetSector(path); if (size_t(path.systemIndex) >= s->m_systems.size()) { char buf[128]; std::sprintf(buf, "System %u in sector <%d,%d,%d> does not exist", unsigned(path.systemIndex), int(path.sectorX), int(path.sectorY), int(path.sectorZ)); throw InvalidGameStartLocation(std::string(buf)); } RefCountedPtr<StarSystem> sys = m_galaxy->GetStarSystem(path); if (path.bodyIndex >= sys->GetNumBodies()) { char buf[256]; std::sprintf(buf, "Body %d in system <%d,%d,%d : %d ('%s')> does not exist", unsigned(path.bodyIndex), int(path.sectorX), int(path.sectorY), int(path.sectorZ), unsigned(path.systemIndex), sys->GetName().c_str()); throw InvalidGameStartLocation(std::string(buf)); } m_space.reset(new Space(this, m_galaxy, path)); Body *b = m_space->FindBodyForPath(&path); assert(b); m_player.reset(new Player("kanara")); m_space->AddBody(m_player.get()); m_player->SetFrame(b->GetFrame()); if (b->GetType() == Object::SPACESTATION) { m_player->SetDockedWith(static_cast<SpaceStation*>(b), 0); } else { const SystemBody *sbody = b->GetSystemBody(); m_player->SetPosition(vector3d(0, 1.5*sbody->GetRadius(), 0)); m_player->SetVelocity(vector3d(0,0,0)); } Polit::Init(m_galaxy); CreateViews(); EmitPauseState(IsPaused()); }
/* * Function: SpawnShipNear * * Create a ship and place it in space near the given <Body>. * * > ship = Space.SpawnShip(type, body, min, max, hyperspace) * * Parameters: * * type - the name of the ship * * body - the <Body> near which the ship should be spawned * * min - minimum distance from the body to place the ship, in Km * * max - maximum distance to place the ship * * hyperspace - optional table containing hyperspace entry information. If * this is provided the ship will not spawn directly. Instead, * a hyperspace cloud will be created that the ship will exit * from. The table contains two elements, a <SystemPath> for * the system the ship is travelling from, and the due * date/time that the ship should emerge from the cloud. * * Return: * * ship - a <Ship> object for the new ship * * Example: * * > -- spawn a ship 10km from the player * > local ship = Ship.SpawnNear("viper_police_craft", Game.player, 10, 10) * * Availability: * * alpha 10 * * Status: * * experimental */ static int l_space_spawn_ship_near(lua_State *l) { if (!Pi::game) luaL_error(l, "Game is not started"); LUA_DEBUG_START(l); const char *type = luaL_checkstring(l, 1); if (! ShipType::Get(type)) luaL_error(l, "Unknown ship type '%s'", type); Body *nearbody = LuaObject<Body>::CheckFromLua(2); float min_dist = luaL_checknumber(l, 3); float max_dist = luaL_checknumber(l, 4); SystemPath *path = 0; double due = -1; _unpack_hyperspace_args(l, 5, path, due); Ship *ship = new Ship(type); assert(ship); Body *thing = _maybe_wrap_ship_with_cloud(ship, path, due); // XXX protect against spawning inside the body Frame * newframe = nearbody->GetFrame(); const vector3d newPosition = (MathUtil::RandomPointOnSphere(min_dist, max_dist)* 1000.0) + nearbody->GetPosition(); // If the frame is rotating and the chosen position is too far, use non-rotating parent. // Otherwise the ship will be given a massive initial velocity when it's bumped out of the // rotating frame in the next update if (newframe->IsRotFrame() && newframe->GetRadius() < newPosition.Length()) { assert(newframe->GetParent()); newframe = newframe->GetParent(); } thing->SetFrame(newframe);; thing->SetPosition(newPosition); thing->SetVelocity(vector3d(0,0,0)); Pi::game->GetSpace()->AddBody(thing); LuaObject<Ship>::PushToLua(ship); LUA_DEBUG_END(l, 1); return 1; }
void Camera::Update() { if (!m_body) return; if (m_shadersEnabled != Render::AreShadersEnabled()) { m_frustum = Render::Frustum(m_width, m_height, m_fovAng); m_shadersEnabled = !m_shadersEnabled; } // make temporary camera frame at the body m_camFrame = new Frame(m_body->GetFrame(), "camera", Frame::TEMP_VIEWING); // interpolate between last physics tick position and current one, // to remove temporal aliasing matrix4x4d bodyPose = m_body->GetInterpolatedTransform(); m_camFrame->SetTransform(bodyPose * m_pose); // make sure old orient and interpolated orient (rendering orient) are not rubbish m_camFrame->ClearMovement(); // evaluate each body and determine if/where/how to draw it m_sortedBodies.clear(); for (Space::BodyIterator i = Pi::game->GetSpace()->BodiesBegin(); i != Pi::game->GetSpace()->BodiesEnd(); ++i) { Body *b = *i; // prepare attrs for sorting and drawing BodyAttrs attrs; attrs.body = b; Frame::GetFrameRenderTransform(b->GetFrame(), m_camFrame, attrs.viewTransform); attrs.viewCoords = attrs.viewTransform * b->GetInterpolatedPosition(); attrs.camDist = attrs.viewCoords.Length(); attrs.bodyFlags = b->GetFlags(); m_sortedBodies.push_back(attrs); } // depth sort m_sortedBodies.sort(); }
DrawList::Item::Item(const Body &body, Point pos, Point blur, float cloak, float clip, int swizzle, int step) : position{static_cast<float>(pos.X()), static_cast<float>(pos.Y())}, clip(clip), flags(swizzle) { Body::Frame frame = body.GetFrame(step); tex0 = frame.first; tex1 = frame.second; flags |= static_cast<uint32_t>(frame.fade * 256.f) << 8; double width = body.Width(); double height = body.Height(); Point unit = body.Facing().Unit(); Point uw = unit * width; Point uh = unit * height; if(clip < 1.) { // "clip" is the fraction of its height that we're clipping the sprite // to. We still want it to start at the same spot, though. pos -= uh * ((1. - clip) * .5); position[0] = static_cast<float>(pos.X()); position[1] = static_cast<float>(pos.Y()); uh *= clip; } // (0, -1) means a zero-degree rotation (since negative Y is up). transform[0] = -uw.Y(); transform[1] = uw.X(); transform[2] = -uh.X(); transform[3] = -uh.Y(); // Calculate the blur vector, in texture coordinates. this->blur[0] = unit.Cross(blur) / (width * 4.); this->blur[1] = -unit.Dot(blur) / (height * 4.); if(cloak > 0.) Cloak(cloak); }
Game::Game(const SystemPath &path, const vector3d &pos) : m_time(0), m_state(STATE_NORMAL), m_wantHyperspace(false), m_timeAccel(TIMEACCEL_1X), m_requestedTimeAccel(TIMEACCEL_1X), m_forceTimeAccel(false) { m_space.Reset(new Space(this, path)); Body *b = m_space->FindBodyForPath(&path); assert(b); CreatePlayer(); m_space->AddBody(m_player.Get()); m_player->Enable(); m_player->SetFrame(b->GetFrame()); m_player->SetPosition(pos); m_player->SetVelocity(vector3d(0,0,0)); CreateViews(); }
/* * Function: SpawnShipLandedNear * * Create a ship and place it on the surface near the given <Body>. * * > ship = Space.SpawnShipLandedNear(type, body, min, max) * * Parameters: * * type - the name of the ship * * body - the <Body> near which the ship should be spawned. It must be on the ground or close to it, * i.e. it must be in the rotating frame of the planetary body. * * min - minimum distance from the surface point below the body to place the ship, in Km * * max - maximum distance to place the ship * * Return: * * ship - a <Ship> object for the new ship * * Example: * * > -- spawn a ship 10km from the player * > local ship = Ship.SpawnShipLandedNear("viper_police", Game.player, 10, 10) * * Availability: * * July 2013 * * Status: * * experimental */ static int l_space_spawn_ship_landed_near(lua_State *l) { if (!Pi::game) luaL_error(l, "Game is not started"); LUA_DEBUG_START(l); const char *type = luaL_checkstring(l, 1); if (! ShipType::Get(type)) luaL_error(l, "Unknown ship type '%s'", type); Body *nearbody = LuaObject<Body>::CheckFromLua(2); const float min_dist = luaL_checknumber(l, 3); const float max_dist = luaL_checknumber(l, 4); if (min_dist > max_dist) luaL_error(l, "min_dist must not be larger than max_dist"); Ship *ship = new Ship(type); assert(ship); // XXX protect against spawning inside the body Frame * newframe = nearbody->GetFrame()->GetRotFrame(); if (!newframe->IsRotFrame()) luaL_error(l, "Body must be in rotating frame"); SystemBody *sbody = newframe->GetSystemBody(); if (sbody->GetSuperType() != SystemBody::SUPERTYPE_ROCKY_PLANET) luaL_error(l, "Body is not on a rocky planet"); if (max_dist > sbody->GetRadius()) luaL_error(l, "max_dist too large for planet radius"); // We assume that max_dist is much smaller than the planet radius, i.e. that our area is reasonably flat // So, we const vector3d up = nearbody->GetPosition().Normalized(); vector3d x; vector3d y; // Calculate a orthonormal basis for a horizontal plane. For numerical reasons we do that determining the smallest // coordinate and take the cross product with (1,0,0), (0,1,0) or (0,0,1) respectively to calculate the first vector. // The second vector is just the cross product of the up-vector and out first vector. if (up.x <= up.y && up.x <= up.z) { x = vector3d(0.0, up.z, -up.y).Normalized(); y = vector3d(-up.y*up.y - up.z*up.z, up.x*up.y, up.x*up.z).Normalized(); } else if (up.y <= up.x && up.y <= up.z) { x = vector3d(-up.z, 0.0, up.x).Normalized(); y = vector3d(up.x*up.y, -up.x*up.x - up.z*up.z, up.y*up.z).Normalized(); } else { x = vector3d(up.y, -up.x, 0.0).Normalized(); y = vector3d(up.x*up.z, up.y*up.z, -up.x*up.x - up.y*up.y).Normalized(); } Planet *planet = static_cast<Planet*>(newframe->GetBody()); const double radius = planet->GetSystemBody()->GetRadius(); const vector3d planar = MathUtil::RandomPointInCircle(min_dist * 1000.0, max_dist * 1000.0); vector3d pos = (radius * up + x * planar.x + y * planar.y).Normalized(); float latitude = atan2(pos.y, sqrt(pos.x*pos.x + pos.z * pos.z)); float longitude = atan2(pos.x, pos.z); Pi::game->GetSpace()->AddBody(ship); ship->SetLandedOn(planet, latitude, longitude); LuaObject<Ship>::PushToLua(ship); LUA_DEBUG_END(l, 1); return 1; }