C 语言链式调用与Tween算法实现(4)链式封装接口
2016-12-07 21:52
417 查看
在有上下文this指针的语言中,可以把this指针return出去。这样就可以形成一种链式调用的效果。配合上良好的方法命名,能够让函数功能的组合调用,使用起来非常的直觉化。在C语言中并没有this指针,所有的上下文对象需要,手动传入上下文对象。
以前介绍了3篇关于C语言如何实现tween缓动算法的。
C 实现通用Tween缓动动画(1)插值公式
C 实现通用Tween缓动动画(2)Tween数据结构
然而,函数的调用缺少链式调用非常的不流畅。而tween又很多默认参数的设定,往往链式调用能够更加方便的使用。
本文结合一种实现链式调用的方式,来在tween的实现之上进行一个链式调用的封装。我的思路很简单,链式调用需要上下文,C没有,那我们就要构造一个上下文以供使用。那我们看代码。
我们需要一个链式调用的发起者,通常是一个单例对象。这里就是有ATweenTool充当。可以看到,几乎所有的函数都会直接返回 ATweenTool结构指针,这样就可以在函数调用完成的时候,链式的调用所属的其它函数形成链式调用。ATweenTool的方法有3大类。
第一类,生成一个Action,以SetAction开头的函数以及SetInterval函数,都会生成一个上下文Action对象。以后针对Action属性的设置函数,比如SetDuration,SetUserData等等,都会使用这个上下文的Action,可以看到这些函数并没有传入Action对象作为参数。当重新SetAction的时候,上下文对象就会重置。
第二类,生成一个ActionValue,以SetMove,SetScale等等这样的函数,都会生成一个上下文的ActionValue对象。以后针对ActionValue属性的设置函数,比如SetRelative等函数,都会使用这个上下文的ActionValue,可以看到这些函数并没有传入ActionValue作为参数。 当重新SetMove等时候,上下文对象就会重置。
第三类,RunActions和RunTargets两个函数,返回值不再是ATweenTool这样返回。意味着这是链式调用的终点。一旦调用Tween动画开始执行。
接下来,看看上下文是如何生成的。
就是简单的使用了一个static变量持有了Action数组。也就是说上下文Action的生成是有上限的。在执行tween动画执行之前,一共只能生成action_length个Action。那么,action和actionValue变量,就是记录了当前上下文的对象。随着新Action和ActionValue的设置,当前变量不断的被赋值。
可以看到,所有链式调用的函数最后都会return ATweenTool结构。但执行tween动画以后,就会重置当前的上下文变量。那么,使用起来是一下这个样子的。
最后给出,额外辅助的结构。
以前介绍了3篇关于C语言如何实现tween缓动算法的。
C 实现通用Tween缓动动画(1)插值公式
C 实现通用Tween缓动动画(2)Tween数据结构
然而,函数的调用缺少链式调用非常的不流畅。而tween又很多默认参数的设定,往往链式调用能够更加方便的使用。
本文结合一种实现链式调用的方式,来在tween的实现之上进行一个链式调用的封装。我的思路很简单,链式调用需要上下文,C没有,那我们就要构造一个上下文以供使用。那我们看代码。
struct ATweenTool { /** * Create one TweenAction in context for chain setting */ struct ATweenTool* (*SetAction) (); /** * Create action with no actionValue * just through duration time then callback */ struct ATweenTool* (*SetInterval) (float duration); //-------------------------------------------------------------------------------------------------- // Create one TweenAction with TweenActionValue //-------------------------------------------------------------------------------------------------- struct ATweenTool* (*SetActionMoveX) (float moveX, float duration); struct ATweenTool* (*SetActionMoveY) (float moveY, float duration); struct ATweenTool* (*SetActionMove) (float moveX, float moveY, float duration, bool isRelative, TweenEaseType easeType); struct ATweenTool* (*SetActionScaleX) (float scaleX, float duration); struct ATweenTool* (*SetActionScaleY) (float scaleY, float duration); struct ATweenTool* (*SetActionScale) (float scaleX, float scaleY, float duration, bool isRelative, TweenEaseType easeType); struct ATweenTool* (*SetActionRotateZ)(float rotateZ, float duration); struct ATweenTool* (*SetActionFadeTo) (float fadeTo, float duration); //-------------------------------------------------------------------------------------------------- // After SetAction then set TweenAction property for current context created //-------------------------------------------------------------------------------------------------- struct ATweenTool* (*SetDuration) (float duration); struct ATweenTool* (*SetUserData) (void* userData); struct ATweenTool* (*SetQueue) (bool isQueue); struct ATweenTool* (*SetOnComplete) (TweenActionOnComplete OnComplete); struct ATweenTool* (*SetTarget) (void* target); /** * Get TweenAction in current context */ struct ATweenTool* (*GetAction) (TweenAction** outActionPtr); //-------------------------------------------------------------------------------------------------- // Add new TweenActionValue into context TweenAction //-------------------------------------------------------------------------------------------------- struct ATweenTool* (*SetMoveX) (float moveX); struct ATweenTool* (*SetMoveY) (float moveY); struct ATweenTool* (*SetScaleX) (float scaleX); struct ATweenTool* (*SetScaleY) (float scaleY); struct ATweenTool* (*SetRotateZ) (float rotateZ); struct ATweenTool* (*SetFadeTo) (float fadeTo); //-------------------------------------------------------------------------------------------------- // After SetValue then set TweenActionValue property for current context created //-------------------------------------------------------------------------------------------------- /** * After SetValue then SetRelative on new created TweenActiveValue */ struct ATweenTool* (*SetRelative) (bool isRelative); /** * After SetValue then SetEaseType on new created TweenActiveValue */ struct ATweenTool* (*SetEaseType) (TweenEaseType easeType); //-------------------------------------------------------------------------------------------------- /** * 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 struct ATweenTool ATweenTool[1];
我们需要一个链式调用的发起者,通常是一个单例对象。这里就是有ATweenTool充当。可以看到,几乎所有的函数都会直接返回 ATweenTool结构指针,这样就可以在函数调用完成的时候,链式的调用所属的其它函数形成链式调用。ATweenTool的方法有3大类。
第一类,生成一个Action,以SetAction开头的函数以及SetInterval函数,都会生成一个上下文Action对象。以后针对Action属性的设置函数,比如SetDuration,SetUserData等等,都会使用这个上下文的Action,可以看到这些函数并没有传入Action对象作为参数。当重新SetAction的时候,上下文对象就会重置。
第二类,生成一个ActionValue,以SetMove,SetScale等等这样的函数,都会生成一个上下文的ActionValue对象。以后针对ActionValue属性的设置函数,比如SetRelative等函数,都会使用这个上下文的ActionValue,可以看到这些函数并没有传入ActionValue作为参数。 当重新SetMove等时候,上下文对象就会重置。
第三类,RunActions和RunTargets两个函数,返回值不再是ATweenTool这样返回。意味着这是链式调用的终点。一旦调用Tween动画开始执行。
接下来,看看上下文是如何生成的。
#define action_length 30 static Array(TweenAction*) actionArr[1] = { (TweenAction*[action_length]) {}, 0 }; static TweenAction* action = NULL; static TweenActionValue* actionValue = NULL;
就是简单的使用了一个static变量持有了Action数组。也就是说上下文Action的生成是有上限的。在执行tween动画执行之前,一共只能生成action_length个Action。那么,action和actionValue变量,就是记录了当前上下文的对象。随着新Action和ActionValue的设置,当前变量不断的被赋值。
#define CheckAction(tag) \ ALogA(action != NULL, "ATweenTool " tag " TweenAction not created"); #define CheckActionValue(tag) \ ALogA(actionValue != NULL, "ATweenTool " tag " TweenActionValue invalid"); static struct ATweenTool* SetAction() { ALogA ( actionArr->length <= action_length, "ATweenTool can not cache TweenActions = %d more than %d", actionArr->length, action_length ); action = ATween->GetAction(); actionValue = NULL; AArraySet ( actionArr, actionArr->length++, action, TweenAction* ); return ATweenTool; } static inline struct ATweenTool* SetValue(TweenActionValueGetSet* valueGetSet, float value) { CheckAction("SetValue"); actionValue = ATween->AddTweenActionValue(action); actionValue->OnGet = valueGetSet->OnGet; actionValue->OnSet = valueGetSet->OnSet; actionValue->value = value; return ATweenTool; } static struct ATweenTool* SetDuration(float duration) { CheckAction("SetDuration"); action->duration = duration; return ATweenTool; } static struct ATweenTool* SetRelative(bool isRelative) { CheckAction ("SetRelative"); CheckActionValue("SetRelative"); actionValue->isRelative = isRelative; return ATweenTool; } static struct ATweenTool* SetEaseType(TweenEaseType easeType) { CheckAction ("SetEaseType"); CheckActionValue("SetEaseType"); actionValue->easeType = easeType; return ATweenTool; } static struct ATweenTool* SetInterval(float duration) { SetAction(); SetDuration(duration); return ATweenTool; } //-------------------------------------------------------------------------------------------------- static struct ATweenTool* SetActionMoveX(float moveX, float duration) { SetAction(); SetValue(ATweenActionValueGetSetImpl->moveX, moveX); SetDuration(duration); return ATweenTool; } static struct ATweenTool* SetActionMoveY(float moveY, float duration) { SetAction(); SetValue(ATweenActionValueGetSetImpl->moveY, moveY); SetDuration(duration); return ATweenTool; } static struct ATweenTool* SetActionMove(float moveX, float moveY, float duration, bool isRelative, TweenEaseType easeType) { SetAction (); SetValue (ATweenActionValueGetSetImpl->moveX, moveX); SetRelative(isRelative); SetEaseType(easeType); SetValue (ATweenActionValueGetSetImpl->moveY, moveY); SetRelative(isRelative); SetEaseType(easeType); SetDuration(duration); return ATweenTool; } static struct ATweenTool* SetActionScaleX(float scaleX, float duration) { SetAction(); SetValue(ATweenActionValueGetSetImpl->scaleX, scaleX); SetDuration(duration); return ATweenTool; } static struct ATweenTool* SetActionScaleY(float scaleY, float duration) { SetAction(); SetValue(ATweenActionValueGetSetImpl->scaleY, scaleY); SetDuration(duration); return ATweenTool; } static struct ATweenTool* SetActionScale(float scaleX, float scaleY, float duration, bool isRelative, TweenEaseType easeType) { SetAction (); SetValue (ATweenActionValueGetSetImpl->scaleX, scaleX); SetRelative(isRelative); SetEaseType(easeType); SetValue (ATweenActionValueGetSetImpl->scaleY, scaleY); SetRelative(isRelative); SetEaseType(easeType); SetDuration(duration); return ATweenTool; } static struct ATweenTool* SetActionRotateZ(float rotateZ, float duration) { SetAction(); SetValue(ATweenActionValueGetSetImpl->rotateZ, rotateZ); SetDuration(duration); return ATweenTool; } static struct ATweenTool* SetActionFadeTo(float fadeTo, float duration) { SetAction(); SetValue(ATweenActionValueGetSetImpl->fadeTo, fadeTo); SetDuration(duration); return ATweenTool; } //-------------------------------------------------------------------------------------------------- static struct ATweenTool* SetUserData(void* userData) { CheckAction("SetUserData"); action->userData = userData; return ATweenTool; } static struct ATweenTool* SetQueue(bool isQueue) { CheckAction("SetQueue"); action->isQueue = isQueue; return ATweenTool; } static struct ATweenTool* SetOnComplete(TweenActionOnComplete OnComplete) { CheckAction("SetOnComplete"); action->OnComplete = OnComplete; return ATweenTool; } static struct ATweenTool* SetTarget(void* target) { CheckAction("SetTarget"); action->target = target; return ATweenTool; } static struct ATweenTool* GetAction(TweenAction** outActionPtr) { CheckAction("GetAction"); *outActionPtr = action; return ATweenTool; } //-------------------------------------------------------------------------------------------------- static struct ATweenTool* SetMoveX(float moveX) { return SetValue(ATweenActionValueGetSetImpl->moveX, moveX); } static struct ATweenTool* SetMoveY(float moveY) { return SetValue(ATweenActionValueGetSetImpl->moveY, moveY); } static struct ATweenTool* SetScaleX(float scaleX) { return SetValue(ATweenActionValueGetSetImpl->scaleX, scaleX); } static struct ATweenTool* SetScaleY(float scaleY) { return SetValue(ATweenActionValueGetSetImpl->scaleY, scaleY); } static struct ATweenTool* SetRotateZ(float rotateZ) { return SetValue(ATweenActionValueGetSetImpl->rotateZ, rotateZ); } static struct ATweenTool* SetFadeTo(float fadeTo) { return SetValue(ATweenActionValueGetSetImpl->fadeTo, fadeTo); } //-------------------------------------------------------------------------------------------------- static void RunActions(void* target) { ALogA(target, "RunActions, target must not NULL"); for (int i = 0; i < actionArr->length; i++) { TweenAction* action = AArrayGet(actionArr, i, TweenAction*); if (action->actionValueList->size > 0) { action->target = target; } } ATween->RunActions(actionArr, &target); actionArr->length = 0; action = NULL; actionValue = NULL; } static void* RunTargets() { for (int i = 0; i < actionArr->length; i++) { TweenAction* action = AArrayGet(actionArr, i, TweenAction*); if (action->actionValueList->size > 0) { ALogA ( action->target != NULL, "RunActions, the {%d} action has actionValue, so must set target", i ); } } void* tweenId = NULL; ATween->RunActions(actionArr, &tweenId); actionArr->length = 0; action = NULL; actionValue = NULL; return tweenId; } struct ATweenTool ATweenTool[1] = { SetAction, SetInterval, SetActionMoveX, SetActionMoveY, SetActionMove, SetActionScaleX, SetActionScaleY, SetActionScale, SetActionRotateZ, SetActionFadeTo, SetDuration, SetUserData, SetQueue, SetOnComplete, SetTarget, GetAction, SetMoveX, SetMoveY, SetScaleX, SetScaleY, SetRotateZ, SetFadeTo, SetRelative, SetEaseType, RunActions, RunTargets, }; #undef action_length #undef CheckAction #undef CheckActionValue
可以看到,所有链式调用的函数最后都会return ATweenTool结构。但执行tween动画以后,就会重置当前的上下文变量。那么,使用起来是一下这个样子的。
ATweenTool->SetActionMoveX(deltaX * 0.95f, enemy->hurtXTime) ->SetEaseType (tween_ease_quad_in) ->SetQueue (false) ->SetOnComplete (AttackOnComplete) ->SetUserData (enemy) ->SetActionMoveY(0.03f, enemy->hurtYUpTime) ->SetEaseType (tween_ease_quad_in) ->SetActionMoveY(-0.03f, enemy->hurtYDownTime) ->SetEaseType (tween_ease_quad_out) ->RunActions (enemyDrawable);
最后给出,额外辅助的结构。
typedef struct { TweenActionValueOnGet OnGet; TweenActionValueOnSet OnSet; } TweenActionValueGetSet; struct ATweenActionValueGetSetImpl { TweenActionValueGetSet moveX [1]; TweenActionValueGetSet moveY [1]; TweenActionValueGetSet scaleX [1]; TweenActionValueGetSet scaleY [1]; TweenActionValueGetSet rotateZ[1]; TweenActionValueGetSet fadeTo [1]; }; /** * Application must implement tween action value get set method */ extern struct ATweenActionValueGetSetImpl ATweenActionValueGetSetImpl[1];
相关文章推荐
- C 实现通用Tween缓动动画(3)快捷链式调用接口
- 读书笔记之 - javascript 设计模式 - 接口、封装和链式调用
- 基于JDK动态代理实现的接口链式调用(Fluent Interface)工具
- Android中设计模式--策略模式(封装会变化的算法部分,面向接口不针对实现)
- 实现JavaScript自定义函数的整合、链式调用及类的封装
- 35. OP-TEE中基本算法接口调用实现
- Oracle 调用接口 (Orale Call Interface,OCI) 【实现各种语言操作Oracle数据库】简介
- 通过dubbo+zookeeper实现服务接口的封装及调用
- 基于JDK动态代理实现的接口链式调用(Fluent Interface)工具
- NodeJS用递归实现异步操作的链式调用,完成一个简易的命令行输入输出REPL交互接口
- 如何在linux C/C++语言中调用 sqlite 的函数接口来实现对数据库的管理(转)
- (转)如何在linux C/C++语言中调用 sqlite 的函数接口来实现对数据库的管理
- Java 多线程拷贝文件夹并调用tinyPng算法接口压缩图片实现(生产消费变种)
- 利用Castle IOC实现远程调用的接口统一(上)
- (八)线程--借助 封装类 实现“线程调用带参方法”(示例下载)
- 带权二分图的完备匹配算法(JAVA语言实现)
- 地磅称量系统之(53)在封装对象的类库中实现包括IDataErrorInfo接口提供的所有方法和并且扩展对异常具有添加和删除功能的基本业务对象基类
- Socket接口原理及用C#语言实现
- 跨语言平台的RSA加密、解密、签名、验证算法的实现
- 借助封装类实现线程调用带参方法