本篇是游戏中物件的定义与使用(6)的续篇。
下载源码和工程
cMapIcs类的测试代码:
以创建游戏内核【OO改良版】和创建3D图形引擎【OO改良版】的代码为基础进行开发。
/************************************************************************************
PURPOSE:
map ics test.
************************************************************************************/
#include "core_common.h"
#include "core_framework.h"
#include "core_graphics.h"
#include "core_input.h"
#include "core_sound.h"
#include "frustum.h"
#include "node_tree_mesh.h"
#include "map_ics.h"
#include "mil.h"
#define MAX_ITEMS 1024
class cApp : public cFramework
{
private:
cCamera m_camera;
cLight m_light;
cFont m_font;
cInput m_input;
cInputDevice m_keyboard;
cInputDevice m_mouse;
cMesh m_scene_mesh;
cNodeTreeMesh m_node_tree_mesh;
sItem m_items[MAX_ITEMS];
cMapIcs m_map_ics;
cMesh m_item_mesh;
cObject m_item_object;
cMesh m_target_mesh;
cObject m_target_object;
float m_x_pos, m_y_pos, m_z_pos;
static const float m_above_floor;
public:
bool init()
{
if(! create_display(g_hwnd, get_client_width(g_hwnd), get_client_height(g_hwnd), 16, TRUE, TRUE))
return FALSE;
set_perspective(D3DX_PI / 4, 1.3333f, 1.0f, 10000.0f);
ShowCursor(TRUE);
m_font.create("Arial", 16, TRUE, FALSE);
// enable lighting and setup light
g_d3d_device->SetRenderState(D3DRS_LIGHTING, TRUE);
set_ambient_light(48, 48, 48);
g_d3d_device->LightEnable(0, TRUE);
m_light.set_default_state();
m_light.set_range(1000.0f);
m_camera.build_view_matrix();
// initialize input and input device
m_input.create(g_hwnd, get_window_inst());
m_keyboard.create_keyboard(&m_input);
m_mouse.create_mouse(&m_input, TRUE);
// load the mesh and create a nodetree mesh from it
if(! m_scene_mesh.load("..\\Data\\Map.x", "..\\Data\\"))
return FALSE;
m_node_tree_mesh.create(&m_scene_mesh, QUADTREE, 256.0f, 32);
// position view at origin
m_x_pos = m_y_pos = m_z_pos = 0.0f;
if(! m_map_ics.load("..\\Data\\MapItems.mi"))
return FALSE;
// load a generic item mesh and targeting mesh and setup their objects
if(! m_item_mesh.load("..\\Data\\Item.x", "..\\Data\\"))
return FALSE;
m_item_object.create(&m_item_mesh);
if(! m_target_mesh.load("..\\Data\\Target.x", "..\\Data\\"))
return FALSE;
m_target_object.create(&m_target_mesh);
// load in mil list
ZeroMemory(m_items, sizeof(m_items));
FILE* fp;
if((fp = fopen("..\\Data\\Default.mil", "rb")) != NULL)
{
fread(&m_items, 1, sizeof(m_items), fp);
fclose(fp);
}
return TRUE;
}
bool frame()
{
static DWORD time_now = timeGetTime();
// calculate elapsed time (plus speed boost)
ulong time_elapsed = timeGetTime() - time_now;
time_now = timeGetTime();
// read keyboard and mouse data
m_keyboard.read();
m_mouse.read();
// process input and update everything, ESC quits program.
if(m_keyboard.get_key_state(KEY_ESC))
return FALSE;
float x_move, z_move;
// process movement
x_move = z_move = 0.0f;
if(m_keyboard.get_key_state(KEY_UP) || m_keyboard.get_key_state(KEY_W))
{
x_move = (float) sin(m_camera.get_y_rotation()) * time_elapsed;
z_move = (float) cos(m_camera.get_y_rotation()) * time_elapsed;
}
if(m_keyboard.get_key_state(KEY_DOWN) || m_keyboard.get_key_state(KEY_S))
{
x_move = (float) -sin(m_camera.get_y_rotation()) * time_elapsed;
z_move = (float) -cos(m_camera.get_y_rotation()) * time_elapsed;
}
if(m_keyboard.get_key_state(KEY_LEFT) || m_keyboard.get_key_state(KEY_A))
{
x_move = (float) sin(m_camera.get_y_rotation() - 1.57f) * time_elapsed;
z_move = (float) cos(m_camera.get_y_rotation() - 1.57f) * time_elapsed;
}
if(m_keyboard.get_key_state(KEY_RIGHT) || m_keyboard.get_key_state(KEY_D))
{
x_move = (float) sin(m_camera.get_y_rotation() + 1.57f) * time_elapsed;
z_move = (float) cos(m_camera.get_y_rotation() + 1.57f) * time_elapsed;
}
// check for movement collision - can not walk past anything blocking path.
if(m_node_tree_mesh.is_ray_intersect_mesh(m_x_pos, m_y_pos + m_above_floor, m_z_pos,
m_x_pos + x_move, m_y_pos + m_above_floor, m_z_pos,
NULL))
{
x_move = 0.0f;
}
if(m_node_tree_mesh.is_ray_intersect_mesh(m_x_pos, m_y_pos + m_above_floor, m_z_pos,
m_x_pos, m_y_pos + m_above_floor, m_z_pos + z_move,
NULL))
{
z_move = 0.0f;
}
// update view coordinats
m_x_pos += x_move;
m_z_pos += z_move;
long item_index;
if(m_mouse.get_button_state(MOUSE_RBUTTON))
{
// Lock it, so press down right mouse button will not drop item all along.
m_mouse.set_lock(MOUSE_RBUTTON, TRUE);
// drop an item - pick a random one
while(1)
{
item_index = rand() % MAX_ITEMS;
if(m_items[item_index].name[0]) // found a valid item
break;
}
m_map_ics.add(item_index, 1,
m_x_pos + (float)sin(m_camera.get_y_rotation()) * 200.0f,
m_y_pos,
m_z_pos + (float)cos(m_camera.get_y_rotation()) * 200.0f,
NULL);
}
// position camera and rotate based on mouse position
m_camera.move(m_x_pos, m_y_pos + 100.0f, m_z_pos);
// m_mouse.get_y_delta():
// get mouse's relative x movement coordinate.
//
// m_mouse.get_x_delta():
// get mouse's relative y movement coordinate.
m_camera.rotate_rel((float) m_mouse.get_y_delta() / 200.0f, (float) m_mouse.get_x_delta() / 200.0f, 0.0f);
// position light
m_light.move(m_x_pos, m_y_pos + 100.0f, m_z_pos);
g_d3d_device->SetLight(0, m_light.get_d3d_light());
cFrustum frustum;
// set camera and calculate frustum
g_d3d_device->SetTransform(D3DTS_VIEW, m_camera.get_view_matrix());
frustum.create(0.0f);
// render everything
clear_display(0, 1.0f);
sMapItemPtr closest_item = NULL;
// begin render now
if(SUCCEEDED(g_d3d_device->BeginScene()))
{
g_d3d_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
g_d3d_device->SetRenderState(D3DRS_LIGHTING, TRUE);
// render scene
m_node_tree_mesh.render(&frustum, 0.0f);
// draw all items, scanning for closest one to viewer.
sMapItemPtr item;
float closest;
for(item = m_map_ics.get_root_item(); item != NULL; item = item->next)
{
// do not bother with child objects
if(item->parent)
continue;
// get the radius of the generic item object
float radius;
m_item_object.get_bounds(NULL, NULL, NULL, NULL, NULL, NULL, &radius);
// frustum check and draw it if visible
if(! frustum.is_sphere_in(item->x_pos, item->y_pos, item->z_pos, radius))
continue;
m_item_object.move(item->x_pos, item->y_pos, item->z_pos);
m_item_object.render();
// figure if current item is closest to viewer
float x_diff = (float) fabs(item->x_pos - m_x_pos);
float z_diff = (float) fabs(item->z_pos - m_z_pos);
float dist = x_diff * x_diff + z_diff * z_diff;
if(dist >= 100000.0f)
continue;
if(closest_item == NULL || dist < closest)
{
closest_item = item;
closest = dist;
}
}
// rotate target and move into position
if(closest_item)
{
m_target_object.rotate_rel(0.0f, (float) time_elapsed * 0.01f, 0.0f);
m_target_object.move(closest_item->x_pos, closest_item->y_pos + 50.0f, closest_item->z_pos);
m_target_object.render();
// print item name
char text[256];
sprintf(text, "index:%lu, name:%s, quantity:%lu",
closest_item->item_index, m_items[closest_item->item_index].name, closest_item->quantity);
m_font.draw(text, 0, 0, 0, 0, 0xFFFFFFFF, DT_LEFT);
}
g_d3d_device->EndScene();
}
present_display();
// check for picking up item, put here to make easier for clostet item.
if(m_mouse.get_button_state(MOUSE_LBUTTON))
{
m_mouse.set_lock(MOUSE_LBUTTON, TRUE);
// pick up closest item
if(closest_item)
m_map_ics.remove(closest_item);
}
return TRUE;
}
bool shutdown()
{
m_map_ics.save("..\\Data\\MapItems.mi");
return TRUE;
}
};
const float cApp::m_above_floor = 64.0f;
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
DWORD client_width = 640;
DWORD client_height = 480;
DWORD x_pos = (get_screen_width() - client_width) / 2;
DWORD y_pos = (get_screen_height() - client_height) / 4;
if(! build_window(inst, "map_ics_class", "map ics test",
WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
x_pos, y_pos, client_width, client_height))
{
return -1;
}
cApp app;
app.run();
return 0;
}