SDL中文论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 3999|回复: 0
打印 上一主题 下一主题

[Animation] 逐进变量

[复制链接]

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
跳转到指定楼层
楼主
发表于 2017-6-3 15:35:31 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 ancientcc 于 2017-6-3 15:39 编辑

代码中处理逐进变量
让深入程序,分析代码是如何处理逐进变量。处理逐进变量主要是两个操作,赋值和取值。程序用template <class T> class progressive_类封装逐进变量。简单的说,赋值就是根据一条mod中的逐进变量语句生成一个progressive_对象,取值就是借助当前时刻参数,从progressive_对象读出变量值。
(<class T> class progressive_类,当中模板参数T可取int,double,int的就typedef为progressive_int,double的就typedef为progressive_double。以上halo_y就以progressive_int类型被处理,offset则是progressive_double。)

赋值
根据一条mod中的逐进变量语句生成一个progressive_对象。让以duration=350; halo_y=-54:120,-54~-45,-45~-27,-27~0为例来说明。
  1. // @data: mod中的逐进变量字符串。实例值:-54:120,-54~-45,-45~-27,-27~0
  2. // @duration: 持续时间,单位毫秒。实例值:350
  3. template <class T>
  4. progressive_<T>::progressive_(const std::string &data, int duration) :
  5.         data_(),
  6.         input_(data)
  7. {
  8.         // utils::split将以逗号为分隔符把字符串data变成字组串数组
  9.         const std::vector<std::string> first_split = utils::split(data);
  10.         // 生成的first_split:[4]("-54:120", "-54~-45","-45~-27","-27~0")
  11.         const int time_chunk = std::max<int>(duration / (first_split.size()?first_split.size():1),1);
  12.         // time_chunk就是默认的时间片持续时间:350 / 4 = 87(毫秒)

  13.         std::vector<std::string>::const_iterator tmp;
  14.         std::vector<std::pair<std::string,int> > first_pass;
  15.         // 逐个处理值项
  16.         for (tmp = first_split.begin(); tmp != first_split.end() ; tmp++) {
  17.                 std::vector<std::string> second_pass = utils::split(*tmp,':');
  18.                 if (second_pass.size() > 1) {
  19.                         // 值项中指定了时间,则把时间取出来作为该时间片时间然后生成pair
  20.                         first_pass.push_back(std::pair<std::string,int>(second_pass[0],atoi(second_pass[1].c_str())));
  21.                 } else {
  22.                         // 值项中没指定时间,以默认时间片生成pair
  23.                         first_pass.push_back(std::pair<std::string,int>(second_pass[0],time_chunk));
  24.                 }
  25.         }
  26.         // 生成的first_pass值:
  27.         //                [0]        ("-54",120)
  28.         //                [1]        ("-54~-45",87)
  29.         //                [2]        ("-45~-27",87)
  30.         //                [3]        ("-27~0",87)
  31.     // 因为#0值项由87改为了120,这个总的过程时间已由350变成381
  32.         std::vector<std::pair<std::string,int> >::const_iterator tmp2;
  33.         // 逐个处理修正过时间片时间的值项
  34.         for (tmp2=first_pass.begin();tmp2 != first_pass.end() ; tmp2++) {
  35.                 std::vector<std::string> range = utils::split(tmp2->first,'~');
  36.                 // 检查值项字符串是否有波浪号。
  37.                 // 1. 如果有波浪号,波浪号前的做为pair的first,后面的做为pair的second
  38.                 // 2. 如果没有波浪号,pair的second=first
  39.                 data_.push_back(std::pair<std::pair<T, T>,int> (
  40.                         std::pair<T, T>(
  41.                                 lexical_cast<T>(range[0].c_str()),
  42.                                 lexical_cast<T>(range.size() > 1 ? range[1].c_str() : range[0].c_str())),
  43.                                 tmp2->second));
  44.         }
  45.         // 最终生成的data_:
  46.         //                [0]        ((-54,-54),120)
  47.         //                [1]        ((-54,-45),87)
  48.         //                [2]        ((-45,-27),87)
  49.         //                [3]        ((-27,0),87)
  50. }
复制代码

取值
取值就是根据访问时刻返回“正确”值项中的值。
以在130毫秒来取值为例来说明。
  1. // @current_time:当前访问时刻。值可以不在[0, duration],函数会执行修正。实例值:130
  2. // @default_val:当mod中其实未指定要访问的逐进变量时,要被返回的值。默认0
  3. template <class T>
  4. const T progressive_<T>::get_current_element(int current_time, T default_val) const
  5. {
  6.         int time = 0;
  7.         unsigned int sub_halo = 0;
  8.         int searched_time = current_time;
  9.         // 检查current_time有效性,不在[0, duration()]的务必使它落在这范围
  10.         // duration()返回data_中时间片时间的累加值,也就是说返回的将是381而不是mod中写的350
  11.         if (searched_time < 0) searched_time = 0;
  12.         if (searched_time > duration()) searched_time = duration();
  13.         // 这或许是mod中就没有该逐进变量,返回默认值。
  14.         if (data_.empty()) return default_val;
  15.         // 找出current_time是落在哪个时间片上
  16.         while (time < searched_time&& sub_halo < data_.size()) {
  17.                 time += data_[sub_halo].second;
  18.                 sub_halo++;

  19.         }
  20.         // (sub_halo!=0)时,sub_halo是一个计数值而不是索引值,作为下标时应该被修正
  21.         if (sub_halo != 0) {
  22.                 sub_halo--;
  23.                 time -= data_[sub_halo].second;
  24.         }
  25.         if (sub_halo >= data_.size()) {
  26.                 sub_halo = data_.size();
  27.                 time = searched_time; // Never more than max allowed
  28.         }

  29.         // 已确定出current_time是在#1区间,现在要确定出具体值
  30.         const T first =  data_[sub_halo].first.first;
  31.         const T second =  data_[sub_halo].first.second;

  32.         // time = data_[0].second: 120
  33.         // data_[1].second: 87
  34.         // first = data_[1].first.first: -54
  35.         // second = data_[1].first.second: -45
  36.         // ====>
  37.         // (130 - 120) / 87 * 9 + (-54) = -53

  38.         return T((static_cast<double>(searched_time - time) /
  39.                 static_cast<double>(data_[sub_halo].second)) *
  40.                 (second - first) + first);       
  41. }
复制代码

代码中封装逐进变量还有一个类:progressive_string,和progressive_差不多赋值/取值逻辑。它们不同点:
  • progressive_是模板类,progressive_string不是;
  • progressive_值项中的first要表示一个范围,定义了std::pair,progressive_string表示一个字符串,类型std::string;

由于progressive_string的data_[#].first不是范围,它处理上要比progressive_简单。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|丽谷软件|libsdl.cn

GMT+8, 2025-5-2 00:41 , Processed in 0.058696 second(s), 19 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表