From 70e975b976febea9f5a8cce8eb0a4622fb5e0439 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 14 Feb 2010 18:36:32 +0000 Subject: [PATCH] Tidy up trees a little bit --- src/Editor.cpp | 819 +++++++++++++++++++++++++------------------------ src/Game.cpp | 486 ++++++++++++++--------------- 2 files changed, 654 insertions(+), 651 deletions(-) diff --git a/src/Editor.cpp b/src/Editor.cpp index 90b6cd9..922a9e2 100644 --- a/src/Editor.cpp +++ b/src/Editor.cpp @@ -33,73 +33,73 @@ // Concrete editor class class Editor : public IScreen { public: - Editor(IMapPtr aMap); - Editor(const string& aMapName); - ~Editor(); + Editor(IMapPtr aMap); + Editor(const string& aMapName); + ~Editor(); - void display(IGraphicsPtr aContext) const; - void overlay() const; - void update(IPickBufferPtr aPickBuffer, int aDelta); - void onKeyDown(SDLKey aKey); - void onKeyUp(SDLKey aKey); - void onMouseMove(IPickBufferPtr aPickBuffer, int x, int y, int xrel, int yrel); - void onMouseClick(IPickBufferPtr aPickBuffer, int x, int y, - MouseButton aButton); - void onMouseRelease(IPickBufferPtr aPickBuffer, int x, int y, - MouseButton aButton); + void display(IGraphicsPtr aContext) const; + void overlay() const; + void update(IPickBufferPtr aPickBuffer, int aDelta); + void onKeyDown(SDLKey aKey); + void onKeyUp(SDLKey aKey); + void onMouseMove(IPickBufferPtr aPickBuffer, int x, int y, int xrel, int yrel); + void onMouseClick(IPickBufferPtr aPickBuffer, int x, int y, + MouseButton aButton); + void onMouseRelease(IPickBufferPtr aPickBuffer, int x, int y, + MouseButton aButton); - // Different tools the user can be using - enum Tool { - TRACK_TOOL, RAISE_TOOL, LOWER_TOOL, DELETE_TOOL, - LEVEL_TOOL, START_TOOL, STATION_TOOL, BUILDING_TOOL, - TREE_TOOL - }; - void setTool(Tool aTool) { myTool = aTool; } - - IMapPtr getMap() { return map; } - void setMap(IMapPtr aMap); + // Different tools the user can be using + enum Tool { + TRACK_TOOL, RAISE_TOOL, LOWER_TOOL, DELETE_TOOL, + LEVEL_TOOL, START_TOOL, STATION_TOOL, BUILDING_TOOL, + TREE_TOOL + }; + void setTool(Tool aTool) { myTool = aTool; } + + IMapPtr getMap() { return map; } + void setMap(IMapPtr aMap); private: - void buildGUI(); - void drawDraggedTrack(); - bool drawTrackTile(const Point& aPoint, const track::Direction& anAxis); - void drawDraggedStraight(const track::Direction& anAxis, int aLength); - void drawDraggedCurve(int xLength, int yLength); - bool canConnect(const Point& aFirstPoint, - const Point& aSecondPoint) const; - void dragBoxBounds(int& xMin, int& xMax, int &yMin, int& yMax) const; - void deleteObjects(); - void plantTrees(); - void save(); + void buildGUI(); + void drawDraggedTrack(); + bool drawTrackTile(const Point& aPoint, const track::Direction& anAxis); + void drawDraggedStraight(const track::Direction& anAxis, int aLength); + void drawDraggedCurve(int xLength, int yLength); + bool canConnect(const Point& aFirstPoint, + const Point& aSecondPoint) const; + void dragBoxBounds(int& xMin, int& xMax, int &yMin, int& yMax) const; + void deleteObjects(); + void plantTrees(); + void save(); - IMapPtr map; + IMapPtr map; - ILightPtr mySun; - Vector myPosition; + ILightPtr mySun; + Vector myPosition; - Tool myTool; - bool amScrolling; + Tool myTool; + bool amScrolling; - // Variables for dragging track segments - Point dragBegin, dragEnd; - bool amDragging; + // Variables for dragging track segments + Point dragBegin, dragEnd; + bool amDragging; - // GUI elements - gui::ILayoutPtr layout; - IBuildingPickerPtr buildingPicker; + // GUI elements + gui::ILayoutPtr layout; + IBuildingPickerPtr buildingPicker; }; Editor::Editor(IMapPtr aMap) - : map(aMap), myPosition(4.5, -17.5, -21.5), - myTool(TRACK_TOOL), amScrolling(false), amDragging(false) + : map(aMap), myPosition(4.5, -17.5, -21.5), + myTool(TRACK_TOOL), amScrolling(false), amDragging(false) { - mySun = makeSunLight(); + mySun = makeSunLight(); - buildGUI(); + buildGUI(); - map->setGrid(true); + map->setGrid(true); - log() << "Editing " << aMap->name(); + log() << "Editing " << aMap->name(); } Editor::~Editor() @@ -109,86 +109,86 @@ Editor::~Editor() void Editor::buildGUI() { - using namespace placeholders; + using namespace placeholders; - layout = gui::makeLayout("layouts/editor.xml"); + layout = gui::makeLayout("layouts/editor.xml"); - layout->get("/tool_wnd/tools/track").connect(gui::Widget::SIG_CLICK, - bind(&Editor::setTool, this, TRACK_TOOL)); - layout->get("/tool_wnd/tools/raise").connect(gui::Widget::SIG_CLICK, - bind(&Editor::setTool, this, RAISE_TOOL)); - layout->get("/tool_wnd/tools/lower").connect(gui::Widget::SIG_CLICK, - bind(&Editor::setTool, this, LOWER_TOOL)); - layout->get("/tool_wnd/tools/level").connect(gui::Widget::SIG_CLICK, - bind(&Editor::setTool, this, LEVEL_TOOL)); - layout->get("/tool_wnd/tools/delete").connect(gui::Widget::SIG_CLICK, - bind(&Editor::setTool, this, DELETE_TOOL)); - layout->get("/tool_wnd/tools/start").connect(gui::Widget::SIG_CLICK, - bind(&Editor::setTool, this, START_TOOL)); - layout->get("/tool_wnd/tools/station").connect(gui::Widget::SIG_CLICK, - bind(&Editor::setTool, this, STATION_TOOL)); - layout->get("/tool_wnd/tools/building").connect(gui::Widget::SIG_CLICK, - bind(&Editor::setTool, this, BUILDING_TOOL)); - layout->get("/tool_wnd/tools/tree").connect(gui::Widget::SIG_CLICK, - bind(&Editor::setTool, this, TREE_TOOL)); + layout->get("/tool_wnd/tools/track").connect(gui::Widget::SIG_CLICK, + bind(&Editor::setTool, this, TRACK_TOOL)); + layout->get("/tool_wnd/tools/raise").connect(gui::Widget::SIG_CLICK, + bind(&Editor::setTool, this, RAISE_TOOL)); + layout->get("/tool_wnd/tools/lower").connect(gui::Widget::SIG_CLICK, + bind(&Editor::setTool, this, LOWER_TOOL)); + layout->get("/tool_wnd/tools/level").connect(gui::Widget::SIG_CLICK, + bind(&Editor::setTool, this, LEVEL_TOOL)); + layout->get("/tool_wnd/tools/delete").connect(gui::Widget::SIG_CLICK, + bind(&Editor::setTool, this, DELETE_TOOL)); + layout->get("/tool_wnd/tools/start").connect(gui::Widget::SIG_CLICK, + bind(&Editor::setTool, this, START_TOOL)); + layout->get("/tool_wnd/tools/station").connect(gui::Widget::SIG_CLICK, + bind(&Editor::setTool, this, STATION_TOOL)); + layout->get("/tool_wnd/tools/building").connect(gui::Widget::SIG_CLICK, + bind(&Editor::setTool, this, BUILDING_TOOL)); + layout->get("/tool_wnd/tools/tree").connect(gui::Widget::SIG_CLICK, + bind(&Editor::setTool, this, TREE_TOOL)); - layout->get("/lower/action_wnd/save").connect(gui::Widget::SIG_CLICK, - bind(&Editor::save, this)); + layout->get("/lower/action_wnd/save").connect(gui::Widget::SIG_CLICK, + bind(&Editor::save, this)); - buildingPicker = makeBuildingPicker(layout); + buildingPicker = makeBuildingPicker(layout); } void Editor::setMap(IMapPtr aMap) { - map = aMap; - map->setGrid(true); + map = aMap; + map->setGrid(true); } void Editor::save() { - map->save(); + map->save(); } // Calculate the bounds of the drag box accounting for the different // possible directions of dragging void Editor::dragBoxBounds(int& xMin, int& xMax, int &yMin, int& yMax) const { - xMin = min(dragBegin.x, dragEnd.x); - xMax = max(dragBegin.x, dragEnd.x); + xMin = min(dragBegin.x, dragEnd.x); + xMax = max(dragBegin.x, dragEnd.x); - yMin = min(dragBegin.y, dragEnd.y); - yMax = max(dragBegin.y, dragEnd.y); + yMin = min(dragBegin.y, dragEnd.y); + yMax = max(dragBegin.y, dragEnd.y); } // Render the next frame void Editor::display(IGraphicsPtr aContext) const { - if (!map) - return; + if (!map) + return; - aContext->setCamera(myPosition, makeVector(45.0f, 45.0f, 0.0f)); + aContext->setCamera(myPosition, makeVector(45.0f, 45.0f, 0.0f)); - mySun->apply(); + mySun->apply(); - map->render(aContext); + map->render(aContext); - // Draw the highlight if we are dragging track - if (amDragging) { - int xmin, xmax, ymin, ymax; - dragBoxBounds(xmin, xmax, ymin, ymax); + // Draw the highlight if we are dragging track + if (amDragging) { + int xmin, xmax, ymin, ymax; + dragBoxBounds(xmin, xmax, ymin, ymax); - for (int x = xmin; x <= xmax; x++) { - for (int y = ymin; y <= ymax; y++) - map->highlightTile(aContext, makePoint(x, y), - make_tuple(1.0f, 1.0f, 1.0f)); - } - } + for (int x = xmin; x <= xmax; x++) { + for (int y = ymin; y <= ymax; y++) + map->highlightTile(aContext, makePoint(x, y), + make_tuple(1.0f, 1.0f, 1.0f)); + } + } } // Render the overlay void Editor::overlay() const { - layout->render(); + layout->render(); } // Prepare the next frame @@ -200,372 +200,372 @@ void Editor::update(IPickBufferPtr aPickBuffer, int aDelta) // True if the `aFirstPoint' is a valid track segment and it can // connect to `aSecondPoint' bool Editor::canConnect(const Point& aFirstPoint, - const Point& aSecondPoint) const + const Point& aSecondPoint) const { - if (!map->isValidTrack(aFirstPoint)) - return false; + if (!map->isValidTrack(aFirstPoint)) + return false; - ITrackSegmentPtr track = map->trackAt(aFirstPoint); + ITrackSegmentPtr track = map->trackAt(aFirstPoint); - Vector dir = makeVector( - aFirstPoint.x - aSecondPoint.x, - 0, - aFirstPoint.y - aSecondPoint.y).normalise(); + Vector dir = makeVector( + aFirstPoint.x - aSecondPoint.x, + 0, + aFirstPoint.y - aSecondPoint.y).normalise(); - return track->isValidDirection(dir) - || track->isValidDirection(-dir); + return track->isValidDirection(dir) + || track->isValidDirection(-dir); } // Draw a single tile of straight track and check for collisions // Returns `false' if track cannot be placed here bool Editor::drawTrackTile(const Point& aPoint, const track::Direction& anAxis) { - if (map->isValidTrack(aPoint)) { - ITrackSegmentPtr merged = map->trackAt(aPoint)->mergeExit(aPoint, anAxis); - if (merged) { - map->setTrackAt(aPoint, merged); - return true; - } - else { - warn() << "Cannot merge track"; - return false; - } - } - else { - map->setTrackAt(aPoint, makeStraightTrack(anAxis)); - return true; - } + if (map->isValidTrack(aPoint)) { + ITrackSegmentPtr merged = map->trackAt(aPoint)->mergeExit(aPoint, anAxis); + if (merged) { + map->setTrackAt(aPoint, merged); + return true; + } + else { + warn() << "Cannot merge track"; + return false; + } + } + else { + map->setTrackAt(aPoint, makeStraightTrack(anAxis)); + return true; + } } // Special case where the user drags a rectangle of width 1 // This just draws straight track along the rectangle void Editor::drawDraggedStraight(const track::Direction& anAxis, int aLength) { - Point where = dragBegin; + Point where = dragBegin; - for (int i = 0; i < aLength; i++) { - drawTrackTile(where, anAxis); + for (int i = 0; i < aLength; i++) { + drawTrackTile(where, anAxis); - where.x += anAxis.x; - where.y += anAxis.z; - } + where.x += anAxis.x; + where.y += anAxis.z; + } } // Called when the user has finished dragging a rectangle for track // Connect the beginning and end up in the simplest way possible void Editor::drawDraggedTrack() { - track::Direction straight; // Orientation for straight track section + track::Direction straight; // Orientation for straight track section - int xmin, xmax, ymin, ymax; - dragBoxBounds(xmin, xmax, ymin, ymax); + int xmin, xmax, ymin, ymax; + dragBoxBounds(xmin, xmax, ymin, ymax); - int xlen = abs(xmax - xmin) + 1; - int ylen = abs(ymax - ymin) + 1; - - // Try to merge the start and end directly - const track::Direction mergeAxis = - xlen > ylen ? (dragBegin.x < dragEnd.x ? -axis::X : axis::X) - : (dragBegin.y < dragEnd.y ? -axis::Y : axis::Y); - if (map->isValidTrack(dragEnd)) { - ITrackSegmentPtr merged = - map->trackAt(dragEnd)->mergeExit(dragBegin, mergeAxis); - - if (merged) { - // Erase all the tiles covered - for (int x = xmin; x <= xmax; x++) { - for (int y = ymin; y <= ymax; y++) - map->eraseTile(x, y); - } + int xlen = abs(xmax - xmin) + 1; + int ylen = abs(ymax - ymin) + 1; + + // Try to merge the start and end directly + const track::Direction mergeAxis = + xlen > ylen ? (dragBegin.x < dragEnd.x ? -axis::X : axis::X) + : (dragBegin.y < dragEnd.y ? -axis::Y : axis::Y); + if (map->isValidTrack(dragEnd)) { + ITrackSegmentPtr merged = + map->trackAt(dragEnd)->mergeExit(dragBegin, mergeAxis); + + if (merged) { + // Erase all the tiles covered + for (int x = xmin; x <= xmax; x++) { + for (int y = ymin; y <= ymax; y++) + map->eraseTile(x, y); + } - map->setTrackAt(dragEnd, merged); - return; - } - } + map->setTrackAt(dragEnd, merged); + return; + } + } - // Normalise the coordinates so the start is always the one with - // the smallest x-coordinate - if (dragBegin.x > dragEnd.x) - swap(dragBegin, dragEnd); - - track::Direction startDir, endDir; - bool startWasGuess = false; - bool endWasGuess = false; - - // Try to work out the direction of the track start - if (canConnect(dragBegin.left(), dragBegin) - || canConnect(dragBegin.right(), dragBegin)) { - startDir = axis::X; - } - else if (canConnect(dragBegin.up(), dragBegin) - || canConnect(dragBegin.down(), dragBegin)) { - startDir = axis::Y; - } - else - startWasGuess = true; - - // Try to work out the direction of the track end - if (canConnect(dragEnd.left(), dragEnd) - || canConnect(dragEnd.right(), dragEnd)) { - endDir = axis::X; - } - else if (canConnect(dragEnd.up(), dragEnd) - || canConnect(dragEnd.down(), dragEnd)) { - endDir = axis::Y; - } - else - endWasGuess = true; - - // If we have to guess both orientations use a heuristic to decide - // between S-bends and curves - if (endWasGuess && startWasGuess) { - if (min(xlen, ylen) <= 2) { - if (xlen > ylen) - startDir = endDir = axis::X; - else - startDir = endDir = axis::Y; - } - else { - startDir = axis::X; - endDir = axis::Y; - } - } - // Otherwise always prefer curves to S-bends - else if (startWasGuess) - startDir = endDir == axis::X ? axis::Y : axis::X; - else if (endWasGuess) - endDir = startDir == axis::X ? axis::Y : axis::X; + // Normalise the coordinates so the start is always the one with + // the smallest x-coordinate + if (dragBegin.x > dragEnd.x) + swap(dragBegin, dragEnd); + + track::Direction startDir, endDir; + bool startWasGuess = false; + bool endWasGuess = false; + + // Try to work out the direction of the track start + if (canConnect(dragBegin.left(), dragBegin) + || canConnect(dragBegin.right(), dragBegin)) { + startDir = axis::X; + } + else if (canConnect(dragBegin.up(), dragBegin) + || canConnect(dragBegin.down(), dragBegin)) { + startDir = axis::Y; + } + else + startWasGuess = true; + + // Try to work out the direction of the track end + if (canConnect(dragEnd.left(), dragEnd) + || canConnect(dragEnd.right(), dragEnd)) { + endDir = axis::X; + } + else if (canConnect(dragEnd.up(), dragEnd) + || canConnect(dragEnd.down(), dragEnd)) { + endDir = axis::Y; + } + else + endWasGuess = true; + + // If we have to guess both orientations use a heuristic to decide + // between S-bends and curves + if (endWasGuess && startWasGuess) { + if (min(xlen, ylen) <= 2) { + if (xlen > ylen) + startDir = endDir = axis::X; + else + startDir = endDir = axis::Y; + } + else { + startDir = axis::X; + endDir = axis::Y; + } + } + // Otherwise always prefer curves to S-bends + else if (startWasGuess) + startDir = endDir == axis::X ? axis::Y : axis::X; + else if (endWasGuess) + endDir = startDir == axis::X ? axis::Y : axis::X; - if (xlen == 1 && ylen == 1) { - // A single tile - drawTrackTile(dragBegin, startDir); - } - else if (xlen == 1) - drawDraggedStraight(dragBegin.y < dragEnd.y ? axis::Y : -axis::Y, ylen); - else if (ylen == 1) - drawDraggedStraight(axis::X, xlen); - else if (startDir == endDir) { - // An S-bend (not implemented) - warn() << "Sorry! No S-bends yet..."; - } - else { - // Curves at the moment cannot be ellipses so lay track down - // until the dragged area is a square - while (xlen != ylen) { - if (xlen > ylen) { - // One of the ends must lie along the x-axis since all - // curves are through 90 degrees so extend that one - if (startDir == axis::X) { - drawTrackTile(dragBegin, axis::X); - dragBegin.x++; - } - else { - drawTrackTile(dragEnd, axis::X); - dragEnd.x--; - } - xlen--; + if (xlen == 1 && ylen == 1) { + // A single tile + drawTrackTile(dragBegin, startDir); + } + else if (xlen == 1) + drawDraggedStraight(dragBegin.y < dragEnd.y ? axis::Y : -axis::Y, ylen); + else if (ylen == 1) + drawDraggedStraight(axis::X, xlen); + else if (startDir == endDir) { + // An S-bend (not implemented) + warn() << "Sorry! No S-bends yet..."; + } + else { + // Curves at the moment cannot be ellipses so lay track down + // until the dragged area is a square + while (xlen != ylen) { + if (xlen > ylen) { + // One of the ends must lie along the x-axis since all + // curves are through 90 degrees so extend that one + if (startDir == axis::X) { + drawTrackTile(dragBegin, axis::X); + dragBegin.x++; } else { - // Need to draw track along y-axis - if (startDir == axis::Y) { - drawTrackTile(dragBegin, axis::Y); - - // The y-coordinate for the drag points is not guaranteed - // to be sorted - if (dragBegin.y > dragEnd.y) - dragBegin.y--; - else - dragBegin.y++; - } - else { - drawTrackTile(dragEnd, axis::Y); - - if (dragBegin.y > dragEnd.y) - dragEnd.y++; - else - dragEnd.y--; - } - ylen--; + drawTrackTile(dragEnd, axis::X); + dragEnd.x--; } - } - - track::Angle startAngle, endAngle; - Point where; - - if (startDir == axis::X && endDir == axis::Y) { - if (dragBegin.y < dragEnd.y) { - startAngle = 90; - endAngle = 180; - where = dragEnd; + xlen--; + } + else { + // Need to draw track along y-axis + if (startDir == axis::Y) { + drawTrackTile(dragBegin, axis::Y); + + // The y-coordinate for the drag points is not guaranteed + // to be sorted + if (dragBegin.y > dragEnd.y) + dragBegin.y--; + else + dragBegin.y++; } else { - startAngle = 0; - endAngle = 90; - where = dragBegin; - } - } - else { - if (dragBegin.y < dragEnd.y) { - startAngle = 270; - endAngle = 360; - where = dragBegin; - } - else { - startAngle = 180; - endAngle = 270; - where = dragEnd; - } - } - - ITrackSegmentPtr track = makeCurvedTrack(startAngle, endAngle, xlen); - track->setOrigin(where.x, where.y); - - list > exits; - track->getEndpoints(exits); - - bool ok = true; - for (list >::iterator it = exits.begin(); - it != exits.end(); ++it) { - if (map->isValidTrack(*it)) { - warn() << "Cannot place curve here"; - ok = false; - break; + drawTrackTile(dragEnd, axis::Y); + + if (dragBegin.y > dragEnd.y) + dragEnd.y++; + else + dragEnd.y--; } - } + ylen--; + } + } + + track::Angle startAngle, endAngle; + Point where; + + if (startDir == axis::X && endDir == axis::Y) { + if (dragBegin.y < dragEnd.y) { + startAngle = 90; + endAngle = 180; + where = dragEnd; + } + else { + startAngle = 0; + endAngle = 90; + where = dragBegin; + } + } + else { + if (dragBegin.y < dragEnd.y) { + startAngle = 270; + endAngle = 360; + where = dragBegin; + } + else { + startAngle = 180; + endAngle = 270; + where = dragEnd; + } + } + + ITrackSegmentPtr track = makeCurvedTrack(startAngle, endAngle, xlen); + track->setOrigin(where.x, where.y); + + list > exits; + track->getEndpoints(exits); + + bool ok = true; + for (list >::iterator it = exits.begin(); + it != exits.end(); ++it) { + if (map->isValidTrack(*it)) { + warn() << "Cannot place curve here"; + ok = false; + break; + } + } - if (ok) - map->setTrackAt(where, track); - } + if (ok) + map->setTrackAt(where, track); + } } // Delete all objects in the area selected by the user void Editor::deleteObjects() { - int xmin, xmax, ymin, ymax; - dragBoxBounds(xmin, xmax, ymin, ymax); + int xmin, xmax, ymin, ymax; + dragBoxBounds(xmin, xmax, ymin, ymax); - for (int x = xmin; x <= xmax; x++) { - for (int y = ymin; y <= ymax; y++) - map->eraseTile(x, y); - } + for (int x = xmin; x <= xmax; x++) { + for (int y = ymin; y <= ymax; y++) + map->eraseTile(x, y); + } } void Editor::plantTrees() { - int xmin, xmax, ymin, ymax; - dragBoxBounds(xmin, xmax, ymin, ymax); + int xmin, xmax, ymin, ymax; + dragBoxBounds(xmin, xmax, ymin, ymax); - for (int x = xmin; x <= xmax; x++) { - for (int y = ymin; y <= ymax; y++) - map->addScenery(makePoint(x, y), makeLTree()); - } + for (int x = xmin; x <= xmax; x++) { + for (int y = ymin; y <= ymax; y++) + map->addScenery(makePoint(x, y), makeLTree()); + } } void Editor::onMouseMove(IPickBufferPtr aPickBuffer, int x, int y, - int xrel, int yrel) + int xrel, int yrel) { - if (amDragging) { - // Extend the selection rectangle - map->setPickMode(true); - IGraphicsPtr pickContext = aPickBuffer->beginPick(x, y); - display(pickContext); - int id = aPickBuffer->endPick(); - map->setPickMode(false); - - if (id > 0) - dragEnd = map->pickPosition(id); - } - else if (amScrolling) { - const float speed = 0.05f; + if (amDragging) { + // Extend the selection rectangle + map->setPickMode(true); + IGraphicsPtr pickContext = aPickBuffer->beginPick(x, y); + display(pickContext); + int id = aPickBuffer->endPick(); + map->setPickMode(false); + + if (id > 0) + dragEnd = map->pickPosition(id); + } + else if (amScrolling) { + const float speed = 0.05f; - myPosition.x -= xrel * speed; - myPosition.z -= xrel * speed; + myPosition.x -= xrel * speed; + myPosition.z -= xrel * speed; - myPosition.x += yrel * speed; - myPosition.z -= yrel * speed; - } + myPosition.x += yrel * speed; + myPosition.z -= yrel * speed; + } } void Editor::onMouseClick(IPickBufferPtr aPickBuffer, int x, int y, - MouseButton aButton) + MouseButton aButton) { - if (aButton == MOUSE_RIGHT) { - // Start scrolling - amScrolling = true; - } - else if (aButton == MOUSE_LEFT) { - bool clickedOnGUI = layout->click(x, y); - - if (!clickedOnGUI) { - // See if the user clicked on something in the map - map->setPickMode(true); - IGraphicsPtr pickContext = aPickBuffer->beginPick(x, y); - display(pickContext); - int id = aPickBuffer->endPick(); - map->setPickMode(false); + if (aButton == MOUSE_RIGHT) { + // Start scrolling + amScrolling = true; + } + else if (aButton == MOUSE_LEFT) { + bool clickedOnGUI = layout->click(x, y); + + if (!clickedOnGUI) { + // See if the user clicked on something in the map + map->setPickMode(true); + IGraphicsPtr pickContext = aPickBuffer->beginPick(x, y); + display(pickContext); + int id = aPickBuffer->endPick(); + map->setPickMode(false); - if (id > 0) { - // Begin dragging a selection rectangle - Point where = map->pickPosition(id); + if (id > 0) { + // Begin dragging a selection rectangle + Point where = map->pickPosition(id); - dragBegin = dragEnd = where; - amDragging = true; - } - } - } - else if (aButton == MOUSE_WHEEL_UP) { - myPosition.y -= 0.5; - } - else if (aButton == MOUSE_WHEEL_DOWN) { - myPosition.y += 0.5; - } + dragBegin = dragEnd = where; + amDragging = true; + } + } + } + else if (aButton == MOUSE_WHEEL_UP) { + myPosition.y -= 0.5; + } + else if (aButton == MOUSE_WHEEL_DOWN) { + myPosition.y += 0.5; + } } void Editor::onMouseRelease(IPickBufferPtr aPickBuffer, int x, int y, - MouseButton aButton) + MouseButton aButton) { - if (amDragging) { - // Stop dragging and perform the action - switch (myTool) { - case TRACK_TOOL: - drawDraggedTrack(); - break; - case RAISE_TOOL: - map->raiseArea(dragBegin, dragEnd); - break; - case LOWER_TOOL: - map->lowerArea(dragBegin, dragEnd); - break; - case LEVEL_TOOL: - map->levelArea(dragBegin, dragEnd); - break; - case DELETE_TOOL: - deleteObjects(); - break; - case START_TOOL: - map->setStart(dragBegin.x, dragBegin.y); - break; - case STATION_TOOL: - map->extendStation(dragBegin, dragEnd); - break; - case BUILDING_TOOL: - { - float angle; - IBuildingPtr building; - tie(building, angle) = buildingPicker->get(); - map->placeBuilding(dragBegin, building, angle); - } - break; - case TREE_TOOL: - plantTrees(); - break; - } + if (amDragging) { + // Stop dragging and perform the action + switch (myTool) { + case TRACK_TOOL: + drawDraggedTrack(); + break; + case RAISE_TOOL: + map->raiseArea(dragBegin, dragEnd); + break; + case LOWER_TOOL: + map->lowerArea(dragBegin, dragEnd); + break; + case LEVEL_TOOL: + map->levelArea(dragBegin, dragEnd); + break; + case DELETE_TOOL: + deleteObjects(); + break; + case START_TOOL: + map->setStart(dragBegin.x, dragBegin.y); + break; + case STATION_TOOL: + map->extendStation(dragBegin, dragEnd); + break; + case BUILDING_TOOL: + { + float angle; + IBuildingPtr building; + tie(building, angle) = buildingPicker->get(); + map->placeBuilding(dragBegin, building, angle); + } + break; + case TREE_TOOL: + plantTrees(); + break; + } - amDragging = false; - } - else if (amScrolling) { - amScrolling = false; - } + amDragging = false; + } + else if (amScrolling) { + amScrolling = false; + } } void Editor::onKeyUp(SDLKey aKey) @@ -575,18 +575,21 @@ void Editor::onKeyUp(SDLKey aKey) void Editor::onKeyDown(SDLKey aKey) { - switch (aKey) { - case SDLK_g: - // Toggle grid - map->setGrid(true); - break; - default: - break; - } + switch (aKey) { + case SDLK_g: + // Toggle grid + map->setGrid(true); + break; + case SDLK_PRINT: + getGameWindow()->takeScreenShot(); + break; + default: + break; + } } // Create an instance of the editor screen IScreenPtr makeEditorScreen(IMapPtr aMap) { - return IScreenPtr(new Editor(aMap)); + return IScreenPtr(new Editor(aMap)); } diff --git a/src/Game.cpp b/src/Game.cpp index 8fbd241..b63a42f 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -37,72 +37,72 @@ // Implementation of the main play screen class Game : public IScreen { public: - Game(IMapPtr aMap); - ~Game(); + Game(IMapPtr aMap); + ~Game(); - void display(IGraphicsPtr aContext) const; - void overlay() const; - void update(IPickBufferPtr aPickBuffer, int aDelta); - void onKeyDown(SDLKey aKey); - void onKeyUp(SDLKey aKey); - void onMouseMove(IPickBufferPtr aPickBuffer, int x, int y, int xrel, - int yrel); - void onMouseClick(IPickBufferPtr aPickBuffer, int x, int y, - MouseButton aButton); - void onMouseRelease(IPickBufferPtr aPickBuffer, int x, int y, - MouseButton aButton) {} + void display(IGraphicsPtr aContext) const; + void overlay() const; + void update(IPickBufferPtr aPickBuffer, int aDelta); + void onKeyDown(SDLKey aKey); + void onKeyUp(SDLKey aKey); + void onMouseMove(IPickBufferPtr aPickBuffer, int x, int y, int xrel, + int yrel); + void onMouseClick(IPickBufferPtr aPickBuffer, int x, int y, + MouseButton aButton); + void onMouseRelease(IPickBufferPtr aPickBuffer, int x, int y, + MouseButton aButton) {} private: - void lookAhead(); - void setStatus(const string& s) { statusMsg = s; } - void nearStation(IStationPtr s); - void leftStation(); - Vector cameraPosition(float aRadius) const; - void switchToBirdCamera(); - void stoppedAtStation(); - - enum TrackStateReq { NEXT, PREV }; - void alterTrackState(TrackStateReq req); + void lookAhead(); + void setStatus(const string& s) { statusMsg = s; } + void nearStation(IStationPtr s); + void leftStation(); + Vector cameraPosition(float aRadius) const; + void switchToBirdCamera(); + void stoppedAtStation(); + + enum TrackStateReq { NEXT, PREV }; + void alterTrackState(TrackStateReq req); - IMapPtr map; - ITrainPtr train; - ILightPtr sun; + IMapPtr map; + ITrainPtr train; + ILightPtr sun; - // Station the train is either approaching or stopped at - IStationPtr activeStation; + // Station the train is either approaching or stopped at + IStationPtr activeStation; - // Camera position - float horizAngle, vertAngle, viewRadius; + // Camera position + float horizAngle, vertAngle, viewRadius; - // Camera adjustment - float cameraHTarget, cameraVTarget; - float cameraSpeed; + // Camera adjustment + float cameraHTarget, cameraVTarget; + float cameraSpeed; - enum CameraMode { CAMERA_FLOATING, CAMERA_FIXED, CAMERA_BIRD }; - CameraMode cameraMode; + enum CameraMode { CAMERA_FLOATING, CAMERA_FIXED, CAMERA_BIRD }; + CameraMode cameraMode; - gui::ILayoutPtr layout; + gui::ILayoutPtr layout; - string statusMsg; - gui::IFontPtr statusFont; + string statusMsg; + gui::IFontPtr statusFont; }; Game::Game(IMapPtr aMap) - : map(aMap), - horizAngle(M_PI/4.0f), - vertAngle(M_PI/4.0f), - viewRadius(20.0f) + : map(aMap), + horizAngle(M_PI/4.0f), + vertAngle(M_PI/4.0f), + viewRadius(20.0f) { - train = makeTrain(map); - sun = makeSunLight(); + train = makeTrain(map); + sun = makeSunLight(); - map->setGrid(false); + map->setGrid(false); - // Build the GUI - layout = gui::makeLayout("layouts/game.xml"); + // Build the GUI + layout = gui::makeLayout("layouts/game.xml"); - statusFont = gui::loadFont("fonts/Vera.ttf", 18); + statusFont = gui::loadFont("fonts/Vera.ttf", 18); - switchToBirdCamera(); + switchToBirdCamera(); } Game::~Game() @@ -112,251 +112,251 @@ Game::~Game() Vector Game::cameraPosition(float aRadius) const { - // Two angles give unique position on surface of a sphere - // Look up ``spherical coordinates'' - const float yCentre = 0.9f; - Vector position = train->front(); - position.x += aRadius * cosf(horizAngle) * sinf(vertAngle); - position.z += aRadius * sinf(horizAngle) * sinf(vertAngle); - position.y = aRadius * cosf(vertAngle) + yCentre; - - return position; + // Two angles give unique position on surface of a sphere + // Look up ``spherical coordinates'' + const float yCentre = 0.9f; + Vector position = train->front(); + position.x += aRadius * cosf(horizAngle) * sinf(vertAngle); + position.z += aRadius * sinf(horizAngle) * sinf(vertAngle); + position.y = aRadius * cosf(vertAngle) + yCentre; + + return position; } void Game::switchToBirdCamera() { - cameraMode = CAMERA_BIRD; + cameraMode = CAMERA_BIRD; - cameraHTarget = M_PI/4.0f; - cameraVTarget = M_PI/4.0f; + cameraHTarget = M_PI/4.0f; + cameraVTarget = M_PI/4.0f; - cameraSpeed = 100.0f; + cameraSpeed = 100.0f; } void Game::display(IGraphicsPtr aContext) const { - Vector trainPos = train->front(); + Vector trainPos = train->front(); - Vector position = cameraPosition(viewRadius); + Vector position = cameraPosition(viewRadius); - aContext->lookAt(position, trainPos); - setBillboardCameraOrigin(position); + aContext->lookAt(position, trainPos); + setBillboardCameraOrigin(position); - sun->apply(); + sun->apply(); - map->render(aContext); - train->render(); + map->render(aContext); + train->render(); - renderBillboards(); + renderBillboards(); } void Game::overlay() const { - //myStatsPanel->render(); + //myStatsPanel->render(); - layout->render(); + layout->render(); - const int screenH = getGameWindow()->height(); - const int screenW = getGameWindow()->width(); - const int len = statusFont->text_width(statusMsg); - statusFont->print((screenW - len)/2, screenH - 50, - colour::WHITE, statusMsg); + const int screenH = getGameWindow()->height(); + const int screenW = getGameWindow()->width(); + const int len = statusFont->text_width(statusMsg); + statusFont->print((screenW - len)/2, screenH - 50, + colour::WHITE, statusMsg); } void Game::stoppedAtStation() { - debug() << "Stopped at " << activeStation->name(); + debug() << "Stopped at " << activeStation->name(); } void Game::update(IPickBufferPtr aPickBuffer, int aDelta) { - train->update(aDelta); + train->update(aDelta); - // Update the GUI elements - layout->cast("/throttle_meter").value( - train->controller()->throttle()); + // Update the GUI elements + layout->cast("/throttle_meter").value( + train->controller()->throttle()); - const double msToMPH = 2.237; - layout->cast("/speed_label").format( - "Speed: %.1lfmph", train->speed() * msToMPH); + const double msToMPH = 2.237; + layout->cast("/speed_label").format( + "Speed: %.1lfmph", train->speed() * msToMPH); - layout->get("/brake_label").visible(train->controller()->brakeOn()); + layout->get("/brake_label").visible(train->controller()->brakeOn()); - lookAhead(); + lookAhead(); - // Move the camera vertically if it's currently underground + // Move the camera vertically if it's currently underground - // Calculate the location of the near clip plane - const float nearClip = getConfig()->get("NearClip"); - Vector clipPosition = cameraPosition(viewRadius - nearClip); + // Calculate the location of the near clip plane + const float nearClip = getConfig()->get("NearClip"); + Vector clipPosition = cameraPosition(viewRadius - nearClip); - // A hack because we don't calculate the height properly - const float MIN_HEIGHT = 0.25f; - float h = map->heightAt(clipPosition.x, clipPosition.z); + // A hack because we don't calculate the height properly + const float MIN_HEIGHT = 0.25f; + float h = map->heightAt(clipPosition.x, clipPosition.z); - if (h + MIN_HEIGHT > clipPosition.y) { - cameraVTarget -= 0.001f * static_cast(aDelta); - cameraSpeed = 200.0f; - } + if (h + MIN_HEIGHT > clipPosition.y) { + cameraVTarget -= 0.001f * static_cast(aDelta); + cameraSpeed = 200.0f; + } - // Bounce the camera if we need to - vertAngle -= (vertAngle - cameraVTarget) / cameraSpeed; - horizAngle -= (horizAngle - cameraHTarget) / cameraSpeed; + // Bounce the camera if we need to + vertAngle -= (vertAngle - cameraVTarget) / cameraSpeed; + horizAngle -= (horizAngle - cameraHTarget) / cameraSpeed; } // Signal that we are approaching a station void Game::nearStation(IStationPtr s) { - leftStation(); // Clear any previous station + leftStation(); // Clear any previous station - if (s != activeStation) { - activeStation = s; - s->setHighlightVisible(true); - } + if (s != activeStation) { + activeStation = s; + s->setHighlightVisible(true); + } } // Signal that we are no longer at or approaching a station void Game::leftStation() { - if (activeStation) { - activeStation->setHighlightVisible(false); - activeStation.reset(); - } + if (activeStation) { + activeStation->setHighlightVisible(false); + activeStation.reset(); + } } // Look along the track and notify the player of any stations, points, etc. // that they are approaching void Game::lookAhead() { - TrackIterator it = iterateTrack(map, train->tile(), - train->direction()); + TrackIterator it = iterateTrack(map, train->tile(), + train->direction()); - // Are we sitting on a station? - if (it.status == TRACK_STATION) { - nearStation(it.station); + // Are we sitting on a station? + if (it.status == TRACK_STATION) { + nearStation(it.station); - if (train->controller()->stopped()) - stoppedAtStation(); - else - setStatus("Stop here for station " + it.station->name()); + if (train->controller()->stopped()) + stoppedAtStation(); + else + setStatus("Stop here for station " + it.station->name()); - return; - } + return; + } - const int maxLook = 10; - for (int i = 0; i < maxLook; i++) { - it = it.next(); + const int maxLook = 10; + for (int i = 0; i < maxLook; i++) { + it = it.next(); - if (it.status != TRACK_OK) { - bool clearStation = true; + if (it.status != TRACK_OK) { + bool clearStation = true; - switch (it.status) { - case TRACK_STATION: - setStatus("Approaching station " + it.station->name()); - nearStation(it.station); - clearStation = false; - return; - case TRACK_NO_MORE: - setStatus("Oh no! You're going to crash!"); - break; - case TRACK_CHOICE: - setStatus("Oh no! You have to make a decision!"); - it.track->setStateRenderHint(); - break; - default: - break; - } - - if (!clearStation) - leftStation(); - return; - } - } + switch (it.status) { + case TRACK_STATION: + setStatus("Approaching station " + it.station->name()); + nearStation(it.station); + clearStation = false; + return; + case TRACK_NO_MORE: + setStatus("Oh no! You're going to crash!"); + break; + case TRACK_CHOICE: + setStatus("Oh no! You have to make a decision!"); + it.track->setStateRenderHint(); + break; + default: + break; + } + + if (!clearStation) + leftStation(); + return; + } + } - // We're not approaching any station - leftStation(); + // We're not approaching any station + leftStation(); - // Nothing to report - setStatus(""); + // Nothing to report + setStatus(""); } void Game::alterTrackState(TrackStateReq req) { - // Change the state of the nearest points, etc. - TrackIterator it = iterateTrack(map, train->tile(), - train->direction()); + // Change the state of the nearest points, etc. + TrackIterator it = iterateTrack(map, train->tile(), + train->direction()); - const int maxAlterLook = 10; + const int maxAlterLook = 10; - for (int i = 0; i < maxAlterLook; i++) { + for (int i = 0; i < maxAlterLook; i++) { - // Skip over the first section of track which may be some - // points - we don't want to alter the track we're on! - it = it.next(); + // Skip over the first section of track which may be some + // points - we don't want to alter the track we're on! + it = it.next(); - if (it.status == TRACK_CHOICE) { - switch (req) { - case NEXT: - it.track->nextState(); - break; - case PREV: - it.track->prevState(); - break; - } + if (it.status == TRACK_CHOICE) { + switch (req) { + case NEXT: + it.track->nextState(); + break; + case PREV: + it.track->prevState(); + break; + } - return; - } - } + return; + } + } - warn() << "No nearby track state to change"; + warn() << "No nearby track state to change"; } void Game::onKeyDown(SDLKey aKey) { - switch (aKey) { - case SDLK_PAGEUP: - viewRadius = max(viewRadius - 0.2f, 0.1f); - break; - case SDLK_PAGEDOWN: - viewRadius += 0.2f; - break; - case SDLK_b: - train->controller()->actOn(BRAKE_TOGGLE); - break; - case SDLK_r: - train->controller()->actOn(TOGGLE_REVERSE); - break; - case SDLK_LCTRL: - train->controller()->actOn(SHOVEL_COAL); - break; - case SDLK_a: - train->controller()->actOn(THROTTLE_DOWN); - break; - case SDLK_s: - train->controller()->actOn(THROTTLE_UP); - break; - case SDLK_PRINT: - getGameWindow()->takeScreenShot(); - break; - case SDLK_LEFT: - alterTrackState(PREV); - break; - case SDLK_RIGHT: - alterTrackState(NEXT); - break; - case SDLK_UP: - break; - case SDLK_TAB: - if (cameraMode == CAMERA_FLOATING) - cameraMode = CAMERA_FIXED; - else if (cameraMode == CAMERA_FIXED) - switchToBirdCamera(); - else - cameraMode = CAMERA_FLOATING; - break; - default: - break; - } + switch (aKey) { + case SDLK_PAGEUP: + viewRadius = max(viewRadius - 0.2f, 0.1f); + break; + case SDLK_PAGEDOWN: + viewRadius += 0.2f; + break; + case SDLK_b: + train->controller()->actOn(BRAKE_TOGGLE); + break; + case SDLK_r: + train->controller()->actOn(TOGGLE_REVERSE); + break; + case SDLK_LCTRL: + train->controller()->actOn(SHOVEL_COAL); + break; + case SDLK_a: + train->controller()->actOn(THROTTLE_DOWN); + break; + case SDLK_s: + train->controller()->actOn(THROTTLE_UP); + break; + case SDLK_PRINT: + getGameWindow()->takeScreenShot(); + break; + case SDLK_LEFT: + alterTrackState(PREV); + break; + case SDLK_RIGHT: + alterTrackState(NEXT); + break; + case SDLK_UP: + break; + case SDLK_TAB: + if (cameraMode == CAMERA_FLOATING) + cameraMode = CAMERA_FIXED; + else if (cameraMode == CAMERA_FIXED) + switchToBirdCamera(); + else + cameraMode = CAMERA_FLOATING; + break; + default: + break; + } } void Game::onKeyUp(SDLKey aKey) @@ -365,43 +365,43 @@ void Game::onKeyUp(SDLKey aKey) } void Game::onMouseClick(IPickBufferPtr aPickBuffer, int x, int y, - MouseButton aButton) + MouseButton aButton) { - switch (aButton) { - case MOUSE_WHEEL_UP: - viewRadius = max(viewRadius - 1.0f, 0.1f); - break; - case MOUSE_WHEEL_DOWN: - viewRadius += 1.0f; - break; - default: - break; - } + switch (aButton) { + case MOUSE_WHEEL_UP: + viewRadius = max(viewRadius - 1.0f, 0.1f); + break; + case MOUSE_WHEEL_DOWN: + viewRadius += 1.0f; + break; + default: + break; + } } void Game::onMouseMove(IPickBufferPtr aPickBuffer, int x, int y, - int xrel, int yrel) + int xrel, int yrel) { - if (cameraMode == CAMERA_FLOATING) { - cameraHTarget -= xrel / 100.0f; - cameraVTarget += yrel / 100.0f; + if (cameraMode == CAMERA_FLOATING) { + cameraHTarget -= xrel / 100.0f; + cameraVTarget += yrel / 100.0f; - // Don't allow the camera to go under the ground - const float ground = (M_PI / 2.0f) - 0.01f; - if (cameraVTarget > ground) - cameraVTarget = ground; + // Don't allow the camera to go under the ground + const float ground = (M_PI / 2.0f) - 0.01f; + if (cameraVTarget > ground) + cameraVTarget = ground; - // Don't let the camera flip over the top - const float top = 0.01f; - if (cameraVTarget < top) - cameraVTarget = top; + // Don't let the camera flip over the top + const float top = 0.01f; + if (cameraVTarget < top) + cameraVTarget = top; - cameraSpeed = 2.0f; - } + cameraSpeed = 2.0f; + } } // Create an instance of the play screen with the given map IScreenPtr makeGameScreen(IMapPtr aMap) { - return IScreenPtr(new Game(aMap)); + return IScreenPtr(new Game(aMap)); } -- 2.39.2