C++工具箱——动画类之基类

Posted 牧秦丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++工具箱——动画类之基类相关的知识,希望对你有一定的参考价值。

OK,我们已经讨论了单件定时器了,该来点真格的了。这次我们来看看如何通过前面所述的定时器实现动画。我目前想到的动画有大小更改、Alpha 透明度更改、窗口位置更改等几种,后续会逐步加上。


我们先来思考动画的实质。动画其实就是通过定时器,一步步逼近一个期望结果的过程。我们期望的动画类是这样的:

1、接口简单、使用方便;

2、可扩展。比如我们后续加上新的动画类时不必太费力;

3、添加新动画类时不必操心动画共有的部分;(如计时器、回调等等)


一个动画有以下共有性质:

1、两次动画间的时间间隔(ms 为单位);

2、动画是否已经开启了;

3、整个动画展示完成后的回调(可选);

4、动画对象的管理


第四个尤为重要,因为我们可能在一个如何一个函数(全局函数、类成员方法、某一个线程处理函数)中启用一个动画,如果还需手动管理动画对象的生命周期的话,那就太不Fashion了!(你可以思考下如果让你来设计,你会怎么设计这个动画的基类)


好的,我们来看我设计的动画基类,如果你有更好的点子,可以找我沟通。你可能需要定时器Boost相关的知识。如下:

/**
 * \\file 	frameanimation.h
 * \\author	arnozhang
 * \\date	2012.9.13	
 * \\brief	窗口动画基类.
 */

#ifndef	__FRAME_ANIMATION_BASE_H__
#define	__FRAME_ANIMATION_BASE_H__


#include "wnd.h"
#include "timer.h"


namespace Util



template <typename _Co_Animation> class CFrameAnimation

public:
    // 动画完成回调.
    typedef _Co_Animation this_class;
    typedef boost::function<void(void)> AnimationFinishCallback;

    // 获取一个动画对象.
    static _Co_Animation& GetAnimation(CWnd* targetFrame)
    
        return *(new _Co_Animation(targetFrame));
    

    // 启动动画.
    void StartAnimation()
    
        if (m_bAnimationStarted || !m_targetFrame)
        
            return ;
        

        m_bAnimationStarted = TRUE;
        if (_PrepareAnimation())
        
            Util::SetTimerCallback(
                m_targetFrame,
                m_dwTimeInterval,
                TIMER_CALL_BIND(this_class, AnimationHandler_Bind_Proc)
                );
        
    

    // 设置动画时间间隔.
    void SetTimeInterval(
        DWORD dwTimeInteval = DEFAULT_ANIMATION_TIME_INTERVAL
        )
    
        m_dwTimeInterval = dwTimeInteval;
    

	// 设置动画帧数.
	void SetFrameCount(DWORD dwFrameCnt)
	
		m_dwFrameCount = dwFrameCnt;
	
	
    // 设置整个动画完成后的回调.
    void SetFinishedCallback(const AnimationFinishCallback& finishedCbk)
    
        delete m_pFinishedCallback;
        m_pFinishedCallback = new AnimationFinishCallback(finishedCbk);
    


private:
    // 动画处理器.
    void AnimationHandler_Bind_Proc()
    
        _AnimationHandler();
    


protected:
    virtual bool _PrepareAnimation() = 0;
    virtual void _AnimationHandler() = 0;

    // 动画执行完毕.
    void _AnimationFinished()
    
        // 清除计时器.
        Util::KillTimerCallback(m_targetFrame);

        // 调用完成回调.
        if (m_pFinishedCallback)
        
            (*m_pFinishedCallback)();
        

        // 删除动画对象.
        delete this;
    

    CFrameAnimation(CWnd* targetFrame)
    
        m_targetFrame       = targetFrame;
        m_dwTimeInterval    = DEFAULT_ANIMATION_TIME_INTERVAL;
        m_dwFrameCount		= 0;
        m_bAnimationStarted = FALSE;
        m_pFinishedCallback = 0;
    

    virtual ~CFrameAnimation()
    
        delete m_pFinishedCallback;
    

    CWnd*	m_targetFrame;
    DWORD	m_dwFrameCount;


