天天看點

C 實作通用Tween緩動動畫(3)快捷鍊式調用接口

  Tween建立action有很多屬性設定,不同的動畫效果,需要不同的屬性控制。多個action的動畫需要多次設定,使用起來十分不友善,還要建立臨時數組存放一組action。通常,tween的參數設定會使用鍊式調用,形成一組連續的控制。在面向對象中上下文可以獲得目前對象,但在C中無法獲得。往往在C中方法設定一個對象的屬性,需要把目前對象手動傳進去非常不友善。是以,我們需要建構一個上下文,儲存鍊式調用中建立的對象,好像方法不需要每次都傳入目前對象。

   在Tween的實作函數之上,将會封裝一套便捷的使用接口,完成以下功能。

  • 鍊式調用建立多個action并執行
  • 鍊式調用設定action和actionValue的屬性
  • 緩存目前建立的action作為調用方法的上下文
  • 緩存actionValueIndex作為調用方法的上下文

   完整實作代碼如下:

/*
 * TweenTool.h
 *
 *  Created on: 2016-6-24
 *      Author: scott.cgi
 */

#ifndef tween_tool_h_
#define tween_tool_h_

#include <stdbool.h>
#include "Mojoc/Toolkit/Utils/Tween.h"


typedef struct
{
	TweenActionValueOnGet get;
	TweenActionValueOnSet set;
}
TweenActionValueCallback;


typedef struct _ATweenTool_ _ATweenTool_;
struct _ATweenTool_
{
	/**
	 * Create one TweenAction in context for chain setting
	 **/

	_ATweenTool_* (*CreateAction)    (int actionValueCount);


	/**
	 * Create one TweenAction with one action value in context for chain setting
	 */
	_ATweenTool_* (*CreateActionOne) (TweenActionValueCallback valueCallback, float value, float duration);


	/**
	 * Create action with no actionValue, so actionValueCount is 0
	 * just through duration time then callback
	 */
	_ATweenTool_* (*CreateInterval)  (float duration);


	/**
	 * Set TweenAction property for current context created
	 **/


	_ATweenTool_* (*SetDuration)     (float                    duration);
	_ATweenTool_* (*SetUserData)     (void*                    userData);
	_ATweenTool_* (*SetQueue)        (bool                     isQueue);
	_ATweenTool_* (*SetOnComplete)   (TweenActionOnComplete    OnComplete);
	_ATweenTool_* (*SetTarget)       (void*                    target);

	/**
	 * Get TweenAction in current context
	 */
	_ATweenTool_* (*GetAction)       (TweenAction**            outActionPtr);



	/**
	 * Set TweenActionValue property for current context created
	 **/


	_ATweenTool_* (*SetRelative)     (bool                     isRelative);
	_ATweenTool_* (*SetEaseType)     (TweenEaseType            easeType);

	/**
	 * Update new value index, and index must smaller than actionValueCount
	 * after, each set TweenActionValue property will on this current index
	 */
	_ATweenTool_* (*SetValue)        (TweenActionValueCallback valueCallback, float value);


	/**
	 * Run actions all in current context, set action target if has actionValue
	 * and use target be tweenId
	 */
	void          (*RunActions)      (void* target);

	/**
	 * Run actions all in current context, action must set target if has actionValue
	 * and return tweenId
	 */
	void*         (*RunTargets)      ();

};

extern _ATweenTool_ ATweenTool[1];

#endif
           
/*
 * TweenTool.c
 *
 *  Created on: 2016-6-24
 *      Author: scott.cgi
 */

#include "Mojoc/Toolkit/Utils/TweenTool.h"
#include "Mojoc/Toolkit/Platform/Log.h"
#include "Mojoc/Toolkit/Utils/Array.h"

#define action_length 30

static Array(TweenAction*) actionArr[1] =
{
	(TweenAction*[action_length]) {},
	0
};

static TweenAction* action      = NULL;
static int          valueCount  =  0;
static int          valueIndex  = -1;


#define CheckAction(tag) \
	ALog_A(action, "ATweenTool " tag " TweenAction not created");

#define CheckIndex(tag, actionValueIndex) \
	ALog_A(valueIndex > -1 && actionValueIndex < valueCount, "ATweenTool " tag " actionValueIndex invalid");

