OpenTTD的视觉系统2.5D形式展现,素材都是图片,通过屏幕贴图的方式生成界面元素,因此不能像真3D游戏那样在游戏过程中旋转视角,看到3D模型侧面或者背面的情况。这种2.5D的展示方式对显卡要求较低,大量使用在手机游戏里面,比如 王者荣耀、部落冲突、三国志策略版的界面,我们都能看到这种显示模式的身影。Openttd.cpp 代码量不大(行数 3000+),函数数量多(50+),其中对外服务函数26个,私有服务 27个。上层调用者主要包括 gui类、cmd类以及游戏初始化阶段的各种类,向下调用 gfx.cpp set dirty(把屏幕部分或者全部设置刷新) , Draw开头的绘制等操作,下面是整理出来的主要函数调用关系及说明。
viewport是游戏进行中的主界面,我们以铺设铁轨为例,修建铁路相关的界面在rail_gui.cpp定义,操作流程:
1.点开toolbar的铁路菜单栏;
2.选择修建铁路图标;
3.鼠标左键拖动修建铁路;
4.鼠标拖动过程中,界面对应Tile对应显示铁轨;
5.鼠标左键抬起,完成修建动作;
以上3-5步骤分别由 viewport.cpp的三个函数实现
VpStartPlaceSizing() 开始拖动
<- rail_gui.cpp OnPlaceObject()
<- viewport.cpp PlaceObject()
<- viewport.cpp VpStartDragging() 拖动中
VpHandlePlaceSizingDrag() 拖动完成
<- rail_gui.cpp OnPlaceMouseUp()
通过上面的分析,我们可以看到,实现拖动架设铁路的操作是由 viewport.cpp 与 rail_gui.cpp 几个函数之间互相调用实现
铺设铁路调用链
说明:
a<-b 表示函数a被函数b调用
<= 后面是这个函数的说明
格式:<-(第一行没有) 源码文件名 函数名 <= 函数说明
rail_gui.cpp DoRailroadTrack() <= 调用DoCommandP()
<- HandleAutodirPlacement() <= select_proc=DDSP_PLACE_RAIL
<- OnPlaceMouseUp() <= select_proc=DDSP_PLACE_RAIL
<- PlaceRail_Bridge() <= Start placing a rail bridge.
<- OnPlaceObject() <= this->last_user_action=WID_RAT_BUILD_BRIDGE
<- viewport.cpp <= PlaceObject()
<- HandleViewportClicked()
<- window.cpp MouseLoop() <= 每一个tick
<- HandleMouseEvents()
<- sdl2_v.cpp VideoDriver_SDL_Base::PollEvent()
<- video_driver.cpp VideoDriver::Tick()
最后,是viewport.cpp的函数清单
说明:
a() <- b() 表示函数a被 函数b调用
: 后面是这个函数的中英文说明
*3 表示这是需要重要关注的函数
----public----
- StartSpriteCombine() <- *_cmd.cpp 一般是draw操作前调用
: Starts a block of sprites, which are “combined” into a single bounding box. - EndSpriteCombine() <- *_cmd.cpp 与上面成对出现
: Terminates a block of sprites started by #StartSpriteCombine.
*3. ViewportDoDraw() <- screenshot.cpp LargeWorldCallback() & this.ViewportDraw()
: 调用 ViewportDraw 开头的几个私有函数完成ViewPort的绘制 - DrawViewport() <- widget.cpp NWidgetViewport::Draw()
: Draw the viewport of this window.
: 在窗口的小组件widget绘制的时候,直接调用 ViewportDraw() 间接调用 ViewportDoDraw() - ViewportAddString() <- texteff.cpp DrawTextEffects() & this.ViewportAddKdtreeSigns()
: Add a string to draw in the viewport
: 界面上增加字符串
------六个Make开头的函数 被 cmd类程序发起 - MakeStation() <- station_map.h 创建车站、码头、机场等Tile & this.RebuildViewportKdtree()
- MakeWaypoint() <- waypoint_cmd.cpp Waypoint::UpdateVirtCoord() & this.RebuildViewportKdtree()
- MakeTown() <- town_cmd.cpp Town::UpdateVirtCoord() & this.RebuildViewportKdtree()
- MakeSign() <- signs.cpp Sign::UpdateVirtCoord() & this.RebuildViewportKdtree()
------ - RebuildViewportKdtree() <- afterload.cpp AfterLoadGame() UpdateAllVirtCoords() & misc.cpp InitializeGame()
- ScrollWindowTo() <- main_gui.cpp ZoomInOrOutToCursorWindow() & smallmap_gui.cpp ScrollMainWindowTo()
: Scrolls the viewport in a window to a given location. - ScrollWindowToTile() <- *_gui.cpp OnResize() 包括 industry/town/waypoint
: Scrolls the viewport in a window to a given location. - ScrollMainWindowToTile() <- *_gui.cpp 大量调用这个方法 跳转视角
: Scrolls the viewport of the main window to a given location. - UpdateTileSelection() <- window.cpp MouseLoop() & station_gui.cpp StationJoinerNeeded()
: Updates tile highlighting for all cases. - VpSelectTilesWithMethod() <- *_gui.cpp OnPlaceDrag()
: Selects tiles while dragging - VpHandlePlaceSizingDrag() <- window.cpp MouseLoop()
: Handle the mouse while dragging for placement/resizing. - SetObjectToPlaceWnd() <- *_gui.cpp OnClick()
: 调用SetObjectToPlace() - SetObjectToPlace() <- genworld.cpp GenerateWorld() & *_gui.cpp OnClick()
: Change the cursor and mouse click/drag handling - ResetObjectToPlace()
: Reset the cursor and mouse mode handling back to default
: 调用SetObjectToPlace() - GetViewportStationMiddle() <- linkgraph_gui.cpp GetStationMiddle()
- CmdScrollViewport(): Scroll players main viewport.
- SetViewportCatchmentStation():
- SetViewportCatchmentTown(): Town’s coverage set dirty
----init----
- InitializeSpriteSorter() <- openttd.cpp main()
- InitializeWindowViewport() <- widget.cpp NWidgetViewport::InitializeViewport()
: 很多 gui 创建新窗口的时候调用
----private----
- MarkCatchmentTilesDirty() <- SetViewportCatchmentStation()
- CalcRaildirsDrawstyle() <- VpSelectTilesWithMethod()
: while dragging - DoSetViewportPosition() <- SetViewportPosition()
- SetViewportPosition() <- UpdateViewportPosition()
*5. TranslateXYToTileCoord() <- GetTileFromScreenXY() & CheckClickOnLandscape()
: Translate screen coordinate in a viewport to underlying tile coordinate.
: x,y的坐标转换为3D的透视图,调用 landscape.cpp InverseRemapCoords2() 完成转换 - GetTileFromScreenXY() <- GetTileBelowCursor() & GetTileZoomCenterWindow()
: When used for zooming, check area below current coordinates (x,y) - AddTileSpriteToDraw() <- DrawGroundSpriteAt() & DrawSelectionSprite()
: Schedules a tile sprite for drawing. - AddChildSpriteToFoundation() <- DrawGroundSpriteAt() & DrawSelectionSprite()
: Adds a child sprite to the active foundation. - AddCombinedSprite() <- AddSortableSpriteToDraw()
: Draw a (transparent) sprite at given coordinates with a given bounding box. - AddStringToDraw() <- ViewportAddString()
- ViewportSortParentSprites() <- InitializeSpriteSorter()
------下面这一堆函数都被ViewportDoDraw()调用 - ViewportAddLandscape() <- ViewportDoDraw()
- ViewportDrawTileSprites() <- ViewportDoDraw()
- ViewportDrawParentSprites() <- ViewportDoDraw()
- ViewportDrawBoundingBoxes() <- ViewportDoDraw()
- ViewportDrawDirtyBlocks() <- ViewportDoDraw()
: Draw/colour the blocks that have been redrawn. - ViewportDrawStrings() <- ViewportDoDraw()
------上面这一堆函数都被ViewportDoDraw()调用 - ClampViewportToMap() <- UpdateViewportPosition()
: Ensure that a given viewport has a valid scroll position. - SetSelectionTilesDirty() <- SetSelectionRed() & UpdateTileSelection() & SetObjectToPlace()
: Marks the selected tiles as dirty. - UpdateViewportPosition() <- window.cpp UpdateWindows()
: Update the viewport position being displayed. - CheckClickOnViewportSign() <- HandleViewportClicked()
: Check whether any viewport sign was clicked, and dispatch the click. - CheckClickOnLandscape() <- HandleViewportClicked()
- PlaceObject() <- HandleViewportClicked()
- HandleViewportClicked() <- window.cpp MouseLoop()
: 点击鼠标左键的事件响应 - ViewportDraw() <- Window::DrawViewport()
: Draw the viewport of this window. - RebuildViewportOverlay() <- ScrollWindowTo()
: 区域 SetDirty()