天行健 君子当自强而不息

Creating Combat Sequences(5)

cApp::get_char_at

One of the coolest functions is get_char_at, which scans through the list of characters
and determines which one is positioned at the specified display coordinates.
Although doing this might be as easy as performing a bounding check on the character’s
display coordinates, go the extra mile and make the selection work on a
polygon face level:

long cApp::get_char_at(long x_pos, long y_pos)
{
    D3DXMATRIX mat_proj, mat_view, mat_inv;

    
// get the project, view, and inversed view matrices.
    get_display_proj_matrix(&mat_proj);
    get_display_view_matrix(&mat_view);
    D3DXMatrixInverse(&mat_inv, NULL, &mat_view);

    D3DXVECTOR3 temp;

    
// compute the vector of the pick ray in screen space
    temp.x =  ((2.0f * x_pos) / get_client_width(g_hwnd) - 1.0f)  / mat_proj._11;
    temp.y = -((2.0f * y_pos) / get_client_height(g_hwnd) - 1.0f) / mat_proj._22;
    temp.z = 1.0f;

    D3DXVECTOR3 ray, dir;

    ray.x = mat_inv._41;
    ray.y = mat_inv._42;
    ray.z = mat_inv._43;

    dir.x = temp.x * mat_inv._11 + temp.y * mat_inv._21 + temp.z * mat_inv._31;
    dir.y = temp.x * mat_inv._12 + temp.y * mat_inv._22 + temp.z * mat_inv._32;
    dir.z = temp.x * mat_inv._13 + temp.y * mat_inv._23 + temp.z * mat_inv._33;

    
// scan through each character and intersect check
    for(sCharacter* character = m_char_controller.get_root_char(); character != NULL; character = character->next)
    {
        sMeshInfo* root_mesh_info = character->
object.m_mesh->get_root_mesh();

        
// scan through character meshes
        for(sMeshInfo* mesh_info = root_mesh_info; mesh_info != NULL; mesh_info = mesh_info->m_next)
        {
            
// transform ray and direction by object's world transformation matrix

            D3DXMatrixInverse(&mat_inv, NULL, character->
object.get_matrix());

            D3DXVECTOR3 mesh_ray, mesh_dir;
            D3DXVec3TransformCoord(&mesh_ray, &ray, &mat_inv);
            D3DXVec3TransformNormal(&mesh_dir, &dir, &mat_inv);

            DWORD face_index;
            BOOL  hit;
            
float u, v, dist;

            D3DXIntersect(mesh_info->m_d3d_mesh, &mesh_ray, &mesh_dir, &hit, &face_index, &u, &v, &dist, NULL, NULL);

            
if(hit)
                
return character->id;
        }
    }

    
return -1;  // no hit
}

You want to check every character to see which one was clicked, so get_char_at
starts by first determining whether any characters exist. At that point, you need to
compute a ray to test for polygon intersections from the mouse cursor to each mesh.

Now that the ray is configured, you continue the execution by
entering a loop that iterates through all characters. For each character, the
get_char_at function scans through each contained mesh to check for a ray-to polygon
intersection.

Note that for each character in question, you have to offset the ray’s coordinates by
the character’s orientation in the world (obtained from the character object’s transformation
matrix). You do so because the intersect function doesn’t take the world
transformation of each character into mind; you do that.

If a polygon is intersected, the function returns the identification number of the
character. On the other hand, if no intersection is found, you check the next character
mesh, followed by the next character in the list. If no characters are found,
the function returns an error (signified by -1).

 

Using Battle Arrangements

Although I intentionally hard-coded the functions that determine the characters to
use in the combat sequence in the Battle demo, in a real game application, you base
the selection of monsters on the map region in which the player is currently
located.

For example, players in a haunted house will encounter ghosts and zombies. In the
countryside, players might encounter large beasts native to the area. You need to
determine each type of monster that players can encounter (and where).

The best way to determine which monsters to battle in each sequence is to use battle
arrangements, pre-configured sets of monsters. In a haunted house, you could
have one arrangement with two ghosts and another arrangement with three zombies.
When combat starts, one arrangement is picked at random by the game.

How do you store the arrangements? With scripts, of course!  All you do is determine which script to load and
then process it, allowing the script to add the arrangement of monsters to the
sequence.

The great thing is that you can force a specific battle sequence to take place. For
example, if it is time to fight a boss monster, you can specifically load that script.
Within the script, you can load a song to play signifying that a major battle is
occurring. There are no limits when using scripting!

download source and solution

 

posted on 2007-12-12 22:18 lovedday 阅读(224) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论