minetest源码解析四:game界面刷新绘制流程及核心函数介绍
game界面刷新绘制流程及核心函数介绍
一 流程图
二 流程图中涉及到的核心函数介绍
1.Draw "Loading"screen
绘制点击start game之后的界面。
主要涉及函数
draw_load_screen(text, device, font,0,0);
场景绘制(绘制云)、driver->draw2DRectangle(视频驱动指针直接绘制)、GUI绘制(文字)
2.创建 texture source、shader source、item definition manager、node definition manager
初始化创建。
texture source:shader source:
item definition manager:界面上items(从服务端线程在不断获取出来,底下物品栏中)
node definition manager:界面上的场景node(从服务端线程在不断获取出来的可视范围内)
主要涉及函数
draw_load_screen(text, device, font,0,0);
场景绘制(绘制云)、driver->draw2DRectangle(视频驱动指针直接绘制)、GUI绘制(文字)
3.Create server
创建服务器。进行服务器地址的分解等等,并创建Server实例。
主要涉及函数
server = newServer(map_dir, gamespec, simple_singleplayer_mode, bind_addr.isIPv6());
server->start(bind_addr);
4.Create Client
创建客户端。先解析地址,设置连接地址,创建Client实例。
代码中这之前的do while循环可以直接去除
主要涉及函数
Client client(device, playername.c_str(), password, draw_control, tsrc, shsrc, itemdef, nodedef, sound, &eventmgr, connect_address.isIPv6());
5.Connet to the server
连接服务器。
主要涉及函数
client.connect(connect_address);
6.Wait for server to accept connection
这里主要通过一个循环不断更新以及获取状态信息(client.getState())。
主要涉及函数
while(device->run())
{
// Update client and server
client.step(dtime);
server->step(dtime);
// End condition
if(client.getState() ==LC_Init)
// Break conditions
if(client.accessDenied())
if(input->wasKeyDown(EscapeKey))
// Display status
wchar_t* text =wgettext("Connecting to server...");
draw_load_screen(text, device, font, dtime,100);
}
7.Wait until content has been received
主要在一个循环体去获取客户端item 和node是否reveived(client.mediaReceived() &&client.itemdefReceived() &&client.nodedefReceived())。
主要涉及函数
while(device->run())
{
// Update client and server
client.step(dtime);
server->step(dtime);
// End condition
if(client.mediaReceived() && client.itemdefReceived() && client.nodedefReceived())
// Break conditions
if(client.accessDenied())
if(client.getState() <LC_Init)
if(input->wasKeyDown(EscapeKey))
// Display status
if (!client.itemdefReceived())
wchar_t* text =wgettext("Item definitions...");
elseif (!client.nodedefReceived())
wchar_t* text =wgettext("Node definitions...");
else
message << gettext("Media...");
}
8.Update cached texture,mesh,materials
Update cached texture,mesh,materials:所有内容全部接受到之后。
主要涉及函数
client.afterContentReceived(device,font);
更新texture以及mesh、materials的。
9.Create the camera node
minetest->camera.h
创建一个Camera的实例。管理玩家、场景中的nodes、视距以及右下角舞动的工具。
主要涉及函数
Camera camera(smgr, draw_control, gamedef);
10.Create Clouds
minetest->clouds.h
创建一个Clouds的实例。Clouds是一个ScenceNode,所以它绘制时需要场景管理器绘制。
主要涉及函数
clouds = newClouds(smgr->getRootSceneNode(), smgr, -1,time(0));
11.Create Clouds
minetest->clouds.h
创建一个Clouds的实例。Clouds是一个ScenceNode,所以它绘制时需要场景管理器绘制。
主要涉及函数
clouds = newClouds(smgr->getRootSceneNode(), smgr, -1,time(0));
12.Create Sky
minetest->sky.h
创建一个Sky的实例。Sky是一个ScenceNode,所以它绘制时需要场景管理器绘制。
主要涉及函数
new Sky(smgr->getRootSceneNode(), smgr, -1, client.getEnv().getLocalPlayer());
13.Add some gui stuff
主要是加入了一些左上角显示的debug信息等,这种一般是在gui环境中加入staticText控件。
14.HUD object
minetest->hud.h
创建一个Hud的实例。主要这个对象中都是封装了一些绘制函数。
主要涉及函数
Hud hud(driver, smgr, guienv, font, text_height, gamedef, player, &local_inventory);
15.处理一些game中回调
譬如若点击esc退出后,选择了菜单中的Exit to Menu,退出game循环了。
if(g_gamecallback->disconnect_requested)
{
g_gamecallback->disconnect_requested =false;
break;
}
或者访问受限,退出game循环了。
if(client.accessDenied())
{
break;
}
16.游戏过程中依据按键启动菜单判断
按下按键,按键这个事件主要是鬼火引擎IEventReceiver去截取的,RealInputHandler这个对象去判断根据不同的key分别执行不同的函数。
自己去截取,RealInputHandler这个对象去判断根据不同的key分别执行不同的函数。input = newRealInputHandler();
RealInputHandler::InputHandler
如果窗口没有**或者一些menu正在**,需要input->clear().
主要涉及函数
create_formspec_menu(¤t_formspec, &client, gamedef, tsrc, device, fs_src, txt_dst);
17.滚轮选择底下物品栏Item
按下按键,按键这个事件主要是通过RealInputHandler这个对象截获的。根据不同的key分别执行不同的函数。
input = newRealInputHandler();
RealInputHandler::InputHandler
主要涉及函数
create_formspec_menu(¤t_formspec, &client, gamedef, tsrc, device, fs_src, txt_dst);
18.客户端设置玩家Control
minetest->player.h
PlayerControl control(input->isKeyDown(getKeySetting("keymap_forward")),
input->isKeyDown(getKeySetting("keymap_backward")),
…)
client.setPlayerControl(control);
19.服务端、客户端运行 step
server->step(dtime);
client.step(dtime); 这个比较重要,有获取数据,事件获取、环境处理等等。minetest->client.cpp
主要涉及函数
void Client::step(float dtime)
{
…
ReceiveAll();
…
}
void Client::ProcessData(u8 *data,u32 datasize, u16 sender_peer_id);处理从服务器端不断获取的数据
这里的ProcessData可能会更改ClientEvent的type。
20.读取客户端event
这里的事件不是key、鼠标这些事件,而是把这些响应之后执行的事件,如玩家移动、加粒子等。
ClientEvent event = client.getClientEvent();
if(event.type ==CE_NONE)
break;
else if(event.type ==CE_PLAYER_DAMAGE && client.getHP() !=0)
else if(event.type ==CE_PLAYER_FORCE_MOVE)
else if(event.type ==CE_DEATHSCREEN)
else if (event.type ==CE_SHOW_FORMSPEC)
else if(event.type ==CE_SPAWN_PARTICLE)
else if(event.type ==CE_ADD_PARTICLESPAWNER)
else if(event.type ==CE_DELETE_PARTICLESPAWNER)
else if (event.type ==CE_HUDADD)
else if (event.type ==CE_HUDRM)
else if (event.type ==CE_HUDCHANGE)
else if (event.type ==CE_SET_SKY)
else if (event.type ==CE_OVERRIDE_DAY_NIGHT_RATIO)
涉及主要函数
void Client::ProcessData(u8 *data,u32 datasize, u16 sender_peer_id)
{
…
ToClientCommand command = (ToClientCommand)readU16(&data[0]);
…
}
21.更新camera
camera.update(player, dtime, busytime, tool_reload_ratio,current_camera_mode, client.getEnv());
Camera更新:计算不同camera mode的玩家眼睛偏移、计算camera自己位置、自己target位置。Wielded tool的位置、更新视野范围等等。
界面、挥舞的工具、视角等等。
client.getEnv().getClientMap().updateCamera(camera_position,camera_direction, camera_fov, camera_offset);
ClientMap 更新camera的位置、方向、偏移等等。
如果注释掉地图不显示出来
22.创建PointedThing对象
minetest->util->pointedthing.h
PointedThing pointed =getPointedThing(
// input
&client, player_position, camera_direction,
camera_position, shootline, d,
playeritem_def.liquids_pointable, !ldown_for_dig,
camera_offset,
// output
hilightboxes,
selected_object);
这个对象中有个PointedThingType type,这个类型一般有POINTEDTHING_NOTHING、POINTEDTHING_NODE、POINTEDTHING_OBJECT。
23.底下物品栏更新
client.selectPlayerItem(new_playeritem) 客户端切换选择的物品
client.getLocalInventory(local_inventory);客户端获取本地物品
camera.wield(item, client.getPlayerItem());camera的右下角挥舞的node更新
24.更新block绘制列表
200ms或者camera的方向改变时,更新列表。
client.getEnv().getClientMap().updateDrawList(driver);
这里更新需要绘制的block,如果注释掉了,地图就显示不出来了。
25.绘制云、sky
直接调用引擎的场景管理器绘制.
26.选中block的提示框绘制
show_hud
hud.drawSelectionBoxes(hilightboxes);
27.camera wield 工具绘制
show_hud
camera.drawWieldedTool();
28.Crosshair绘制
show_hud
hud.drawCrosshair();
29.底下物品栏绘制
show_hud
hud.drawHotbar(client.getPlayerItem());
之前这句代码必须执行过client.getLocalInventory(local_inventory);客户端获取本地物品,否则是绘制不出来的。
30.生命值绘制
show_hud
hud.drawLuaElements(camera.getOffset());
31.gui绘制
包括debug的staticText,聊天的staticText,以及某些key按下弹出的界面。