相册模块
数据类的头文件
//描述单张照片的结构体
struct StructCandyPhotoCollect
{
//每个photo的唯一标识,这个ID必须是正整数
int photo_id;
//photo名
std::string name_en;
std::string name_zh;
//说明
std::string info_en;
std::string info_zh;
//日期
int date_begin;
int date_end;
//如果一个节日有多张图,需要限制各张图在哪个关卡解锁
int level_limit;
//关卡
int level_begin;
//0表示没有解锁。解锁了就是大于0的数。(如2表示该图是第二顺位解锁的)
int unlock_order;
//碎片的状态:0未获得,1获得未拼好,2获得且拼好
std::vector<int> pieces_array;
StructCandyPhotoCollect()
{
photo_id = PHOTO_COLLECT_INVALID_PHOTO_ID; //初始化为无效的photo id
date_begin = 0; //初始化为无效日期
date_end = 0; //初始化为无效日期
level_limit = 0; //初始化为无效关卡号
level_begin = 0; //初始化为无效关卡号
unlock_order = 0; //初始化为未解锁
pieces_array.resize(PHOTO_COLLECT_PIECE_COUNT, 0); //初始化为所有碎片都未得到
}
};
// 用于管理照片收集的类
class CandyPhotoCollect
{
public:
//构造函数
CandyPhotoCollect();
//读配置和进度
void of_load_data();
/**
* 得碎片
*
* 如果发碎片成功,函数返回true,photo_id 和 piece_id 有值。
*
* @param game_model 游戏的类型,"001"表示主线模式,只有在主线模式下才会给玩家碎片
* @param date_of_today 今天的日期,如3月2号就应该传入302
* @param current_level 当前所处的关卡号
* @param min_level 可以获得碎片的最小关卡号
* @param photo_id 发给玩家的碎片所属的图ID
* @param piece_index 发给玩家的碎片的索引,假如有16个碎片,索引就是从0到15
*/
bool of_get_award_piece(const std::string& game_model, int date_of_today, int current_level, int min_level, int& photo_id, int& piece_index);
//查:上一次得到的碎片属于哪张图,有两种情况会返回无效的photo id,(1)未解锁过任何图;(2)解锁了id为n的图,但游戏更新后,id为n的图从配置里删除了;
int of_get_last_open_photo();
//查:解锁了哪些图,返回的数组是按解锁顺序排列的
std::vector<int> of_get_unlock_photos();
//查:某一张图的所有碎片状态,返回的数组包含该图中所有碎片
std::vector<int> of_get_pieces(int photo_id);
//查:某一张图有多少已拼好碎片
int of_get_photo_ok_piece_count(int photo_id);
//查:某一张图的名字,需要传入语言类型
std::string of_get_name(int photo_id, const std::string& language_type);
//查:某一张图的说明,需要传入语言类型
std::string of_get_introduce(int photo_id, const std::string& language_type);
//改:修改某一张图的某一个碎片的状态,只有两处会调用这个方法:(1)碎片从未获得变为获得;(2)碎片从未拼好变为拼好。这两个变化都是不可逆的。
void of_set_piece_status(int photo_id, int piece_id, int piece_status);
//改:修改上一次获得的碎片属于哪一张图,只有一处会调用这个方法:过关后,成功找到一个碎片发给玩家
void of_set_last_open_photo(int photo_id);
private:
//读配置
void of_load_config();
//存文件,这个函数里有断言,如果在数据没有发生改变的时候去调用,会报错
void of_save();
//查:解锁了多少张图
int of_get_unlock_photo_count();
//查:某一张图有多少空闲碎片
int of_get_photo_free_piece_count(int photo_id);
//查:某一张图有多少已获得碎片
int of_get_photo_got_piece_count(int photo_id);
//查:某一张图还有哪些碎片是空闲的,返回的数组包含该图中所有空闲碎片
std::vector<int> of_get_photo_free_pieces(int photo_id);
//查:找出所有日期类型的配置,返回值是一个vector,内容是photo id,排在前面的是带关卡限制的日期配置,并且是按由小到大的顺序排列的
std::vector<int> of_get_date_config();
//查:找出所有根据关卡号来解锁图片的配置,返回值是一个map,键是关卡号,值是图ID
std::map<int, int> of_get_level_config();
private:
//上一次得到的碎片所属于的photo的id,如果没有得到过碎片,这个值是无效值
int last_photo_id_;
//所有图片的状态
std::map<int, StructCandyPhotoCollect> photos_;
};
数据类的实现文件
CandyPhotoCollect()
: last_photo_id_(PHOTO_COLLECT_INVALID_PHOTO_ID)
{
}
void CandyPhotoCollect::of_load_config()
{
photos_.clear();
std::map<int, int> map_level_config;
std::string str_content = cocos2d::FileUtils::getInstance()->getStringFromFile(PHOTO_COLLECT_CONFIG_PATH);
rapidjson::Document doc;
doc.Parse(str_content.c_str());
assert(doc.HasMember("type_date"));
assert(doc["type_date"].IsArray());
const rapidjson::Value& v1 = doc["type_date"].GetArray();
for (rapidjson::SizeType i = 0; i < v1.Size(); i++)
{
const rapidjson::Value& v_item = v1[i];
StructCandyPhotoCollect st;
//id
assert(v_item.HasMember("id"));
assert(v_item["id"].IsUint());
int photo_id = v_item["id"].GetInt();
assert(photos_.find(photo_id) == photos_.end());
st.photo_id = photo_id;
//英文名
assert(v_item.HasMember("name_en"));
assert(v_item["name_en"].IsString());
st.name_en = v_item["name_en"].GetString();
//中文名
assert(v_item.HasMember("name_zh"));
assert(v_item["name_zh"].IsString());
st.name_zh = v_item["name_zh"].GetString();
//英文说明
assert(v_item.HasMember("info_en"));
assert(v_item["info_en"].IsString());
st.info_en = v_item["info_en"].GetString();
//中文说明
assert(v_item.HasMember("info_zh"));
assert(v_item["info_zh"].IsString());
st.info_zh = v_item["info_zh"].GetString();
//开始日期
assert(v_item.HasMember("date_begin"));
assert(v_item["date_begin"].IsNumber());
st.date_begin = v_item["date_begin"].GetInt();
assert(101 <= st.date_begin && st.date_begin <= 1231);
//结束日期
assert(v_item.HasMember("date_end"));
assert(v_item["date_end"].IsNumber());
st.date_end = v_item["date_end"].GetInt();
assert(101 <= st.date_end && st.date_end <= 1231);
assert(st.date_end >= st.date_begin);
//关卡限制
if (v_item.HasMember("level_limit") && v_item["level_limit"].IsNumber())
{
st.level_limit = v_item["level_limit"].GetInt();
}
//不能有 level_begin
if (v_item.HasMember("level_begin"))
{
assert(false);
}
photos_[st.photo_id] = st;
}
assert(doc.HasMember("type_level"));
assert(doc["type_level"].IsArray());
const rapidjson::Value& v2 = doc["type_level"].GetArray();
for (rapidjson::SizeType i = 0; i < v2.Size(); i++)
{
const rapidjson::Value& v_item = v2[i];
StructCandyPhotoCollect st;
//id
assert(v_item.HasMember("id"));
assert(v_item["id"].IsUint());
int photo_id = v_item["id"].GetInt();
assert(photos_.find(photo_id) == photos_.end());
st.photo_id = photo_id;
//英文名
assert(v_item.HasMember("name_en"));
assert(v_item["name_en"].IsString());
st.name_en = v_item["name_en"].GetString();
//中文名
assert(v_item.HasMember("name_zh"));
assert(v_item["name_zh"].IsString());
st.name_zh = v_item["name_zh"].GetString();
//英文说明
assert(v_item.HasMember("info_en"));
assert(v_item["info_en"].IsString());
st.info_en = v_item["info_en"].GetString();
//中文说明
assert(v_item.HasMember("info_zh"));
assert(v_item["info_zh"].IsString());
st.info_zh = v_item["info_zh"].GetString();
//解锁关卡
assert(v_item.HasMember("level_begin"));
assert(v_item["level_begin"].IsUint());
st.level_begin = v_item["level_begin"].GetInt();
assert(st.level_begin > 0);
//不能有 date_begin 和 date_end
if (v_item.HasMember("date_begin") || v_item.HasMember("date_end"))
{
assert(false);
}
//存入本地变量map_level_config
assert(map_level_config.find(st.level_begin) == map_level_config.end());
map_level_config[st.level_begin] = st.photo_id;
//存入成员变量photos_
photos_[st.photo_id] = st;
}
//配置的图片列表肯定不为空
assert(photos_.size() > 0);
}
std::vector<int> CandyPhotoCollect::of_get_date_config()
{
std::vector<int> ret;
std::map<int, int> m;
std::vector<int> v;
for (auto i : photos_)
{
int date_begin = i.second.date_begin;
if (date_begin > 0)
{
int level_limit = i.second.level_limit;
if (level_limit > 0)
{
m[level_limit] = i.first;
}
else
{
v.push_back(i.first);
}
}
}
for (auto i : m)
{
ret.push_back(i.second);
}
for (auto i : v)
{
ret.push_back(i);
}
return ret;
}
std::map<int, int> CandyPhotoCollect::of_get_level_config()
{
std::map<int, int> ret;
for (auto i : photos_)
{
int level_begin = i.second.level_begin;
if (level_begin > 0)
{
ret[level_begin] = i.first;
}
}
return ret;
}
void CandyPhotoCollect::of_load_data()
{
of_load_config();
std::string str_progress_file_path = cocos2d::FileUtils::getInstance()->getWritablePath() + PHOTO_COLLECT_PROGRESS_FILENAME;
std::string str_content = cocos2d::FileUtils::getInstance()->getStringFromFile(str_progress_file_path);
if (str_content.empty())
{
//这里返回就代表没有读进度。此时last_photo_id_的值等于PHOTO_COLLECT_INVALID_PHOTO_ID
return;
}
rapidjson::Document doc;
doc.Parse(str_content.c_str());
//1. 读解锁顺序。注意:进度里存的值不都是有效的,(假如进度中存的是:"unlock_order":[19,11,33],但更新游戏后id为11的图被删掉了,那么11那个值就没用了,会跳过)
if (doc.HasMember("unlock_order") && doc["unlock_order"].IsArray())
{
int unlock_index = 1;
const rapidjson::Value& rjv_unlock_order = doc["unlock_order"].GetArray();
for (rapidjson::SizeType i = 0; i < rjv_unlock_order.Size(); i++)
{
const rapidjson::Value& rjv_item = rjv_unlock_order[i];
if (rjv_item.IsUint())
{
int photo_id = rjv_item.GetInt();
if (photos_.find(photo_id) == photos_.end())
{
continue;
}
photos_[photo_id].unlock_order = unlock_index;
unlock_index++;
}
}
}
//2. 读最近解锁的哪张图
if (doc.HasMember("last_piece_belong_to_which_photo") && doc["last_piece_belong_to_which_photo"].IsUint())
{
int last_photo_id = doc["last_piece_belong_to_which_photo"].GetInt();
if (photos_.find(last_photo_id) != photos_.end())
{
last_photo_id_ = last_photo_id;
}
}
//3. 读每张图的碎片状态
for (auto i : photos_)
{
int photo_id = i.first;
std::string str_key_pieces = "photo_" + std::to_string(photo_id) + "_pieces";
if (doc.HasMember(str_key_pieces.c_str()) == false)
{
//说明更新游戏后,新增了图,进度里是没有这张图的。
continue;
}
if (doc[str_key_pieces.c_str()].IsArray())
{
const rapidjson::Value& rjv_pieces_status = doc[str_key_pieces.c_str()].GetArray();
if (rjv_pieces_status.Size() == PHOTO_COLLECT_PIECE_COUNT)
{
for (rapidjson::SizeType j = 0; j < rjv_pieces_status.Size(); j++)
{
const rapidjson::Value& rjv_item = rjv_pieces_status[j];
if (rjv_item.IsInt())
{
int piece_status = rjv_item.GetInt();
if (piece_status == 0 || piece_status == 1 || piece_status == 2)
{
photos_[photo_id].pieces_array[j] = piece_status;//把碎片的状态从文件里写进内存里
}
}
}
}
}
}
//校验,如果last photo id是一个有效值的话,那么它对应的photo的unlock order肯定是大于0的,即肯定是解锁了的。
if (PHOTO_COLLECT_INVALID_PHOTO_ID != last_photo_id_)
{
if (photos_[last_photo_id_].unlock_order <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
last_photo_id_ = PHOTO_COLLECT_INVALID_PHOTO_ID;
}
}
//校验unlcok order的值和pieces array的值是否匹配,如果解锁顺序大于0,那么碎片数组里肯定有状态大于0的碎片
for (auto& i : photos_)
{
if (i.second.unlock_order > 0)
{
bool b = false;
for (size_t j = 0; j < i.second.pieces_array.size(); ++j)
{
if (i.second.pieces_array.at(j) > 0)
{
b = true;
break;
}
}
if (!b)
{
PHOTO_COLLECT_ERROR_LOG;
i.second.unlock_order = 0;
}
}
}
}
void CandyPhotoCollect::of_save()
{
if (photos_.find(last_photo_id_) == photos_.end())
{
PHOTO_COLLECT_ERROR_LOG;
return;
}
rapidjson::Document writedoc(rapidjson::kObjectType);
rapidjson::Document::AllocatorType& allocator = writedoc.GetAllocator();
//1.存最近一次得到的碎片属于哪张图
{
rapidjson::Value rjv_last_photo_id;
rjv_last_photo_id.SetInt(last_photo_id_);
writedoc.AddMember("last_piece_belong_to_which_photo", rjv_last_photo_id, allocator);
}
//2.按先后顺序存解锁了的图
{
//这个数组用来存所有的解锁顺序,用来验证解锁顺序是不是从1开始递增的
std::vector<int> vec_unlock_order;
for (auto& i : photos_)
{
bool b_unlock = false;
for (size_t j = 0; j < i.second.pieces_array.size(); ++j)
{
if (i.second.pieces_array.at(j) > 0)
{
b_unlock = true;
break;
}
}
if (b_unlock)
{
int unlock_order = i.second.unlock_order;
if (unlock_order <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
return;
}
else
{
vec_unlock_order.push_back(unlock_order);
}
}
}
std::sort(vec_unlock_order.begin(), vec_unlock_order.end());
for (int i = 0; i < vec_unlock_order.size(); ++i)
{
if (vec_unlock_order[i] != i + 1)
{
PHOTO_COLLECT_ERROR_LOG;
return;
}
}
//执行到这里说明验证通过,接下来用一个map把所有解锁的图,按解锁的先后顺序存起来
std::map<int, int> map_unlock_order;
for (auto i : photos_)
{
int photo_id = i.first;
int unlock_order = i.second.unlock_order;
if (unlock_order > 0)
{
map_unlock_order[unlock_order] = photo_id;
}
}
//根据刚才得到的map,把所有解锁了的图的id,按先后顺序写入文件
rapidjson::Value rjv(rapidjson::kArrayType);
for (auto i : map_unlock_order)
{
rjv.PushBack(i.second, allocator);
}
writedoc.AddMember("unlock_order", rjv, allocator);
}
//3.存碎片状态
{
for (auto i : photos_)
{
int photo_id = i.first;
std::string str_key = "photo_" + std::to_string(photo_id) + "_pieces";
rapidjson::Value rjv1;
rjv1.SetString(str_key.c_str(), int(str_key.size()), allocator);
rapidjson::Value rjv2(rapidjson::kArrayType);
for (auto j : i.second.pieces_array)
{
if (j != 0 && j != 1 && j != 2)
{
PHOTO_COLLECT_ERROR_LOG;
return;
}
rjv2.PushBack(j, allocator);
}
writedoc.AddMember(rjv1, rjv2, allocator);
}
}
rapidjson::StringBuffer jsonBuffer;
rapidjson::PrettyWriter<rapidjson::StringBuffer> jsonWriter(jsonBuffer);
writedoc.Accept(jsonWriter);
std::string str_going_to_write = jsonBuffer.GetString();
std::string str_progress_path = cocos2d::FileUtils::getInstance()->getWritablePath() + PHOTO_COLLECT_PROGRESS_FILENAME;
cocos2d::FileUtils::getInstance()->writeStringToFile(str_going_to_write, str_progress_path);
}
bool CandyPhotoCollect::of_get_award_piece(const std::string& game_model, int date_of_today, int current_level, int min_level, int& photo_id, int& piece_index)
{
photo_id = 0;
piece_index = 0;
//不是主线关卡不给碎片
if (game_model != "001")
{
return false;
}
//如果当前关卡小于“最小的给碎片关卡”,就返回false
if (current_level < min_level)
{
return false;
}
//“最近获得的碎片的图ID”等于“无效图ID”有两种情况:1.从来没有得到过碎片;2.以前得到过某张图的碎片,后来更新游戏后,这张图对应的ID被删掉了
if (PHOTO_COLLECT_INVALID_PHOTO_ID == last_photo_id_)
{
//匹配日期的图
for (auto id : of_get_date_config())
{
//日期过滤一次
if (date_of_today < photos_[id].date_begin || date_of_today > photos_[id].date_end) continue;
//如果带关卡号限制,再用关卡号限制过滤一次
if (0 != photos_[id].level_limit && photos_[id].level_limit > current_level) continue;
//判断该图是不是还一个碎片都没发出去,再过滤一次
if (of_get_photo_free_piece_count(id) != PHOTO_COLLECT_PIECE_COUNT) continue;
//执行到这里说明找到了满足条件的图,修改返回值
photo_id = id;
piece_index = rand() % PHOTO_COLLECT_PIECE_COUNT;
//修改内部变量并存盘
last_photo_id_ = photo_id;
photos_[photo_id].unlock_order = 1 + of_get_unlock_photo_count();
photos_[photo_id].pieces_array[piece_index] = 1;
of_save();
return true;
}
//匹配关卡的图
for (auto i : of_get_level_config())
{
//如果当前关卡小于解锁关卡,跳过
if (current_level < i.first) continue;
if (of_get_photo_free_piece_count(i.second) != PHOTO_COLLECT_PIECE_COUNT) continue;
photo_id = i.second;
piece_index = rand() % PHOTO_COLLECT_PIECE_COUNT;
last_photo_id_ = photo_id;
photos_[photo_id].unlock_order = 1 + of_get_unlock_photo_count();
photos_[photo_id].pieces_array[piece_index] = 1;
of_save();
return true;
}
//没匹配上
return false;
}
//执行到这里说明last_photo_id_不等于PHOTO_COLLECT_INVALID_PHOTO_ID,校验一下这个值是否合法,要是不合法,就跳过
if (photos_.find(last_photo_id_) == photos_.end())
{
last_photo_id_ = PHOTO_COLLECT_INVALID_PHOTO_ID;//把这个值赋值成初始化的状态,不然永远都发不出碎片了
return false;
}
//统计一下last photo已获得的碎片个数,如果个数小于PHOTO_COLLECT_PIECE_COUNT,那就发这个图的碎片出去
if (of_get_photo_got_piece_count(last_photo_id_) < PHOTO_COLLECT_PIECE_COUNT)
{
//把该图中所有状态为 未发出 的碎片找出来,把它们的索引存进一个 vector 里
auto available_pieces = of_get_photo_free_pieces(last_photo_id_);
//随机一个碎片发出去
int len = available_pieces.size();
int idx = rand() % len;
photo_id = last_photo_id_;
piece_index = available_pieces.at(idx);
photos_[photo_id].pieces_array[piece_index] = 1;
//此时last_photo_id_和photos_[photo_id].unlock_order并没有发生变化
of_save();
return true;
}
//执行到这里说明,last_photo_id_的碎片发完了,要新开一张图
for (auto id : of_get_date_config())
{
auto available_pieces = of_get_photo_free_pieces(id);
if (available_pieces.size() <= 0) continue;
bool b1 = photos_[id].date_begin <= date_of_today && date_of_today <= photos_[id].date_end;//日期是否匹配
if (!b1) continue;
if (0 != photos_[id].level_limit && current_level < photos_[id].level_limit) continue;
int len = available_pieces.size();
int idx = rand() % len;
photo_id = id;
piece_index = available_pieces.at(idx);
photos_[photo_id].unlock_order = 1 + of_get_unlock_photo_count();
last_photo_id_ = photo_id;
photos_[photo_id].pieces_array[piece_index] = 1;
of_save();
return true;
}
//执行到这里说明想要开一张日期匹配的图没找到,那就找一下关卡匹配的图
for (auto i : of_get_level_config())
{
if (current_level < i.first) continue;
int li_photo_id = i.second;
auto available_pieces = of_get_photo_free_pieces(li_photo_id);
if (available_pieces.size() <= 0) continue;
int len = available_pieces.size();
int idx = rand() % len;
photo_id = li_photo_id;
piece_index = available_pieces.at(idx);
photos_[photo_id].unlock_order = 1 + of_get_unlock_photo_count();
last_photo_id_ = photo_id;
photos_[photo_id].pieces_array[piece_index] = 1;
of_save();
return true;
}
return false;
}
int CandyPhotoCollect::of_get_last_open_photo()
{
if (photos_.size() <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
return PHOTO_COLLECT_INVALID_PHOTO_ID;
}
if (photos_.find(last_photo_id_) == photos_.end())
{
PHOTO_COLLECT_ERROR_LOG;
return PHOTO_COLLECT_INVALID_PHOTO_ID;
}
return last_photo_id_;
}
void CandyPhotoCollect::of_set_last_open_photo(int photo_id)
{
if (photos_.size() <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
return;
}
if (photos_.find(photo_id) == photos_.end())
{
PHOTO_COLLECT_ERROR_LOG;
return;
}
last_photo_id_ = photo_id;
of_save();
}
int CandyPhotoCollect::of_get_unlock_photo_count()
{
if (photos_.size() <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
return 0;
}
int cnt = 0;
for (auto i : photos_)
{
for (auto j : i.second.pieces_array)
{
if (j > 0)
{
cnt++;
break;
}
}
}
return cnt;
}
std::vector<int> CandyPhotoCollect::of_get_unlock_photos()
{
std::vector<int> ret;
int cnt = 1;
bool flag = false;
do
{
flag = false;
for (auto i : photos_)
{
if (i.second.unlock_order == cnt)
{
flag = true;
ret.push_back(i.first);
cnt++;
break;
}
}
} while (flag);
return ret;
}
std::vector<int> CandyPhotoCollect::of_get_pieces(int photo_id)
{
if (photos_.size() <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
return std::vector<int>();
}
if (photos_.find(photo_id) == photos_.end())
{
PHOTO_COLLECT_ERROR_LOG;
return std::vector<int>();
}
return photos_[photo_id].pieces_array;
}
std::vector<int> CandyPhotoCollect::of_get_photo_free_pieces(int photo_id)
{
if (photos_.size() <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
return std::vector<int>();
}
if (photos_.find(photo_id) == photos_.end())
{
PHOTO_COLLECT_ERROR_LOG;
return std::vector<int>();
}
if (photos_[photo_id].pieces_array.size() != PHOTO_COLLECT_PIECE_COUNT)
{
PHOTO_COLLECT_ERROR_LOG;
return std::vector<int>();
}
std::vector<int> available_pieces;
for (int i = 0; i < PHOTO_COLLECT_PIECE_COUNT; ++i)
{
if (photos_[photo_id].pieces_array[i] == 0)
{
available_pieces.push_back(i);
}
}
return available_pieces;
}
int CandyPhotoCollect::of_get_photo_free_piece_count(int photo_id)
{
if (photos_.size() <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
return 0;
}
if (photos_.find(photo_id) == photos_.end())
{
PHOTO_COLLECT_ERROR_LOG;
return 0;
}
int cnt = 0;
for (auto status : photos_[photo_id].pieces_array)
{
if (status == 0)
{
cnt++;
}
}
return cnt;
}
int CandyPhotoCollect::of_get_photo_got_piece_count(int photo_id)
{
if (photos_.size() <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
return 0;
}
if (photos_.find(photo_id) == photos_.end())
{
PHOTO_COLLECT_ERROR_LOG;
return 0;
}
int cnt = 0;
for (auto status : photos_[photo_id].pieces_array)
{
if (status >= 1)
{
cnt++;
}
}
return cnt;
}
int CandyPhotoCollect::of_get_photo_ok_piece_count(int photo_id)
{
if (photos_.size() <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
return 0;
}
if (photos_.find(photo_id) == photos_.end())
{
PHOTO_COLLECT_ERROR_LOG;
return 0;
}
int cnt = 0;
for (auto status : photos_[photo_id].pieces_array)
{
if (status == 2)
{
cnt++;
}
}
return cnt;
}
void CandyPhotoCollect::of_set_piece_status(int photo_id, int piece_id, int piece_status)
{
if (photos_.size() <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
return;
}
if (photos_.find(photo_id) == photos_.end())
{
PHOTO_COLLECT_ERROR_LOG;
return;
}
if (piece_id < 0 || piece_id >= PHOTO_COLLECT_PIECE_COUNT)
{
PHOTO_COLLECT_ERROR_LOG;
return;
}
if (piece_status != 0 && piece_status != 1 && piece_status != 2)
{
PHOTO_COLLECT_ERROR_LOG;
return;
}
//修改内存中的值
photos_[photo_id].pieces_array[piece_id] = piece_status;
//修改文件中的值
of_save();
}
std::string CandyPhotoCollect::of_get_name(int photo_id, const std::string & language_type)
{
if (photos_.size() <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
return "";
}
if (photos_.find(photo_id) == photos_.end())
{
PHOTO_COLLECT_ERROR_LOG;
return "";
}
if (language_type == "zh")
{
return photos_[photo_id].name_zh;
}
return photos_[photo_id].name_en;
}
std::string CandyPhotoCollect::of_get_introduce(int photo_id, const std::string & language_type)
{
if (photos_.size() <= 0)
{
PHOTO_COLLECT_ERROR_LOG;
return "";
}
if (photos_.find(photo_id) == photos_.end())
{
PHOTO_COLLECT_ERROR_LOG;
return "";
}
if (language_type == "zh")
{
return photos_[photo_id].info_zh;
}
return photos_[photo_id].info_en;
}
CandyPhotoCollect::
弹框类的头文件
class DialogPhoto : public DialogPub
{
public:
DIALOG_MAKE_FUNC(DialogPhoto);
CREATE_FUNC(DialogPhoto);
DialogPhoto();
//初始化
void of_init_ui() override;
//初始化左侧的列表框
void of_init_listview();
// 根据图片索引,显示某张图的详情
void of_init_single_photo(int index);
//panel_for_touch的触摸回调
void on_touch_piece(Ref* sender, Widget::TouchEventType type);
//切换照片
void on_click_switch_photo(Ref* sender);
// 关闭
void on_close();
//点击宝箱事件,三个宝箱,对应的index是012
void on_touch_award_box(Ref* sender, Widget::TouchEventType type, int box_index);
//更新宝箱按钮旁边的数字
void refresh_award_box_label(int photo_id);
//更新左侧列表框里的缩略图的显示
void refresh_list_view_photo(int photo_id);
//检查是否发奖,如果该发奖就发奖
void check_need_award_box(int photo_id);
//把单个的csb photo添加到指定的父节点上
void of_add_photo_one(Widget* parent_wgt, int photo_id, float arg_scale);
//根据photo id找到对应的图片路径
string of_get_photo_path_by_id(int li_photo_id);
string of_get_gray_photo_path_by_id(int li_photo_id);
//拼好之后,亮图淡入完成后的回调
void of_callback_all_pieces_ok(int li_photo_id);
//拼好一个碎片后
void of_work_after_piece_status_turn_to_ok(int li_photo_id, Vec2 piece_pos);
private:
//底图是用美术出的图,还是程序用shader把亮图变暗
const bool kUseShader;
//csb根节点
Node* csb_root;
// 可以被触摸的碎片,即状态为已获得但没有归位的碎片
vector<Sprite*> m_touchable_pieces;
// 正在被触摸的碎片
Sprite* m_touching_piece;
//正在被触摸的碎片移动之前的位置
Vec2 m_touching_piece_pos_before_move;
//正在被触摸的碎片的父节点
Node* m_touching_piece_father_node;
//记录碎片的目的地位置
array<Vec2, PHOTO_COLLECT_PIECE_COUNT> i_piece_position_array;
//下拉宝箱的初始y坐标(三个宝箱都显示)
float if_boxes_original_y_position;
//当前在看哪张图
int i_current_photo_display;
//列表框里子项未选中时的缩放比例
float i_listview_item_select_scale;
//列表框里子项未选中时的缩放比例
float i_listview_item_normal_scale;
};
弹框类的实现文件
DialogPhoto()
: kUseShader(true)
{
}
void DialogPhoto::of_init_ui() {
string ls_csb = "csb_ui_photo/dialog_photocollect_new.csb";
//目前只有“入”的动画,没有“出”的动画。入动画的最后一帧是58
auto l_node_csb = PUI::of_create_dialog(this, ls_csb, 0, g.rrscale, 60);
//目前在csb文件里没有区分中英文,所以没有调用g.of_set_ui_by_country()
csb_root = l_node_csb;
//给关闭按钮添加回调
auto l_button_close = (Button*)PUI::of_find_by_name(l_node_csb, "button_close");
l_button_close->addClickEventListener(CC_CALLBACK_0(DialogPhoto::on_close, this));
//往列表框中加入已解锁的图,每张图的tag是它们的photo id
of_init_listview();
//重新设置宝箱的y坐标,宝箱节点必须贴在屏幕的上边缘
{
auto origin = Director::getInstance()->getVisibleOrigin();
auto visize = Director::getInstance()->getVisibleSize();
auto node = PUI::of_find_by_name(l_node_csb, "node_album_gift_top_pos");
auto node_pos = node->getPosition();
auto parent = node->getParent();
auto world_pos = parent->convertToWorldSpace(node_pos);
auto world_pos_1 = Vec2(world_pos.x, origin.y + visize.height);
auto node_pos_1 = parent->convertToNodeSpace(world_pos_1);
node->setPosition(node_pos_1);
if_boxes_original_y_position = node_pos_1.y;
}
//得到每个碎片的最终位置,存进i_piece_position_array这个成员变量里,一会儿用来判断碎片“归位”
{
auto csb_file = CSLoader::createNode("csb_ui_photo/node_photo_one.csb");
for (int i = 0; i < PHOTO_COLLECT_PIECE_COUNT; i++)
{
auto piece_node = PUI::of_find_by_name(csb_file, StringUtils::format("sp_piece%d", i));
i_piece_position_array[i] = piece_node->getPosition();
}
}
//给面板添加触摸回调
auto panel_for_touch = (Layout*)PUI::of_find_by_name(l_node_csb, "panel_for_touch");
panel_for_touch->removeAllChildren();
panel_for_touch->addTouchEventListener(CC_CALLBACK_2(DialogPhoto::on_touch_piece, this));
//给每个宝箱添加触摸回调,并隐藏每个宝箱的说明
auto btn_box_1 = (Button*)PUI::of_find_by_name(l_node_csb, "btn_albumgiftbox_1");
auto btn_box_2 = (Button*)PUI::of_find_by_name(l_node_csb, "btn_albumgiftbox_2");
auto btn_box_3 = (Button*)PUI::of_find_by_name(l_node_csb, "btn_albumgiftbox_3");
btn_box_1->addTouchEventListener(CC_CALLBACK_2(DialogPhoto::on_touch_award_box, this, 0));
btn_box_2->addTouchEventListener(CC_CALLBACK_2(DialogPhoto::on_touch_award_box, this, 1));
btn_box_3->addTouchEventListener(CC_CALLBACK_2(DialogPhoto::on_touch_award_box, this, 2));
PUI::of_find_by_name(l_node_csb, "sp_albumgiftbox_info_1")->setVisible(false);
PUI::of_find_by_name(l_node_csb, "sp_albumgiftbox_info_2")->setVisible(false);
PUI::of_find_by_name(l_node_csb, "sp_albumgiftbox_info_3")->setVisible(false);
//在右侧显示详情
int li_last_open_photo = g.candy_photo_collect->of_get_last_open_photo();
if (li_last_open_photo != PHOTO_COLLECT_INVALID_PHOTO_ID)
{
of_init_single_photo(li_last_open_photo);
}
else
{
of_init_single_photo(999);
}
}
//初始化左侧列表框
void DialogPhoto::of_init_listview()
{
auto l_lsv = (ListView*)PUI::of_find_by_name(csb_root, "listview_photos");
l_lsv->removeAllChildren();
//得到列表框的宽度 280
float lf_lsv_w = l_lsv->getContentSize().width;
//得到一张图的宽高
float lf_photo_w = 856;
float lf_photo_h = 900;
//计算列表框里子项未选中时的缩放比例
float lf_item_width = lf_lsv_w - 20;//260,没选中时的宽度
i_listview_item_normal_scale = lf_item_width / lf_photo_w;//没选中时的缩放
float lf_item_height = lf_photo_h * i_listview_item_normal_scale;//没选中时的高度
//计算列表框里子项选中时的缩放比例
i_listview_item_select_scale = lf_lsv_w / lf_item_width;
//得到已经解锁的所有photo的id的集合
auto l_vector_unlock_photos_id = g.candy_photo_collect->of_get_unlock_photos();
//得到最近得到的碎片所属于的photo id
int li_last_open_photo = g.candy_photo_collect->of_get_last_open_photo();
for (auto i : l_vector_unlock_photos_id)
{
auto panel = Layout::create();
panel->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
panel->setContentSize(Size(lf_item_width, lf_item_height));
panel->setTag(i);
panel->setTouchEnabled(true);
panel->addClickEventListener(CC_CALLBACK_1(DialogPhoto::on_click_switch_photo, this));
l_lsv->pushBackCustomItem(panel);
//加载csb到这个widget上
of_add_photo_one(panel, i, i_listview_item_normal_scale);
}
//在列表框尾部添加“敬请期待”
{
auto panel = Layout::create();
panel->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
panel->setContentSize(Size(lf_item_width, lf_item_height));
panel->setTag(999);
panel->setTouchEnabled(true);
panel->addClickEventListener(CC_CALLBACK_1(DialogPhoto::on_click_switch_photo, this));
l_lsv->pushBackCustomItem(panel);
auto spr = Sprite::create("photoes/coming_soon/999_normal.png");
spr->setPosition(Vec2(lf_item_width / 2, lf_item_height / 2));
spr->setScale(i_listview_item_normal_scale);
panel->addChild(spr);
string ls_name_path = g.is_country == "zh" ? "photoes/coming_soon/photo_name_999_zh.png" : "photoes/coming_soon/photo_name_999.png";
auto spr_name = Sprite::create(ls_name_path);
spr_name->setPosition(Vec2(367, 75));
spr->addChild(spr_name);
auto spr2 = Sprite::create("photoes/coming_soon/999_co.png");
spr2->setScale(1.99f);
spr2->setPosition(Vec2(spr->getContentSize().width / 2, spr->getContentSize().height / 2));
spr->addChild(spr2);
}
}
//显示单张图
void DialogPhoto::of_init_single_photo(int photo_id)
{
m_touchable_pieces.clear();
auto panel_for_touch = (Layout*)PUI::of_find_by_name(csb_root, "panel_for_touch");
panel_for_touch->removeAllChildren();
if (photo_id == 999)
{
auto sp = Sprite::create("photoes/coming_soon/999_normal.png");
sp->setPosition(Vec2(panel_for_touch->getContentSize().width / 2, panel_for_touch->getContentSize().height / 2));
panel_for_touch->addChild(sp);
auto spr2 = Sprite::create("photoes/coming_soon/999_co.png");
spr2->setScale(1.996f);
spr2->setPosition(Vec2(sp->getContentSize().width / 2, sp->getContentSize().height / 2));
sp->addChild(spr2);
string ls_name_path = g.is_country == "zh" ? "photoes/coming_soon/photo_name_999_zh.png" : "photoes/coming_soon/photo_name_999.png";
auto spr_name = Sprite::create(ls_name_path);
spr_name->setPosition(Vec2(367, 75));
sp->addChild(spr_name);
PUI::of_find_by_name(this, "node_album_gift_top_pos")->setVisible(false);
//当photo_id是999时,没有给i_current_photo_display赋值,也不影响
return;
}
i_current_photo_display = photo_id;
auto csb_file = CSLoader::createNode("csb_ui_photo/node_photo_one.csb");
auto csb_act = CSLoader::createTimeline("csb_ui_photo/node_photo_one.csb");
panel_for_touch->addChild(csb_file);
csb_file->runAction(csb_act);
csb_act->gotoFrameAndPlay(0, 60, false);
//查询该图拼完没有
int ok_piece_cnt = g.candy_photo_collect->of_get_photo_ok_piece_count(photo_id);
if (ok_piece_cnt < PHOTO_COLLECT_PIECE_COUNT)
{
//显示底图
auto l_sp_shadow_one = (Sprite*)PUI::of_find_by_name(csb_file, "sp_photo_shadow_bg");
l_sp_shadow_one->setVisible(true);
if (kUseShader)
{
PUI::of_sprite_set_texture(l_sp_shadow_one, of_get_photo_path_by_id(photo_id));
PUI::of_node_set_gray(l_sp_shadow_one);
}
else
{
PUI::of_sprite_set_texture(l_sp_shadow_one, of_get_gray_photo_path_by_id(photo_id));
}
//显示碎片
auto arr = g.candy_photo_collect->of_get_pieces(photo_id);
for (int i = 0; i < PHOTO_COLLECT_PIECE_COUNT; i++)
{
auto piece_sprite = (Sprite*)PUI::of_find_by_name(csb_file, StringUtils::format("sp_piece%d", i));
piece_sprite->setCascadeOpacityEnabled(true);
piece_sprite->setTag(i);
int piece_status = arr[i];
if (piece_status == 0)
{
piece_sprite->setVisible(false);//未得到的碎片不显示
continue;
}
auto piece_pos = piece_sprite->getPosition();
auto piece_size = piece_sprite->getContentSize();
auto sp_stencil = Sprite::create(piece_sprite->getTexture()->getPath());
auto node_clip = ClippingNode::create(sp_stencil);
node_clip->setAlphaThreshold(0);
node_clip->setInverted(false);
node_clip->setPosition(Vec2(piece_size.width / 2, piece_size.height / 2));
node_clip->setCascadeOpacityEnabled(true);
piece_sprite->addChild(node_clip);
auto sp_content = Sprite::create(of_get_photo_path_by_id(photo_id));
sp_content->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
sp_content->setPosition(Vec2(10 - piece_pos.x, 130 - piece_pos.y));
node_clip->addChild(sp_content);
auto sp_shield = Sprite::create(StringUtils::format("photoes/ui/001_%d_1.png", i));
sp_shield->setPosition(Vec2(piece_size.width / 2, piece_size.height / 2));
sp_shield->setCascadeOpacityEnabled(true);
piece_sprite->addChild(sp_shield);
if (piece_status == 1)//没有归位的碎片,打乱位置显示
{
int n = m_touchable_pieces.size();
piece_sprite->setPosition(Vec2(150 + 30 * n, 100));
piece_sprite->setLocalZOrder(2);
m_touchable_pieces.push_back(piece_sprite);
}
}
//隐藏亮图
auto sp_normal_one = (Sprite*)PUI::of_find_by_name(csb_file, "sp_photo_normal_bg");
sp_normal_one->setVisible(false);
}
else
{
//隐藏底图
auto l_sp_shadow_one = (Sprite*)PUI::of_find_by_name(csb_file, "sp_photo_shadow_bg");
l_sp_shadow_one->setVisible(false);
//隐藏碎片
PUI::of_find_by_name(csb_file, "node_pieces")->setVisible(false);
//显示亮图
auto sp_normal_one = (Sprite*)PUI::of_find_by_name(csb_file, "sp_photo_normal_bg");
PUI::of_sprite_set_texture(sp_normal_one, of_get_photo_path_by_id(photo_id));
sp_normal_one->setCascadeOpacityEnabled(true);
}
//不显示节日名
PUI::of_find_by_name(csb_file, "txt_name_en")->setVisible(false);
PUI::of_find_by_name(csb_file, "txt_name_zh")->setVisible(false);
//显示节日说明
auto photo_text_en = (Text*)PUI::of_find_by_name(csb_file, "txt_info_en");
auto photo_text_zh = (Text*)PUI::of_find_by_name(csb_file, "txt_info_zh");
if (ok_piece_cnt < PHOTO_COLLECT_PIECE_COUNT)
{
photo_text_en->setVisible(false);
photo_text_zh->setVisible(false);
}
else
{
photo_text_en->setString(g.candy_photo_collect->of_get_introduce(photo_id, g.is_country));
photo_text_zh->setString(g.candy_photo_collect->of_get_introduce(photo_id, g.is_country));
photo_text_en->setVisible(g.is_country == "zh" ? false : true);
photo_text_zh->setVisible(g.is_country == "zh" ? true : false);
}
//显示宝箱上的数字
refresh_award_box_label(photo_id);
PUI::of_find_by_name(csb_root, "sp_albumgiftbox_info_1")->setVisible(false);
PUI::of_find_by_name(csb_root, "sp_albumgiftbox_info_2")->setVisible(false);
PUI::of_find_by_name(csb_root, "sp_albumgiftbox_info_3")->setVisible(false);
}
//点击碎片的回调
void DialogPhoto::on_touch_piece(Ref* sender, Widget::TouchEventType type)
{
auto lyt = dynamic_cast<Layout*>(sender);
if (type == Widget::TouchEventType::BEGAN)
{
m_touching_piece = nullptr;
auto pos_world = lyt->getTouchBeganPosition();
for (auto it = m_touchable_pieces.crbegin(); it != m_touchable_pieces.crend(); ++it)
{
auto sp_size = (*it)->getContentSize();
auto pos_node = (*it)->convertToNodeSpace(pos_world);
if (pos_node.x > 0
&& pos_node.x < sp_size.width
&& pos_node.y > 0
&& pos_node.y < sp_size.height)
{
m_touching_piece = (*it);
m_touching_piece->setLocalZOrder(3);//正在被拖动的碎片的层级比其他碎片高
m_touching_piece_pos_before_move = m_touching_piece->getPosition();
m_touching_piece_father_node = m_touching_piece->getParent();
break;
}
}
if (m_touching_piece)
{
for (auto it = m_touchable_pieces.crbegin(); it != m_touchable_pieces.crend(); ++it)
{
(*it)->setVisible((*it) == m_touching_piece);
}
}
}
else if (type == Widget::TouchEventType::MOVED)
{
if (m_touching_piece)
{
auto size_touching_sp = m_touching_piece->getContentSize();
auto touch_pos_1 = m_touching_piece_father_node->convertToNodeSpace(lyt->getTouchBeganPosition());
auto touch_pos_2 = m_touching_piece_father_node->convertToNodeSpace(lyt->getTouchMovePosition());
auto touch_pos_delta = touch_pos_2 - touch_pos_1;
auto new_pos = m_touching_piece_pos_before_move + touch_pos_delta;
bool x_can_move = (new_pos.x > 0 + size_touching_sp.width / 2 - 65) && (new_pos.x < lyt->getContentSize().width - size_touching_sp.width / 2 - 65);
bool y_can_move = (new_pos.y > 0 + size_touching_sp.height / 2 - 18) && (new_pos.y < lyt->getContentSize().height - size_touching_sp.height / 2 - 18);
if (x_can_move || y_can_move)//移动不能超出父容器
{
if (x_can_move && y_can_move)
{
auto destination_position = i_piece_position_array[m_touching_piece->getTag()];
if (abs(new_pos.x - destination_position.x) < 8 && abs(new_pos.y - destination_position.y) < 8)//靠近目标位置就吸附上去
{
m_touching_piece->setPosition(destination_position);
m_touching_piece->setLocalZOrder(1);
//碎片归位之后,播放一个光效
PUI::of_create_movie_by_csb_once(m_touching_piece, "csb_ui_awardbox/node_effect_end_par.csb", m_touching_piece->getContentSize().width / 2, m_touching_piece->getContentSize().height / 2, 1.4f, 1.4f);
for (auto it = m_touchable_pieces.begin(); it != m_touchable_pieces.end(); ++it)//碎片归位后,把它从可移动的碎片vector里移除
{
if (*it == m_touching_piece)
{
m_touchable_pieces.erase(it);
break;
}
}
//存档,这里是更新当前显示这张图的某个碎片的状态
g.candy_photo_collect->of_set_piece_status(i_current_photo_display, m_touching_piece->getTag(), 2);
//把正在触摸的碎片置空
m_touching_piece = nullptr;
//拼好之后要做哪些事
of_work_after_piece_status_turn_to_ok(i_current_photo_display, destination_position);
}
else
{
m_touching_piece->setPosition(new_pos);
}
}
else if (x_can_move)
{
m_touching_piece->setPositionX(new_pos.x);
}
else
{
m_touching_piece->setPositionY(new_pos.y);
}
}
}
}
else if (type == Widget::TouchEventType::ENDED)
{
m_touching_piece = nullptr;
for (auto sp : m_touchable_pieces)
{
sp->setVisible(true);
sp->setLocalZOrder(2);
}
}
else if (type == Widget::TouchEventType::CANCELED)
{
m_touching_piece = nullptr;
for (auto sp : m_touchable_pieces)
{
sp->setVisible(true);
sp->setLocalZOrder(2);
}
}
}
//点击左侧的列表框,切换照片
void DialogPhoto::on_click_switch_photo(Ref * sender)
{
auto wgt = dynamic_cast<Widget*>(sender);
auto lsv = (ListView*)PUI::of_find_by_name(csb_root, "listview_photos");
auto items = lsv->getItems();
for (auto item : items)
{
if (wgt == item)
{
item->setScale(i_listview_item_select_scale);
}
else
{
item->setScale(1);
}
}
int tag = wgt->getTag();//这个tag就是图片的ID
of_init_single_photo(tag);
}
//点击关闭的回调
void DialogPhoto::on_close() {
if (dialog_listener != nullptr) {
dialog_listener->doDialogAction(this, DialogAction::dialog_photo_close);
}
of_close_dialog();
g.play_sound("music/sound_button_clicked.mp3");
}
//点击右侧的宝箱,显示这个宝箱的奖励内容
void DialogPhoto::on_touch_award_box(Ref* sender, Widget::TouchEventType type, int box_index)
{
if (type == Widget::TouchEventType::BEGAN)
{
auto n1 = PUI::of_find_by_name(this, "sp_albumgiftbox_info_1");
auto n2 = PUI::of_find_by_name(this, "sp_albumgiftbox_info_2");
auto n3 = PUI::of_find_by_name(this, "sp_albumgiftbox_info_3");
auto act2 = Show::create();
auto act3 = DelayTime::create(2.3f);
auto act4 = Hide::create();
auto act = Sequence::create(act2, act3, act4, nullptr);
if (box_index == 0)
{
if (n1->isVisible() == false) n1->runAction(act);
n2->setVisible(false);
n3->setVisible(false);
}
else if (box_index == 1)
{
n1->setVisible(false);
if (n2->isVisible() == false) n2->runAction(act);
n3->setVisible(false);
}
else if (box_index == 2)
{
n1->setVisible(false);
n2->setVisible(false);
if (n3->isVisible() == false) n3->runAction(act);
}
}
}
//更新宝箱下面的数字显示
void DialogPhoto::refresh_award_box_label(int photo_id)
{
auto node_boxes_parent = PUI::of_find_by_name(csb_root, "node_album_gift_top_pos");
node_boxes_parent->setVisible(true);
auto fnt_box_1 = (TextBMFont*)PUI::of_find_by_name(this, "fnt_albumgiftbox_1");
auto fnt_box_2 = (TextBMFont*)PUI::of_find_by_name(this, "fnt_albumgiftbox_2");
auto fnt_box_3 = (TextBMFont*)PUI::of_find_by_name(this, "fnt_albumgiftbox_3");
int ok_piece_cnt = g.candy_photo_collect->of_get_photo_ok_piece_count(photo_id);
auto box1 = PUI::of_find_by_name(node_boxes_parent, "node_albumgiftbox_1");
auto box2 = PUI::of_find_by_name(node_boxes_parent, "node_albumgiftbox_2");
auto box3 = PUI::of_find_by_name(node_boxes_parent, "node_albumgiftbox_3");
if (ok_piece_cnt >= 16)
{
box1->setVisible(false);
box2->setVisible(false);
box3->setVisible(false);
fnt_box_1->setString("3/3");
fnt_box_2->setString("9/9");
fnt_box_3->setString("16/16");
}
else if (ok_piece_cnt >= 9)
{
box1->setVisible(false);
box2->setVisible(false);
box3->setVisible(true);
node_boxes_parent->setPositionY(if_boxes_original_y_position + 447);
fnt_box_1->setString("3/3");
fnt_box_2->setString("9/9");
fnt_box_3->setString(StringUtils::format("%d/16", ok_piece_cnt));
}
else if (ok_piece_cnt >= 3)
{
box1->setVisible(false);
box2->setVisible(true);
box3->setVisible(true);
node_boxes_parent->setPositionY(if_boxes_original_y_position + 224);
fnt_box_1->setString("3/3");
fnt_box_2->setString(StringUtils::format("%d/9", ok_piece_cnt));
fnt_box_3->setString(StringUtils::format("%d/16", ok_piece_cnt));
}
else
{
box1->setVisible(true);
box2->setVisible(true);
box3->setVisible(true);
node_boxes_parent->setPositionY(if_boxes_original_y_position);
fnt_box_1->setString(StringUtils::format("%d/3", ok_piece_cnt));
fnt_box_2->setString(StringUtils::format("%d/9", ok_piece_cnt));
fnt_box_3->setString(StringUtils::format("%d/16", ok_piece_cnt));
}
}
//更新左侧列表框里的缩略图的显示
void DialogPhoto::refresh_list_view_photo(int photo_id)
{
if (csb_root)
{
auto lsv = (ListView*)PUI::of_find_by_name(csb_root, "listview_photos");
if (lsv)
{
auto panel = dynamic_cast<Layout*>(lsv->getChildByTag(photo_id));
if (panel)
{
of_add_photo_one(panel, photo_id, i_listview_item_normal_scale);
}
}
}
}
//检查是否需要发奖
void DialogPhoto::check_need_award_box(int photo_id)
{
int ok_piece_cnt = g.candy_photo_collect->of_get_photo_ok_piece_count(photo_id);
if (ok_piece_cnt == 3)
{
g.is_message_for_dialog = "beforelineline,1;beforesame,1";
g.cm->of_award_by_string(g.is_message_for_dialog);
DialogAwardBox::make(this, 999, nullptr);
}
else if (ok_piece_cnt == 9)
{
g.is_message_for_dialog = "beforebombbomb,1;beforesame,1;coin_little,100";
g.cm->of_award_by_string(g.is_message_for_dialog);
DialogAwardBox::make(this, 999, nullptr);
}
else if (ok_piece_cnt == 16)
{
auto node_photo_one = PUI::of_find_by_name(csb_root, "node_photo_one");
PUI::of_find_by_name(csb_root, "node_pieces")->setVisible(false);
//拼完就把亮图显示出来,淡入
auto sp_normal_one = (Sprite*)PUI::of_find_by_name(node_photo_one, "sp_photo_normal_bg");
PUI::of_sprite_set_texture(sp_normal_one, of_get_photo_path_by_id(photo_id));
sp_normal_one->setVisible(true);
sp_normal_one->setOpacity(0);
auto act1 = FadeIn::create(2.5f);
auto act2 = CallFunc::create(CC_CALLBACK_0(DialogPhoto::of_callback_all_pieces_ok, this, photo_id));
auto act = Sequence::create(act1, act2, nullptr);
sp_normal_one->runAction(act);
}
}
//把单个的csb photo添加到指定的父节点上
void DialogPhoto::of_add_photo_one(Widget * l_widget_parent, int li_photo_id, float lf_scale)
{
l_widget_parent->removeAllChildren();
auto l_node_csb = CSLoader::createNode("csb_ui_photo/node_photo_one.csb");
l_node_csb->setScale(lf_scale);
l_widget_parent->addChild(l_node_csb);
auto l_timeline_action_csb = CSLoader::createTimeline("csb_ui_photo/node_photo_one.csb");
l_node_csb->runAction(l_timeline_action_csb);
l_timeline_action_csb->gotoFrameAndPause(65);//这个csb有一个淡入的动画,是0到60帧,这里直接显示65帧,不需要淡入动画
//查询该图拼完没有,如果没拼完就显示暗图和碎片,如果拼完了就显示亮图
int li_ok_piece_cnt = g.candy_photo_collect->of_get_photo_ok_piece_count(li_photo_id);
if (li_ok_piece_cnt < PHOTO_COLLECT_PIECE_COUNT)
{
//显示底图
auto l_sp_shadow_one = (Sprite*)PUI::of_find_by_name(l_node_csb, "sp_photo_shadow_bg");
l_sp_shadow_one->setVisible(true);
if (kUseShader)
{
PUI::of_sprite_set_texture(l_sp_shadow_one, of_get_photo_path_by_id(li_photo_id));
PUI::of_node_set_gray(l_sp_shadow_one);
}
else
{
PUI::of_sprite_set_texture(l_sp_shadow_one, of_get_gray_photo_path_by_id(li_photo_id));
}
//显示碎片
auto l_vector_pieces_array = g.candy_photo_collect->of_get_pieces(li_photo_id);
for (int i = 0; i < PHOTO_COLLECT_PIECE_COUNT; i++)
{
auto l_sprite_piece = (Sprite*)PUI::of_find_by_name(l_node_csb, StringUtils::format("sp_piece%d", i));
l_sprite_piece->setTag(i);
int li_piece_status = l_vector_pieces_array[i];
if (li_piece_status != 2)
{
l_sprite_piece->setVisible(false);//未归位的碎片不显示
continue;
}
auto piece_pos = l_sprite_piece->getPosition();
auto piece_size = l_sprite_piece->getContentSize();
auto sp_stencil = Sprite::create(l_sprite_piece->getTexture()->getPath());
auto node_clip = ClippingNode::create(sp_stencil);
node_clip->setAlphaThreshold(0);
node_clip->setInverted(false);
node_clip->setPosition(Vec2(piece_size.width / 2, piece_size.height / 2));
l_sprite_piece->addChild(node_clip);
auto sp_content = Sprite::create(of_get_photo_path_by_id(li_photo_id));
sp_content->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
sp_content->setPosition(Vec2(10 - piece_pos.x, 130 - piece_pos.y));
node_clip->addChild(sp_content);
auto sp_shield = Sprite::create(StringUtils::format("photoes/ui/001_%d_1.png", i));
sp_shield->setPosition(Vec2(piece_size.width / 2, piece_size.height / 2));
l_sprite_piece->addChild(sp_shield);
}
//隐藏亮图
auto sp_normal_one = (Sprite*)PUI::of_find_by_name(l_node_csb, "sp_photo_normal_bg");
sp_normal_one->setVisible(false);
}
else
{
//隐藏底图
auto l_sp_shadow_one = (Sprite*)PUI::of_find_by_name(l_node_csb, "sp_photo_shadow_bg");
l_sp_shadow_one->setVisible(false);
//隐藏碎片,把所有碎片的父节点给隐藏
PUI::of_find_by_name(l_node_csb, "node_pieces")->setVisible(false);
//显示亮图
auto sp_normal_one = (Sprite*)PUI::of_find_by_name(l_node_csb, "sp_photo_normal_bg");
PUI::of_sprite_set_texture(sp_normal_one, of_get_photo_path_by_id(li_photo_id));
}
//显示节日名,根据中英文决定谁不显示
auto l_txt_photo_name_en = (Text*)PUI::of_find_by_name(l_node_csb, "txt_name_en");
l_txt_photo_name_en->setString(g.candy_photo_collect->of_get_name(li_photo_id, g.is_country));
l_txt_photo_name_en->setVisible(g.is_country == "zh" ? false : true);
auto l_txt_photo_name_zh = (Text*)PUI::of_find_by_name(l_node_csb, "txt_name_zh");
l_txt_photo_name_zh->setString(g.candy_photo_collect->of_get_name(li_photo_id, g.is_country));
l_txt_photo_name_zh->setVisible(g.is_country == "zh" ? true : false);
//隐藏节日说明
PUI::of_find_by_name(l_node_csb, "txt_info_en")->setVisible(false);
PUI::of_find_by_name(l_node_csb, "txt_info_zh")->setVisible(false);
}
//根据photo id找到对应的图片路径
string DialogPhoto::of_get_photo_path_by_id(int li_photo_id)
{
return StringUtils::format("photoes/normal/%03d_normal.png", li_photo_id, li_photo_id);
}
string DialogPhoto::of_get_gray_photo_path_by_id(int li_photo_id)
{
return StringUtils::format("photoes/gray/%03d_gray.png", li_photo_id, li_photo_id);
}
//拼好之后,亮图淡入完成后的回调
void DialogPhoto::of_callback_all_pieces_ok(int li_photo_id)
{
auto l_layout_panel_for_touch = PUI::of_find_by_name(csb_root, "panel_for_touch");
//显示节日说明
auto photo_text_en = (Text*)PUI::of_find_by_name(l_layout_panel_for_touch, "txt_info_en");
auto photo_text_zh = (Text*)PUI::of_find_by_name(l_layout_panel_for_touch, "txt_info_zh");
photo_text_en->setString(g.candy_photo_collect->of_get_introduce(li_photo_id, g.is_country));
photo_text_zh->setString(g.candy_photo_collect->of_get_introduce(li_photo_id, g.is_country));
photo_text_en->setVisible(g.is_country == "zh" ? false : true);
photo_text_zh->setVisible(g.is_country == "zh" ? true : false);
g.is_message_for_dialog = "hammer,1;beforelineline,1;beforesame,1;coin_big,100;life_unlimited,1;beforebombbomb,1";
g.cm->of_award_by_string(g.is_message_for_dialog);
DialogAwardBox::make(this, 999, nullptr);
}
void DialogPhoto::of_work_after_piece_status_turn_to_ok(int li_photo_id, Vec2 piece_pos)
{
//根据拼好了多少个碎片来决定飞过去的光效飞到哪个宝箱上
int li_ok_piece_cnt = g.candy_photo_collect->of_get_photo_ok_piece_count(li_photo_id);
//默认飞向第三个宝箱
auto l_node_fly_to = PUI::of_find_by_name(csb_root, "btn_albumgiftbox_3");
if (li_ok_piece_cnt <= 3) l_node_fly_to = PUI::of_find_by_name(csb_root, "btn_albumgiftbox_1");
else if (li_ok_piece_cnt <= 9) l_node_fly_to = PUI::of_find_by_name(csb_root, "btn_albumgiftbox_2");
//拼好一个碎片后,播放一个光效从碎片飞到宝箱上
auto pos_fly_begin_t = m_touching_piece_father_node->convertToWorldSpace(piece_pos);
auto pos_fly_begin = csb_root->convertToNodeSpace(pos_fly_begin_t);
auto pos_fly_end_t = l_node_fly_to->convertToWorldSpace(Vec2(114, 117));
auto pos_fly_end = csb_root->convertToNodeSpace(pos_fly_end_t);
auto par = ParticleSystemQuad::create("particle/particle_juneng_adding.plist");
par->setPosition(pos_fly_begin);
csb_root->addChild(par);
auto act1 = MoveTo::create(1, pos_fly_end);
auto act2 = DelayTime::create(0.4f);
auto act3 = CallFunc::create([this, li_photo_id] {
//拼好一个碎片后,更新宝箱上面的数字
refresh_award_box_label(li_photo_id);
//拼好一个碎片后,检查是否发奖
check_need_award_box(li_photo_id);
//拼好一个碎片后,更新左侧列表框里的缩略图的显示
refresh_list_view_photo(li_photo_id);
});
auto act4 = RemoveSelf::create();
par->runAction(Sequence::create(act1, act2, act3, act4, nullptr));
}
DialogPhoto::
过关之后的判断
void PanelFinish::of_photo_award_dialog() {
if (g.ib_current_level_first_passed == false) return;
//获取今天的日期
int date_of_today = PFJava::of_get_today_number();
date_of_today = date_of_today % 10000;
//获取当前的关卡号
int current_level = g.stages->of_get_passed_index_max();
// 得到碎片图以及序号
int li_photo_id = 0, li_piece_index = 0;
bool lb_piece_found = g.candy_photo_collect->of_get_award_piece(g.game_model, date_of_today, current_level, 5, li_photo_id, li_piece_index);
if (!lb_piece_found) return;
g.candy_photo_collect->of_set_last_open_photo(li_photo_id);
g.candy_photo_collect->of_set_piece_status(li_photo_id, li_piece_index, 1);
// 注意这是一个480的csb
string ls_csb = "csb_ui_photo/dialog_photo_get_piece.csb";
auto d1 = PUI::of_create_dialog(layer, ls_csb, 1999, g.rrscale * 2.0f, 45);
d1->setName("csbnode_dialog_photo_get_piece");
g.of_set_ui_by_country(d1);
auto node_pos_photo_piece = PUI::of_find_by_name(d1, "node_pos_photo_piece");
auto sp_demo = PUI::of_find_by_name(node_pos_photo_piece, "sp_demo");
auto pos0 = sp_demo->getPosition();
sp_demo->setVisible(false);
do {
// 采用动态创建的方式进行创建碎片
auto l_single_node = CSLoader::createNode("csb_ui_photo/node_photo_one.csb");
CC_BREAK_IF(!l_single_node);
auto l_node_pieces = PUI::of_find_by_name(l_single_node, "node_pieces");
CC_BREAK_IF(!l_node_pieces);
string ls_piece_name = StringUtils::format("sp_piece%d", li_piece_index);
auto n_piece1 = static_cast<Sprite*>(l_node_pieces->getChildByName(ls_piece_name));
CC_BREAK_IF(!n_piece1);
Vec2 pos_cur_piece = n_piece1->getPosition();
Size size_cur_piece = n_piece1->getContentSize();
string ls_stencil_filename = n_piece1->getTexture()->getPath();
CC_BREAK_IF(!FileUtils::getInstance()->isFileExist(ls_stencil_filename));
auto l_sprite_stencil = Sprite::create(ls_stencil_filename);
CC_BREAK_IF(!l_sprite_stencil);
string ls_content_filename = StringUtils::format("photoes/normal/%03d_normal.png", li_photo_id, li_photo_id);
CC_BREAK_IF(!FileUtils::getInstance()->isFileExist(ls_content_filename));
auto l_sprite_content = Sprite::create(ls_content_filename);
CC_BREAK_IF(!l_sprite_content);
l_sprite_content->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
l_sprite_content->setPosition(Vec2(10 - pos_cur_piece.x, 130 - pos_cur_piece.y));
auto l_node_clip = ClippingNode::create(l_sprite_stencil);
l_node_clip->setAlphaThreshold(0);
l_node_clip->setInverted(false);
l_node_clip->addChild(l_sprite_content);
l_node_clip->setScale(0.45f);
node_pos_photo_piece->addChild(l_node_clip);
string ls_shield_filename = StringUtils::format("photoes/ui/001_%d_1.png", li_piece_index);
CC_BREAK_IF(!FileUtils::getInstance()->isFileExist(ls_shield_filename));
auto l_sprite_shield = Sprite::create(ls_shield_filename);
CC_BREAK_IF(!l_sprite_shield);
l_sprite_shield->setScale(0.45f);
node_pos_photo_piece->addChild(l_sprite_shield);
} while (0);
//
auto button_close = (Button*)PUI::of_find_by_name(d1, "button_close");
button_close->addClickEventListener(CC_CALLBACK_0(PanelFinish::of_photo_award_dialog_close, this));
auto button_open = (Button*)PUI::of_find_by_name(d1, "button_open");
button_open->addClickEventListener(CC_CALLBACK_0(PanelFinish::of_photo_award_dialog_open, this));
g.of_track_function("n_photo_collect_piece");
g.play_sound("music/sound_gift_get.mp3");
}
void PanelFinish::of_photo_award_dialog_open() {
PUI::of_find_by_name_set_visible(layer, "csbnode_dialog_photo_get_piece", false);
DialogPhoto::make(layer, 1999, nullptr);
}
void PanelFinish::of_photo_award_dialog_close() {
auto d1 = PUI::of_find_by_name(layer, "csbnode_dialog_photo_get_piece");
d1->setVisible(false);
}
配置文件
保存为photo_collect_config.json,放在config目录下。
{
"说明1": "type_date是日期类型的配置,日期类型的配置里不能有level_begin字段",
"说明2": "type_level是关卡类型的配置,关卡类型的配置里不能有date_begin和date_end字段",
"说明3": "id这个字段必须是大于0的整数,并且我们约定1到500表示日期类配置,501到999表示关卡类配置。当然你也可以不遵守这个约定,不影响程序正常运行。这个id的作用是用来找到对应的图片资源",
"说明4": "日期类配置,date_end必须大于或等于date_begin,等于就表示这个节日只有一天",
"说明5": "关卡类配置,level_begin必须各不相同",
"说明6": "日期类配置,同一个日期区间可能会对应多张图,比方说父亲节有3张图,现在到父亲节的日期了,并且3张图都没解锁,那么谁先解锁谁后解锁,可以再加一个关卡号来筛选,也就是level_limit这个字段,这个字段可有可无",
"type_date": [{
"id": 1,
"name_en": "Christmas Day",
"name_zh": "圣诞节",
"info_en": "Luna is going to have a wonderful Christmas with him(or her), Who would be the lucky one?",
"info_zh": "露娜将会跟他(她)在这一起度过一个愉快的圣诞节,那位幸运儿回是谁呢?",
"date_begin": 1201,
"date_end": 1231
}, {
"id": 2,
"name_en": "Valentine's Day",
"name_zh": "情人节",
"info_en": "Luna received a beautiful bouquet of flowers, Who gave her?",
"info_zh": "露娜收到一束漂亮的花,是谁送给她的?",
"date_begin": 201,
"date_end": 218
}, {
"id": 3,
"name_en": "Women's Day",
"name_zh": "妇女节",
"info_en": "Make your own life!",
"info_zh": "创造属于你自己的生活吧!",
"date_begin": 301,
"date_end": 310
}, {
"id": 4,
"name_en": "St.Patrick's Day",
"name_zh": "圣帕特里克节",
"info_en": "Let the shamrocks start your luck.",
"info_zh": "让三叶草给你带来好运!",
"date_begin": 311,
"date_end": 318
}, {
"id": 5,
"name_en": "April Fool's Day",
"name_zh": "愚人节",
"info_en": "A bottle of wine will be delivered in 5 mins.",
"info_zh": "5分钟后会有人给你送一瓶葡萄酒。",
"date_begin": 327,
"date_end": 402
}, {
"id": 6,
"name_en": "Easter",
"name_zh": "复活节",
"info_en": "Go and find the eggs hidden in the game.",
"info_zh": "去寻找游戏里的彩蛋吧!",
"date_begin": 406,
"date_end": 428
}, {
"id": 7,
"name_en": "Mother's Day",
"name_zh": "母亲节",
"info_en": "This is a photo of Luna childhood when she was with her mom on Mother's Day",
"info_zh": "这是露娜小时候陪妈妈一起过母亲节的照片!",
"date_begin": 501,
"date_end": 518
}, {
"id": 8,
"name_en": "Halloween",
"name_zh": "万圣节",
"info_en": "It was the first time that she attend Halloween party when she was 6 years old.",
"info_zh": "这是露娜6岁时参加万圣节派对的照片,她获得了很多糖果!",
"date_begin": 1020,
"date_end": 1120
}, {
"id": 9,
"name_en": "Father's Day",
"name_zh": "父亲节",
"info_en": "Today is Father's Day.I send dad a beautiful bouquet of flowers.",
"info_zh": "父亲节到了,送爸爸一束美丽的鲜花!",
"date_begin": 610,
"date_end": 630,
"level_limit": 60
}, {
"id": 10,
"name_en": "Father's Day",
"name_zh": "父亲节",
"info_en": "On Father's Day,I prepared a lot of gifts for my father.",
"info_zh": "在父亲节这天,我给爸爸准备了很多的礼物。",
"date_begin": 610,
"date_end": 630,
"level_limit": 50
}, {
"id": 11,
"name_en": "Independence Day",
"name_zh": "独立日",
"info_en": "Today is Independence Day,Luna dressed up as a holiday costume,ready to go to a community party.",
"info_zh": "今天是独立日,露娜装扮了节日的装束,准备去参加社区的派对",
"date_begin": 701,
"date_end": 720
}],
"type_level": [{
"id": 501,
"name_en": "Go to the beach",
"name_zh": "去沙滩",
"info_en": "Luna had a good time on the beach!",
"info_zh": "露娜在沙滩玩得很开心!",
"level_begin": 50
}, {
"id": 502,
"name_en": "Making Chocolate",
"name_zh": "爱心巧克力",
"info_en": "Luna's making chocolate hearts.Who will receive them?",
"info_zh": "露娜在做爱心巧克力,谁会收到它呢?",
"level_begin": 30
}, {
"id": 503,
"name_en": "Hold a Dance",
"name_zh": "舞会",
"info_en": "Who will invite Luna for first dance on the ball?",
"info_zh": "舞会上,谁有幸邀请露娜跳第一支舞?",
"level_begin": 60
}, {
"id": 504,
"name_en": "Play the Guitar",
"name_zh": "弹吉他",
"info_en": "Guess which tune will James play for Luna today?",
"info_zh": "猜猜詹姆斯今天想为露娜弹什么曲子?",
"level_begin": 90
}, {
"id": 505,
"name_en": "Make Up",
"name_zh": "化妆",
"info_en": "Luna is dressing herself up.Who will she hang out with?",
"info_zh": "露娜在精心打扮,她待会儿要去见谁?",
"level_begin": 120
}, {
"id": 506,
"name_en": "Watch Stars",
"name_zh": "看星星",
"info_en": "Puff feels like seeing a starry night with Luna.",
"info_zh": "普夫好像和它的主人一起看星空呢!",
"level_begin": 160
}, {
"id": 507,
"name_en": "Candlelight Dinner",
"name_zh": "烛光晚餐",
"info_en": "Who will Luna have candlelight dinner with?",
"info_zh": "邀请露娜共进晚餐的那位是谁呢?",
"level_begin": 200
}]
}