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,
};
這套結構和算法可以更加容易的用面向對象語言改寫。