private:
    AnimationFinishCallback*    m_pFinishedCallback;
    DWORD                       m_dwTimeInterval;
    BOOL                        m_bAnimationStarted;
    static const int DEFAULT_ANIMATION_TIME_INTERVAL = 30;
;


#define BIND_ANIMATION_FINISHED_PROC(class_name, method_name) \\
    boost::bind(&class_name::method_name, this)


 /*namespace Util ends here.*/


#endif /*__FRAME_ANIMATION_BASE_H__*/

我们定义了一个抽象模版基类 CFrameAnimation。其中模版参数  _Co_Animation 是实现动画类的具体类(如 CFrameBlendAnimation CFrameSizeAnimation 等)。如果我们要实现新的动画类,只需继承该类就行了,并且重写 _PrepareAnimation_AnimationHandler这两个虚方法即可。其中 _PrepareAnimation为开启动画前的初始化及准备工作——因为不同的动画类有不同的属性和初始化方法; _AnimationHandler正如其名,是动画处理过程,因为不同的动画类对应的动画处理也不尽相同。这两个方法都是 模版方法


我们将 CFrameAnimation的构造和析构均设为protected属性(CFrameAnimation的子类亦如此),让它们只能通过静态方法GetAnimation得到一个动画对象,让动画对象只能在堆上构造,然后在动画完成后通过delete this; 这句来释放掉——完全保证了动画对象生命周期的独立管理,不需要用户操一点心思。


我们定义了一个 _AnimationFinished方法,每个新的动画类在_AnimationHandler中完成所有动画的处理后,必须调用该函数删除定时器、释放资源。考虑 DEFAULT_ANIMATION_TIME_INTERVAL 为什么为30?因为人眼中,当动画、游戏等帧数为每秒30帧左右的时候,看起来是连贯的。所以这个值为 1000ms / 30 帧,大约等于30。所以,动画对象的 SetTimerInterval 方法一般不需要调用,我们一般通过SetFrameCount 方法来控制动画的播放帧数。


比如我们实现了一个CFrameBlendAnimation来完成窗口的透明度渐变,那么使用方法也很简单:

#include "frameblendanimation"


void animationFinished()

	cout<<"hello! Animation Finished!"<<endl;



void foo()

	CWnd wnd;
	wnd.Create();
	// ...
	
	CFrameBlendAnimation& animation = CFrameBlendAnimation::GetAnimation(&wnd);
	animation.SetStartAlpha(255);
	animation.SetEndAlpha(0);
	
	// 设置播放帧数.
	animation.SetFrameCount(10);
	
	// 完成回调可要可不要,根据需求来.
	animation.SetFinishedCallback(animationFinished);
	
	// 启动动画.
	animation.StartAnimation();



可以看出,我们只需通过 GetAnimation 方法获取一个动画对象,然后做相应的设置,最后调用 StartAnimation启动动画就行了,完全不用我们操心。解耦的好处在这里得到了充分体现。


下一章将实现一个实现上述窗口透明度渐变的动画类 CFrameBlendAnimation。将会有一份实现好的源代码示例可供下载。大家也可趁机想想如何实现这样一个CFrameBlendAnimation类。





以上是关于C++工具箱——动画类之基类的主要内容,如果未能解决你的问题,请参考以下文章

Python_64类的继承之基类构造方法

C++工具箱——动画类之透明度渐变 & 大小渐变

一点一滴,成材之基! Linux后门Trojan Horse检测工具

c++中的虚函数有啥作用?

C++ Primer 5th笔记(chap 18 大型程序工具)类型转换与多个基类

C++ Primer 5th笔记(chap 18 大型程序工具)虚继承