• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天行健 君子當(dāng)自強(qiáng)而不息

            Controlling Players and Characters(24)

             

            The cSpellController Class

            Because the spell controller is needed only for tracking the spell meshes and
            animation, the class definition is relatively small:

            typedef class cSpellController
            {
            private:
                cCharController*    m_char_controller;

                cFrustum*           m_frustum;

                sSpell              m_spells[NUM_SPELL_DEF];
                sSpellTracker*      m_spell_tracker;

                
            long                m_num_mesh_anim;    
                sMeshAnim*          m_mesh_anim;

                
            char                m_texture_path[MAX_PATH];

            Now check the private data of the spell controller before examining the public
            functions. The spell controller uses a frustum object. The frustum
            object (m_frustum) can be supplied from outside code or calculated from within
            the spell-rendering function.

            Next comes the MSL, which is contained in the array m_spells. Notice that the
            macro NUM_SPELL_DEF defines the size of the MSL array, which means that you
            can easily adjust the size for later enhancements.

            Following the MSL is the linked list pointer m_spell_tracker, which tracks the spells
            that have been cast and are being displayed. Next comes
            m_num_mesh_anim (which stores
            the number of meshes used) and
            m_mesh_anim (a list of meshes).

            Because this example uses 3-D meshes to represent the spells, you need to load textures,
            and in order for the spell controller to find those textures, you must store a
            directory path that indicates the location of the bitmaps to be used as textures.

            Something you haven’t seen up to now is the m_char_controller pointer, which points to the
            character controller class object in use. This class pointer triggers the spell effects.

            cSpellController contains two private functions: SetAnimData and SpellSound. The
            set_animData function sets up the mesh to use as well as the movement of the mesh.
            play_spell_sound is called whenever a spell mesh is used; it’s your job to override this function
            to play the appropriate sound as specified in the function’s argument list.

            With private data and functions covered, you can move on to the class’s public functions
            (the Constructor, Destructor, init, shutdown, free, get_spell, add, update, and render):

            public:
                cSpellController()
                {
                    m_char_controller   = NULL;

                    m_frustum           = NULL;
                    m_spell_tracker     = NULL;

                    m_mesh_anim         = NULL;
                    m_num_mesh_anim     = 0;

                    m_texture_path[0]   = '\0';

                    ZeroMemory(m_spells, 
            sizeof(m_spells));
                }

                ~cSpellController()
                {
                    shutdown();
                }

                
            void free()
                {
                    delete m_spell_tracker;
                    m_spell_tracker = NULL;
                }

                sSpell* get_spell(
            long spell_index)
                {
                    
            return &m_spells[spell_index];
                }

                sSpell* get_spell_list()
                {
                    
            return m_spells;
                }

                
            void attach(cCharController* char_controller)
                {
                    m_char_controller = char_controller;
                }

                
            //////////////////////////////////////////////////////////////////////////////////////

                
            bool init(PCSTR msl_file, long num_mesh_anim, PCSTR* mesh_anim_name, PCSTR texture_path);
                
            void shutdown();
                
            bool add(sCharacter* caster);
                
            void update(long elapsed);
                
            void render(cFrustum* frustum, float z_dist);

                
            //////////////////////////////////////////////////////////////////////////////////////

            private:
                
            void set_anim_data(sSpellTracker* tracker, long cur_anim);
                
            virtual void play_spell_sound(long index) { }

            }

             

            cSpellController::cSpellController and cSpellController::~sSpellController

            Typical in C++ classes, the constructor and destructor clear the class data and free
            all used resources, respectively. The destructor relies on a separate function (the
            Shutdown function) to clear the data.


            cSpellController::init and cSpellController::shutdown

            Before using the spell controller class, you must initialize it. When you finish with
            the class, you call Shutdown to free up the resources.

            bool cSpellController::init(PCSTR msl_file, long num_mesh_anim, PCSTR* mesh_anim_name, PCSTR texture_path)
            {
                free();

                
            if(msl_file == NULL || mesh_anim_name == NULL)
                    
            return false;

                
            // load the spells

                FILE* fp;
                
            if((fp = fopen(msl_file, "rb")) == NULL)
                    
            return false;

                fread(m_spells, 1, 
            sizeof(m_spells), fp);
                fclose(fp);

                
            if(texture_path)
                    strcpy(m_texture_path, texture_path);

                
            // get mesh names
                if((m_num_mesh_anim = num_mesh_anim) != 0)
                {
                    m_mesh_anim = 
            new sMeshAnim[num_mesh_anim];

                    
            for(long i = 0; i < m_num_mesh_anim; i++)
                        strcpy(m_mesh_anim[i].filename, mesh_anim_name[i]);
                }

                
            return true;
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////

            void cSpellController::shutdown()
            {
                free();

                
            // release spell meshes
                for(long i = 0; i < m_num_mesh_anim; i++)
                {
                    m_mesh_anim[i].mesh.free();
                    m_mesh_anim[i].anim.free();
                    m_mesh_anim[i].count = 0;
                }

                delete[] m_mesh_anim;
                m_mesh_anim = NULL;

                m_num_mesh_anim = 0;
            }

            cSpellController::free

            When you’re done with a spell controller class instance but want to reuse it without
            having to shut it down, a call to cSpellController::Free is in order. Free releases the
            spell tracking list as well as the mesh list.

            cSpellController::get_spell

            Outside code might need access to the MSL, and GetSpell fills that need. Providing
            the MSL reference number returns a pointer into the array of the loaded MSL.

            cSpellController::add

            Now the real fun begins! Add is the function you use the most because it initiates a spell.

            bool cSpellController::add(sCharacter* caster)
            {
                
            // add a spell to spell tracker list

                
            long spell_index = caster->spell_index;

                
            // make sure character is allowed to cast spell
                if(!(caster->char_def.magic_spell[spell_index/32] & (1 << (spell_index & 31))))
                    
            return false;

                
            // make sure caster has enough mana to cast
                if(caster->mana_points < m_spells[spell_index].cost)
                    
            return false;
              
                
            // allocate a new spell stracker and link into head of list

                sSpellTracker* spell_tracker = 
            new sSpellTracker;

                
            if(m_spell_tracker)
                    m_spell_tracker->prev = spell_tracker;

                spell_tracker->next = m_spell_tracker;

                m_spell_tracker = spell_tracker;

                
            // set structure data
                spell_tracker->spell_index = spell_index;
                spell_tracker->caster      = caster;
                spell_tracker->affect_type = caster->target_type;
                spell_tracker->source_x    = caster->pos_x;
                spell_tracker->source_y    = caster->pos_y;
                spell_tracker->source_z    = caster->pos_z;
                spell_tracker->target_x    = caster->target_x;
                spell_tracker->target_y    = caster->target_y;
                spell_tracker->target_z    = caster->target_z;

                
            // setup the mesh/animation movement data
                set_anim_data(spell_tracker, 0);

                
            return true;
            }

            cSpellController::set_anim_data

            The private function set_anim_data initializes the three meshes in use by a spell. If one
            of the meshes is not used (as specified by the POSITION_NONE value in mesh_pos), the
            next mesh in the three is used. After all three meshes are used up, the spell’s
            effects are triggered.

            oid cSpellController::set_anim_data(sSpellTracker* tracker, long cur_anim)
            {
                sSpell& spell = m_spells[tracker->spell_index];

                
            long mesh_index;
                tracker->cur_anim = cur_anim;

                
            // process spell effect if no more animations left while storing the current animation number.
                if(tracker->cur_anim >= 3)
                {
                    
            if(m_char_controller)
                        m_char_controller->spell(tracker->caster, tracker, m_spells);

                    
            // remove any mesh and animation if any, or just decrease reference count.
                    for(int i = 0; i < 3; i++)
                    {
                        
            if(spell.mesh_pos[i] != POSITION_NONE)
                        {
                            mesh_index = spell.mesh_index[i];

                            
            if(--m_mesh_anim[mesh_index].count == 0)
                            {
                                m_mesh_anim[mesh_index].mesh.free();
                                m_mesh_anim[mesh_index].anim.free();
                            }
                        }
                    }

                    
            // remove spell tracker from list

                    
            if(tracker->prev)
                        tracker->prev->next = tracker->next;
                    
            else
                        m_spell_tracker = tracker->next;

                    
            if(tracker->next)
                        tracker->next->prev = tracker->prev;

                    tracker->prev = tracker->next = NULL;
                    delete tracker;

                    
            return;
                }

                
            // setup local data
                float source_x = tracker->source_x;
                
            float source_y = tracker->source_y;
                
            float source_z = tracker->source_z;
                
            float target_x = tracker->target_x;
                
            float target_y = tracker->target_y;
                
            float target_z = tracker->target_z;

                
            // goto next animation if no mesh to use
                if(spell.mesh_pos[cur_anim] == POSITION_NONE)
                    
            return set_anim_data(tracker, cur_anim+1);

                mesh_index = spell.mesh_index[cur_anim];
                sMeshAnim& mesh_anim = m_mesh_anim[mesh_index];
                
                
            // load mesh and animation if needed
                if(mesh_anim.count == 0)
                {
                    mesh_anim.mesh.load(mesh_anim.filename, m_texture_path);
                    mesh_anim.anim.load(mesh_anim.filename, &mesh_anim.mesh);
                    mesh_anim.anim.set_loop(spell.mesh_loop[cur_anim], "Anim");
                }

                cObject& spell_obj = tracker->
            object;
                spell_obj.create(&mesh_anim.mesh);
                mesh_anim.count++;

                
            float x_angle = 0.0f, y_angle = 0.0f;
                
            float x_diff, y_diff, z_diff, dist;
                
            float scale = 1.0f;

                
            // setup mesh movements
                switch(spell.mesh_pos[cur_anim])
                {
                
            case POSITION_CASTER:
                    tracker->x_pos = source_x;
                    tracker->y_pos = source_y;
                    tracker->z_pos = source_z;
                    tracker->holding_time = spell.mesh_speed[cur_anim];

                    
            if(tracker->caster)
                        y_angle = tracker->caster->direction;

                    
            break;

                
            case POSITION_TOTARGET:
                    
            // store position and speed information
                    tracker->x_pos = source_x;
                    tracker->y_pos = source_y;
                    tracker->z_pos = source_z;
                    tracker->speed = spell.mesh_speed[cur_anim];

                    
            // calculate mevement
                    x_diff = fabs(target_x - source_x);
                    y_diff = fabs(target_y - source_y);
                    z_diff = fabs(target_z - source_z);

                    dist = sqrt(x_diff * x_diff + y_diff * y_diff + z_diff * z_diff);

                    tracker->dist_to_target = dist;

                    
            if(! float_equal(dist, 0.0f))
                    {
                        tracker->x_add = (target_x - source_x) / dist;
                        tracker->y_add = (target_y - source_y) / dist;
                        tracker->z_add = (target_z - source_z) / dist;

                        
            // calculate angles
                        x_angle = -atan(tracker->y_add);
                        y_angle = atan2(tracker->x_add, tracker->z_add);
                    }

                    
            break;

                
            case POSITION_TARGET:
                    tracker->x_pos = target_x;
                    tracker->y_pos = target_y;
                    tracker->z_pos = target_z;
                    tracker->holding_time = spell.mesh_speed[cur_anim];

                    
            // calculate distance from source to target
                    x_diff = fabs(target_x - source_x);
                    z_diff = fabs(target_z - source_z);
                    dist   = sqrt(x_diff * x_diff + z_diff * z_diff);

                    tracker->x_add = (target_x - source_x) / dist;
                    tracker->z_add = (target_z - source_z) / dist;

                    y_angle = atan2(tracker->x_add, tracker->z_add);
                    
            break;

                
            case POSITION_TOCASTER:
                    
            // store position and speed information
                    tracker->x_pos = target_x;
                    tracker->y_pos = target_y;
                    tracker->z_pos = target_z;
                    tracker->speed = spell.mesh_speed[cur_anim];

                    
            // calculate movement
                    x_diff = fabs(source_x - target_x);
                    y_diff = fabs(source_y - target_y);
                    z_diff = fabs(source_z - target_z);

                    dist = sqrt(x_diff * x_diff + y_diff * y_diff + z_diff * z_diff);

                    tracker->dist_to_target = dist;

                    
            if(! float_equal(dist, 0.0f))
                    {
                        tracker->x_add = (source_x - target_x) / dist;
                        tracker->y_add = (source_y - target_y) / dist;
                        tracker->z_add = (source_z - target_z) / dist;

                        
            // calculate angles
                        x_angle = -atan(tracker->y_add);
                        y_angle = atan2(tracker->x_add, tracker->z_add);
                    }

                    
            break;

                
            case POSITION_SCALE:
                    
            // store position and speed information
                    tracker->x_pos = source_x;
                    tracker->y_pos = source_y;
                    tracker->z_pos = source_z;
                    tracker->holding_time = spell.mesh_speed[cur_anim];

                    
            // get distance from source to target and size of mesh

                    x_diff = fabs(target_x - source_x);
                    y_diff = fabs(target_y - source_y);
                    z_diff = fabs(target_z - source_z);

                    dist = sqrt(x_diff * x_diff + y_diff * y_diff + z_diff * z_diff);

                    
            float length;
                    spell_obj.get_bounds(NULL, NULL, NULL, NULL, NULL, &length, NULL);

                    scale = dist / length;

                    tracker->x_add = (target_x - source_x) / dist;
                    tracker->y_add = (target_y - source_y) / dist;
                    tracker->z_add = (target_z - source_z) / dist;

                    x_angle = -atan(tracker->y_add);
                    y_angle = atan2(tracker->x_add, tracker->z_add);

                    
            break;
                }

                spell_obj.rotate(x_angle, y_angle, 0.0f);
                spell_obj.scale(1.0f, 1.0f, scale);
                spell_obj.set_anim_set(&mesh_anim.anim, "Anim", timeGetTime()/30);

                
            if(spell.mesh_sound[cur_anim] != -1)
                    play_spell_sound(spell.mesh_sound[cur_anim]);
            }

            cSpellController::update

            Spells need to move, have their timing updated, and have their mesh initiated at
            the various steps. Update is responsible for all those functions. To use Update, just pass
            the amount of time (in milliseconds) that has elapsed from the last call to Update
            (or the amount of time you want the controller to update the spells).

            void cSpellController::update(long elapsed)
            {
                
            // update all spells based on elapsed time

                sSpellTracker* next_tracker;

                
            // scan through all spells in use
                for(sSpellTracker* tracker = m_spell_tracker; tracker != NULL; tracker = next_tracker)
                {
                    
            // remember next spell in list
                    next_tracker = tracker->next;

                    
            long spell_index = tracker->spell_index;
                    
            long cur_anim    = tracker->cur_anim;

                    
            bool goto_next_anim = false;

                    
            // update/move/countdown spell object
                    switch(m_spells[spell_index].mesh_pos[cur_anim])
                    {
                    
            case POSITION_NONE:
                        goto_next_anim = 
            true;
                        
            break;

                    
            case POSITION_CASTER:
                    
            case POSITION_TARGET:
                    
            case POSITION_SCALE:
                        tracker->holding_time -= elapsed;

                        
            if(tracker->holding_time <= 0)
                            goto_next_anim = 
            true;

                        
            break;

                    
            case POSITION_TOTARGET:
                    
            case POSITION_TOCASTER:
                        
            float speed = elapsed/1000.0f * tracker->speed;
                        tracker->dist_to_target -= speed;

                        
            if(tracker->dist_to_target > 0.0f)
                        {
                            tracker->x_pos += (tracker->x_add * speed);
                            tracker->y_pos += (tracker->y_add * speed);
                            tracker->z_pos += (tracker->z_add * speed);
                        }
                        
            else
                            goto_next_anim = 
            true;

                        
            break;
                    }

                    
            // update next animation if any
                    if(goto_next_anim)
                        set_anim_data(tracker, cur_anim+1);
                }
            }
             

            cSpellController::render

            The last of the functions, Render, is used to render all spell meshes that are in effect.
            Providing the Render function with an optional frustum and viewing distance helps
            alter the way the meshes are rendered.

            void cSpellController::render(cFrustum* frustum, float z_dist)
            {
                m_frustum = frustum;

                
            // construct the viewing frustum (if none passed)
                if(m_frustum == NULL)
                {
                    cFrustum view_frustum;
                    view_frustum.create(z_dist);
                    m_frustum = &view_frustum;
                }

                
            // get time to update animations (30 fps)
                DWORD time = timeGetTime() / 30;

                
            // loop through each spell and draw
                for(sSpellTracker* tracker = m_spell_tracker; tracker != NULL; tracker = tracker->next)
                {
                    
            float radius;
                    tracker->
            object.get_bounds(NULL, NULL, NULL, NULL, NULL, NULL, &radius);

                    
            // draw spell if in viewing frustum
                    if(m_frustum->is_sphere_in(tracker->x_pos, tracker->y_pos, tracker->z_pos, radius))
                    {
                        tracker->
            object.move(tracker->x_pos, tracker->y_pos, tracker->z_pos);
                        tracker->
            object.update_anim(time, TRUE);
                        tracker->
            object.render();
                    }
                }
            }

            posted on 2007-12-03 19:46 lovedday 閱讀(280) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            公告

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關(guān)鏈接

            搜索

            最新評(píng)論

            亚洲国产精品热久久| 亚洲狠狠久久综合一区77777 | 国产99久久精品一区二区| 久久99久久99精品免视看动漫| 久久w5ww成w人免费| 精品久久久久久无码免费| 久久久久亚洲AV成人网人人软件| 久久久久99这里有精品10| 国产精品99久久精品| 久久久青草青青国产亚洲免观| 亚洲精品乱码久久久久久中文字幕| 久久综合九色综合久99| 亚洲国产精品高清久久久| 国内精品免费久久影院| 99999久久久久久亚洲| 欧美亚洲国产精品久久久久| 日韩欧美亚洲综合久久影院d3| 久久中文字幕精品| 久久精品国产99久久久香蕉| 国产精品久久99| 97久久国产综合精品女不卡 | 一本久久综合亚洲鲁鲁五月天| 国产V综合V亚洲欧美久久| 国产精品久久久久免费a∨| 99久久综合狠狠综合久久| 成人综合伊人五月婷久久| 人妻无码中文久久久久专区| 亚洲人成无码www久久久| 国产精品激情综合久久| 国产成人精品久久免费动漫| 性欧美丰满熟妇XXXX性久久久 | 久久国产成人亚洲精品影院| 久久久久夜夜夜精品国产| 91久久婷婷国产综合精品青草| 无码人妻久久一区二区三区免费丨| 欧洲性大片xxxxx久久久| 国产精品成人99久久久久 | 91精品国产91久久久久久蜜臀| 久久久久久人妻无码| 久久av无码专区亚洲av桃花岛| 久久夜色精品国产网站|