static _ATweenTool_* CreateAction(int actionValueCount)
{
	ALog_A
	(
		actionArr->length <=  action_length,
		"ATweenTool can not cache TweenActions = %d more than %d",
		actionArr->length,
		action_length
	);

	action     = ATween->CreateAction(actionValueCount);
	valueCount = actionValueCount;
    valueIndex = -1;

	AArray_Set
	(
		actionArr,
		actionArr->length++,
		action,
		TweenAction*
	);

	return ATweenTool;
}

static _ATweenTool_* CreateActionOne(TweenActionValueCallback valueCallback, float value, float duration)
{
	return CreateAction(1)->SetValue(valueCallback, value)->SetDuration(duration);
}

static _ATweenTool_* CreateInterval(float duration)
{
	return CreateAction(0)->SetDuration(duration);
}


static _ATweenTool_* SetDuration(float duration)
{
	CheckAction("SetDuration");
	action->duration = duration;

	return ATweenTool;
}


static _ATweenTool_* SetUserData(void* userData)
{
	CheckAction("SetUserData");
	action->userData = userData;

	return ATweenTool;
}

static _ATweenTool_* SetQueue(bool isQueue)
{
	CheckAction("SetQueue");
	action->isQueue = isQueue;

	return ATweenTool;
}

static _ATweenTool_* SetOnComplete(TweenActionOnComplete OnComplete)
{
	CheckAction("SetOnComplete");
	action->OnComplete = OnComplete;

	return ATweenTool;
}

static _ATweenTool_* SetTarget(void* target)
{
	CheckAction("SetTarget");
	action->target = target;

	return ATweenTool;
}

static _ATweenTool_* GetAction(TweenAction** outActionPtr)
{
	CheckAction("GetAction");
	*outActionPtr = action;

	return ATweenTool;
}


static _ATweenTool_* SetRelative(bool isRelative)
{
	CheckAction("SetRelative");
	CheckIndex("SetRelative", valueIndex);
	action->actionValues[valueIndex].isRelative = isRelative;

	return ATweenTool;
}

static _ATweenTool_* SetEaseType(TweenEaseType easeType)
{
	CheckAction("SetEaseType");
	CheckIndex ("SetEaseType", valueIndex);
	action->actionValues[valueIndex].easeType = easeType;

	return ATweenTool;
}



static _ATweenTool_* SetValue(TweenActionValueCallback valueCallback, float value)
{
	valueIndex++;

	CheckAction("SetValue");
	CheckIndex ("SetValue", valueIndex);

	action->actionValues[valueIndex].OnGet = valueCallback.get;
	action->actionValues[valueIndex].OnSet = valueCallback.set;
	action->actionValues[valueIndex].value = value;

	return ATweenTool;
}


static void RunActions(void* target)
{
	ALog_A(target, "RunActions, target must not NULL");

	for (int i = 0; i < actionArr->length; i++)
	{
		TweenAction* action = AArray_Get(actionArr, i, TweenAction*);

		if (action->actionValueCount > 0)
		{
			action->target = target;
		}
	}

	ATween->RunActions(actionArr, &target);

	actionArr->length = 0;
    action            = NULL;
}


static void* RunTargets()
{
	for (int i = 0; i < actionArr->length; i++)
	{
		TweenAction* action = AArray_Get(actionArr, i, TweenAction*);

		if (action->actionValueCount > 0)
		{
			ALog_A
			(
				 action->target,
				"RunActions, the {%d} action value count is 0 so must set target",
				i
			);
		}
	}

	void* tweenId = NULL;

	ATween->RunActions(actionArr, &tweenId);

	actionArr->length = 0;
    action            = NULL;

    return tweenId;
}

_ATweenTool_ ATweenTool[1] =
{
	CreateAction,
	CreateActionOne,
	CreateInterval,

	SetDuration,
	SetUserData,
	SetQueue,
	SetOnComplete,
	SetTarget,
	GetAction,

	SetRelative,
	SetEaseType,
	SetValue,

	RunActions,
	RunTargets,
};
           

    這套結構和算法可以更加容易的用面向對象語言改寫。