#include "RUUtils.h" #include "RUPlatform.h" #include #include "RUMapRhombusGrid.h" #include "RUQCoreLayer.h" #include "RUQCoreBtn.h" NS_RU_BEGIN int randomInt(int start, int end){ CCASSERT(end >= start, "----------ERROR:随机值范围不对"); int len = end - start + 1; int value = rand() % len; return value + start; } int randomIndexByRatio(const vector &array){ //权重随机 int allWeight = 0; for (int i = 0; i < array.size(); i++) { allWeight += array.at(i); }; int randomNum = randomInt(1, allWeight); int flagWeight = 0; for (int i = 0; i < array.size(); i++) { int tWeight = array.at(i); flagWeight += tWeight; if (randomNum <= flagWeight) { return i; }; }; return 0; } Vec2 up(const Vec2 &logicPos){ return Vec2(logicPos.x, logicPos.y - 1); } Vec2 down(const Vec2 &logicPos){ return Vec2(logicPos.x, logicPos.y + 1); } Vec2 left(const Vec2 &logicPos){ return Vec2(logicPos.x - 1, logicPos.y); } Vec2 right(const Vec2 &logicPos){ return Vec2(logicPos.x + 1, logicPos.y); } Vec2 upLeft(const Vec2 &logicPos){ return Vec2(logicPos.x - 1, logicPos.y - 1); } Vec2 upRight(const Vec2 &logicPos){ return Vec2(logicPos.x + 1, logicPos.y -1); } Vec2 downLeft(const Vec2 &logicPos){ return Vec2(logicPos.x - 1, logicPos.y + 1); } Vec2 downRight(const Vec2 &logicPos){ return Vec2(logicPos.x + 1, logicPos.y + 1); } void LockScreenForSec(float sec) { redutils::Platform::getInstance()->reportLog("LockScreenForSec start"); Layer* layer = Layer::create(); Scene* scene = Director::getInstance()->getRunningScene(); scene->addChild(layer); EventDispatcher* eventDispatcher = Director::getInstance()->getEventDispatcher(); auto listen = EventListenerTouchOneByOne::create(); listen->onTouchBegan = [](Touch*touch, Event*event){return true;}; listen->setSwallowTouches(true); eventDispatcher->addEventListenerWithSceneGraphPriority(listen,layer); layer->runAction(Sequence::create(DelayTime::create(sec),CallFunc::create(CC_CALLBACK_0(Layer::removeFromParent,layer)),nullptr)); redutils::Platform::getInstance()->reportLog("LockScreenForSec end"); } void LockScreenByTag(int tag) { #define LOCAL_ZORDER_TOP (100000) Layer* layer = Layer::create(); Scene* scene = Director::getInstance()->getRunningScene(); scene->addChild(layer, LOCAL_ZORDER_TOP, tag); EventDispatcher* eventDispatcher = Director::getInstance()->getEventDispatcher(); auto listen = EventListenerTouchOneByOne::create(); listen->onTouchBegan = [](Touch*touch, Event*event){return true;}; listen->setSwallowTouches(true); eventDispatcher->addEventListenerWithSceneGraphPriority(listen, layer); } void unLockScreenByTag(int tag) { Scene* scene = Director::getInstance()->getRunningScene(); Node* node = scene->getChildByTag(tag); if(node){ node->removeFromParent(); } } void splitString(const std::string& s, std::vector& v, const std::string& c) { if (s.length() == 1 && s != c) { v.push_back(s); return; } std::string::size_type pos1, pos2; pos2 = s.find(c); pos1 = 0; while(std::string::npos != pos2) { v.push_back(s.substr(pos1, pos2-pos1)); pos1 = pos2 + c.size(); pos2 = s.find(c, pos1); } if(pos1 != s.length()) v.push_back(s.substr(pos1)); } ProgressTimer* createCCProgressTimeFromCCSprite(Sprite* sprite,const ProgressArgs& args){ auto midPoint = args.midPoint; auto barChangeRate = args.barChangeRate; auto reverse = args.reverse; auto progressType = args.progressType; auto progressTime = ProgressTimer::create(sprite); progressTime->setType(progressType); progressTime->setMidpoint(midPoint); progressTime->setBarChangeRate(barChangeRate); progressTime->setReverseDirection(reverse); progressTime->setScaleX(sprite->getScaleX()); progressTime->setScaleY(sprite->getScaleY()); progressTime->setPosition(sprite->getPosition()); progressTime->setRotation(sprite->getRotation()); sprite->getParent()->addChild(progressTime); sprite->setVisible(false); return progressTime; } int getGTLevel(kGTLevelType type, int baseLevel) { int gtLevel = baseLevel; switch (type) { case kGTLevelType::DEFAULT: gtLevel = -gtLevel; break; case kGTLevelType::MINIGAME: gtLevel += 1000; break; case kGTLevelType::BI_ROOM: gtLevel += 9000; break; case kGTLevelType::BI_TASK: gtLevel += 10000; break; default: break; } return -1 * gtLevel; } bool protobufLoad(const string& fileName, google::protobuf::MessageLite* data){ std::string writablePath = FileUtils::getInstance()->getWritablePath(); string file = writablePath + "/" + fileName; if(FileUtils::getInstance()->isFileExist(file)){ Data datas = FileUtils::getInstance()->getDataFromFile(file); data->ParseFromArray(datas.getBytes(), datas.getSize()); return true; } return false; } void protobufSave(const string& fileName, google::protobuf::MessageLite* data){ std::string writablePath = FileUtils::getInstance()->getWritablePath(); string file = writablePath + "/" + fileName; fstream output(file, ios::out | ios::trunc | ios::binary); data->SerializeToOstream(&output); output.close(); } vector getRhombusGridFromPolygon(const Vec2& ori, vector poly, MapRhombusGrid* rhombusGrid, bool bStrictMode) { /*占用网格,要考虑包容或相交 1.多边形包含网格 判断网格中有点在多边形内部 2.网格包含多边形 判断多边形中有点在网格内部。 (1,2)可以用射线法判断 3.相交 枚举多边形边和网格变判断相交即可。 线段相交 */ Size gridSize = rhombusGrid->getRhombusSize(); #define max(x,y) (x>y?x:y) auto isIntersect = [](const pair& line1, const pair& line2) -> bool { double x1 = line1.first.x, y1 = line1.first.y, x2 = line1.second.x, y2 = line1.second.y; double x3 = line2.first.x, y3 = line2.first.y, x4 = line2.second.x, y4 = line2.second.y; double d = (y2 - y1) * (x4 - x3) - (x2 - x1) * (y4 - y3); if (d == 0) { return false; } double s = ((x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1)) / d; double t = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / (-d); return s >= 0 && s <= 1 && t >= 0 && t <= 1; }; auto checkGridPoly = [=](const vector& gridPoly, const vector& poly)->bool{ for(auto gridPoint:gridPoly){ if(isPointInPolygon(gridPoint, poly))return true; } for(auto polyPoint:poly){ if(isPointInPolygon(polyPoint, gridPoly))return true; } int ngridPoly = (int)gridPoly.size(), npoly = (int)poly.size(); for(int i=0;ires; int n = (int)poly.size(); for(int i=0;imaxX)maxX=item.x; if(item.ymaxY)maxY=item.y; } auto ld = rhombusGrid->getGridPosition(Vec2(minX,minY)); auto ru = rhombusGrid->getGridPosition(Vec2(maxX,maxY)); for(int i=max(0,ld.x-1);i<=ru.x+1;i++){ for(int j=max(0,ld.y-1);j<=ru.y+1;j++){ if((i+j)%2==0) continue; auto gridCenter = rhombusGrid->getGridCenter(Vec2(i,j)); vector gridPoly; if (bStrictMode) { gridPoly.push_back(gridCenter+Vec2(0,gridSize.height/2)); gridPoly.push_back(gridCenter+Vec2(gridSize.width/2,0)); gridPoly.push_back(gridCenter+Vec2(0,-gridSize.height/2)); gridPoly.push_back(gridCenter+Vec2(-gridSize.width/2,0)); } else { float ratio = 0.2; { auto p = gridCenter+Vec2(0,gridSize.height/2)*ratio; float w = gridSize.width * (1.0-ratio) * ratio; gridPoly.push_back(Vec2(p.x - w/2.0, p.y)); gridPoly.push_back(Vec2(p.x + w/2.0, p.y)); } { auto p = gridCenter+Vec2(gridSize.width/2,0)*ratio; float h = gridSize.height * (1.0-ratio) * ratio; gridPoly.push_back(Vec2(p.x, p.y + h/2.0)); gridPoly.push_back(Vec2(p.x, p.y - h/2.0)); } { auto p = gridCenter+Vec2(0,-gridSize.height/2)*ratio; float w = gridSize.width * (1.0-ratio) * ratio; gridPoly.push_back(Vec2(p.x + w/2.0, p.y)); gridPoly.push_back(Vec2(p.x - w/2.0, p.y)); } { auto p = gridCenter+Vec2(-gridSize.width/2,0)*ratio; float h = gridSize.height * (1.0-ratio) * ratio; gridPoly.push_back(Vec2(p.x, p.y - h/2.0)); gridPoly.push_back(Vec2(p.x, p.y + h/2.0)); } } if (checkGridPoly(gridPoly, poly)) { res.push_back(Vec2(i,j)); } } } return res; } int getLocalToday() { // 获取当前的系统时间 auto now = std::chrono::system_clock::now(); // 转换为 time_t std::time_t now_t = std::chrono::system_clock::to_time_t(now); // 转换为本地时间 std::tm* now_local = std::localtime(&now_t); // 计算到1970-1-1的天数,考虑润年,但是不用考虑400年的问题 int days = now_local->tm_yday + (now_local->tm_year - 70) * 365 + (now_local->tm_year - 69) / 4; return days; } ccBezierConfig calBezierConfig(const Vec2& startPoint, const Vec2& endPoint, string stencil, BezierParams* config) { ccBezierConfig res; res.endPosition = endPoint; // 计算endPoint相对于startPoint是哪个象限(方向) float valueX = endPoint.x > startPoint.x ? 1.0 : -1.0; float valueY = endPoint.y > startPoint.y ? 1.0 : -1.0; float distance = startPoint.distance(endPoint); // cos,sin为直线和x轴(1,0)或(-1,0)的夹角值,两值均为正值 float cos = (endPoint.x - startPoint.x) * valueX / distance; float sin = sqrt(1 - pow(cos, 2)); float bezierCur = config->bezierCur; float bezierDec = config->bezierDec; float basisPointRation = config->basisPointRatio; // 下沉后下弧线飞行到目标点 if (stencil == "Subsidence") { // 控制点 2 为两点之间线段的中垂线上的一点,13象限左移x-,y+,24象限左移为x-,y-。此外sin,cos值外翻。 float controlPoint2X = ((endPoint.x - startPoint.x) * basisPointRation + startPoint.x) + valueX * bezierCur * distance * sin; float controlPoint2Y = ((endPoint.y - startPoint.y) * basisPointRation + startPoint.y) - valueY * bezierCur * distance * cos; // 控制点1 为两点延长线的一点 float controlPoint1X = startPoint.x - valueX * bezierDec * distance * cos; float controlPoint1Y = startPoint.y - valueY * bezierDec * distance * sin; res.controlPoint_1 = Vec2(controlPoint1X, controlPoint1Y); res.controlPoint_2 = Vec2(controlPoint2X, controlPoint2Y); } return res; } void iterateParticles(Node* pNode, std::function cb) { if (pNode == nullptr) { return; } cocos2d::Vector children = pNode->getChildren(); for_each(children.begin(), children.end(), [=](Node* child) { ParticleSystem* part = dynamic_cast(child); if (part != nullptr) { cb(part); } if (child != nullptr) { iterateParticles(child, cb); } }); } void iterateNode(Node* pNode, std::function cb) { if (pNode == nullptr) { return; } cocos2d::Vector children = pNode->getChildren(); for_each(children.begin(), children.end(), [=](Node* child) { cb(child); iterateNode(child, cb); }); } void changeNodeParent(Node* node, Node* parent) { if (node->getParent() == parent) { return; } Vec2 pos = node->getParent()->convertToWorldSpace(node->getPosition()); node->retain(); node->removeFromParentAndCleanup(false); parent->addChild(node); node->setPosition(parent->convertToNodeSpace(pos)); node->release(); return; } bool isPointOnLine(const Vec2& point, const Vec2& lineStart, const Vec2& lineEnd) { float minX = fmin(lineStart.x, lineEnd.x); float maxX = fmax(lineStart.x, lineEnd.x); float minY = fmin(lineStart.y, lineEnd.y); float maxY = fmax(lineStart.y, lineEnd.y); // Check if the point's x and y are within the line's bounds if (point.x < minX || point.x > maxX || point.y < minY || point.y > maxY) { return false; } // Check if the point is on the line float dx = lineEnd.x - lineStart.x; float dy = lineEnd.y - lineStart.y; if (abs(dx * (point.y - lineStart.y) - dy * (point.x - lineStart.x)) < 0.00001) { return true; } return false; } bool isPointInPolygon(const Vec2& point, const std::vector& polygon) { bool inside = false; auto i = polygon.begin(); auto j = std::prev(polygon.end()); // last vertex for (; i != polygon.end(); j = i++) { if (isPointOnLine(point, *i, *j)) { // The point is on the boundary return true; } if (((i->y > point.y) != (j->y > point.y)) && (point.x < (j->x - i->x) * (point.y - i->y) / (j->y - i->y) + i->x)) { inside = !inside; } } return inside; } Json getConfigWithName(const std::string& jsonName) { Json json; const string path = jsonName; string cfg; Data datas = FileUtils::getInstance()->getDataFromFile(path); unsigned char* data = datas.getBytes(); ssize_t len = datas.getSize(); string err = ""; cfg = string(data,data+len); json = Json::parse(cfg, err); CCASSERT(err == "", "load config failed !" + jsonName); if (!json.is_null()) { return json["main_sheet"]; } return json; } std::list parseAsFloatList(const string& v) { // str使用,分割的一系列float类型 std::list ret; int startPos = 0; int nPos = v.find(","); string conf = v.substr(startPos, nPos); while (nPos != string::npos) { ret.push_back(Value(conf).asFloat()); startPos = nPos + 1; nPos = v.find(",", startPos); conf = v.substr(startPos, nPos-startPos); } // 最后一个 ret.push_back(Value(conf).asFloat()); return ret; } std::vector parseAsStringList(const string& v, const string& sep) { // str使用,分割的一系列float类型 std::vector ret; int startPos = 0; int nPos = v.find(sep); string conf = v.substr(startPos, nPos); while (nPos != string::npos) { ret.push_back(conf); startPos = nPos + 1; nPos = v.find(sep, startPos); conf = v.substr(startPos, nPos-startPos); } // 最后一个 ret.push_back(conf); return ret; } std::vector parseAsIntList(const string& v) { // str使用,分割的一系列float类型 std::vector ret; int startPos = 0; int nPos = v.find(","); string conf = v.substr(startPos, nPos); while (nPos != string::npos) { ret.push_back(Value(conf).asInt()); startPos = nPos + 1; nPos = v.find(",", startPos); conf = v.substr(startPos, nPos-startPos); } // 最后一个 ret.push_back(Value(conf).asInt()); return ret; } std::vector> parseAsPairList(const string& v, const string& sep) { // str使用,分割的一系列float类型 std::vector> ret; auto nPos = v.find(sep); std::size_t startPos = 0; string conf = v.substr(startPos, nPos); while (nPos != string::npos) { { auto nPos1 = conf.find(":"); ret.push_back({cocos2d::Value(conf.substr(0, nPos1)), cocos2d::Value(conf.substr(nPos1+1))}); } startPos = nPos + 1; nPos = v.find(sep, startPos); conf = v.substr(startPos, nPos-startPos); } // 最后一个 { auto nPos1 = conf.find(":"); ret.push_back({cocos2d::Value(conf.substr(0, nPos1)), cocos2d::Value(conf.substr(nPos1+1))}); } return ret; } std::vector> parseAsPairStringList(const string& v) { // str使用,分割的一系列string类型 std::vector> ret; int startPos = 0; int nPos = v.find(","); string conf = v.substr(startPos, nPos); while (nPos != string::npos) { { int nPos1 = conf.find(":"); ret.push_back({conf.substr(0, nPos1), conf.substr(nPos1+1)}); } startPos = nPos + 1; nPos = v.find(",", startPos); conf = v.substr(startPos, nPos-startPos); } // 最后一个 { int nPos1 = conf.find(":"); ret.push_back({conf.substr(0, nPos1), conf.substr(nPos1+1)}); } return ret; } int parseStringAsTime(const std::string& str) { std::string tStr = str; int secs = 0; auto pos = tStr.find("d"); if (pos != std::string::npos) { int d = std::stoi(tStr.substr(0, pos)); secs = d * 3600 * 24; tStr = tStr.substr(pos+1); } pos = tStr.find("h"); if (pos != std::string::npos) { int h = std::stoi(tStr.substr(0, pos)); secs += h * 3600; tStr = tStr.substr(pos+1); } pos = tStr.find("m"); if (tStr.find("m") != std::string::npos) { int m = std::stoi(tStr.substr(0, pos)); secs += m * 60; tStr = tStr.substr(pos+1); } if (tStr.size() > 0) { secs += std::stoi(tStr); } return secs; } void showTimingInLable(cocos2d::Label* label, std::function getCooldown, bool showHours, bool hourAlways) { if (label->isScheduled("SCH_Update_Time")) { label->unschedule("SCH_Update_Time"); } auto updateLb = [=](int secsCooldown){ // 设置时间 int days = secsCooldown / (3600*24); int hours = (secsCooldown % (3600*24)) / 3600; int mins = (secsCooldown % 3600) / 60; int secs = secsCooldown % 60; std::string str; if (days > 0) { str = Value(days).asString() + "d " + Value(hours).asString() + "h"; } else { if (showHours) { if (hours > 0 || hourAlways) { if (hours >= 10) { str = Value(hours).asString(); } else { if (hourAlways) { str = "0"; } str += Value(hours).asString(); } str += ":"; } } else { mins += hours*60; } if (mins >= 10) { str += Value(mins).asString(); } else { str += "0" + Value(mins).asString(); } str += ":"; if (secs >= 10) { str += Value(secs).asString(); } else { str += "0" + Value(secs).asString(); } } label->setString(str); }; updateLb(getCooldown()); label->schedule([=](float){ int secs = getCooldown(); if (secs >= 0) { updateLb(secs); } // 小于0的时候不更新,由调用者自己决定行为 }, 0.2, 10000000, 0.2, "SCH_Update_Time"); } Node* readNodeWithAdapt(redream::REDReader * reader, const char* resName, bool bUseAdapt) { std::string name = resName; Node* node = nullptr; if (bUseAdapt) { name = resName + Value("_720x1540").asString(); node = reader->readNodeGraphFromFile(name.c_str()); } if (node == nullptr) { node = reader->readNodeGraphFromFile(resName); if (node == nullptr) { name = resName + Value("_680x1200").asString(); node = reader->readNodeGraphFromFile(name.c_str()); } } return node; } QCoreLayer* readLayer(const char* resName, bool bUseAdapt) { // FIXME: 不能写到qcorelayer里面去很尴尬 std::string name = resName; if (bUseAdapt) { name = resName + Value("_720x1540.redream").asString(); if (FileUtils::getInstance()->isFileExist(name)) { return QCoreLayer::Layer(name); } } if (FileUtils::getInstance()->isFileExist(std::string(resName)+".redream")) { return QCoreLayer::Layer(resName); } name = resName + Value("_680x1200.redream").asString(); if (FileUtils::getInstance()->isFileExist(resName)) { return QCoreLayer::Layer(resName); } return nullptr; } void smartScaleHeight(Node* layer, Size designSize) { // 两边留出余量:振屏的时候不穿帮 Size frameSize = Director::getInstance()->getVisibleSize() + Size(30, 0); Size contentSize = layer->getContentSize(); float scaleX = layer->getScaleX(); float scaleY = layer->getScaleY(); contentSize.width *= scaleX; contentSize.height *= scaleY; if ((frameSize.height / frameSize.width) < (contentSize.height / contentSize.width)) { // content 的宽度需要检查 float targetScale = frameSize.width / contentSize.width; layer->setScaleX(targetScale * scaleX); layer->setScaleY(targetScale * scaleY); } else if ((frameSize.height / frameSize.width) > (contentSize.height / contentSize.width)) { // content 的高度需要检查 float targetScale = frameSize.height / contentSize.height; layer->setScaleX(targetScale * scaleX); layer->setScaleY(targetScale * scaleY); } } NS_RU_END