void moveBulldozer(int dist){ for(int n=0; n<dist;n++){ // d.game->sim->getRailPen()->move(1, d.game->sim); Point p = d.game->sim.railPen.getPos(); if(d.game->sim.railPen.getMode() == RailPen::PAINTING){ Rail * newRail = d.game->sim.railPen.makeNewRail(d.game->sim.railMap.getRailAt(p.row, p.col)); d.game->sim.railMap.setRail(p.row, p.col, newRail); ForkRail *rf = dynamic_cast<ForkRail *>(newRail); if(rf){ d.game->sim.addFork(rf); } Point lastPoint = d.game->sim.railPen.getPos(); Dir lastDir = d.game->sim.railPen.getLastDir(); Dir backDir = -lastDir; lastPoint.move(backDir); Rail * lastRail = d.game->sim.railMap.getRailAt(lastPoint.row, lastPoint.col); if(lastRail){ newRail->linkRailAt(backDir, lastRail); } } d.game->sim.railPen.forward(); } }
Rail * RailPen::makeNewRail(Rail * rail){ DirEnv env; if(rail){ env = rail->getEnv(); } env.addPath(-lastDir, dir); Rail * newRail = env.makeNewRail(); if(rail){ for(int n(Dir::E) ;n<(Dir::NUM_DIRS); n++){ Dir dir (n); Rail * linked = rail->getLinkedRailAt(dir); if(linked){ newRail->linkRailAt(dir, linked); } } } return newRail; }
// ojo, no pinta cuando distance es mayor que 1. Testear esto!!!!!!!!!!!!!! bool RailPen::move(int distance, Sim * sim){ Point p = getPos(); if(getMode() == PAINTING){ if(distance>0){ for(int n= 0; n<distance;n++){ Rail * newRail = makeNewRail(sim->railMap.getRailAt(p.row, p.col)); sim->railMap.setRail(p.row, p.col, newRail); ForkRail *rf = dynamic_cast<ForkRail *>(newRail); if(rf){ sim->addFork(rf); } Point lastPoint = getPos(); Dir lastDir = getLastDir(); Dir backDir = -lastDir; lastPoint.move(backDir); Rail * lastRail = sim->railMap.getRailAt(lastPoint.row, lastPoint.col); if(lastRail){ newRail->linkRailAt(backDir, lastRail); } forward(); } }else{ for(int n=0; n>distance;n--){ Point p = getPos(); sim->railMap.setRail(p.row, p.col, 0); backwards(); } } }else{ pos.move(dir, distance); lastDir=dir; } return true; }
void World::Update(const float time_delta) { mCurrentLevelTime += time_delta; // INPUT! const sf::Input& in = GameApp::get_mutable_instance().GetInput(); sf::View& view = GameApp::get_mutable_instance().GetView(); if(GameApp::get_mutable_instance().IsEditorMode()) { float px = 10; if(in.IsKeyDown(sf::Key::LShift) || in.IsKeyDown(sf::Key::RShift)) { px *= 5; } if(in.IsKeyDown(sf::Key::Up)) { view.SetCenter(view.GetCenter().x, view.GetCenter().y - px); } if(in.IsKeyDown(sf::Key::Down)) { view.SetCenter(view.GetCenter().x, view.GetCenter().y + px); } if(in.IsKeyDown(sf::Key::Left)) { view.SetCenter(view.GetCenter().x - px, view.GetCenter().y); } if(in.IsKeyDown(sf::Key::Right)) { view.SetCenter(view.GetCenter().x + px, view.GetCenter().y); } Coordinates mp; mp.SetScreenPixel(GameApp::get_mutable_instance().GetMousePosition()); if(mEditorMouseAction == EMA_GRAB) { mEditorMouseActionEntity->SetPosition( mEditorMouseActionStartEntityPosition.GetWorldFloat() + mp.GetWorldFloat() - mEditorMouseActionStartMousePosition.GetWorldFloat() ); } else if(mEditorMouseAction == EMA_ALPHA) { float mpf = mp.GetScreenFloat().y; float mspf = mEditorMouseActionStartMousePosition.GetScreenFloat().y; float d = (mspf - mpf) * 5.f; float a = mEditorMouseActionStartEntityAlpha + d; if (a > 1) a = 1; if (a < 0) a = 0; mEditorMouseActionEntity->SetAlpha( a ); } else if(mEditorMouseAction == EMA_SCALE) { Vector2D md = mEditorMouseActionStartEntityPosition.GetScreenPixel() - mp.GetScreenPixel(); Vector2D sd = mEditorMouseActionStartEntityPosition.GetScreenPixel() - mEditorMouseActionStartMousePosition.GetScreenPixel(); float f = md.Magnitude() / sd.Magnitude(); mEditorMouseActionEntity->SetScale( mEditorMouseActionStartEntityScale * f ); } else if(mEditorMouseAction == EMA_ROTATE) { Coordinates ep; ep.SetWorldFloat(mEditorMouseActionEntity->GetPosition()); mEditorMouseActionEntity->SetRotation( (mEditorMouseActionStartMousePosition.GetWorldFloat()-ep.GetWorldFloat()).Rotation() -(mp.GetWorldFloat()-ep.GetWorldFloat()).Rotation() + mEditorMouseActionStartEntityRotation ); } } else if(GameApp::get_mutable_instance().GetAppMode() == AM_PUZZLE) { // draw point on closest rail Rail* r = GetClosestRail(); if(r != NULL) { Coordinates tmp; tmp.SetScreenPixel(GameApp::get_mutable_instance().GetMousePosition()); float d = r->ClosestPositionOnLine(tmp.GetWorldFloat()); mClosestRailPoint = r->GetPointFromFloat(d); } mClosestRail = r; } if(GetBoxEntity() != NULL && GetBoxEntity()->UsesPhysics() && !GameApp::get_mutable_instance().GetInput().IsMouseButtonDown(sf::Mouse::Left)) { mCurrentRail = GetClosestRail(true, GetBoxEntity()->GetBody()->getWorldTransform().getOrigin()); } //mDynamicsWorld->stepSimulation(time_delta, 10); if(GameApp::get_mutable_instance().GetAppMode() == AM_PLAY) { mDynamicsWorld->stepSimulation(1 / 60.f, 10); mDynamicsWorld->clearForces(); } Entity* c = GetClosestEntityOnLayer(GameApp::get_mutable_instance().GetMousePosition(), mEditorLayer); BOOST_FOREACH(Entity& entity, mEntities) { int h = 0; if (mEditorSelectedEntity == &entity) h = 2; else if (c == &entity) h = 1; entity.SetHighlightMode(h); entity.Update(time_delta); /*if(entity.GetLifeTime() >= entity.GetTimeToLive()) { mDynamicsWorld->removeRigidBody(entity.GetBody().get()); mEntities.erase_if(boost::bind(&Entity::GetUID, _1) == entity.GetEntityUniqueId()); }*/ }
// draw the rails BOOST_FOREACH(Rail& r, mRails) { r.Update(time_delta); }
// Generates the actual mesh for the river, and adds it to this entitiy's // rendermesh component. void RiverComponent::CreateRiverMesh(corgi::EntityRef& entity) { static const fplbase::Attribute kMeshFormat[] = { fplbase::kPosition3f, fplbase::kTexCoord2f, fplbase::kNormal3f, fplbase::kTangent4f, fplbase::kEND}; static const fplbase::Attribute kBankMeshFormat[] = { fplbase::kPosition3f, fplbase::kTexCoord2f, fplbase::kNormal3f, fplbase::kTangent4f, fplbase::kColor4ub, fplbase::kEND}; std::vector<vec3_packed> track; const RiverConfig* river = entity_manager_->GetComponent<ServicesComponent>() ->config() ->river_config(); RiverData* river_data = Data<RiverData>(entity); river_data->render_mesh_needs_update_ = false; // Initialize the static mesh that will be made around the river banks. auto* physics_component = entity_manager_->GetComponent<PhysicsComponent>(); physics_component->InitStaticMesh(entity); Rail* rail = entity_manager_->GetComponent<ServicesComponent>() ->rail_manager() ->GetRailFromComponents(river_data->rail_name.c_str(), entity_manager_); // Generate the spline data and store it in our track vector: rail->Positions(river->spline_stepsize(), &track); fplbase::AssetManager* asset_manager = entity_manager_->GetComponent<ServicesComponent>()->asset_manager(); const size_t num_bank_contours = river->default_banks()->Length(); const size_t num_bank_quads = num_bank_contours - 2; const size_t river_idx = river->river_index(); const size_t segment_count = track.size(); const size_t river_vert_max = segment_count * 2; const size_t river_index_max = (segment_count - 1) * kNumIndicesPerQuad; const size_t bank_vert_max = segment_count * num_bank_contours; const size_t bank_index_max = (segment_count - 1) * kNumIndicesPerQuad * num_bank_quads; assert(num_bank_contours >= 2 && river_idx < num_bank_contours - 1); const unsigned int num_zones = river->zones()->Length(); // Need to allocate some space to plan out our mesh in: std::vector<NormalMappedVertex> river_verts(river_vert_max); river_verts.clear(); std::vector<unsigned short> river_indices(river_index_max); river_indices.clear(); std::vector<NormalMappedColorVertex> bank_verts(bank_vert_max); bank_verts.clear(); std::vector<unsigned short> bank_indices(bank_index_max); bank_indices.clear(); // Use one set of bank vertices for the entire riverbank, but separate out // the zones via indices, so we can use different materials (and possibly // shaders) per zone. We still keep bank_indices for the normal calculation, // though. std::vector<std::vector<unsigned short>> bank_indices_by_zone; bank_indices_by_zone.resize(num_zones); std::vector<unsigned int> bank_zones; // indexed by segment bank_zones.resize(segment_count, 0); // default of 0 unsigned int zone_id = 0; // TODO: Use a local random number generator. Resetting the global random // number generator is not a nice. Also, there's no guarantee that // mathfu::Random will continue to use rand(). srand(river_data->random_seed); std::vector<float> actual_zone_end; actual_zone_end.resize(segment_count, 1); // Precalculate the actual zone end locations. for (size_t i = 0; i < segment_count; i++) { const float fraction = static_cast<float>(i) / static_cast<float>(segment_count); if (zone_id + 1 < river->zones()->Length() && fraction > river->zones()->Get(zone_id + 1)->zone_start()) { actual_zone_end[zone_id] = fraction; zone_id = zone_id + 1; } } // Start over from zone 0. zone_id = 0; const RiverZone* current_zone = river->zones()->Get(zone_id); Material* current_bank_material = asset_manager->LoadMaterial(current_zone->material()->c_str()); float river_width = current_zone->width() != 0 ? current_zone->width() : river->default_width(); // Construct the actual mesh data for the river: std::vector<vec2> offsets(num_bank_contours); for (size_t i = 0; i < segment_count; i++) { // River track is circular. const size_t prev_i = i == 0 ? segment_count - 1 : i - 1; // Get the current position on the track, and the normal (to the side). const vec3 track_delta = vec3(track[i]) - vec3(track[prev_i]); const vec3 track_normal = vec3::CrossProduct(track_delta, kAxisZ3f).Normalized(); const vec3 track_position = vec3(track[i]) + river->track_height() * kAxisZ3f; // The river texture is tiled several times along the course of the river. // TODO: Change this from tile count to actual physical size for a tile. // Requires that we know the total path distance. const float texture_v = river->texture_tile_size() * static_cast<float>(i) / static_cast<float>(segment_count); // Fraction of the river we have gone through, approximately. const float fraction = static_cast<float>(i) / static_cast<float>(segment_count); if (fraction >= actual_zone_end[zone_id]) { zone_id = zone_id + 1; current_zone = river->zones()->Get(zone_id); // Each zone has its own texture. current_bank_material = asset_manager->LoadMaterial(current_zone->material()->c_str()); // Each zone has its own river width. river_width = current_zone->width() != 0 ? current_zone->width() : river->default_width(); current_bank_material = asset_manager->LoadMaterial( river->zones()->Get(zone_id)->material()->c_str()); } bank_zones[i] = zone_id; float zone_start = zone_id == 0 ? 0 : actual_zone_end[zone_id - 1]; float zone_end = actual_zone_end[zone_id]; float within_fraction = (fraction - zone_start) / (zone_end - zone_start); if (current_bank_material->textures().size() == 1) { // Ensure we stay continuous with transitional zones. within_fraction = within_fraction < 0.5f ? 1.0f : 0.0f; } int within_color = static_cast<int>(255.0 * within_fraction); // Cap the color to 0..255 byte. unsigned char within_color_byte = static_cast<unsigned char>( within_color < 0 ? 0 : (within_color > 255 ? 255 : within_color)); // Get the (side, up) offsets of the bank vertices. // The offsets are relative to `track_position`. // side == distance along `track_normal` // up == distance along kAxisZ3f for (size_t j = 0; j < num_bank_contours; ++j) { const RiverBankContour* b = (current_zone->banks() != nullptr) ? current_zone->banks()->Get(j) : river->default_banks()->Get(j); offsets[j] = vec2(mathfu::Lerp(b->x_min(), b->x_max(), mathfu::Random<float>()), mathfu::Lerp(b->z_min(), b->z_max(), mathfu::Random<float>())); } // Create the bank vertices for this segment. for (size_t j = 0; j < num_bank_contours; ++j) { const bool left_bank = j <= river_idx; const vec2 off = offsets[j]; const vec3 vertex = track_position + (off.x() + river_width * (left_bank ? -1 : 1)) * track_normal + off.y() * kAxisZ3f; // The texture is stretched from the side of the river to the far end // of the bank. There are two banks, however, separated by the river. // We need to know the width of the bank to caluate the `texture_u` // coordinate. const size_t bank_start = left_bank ? 0 : num_bank_contours - 1; const size_t bank_end = left_bank ? river_idx : river_idx + 1; const float bank_width = offsets[bank_start].x() - offsets[bank_end].x(); const float texture_u = (off.x() - offsets[bank_end].x()) / bank_width; bank_verts.push_back(NormalMappedColorVertex()); bank_verts.back().pos = vec3_packed(vertex); bank_verts.back().tc = vec2_packed(vec2(texture_u, texture_v)); bank_verts.back().norm = vec3_packed(vec3(0, 1, 0)); bank_verts.back().tangent = vec4_packed(vec4(1, 0, 0, 1)); unsigned char color_bytes[4] = {255, 255, 255, within_color_byte}; memcpy(bank_verts.back().color, color_bytes, sizeof(color_bytes)); } // Ensure vertices don't go behind previous vertices on the inside of // a tight corner. if (i > 0) { const NormalMappedColorVertex* prev_verts = &bank_verts[bank_verts.size() - 2 * num_bank_contours]; NormalMappedColorVertex* cur_verts = &bank_verts[bank_verts.size() - num_bank_contours]; for (size_t j = 0; j < num_bank_contours; j++) { const vec3 vert_delta = vec3(cur_verts[j].pos) - vec3(prev_verts[j].pos); const float dot = vec3::DotProduct(vert_delta, track_delta); const bool cur_vert_goes_backwards_along_track = dot <= 0.0f; if (cur_vert_goes_backwards_along_track) { cur_verts[j].pos = vec3(prev_verts[j].pos) + 0.000001f * track_delta; } } } // Force the beginning and end to line up in their geometry: if (i == segment_count - 1) { for (size_t j = 0; j < num_bank_contours; j++) bank_verts[bank_verts.size() - (8 - j)].pos = bank_verts[j].pos; } // The river has two of the middle vertices of the bank. // The texture coordinates are different, however. const size_t river_vert = bank_verts.size() - num_bank_contours + river_idx; float normalized_texture_v = i / static_cast<float>(segment_count); river_verts.push_back(NormalMappedVertex()); river_verts.back().pos = bank_verts[river_vert].pos; river_verts.back().tc = vec2(0.0f, normalized_texture_v); river_verts.back().norm = bank_verts[river_vert].norm; river_verts.back().tangent = bank_verts[river_vert].tangent; river_verts.push_back(NormalMappedVertex()); river_verts.back().pos = bank_verts[river_vert + 1].pos; river_verts.back().tc = vec2(1.0f, normalized_texture_v); river_verts.back().norm = bank_verts[river_vert + 1].norm; river_verts.back().tangent = bank_verts[river_vert + 1].tangent; } // Not counting the first segment, create triangles in our index // list to represent this segment. // for (size_t i = 0; i < segment_count - 1; i++) { auto make_quad = [&](std::vector<unsigned short>& indices, int base_index, int off1, int off2) { indices.push_back(static_cast<unsigned short>(base_index + off1)); indices.push_back(static_cast<unsigned short>(base_index + off1 + 1)); indices.push_back(static_cast<unsigned short>(base_index + off2)); indices.push_back(static_cast<unsigned short>(base_index + off2)); indices.push_back(static_cast<unsigned short>(base_index + off1 + 1)); indices.push_back(static_cast<unsigned short>(base_index + off2 + 1)); }; // River only has one quad per segment. make_quad(river_indices, 2 * i, 0, 2); // Case when kNumBankCountours = 8, and river_idx = 3; // // 0___1___2___3 4___5___6___7 // | _/| _/| _/| | _/| _/| _/| // |/__|/__|/__| |/__|/__|/__| // 8 9 10 11 12 13 14 15 for (size_t j = 0; j <= num_bank_quads; ++j) { // Do not create bank geo for the river. if (j == river_idx) continue; unsigned int zone = bank_zones[i]; int base_index = i * num_bank_contours; int offset1 = j; int offset2 = num_bank_contours + j; make_quad(bank_indices, base_index, offset1, offset2); make_quad(bank_indices_by_zone[zone], base_index, offset1, offset2); // Add the same triangles to the static mesh associated with the entity. physics_component->AddStaticMeshTriangle( entity, vec3(bank_verts[base_index + offset1].pos), vec3(bank_verts[base_index + offset1 + 1].pos), vec3(bank_verts[base_index + offset2].pos)); physics_component->AddStaticMeshTriangle( entity, vec3(bank_verts[base_index + offset2].pos), vec3(bank_verts[base_index + offset1 + 1].pos), vec3(bank_verts[base_index + offset2 + 1].pos)); } } // Make sure we used as much data as expected, and no more. assert(river_indices.size() == river_index_max); assert(river_verts.size() == river_vert_max); assert(bank_indices.size() == bank_index_max); assert(bank_verts.size() == bank_vert_max); Mesh::ComputeNormalsTangents(bank_verts.data(), bank_indices.data(), bank_verts.size(), bank_indices.size()); // Load the material from files. Material* river_material = asset_manager->LoadMaterial(river->material()->c_str()); // Create the actual mesh objects, and stuff all the data we just // generated into it. Mesh* river_mesh = new Mesh(river_verts.data(), river_verts.size(), sizeof(NormalMappedVertex), kMeshFormat); river_mesh->AddIndices(river_indices.data(), river_indices.size(), river_material); // Add the river mesh to the river entity. RenderMeshData* mesh_data = Data<RenderMeshData>(entity); mesh_data->shader = asset_manager->LoadShader(river->shader()->c_str()); if (mesh_data->mesh != nullptr) { // Mesh's destructor handles cleaning up its GL buffers delete mesh_data->mesh; mesh_data->mesh = nullptr; } mesh_data->mesh = river_mesh; mesh_data->culling_mask = 0; // Never cull the river. mesh_data->pass_mask = 1 << corgi::RenderPass_Opaque; river_data->banks.resize(num_zones, corgi::EntityRef()); for (unsigned int zone = 0; zone < num_zones; zone++) { Material* bank_material = asset_manager->LoadMaterial( river->zones()->Get(zone)->material()->c_str()); Mesh* bank_mesh = new Mesh(bank_verts.data(), bank_verts.size(), sizeof(NormalMappedColorVertex), kBankMeshFormat); bank_mesh->AddIndices(bank_indices_by_zone[zone].data(), bank_indices_by_zone[zone].size(), bank_material); if (!river_data->banks[zone]) { // Now we make a new entity to hold the bank mesh. river_data->banks[zone] = entity_manager_->AllocateNewEntity(); entity_manager_->AddEntityToComponent<RenderMeshComponent>( river_data->banks[zone]); // Then we stick it as a child of the river entity, so it always moves // with it and stays aligned: auto transform_component = GetComponent<corgi::component_library::TransformComponent>(); transform_component->AddChild(river_data->banks[zone], entity); } RenderMeshData* child_render_data = Data<RenderMeshData>(river_data->banks[zone]); if (bank_material->textures().size() == 1) { child_render_data->shader = asset_manager->LoadShader("shaders/textured_lit"); } else { child_render_data->shader = asset_manager->LoadShader("shaders/textured_lit_bank"); } if (child_render_data->mesh != nullptr) { // Mesh's destructor handles cleaning up its GL buffers delete child_render_data->mesh; child_render_data->mesh = nullptr; } child_render_data->mesh = bank_mesh; child_render_data->culling_mask = 0; // Don't cull the banks for now. child_render_data->pass_mask = 1 << corgi::RenderPass_Opaque; } // Finalize the static physics mesh created on the river bank. short collision_type = static_cast<short>(river->collision_type()); short collides_with = 0; if (river->collides_with()) { for (auto collides = river->collides_with()->begin(); collides != river->collides_with()->end(); ++collides) { collides_with |= static_cast<short>(*collides); } } std::string user_tag = river->user_tag() ? river->user_tag()->c_str() : ""; physics_component->FinalizeStaticMesh(entity, collision_type, collides_with, river->mass(), river->restitution(), user_tag); }