porridgechen890的笔记

梦里不知身是客

去前了解

位置:天池位于新疆阜康县境内的博格达峰下的半山腰,东距乌鲁木齐110公里,海拔1980米。是一个天然的高山湖泊。

怎么去

自驾

跟团

新疆西域户外:

  1. 联系人:千雪13565975751、塔河无疆13999255413

  2. 上车地点和出发时间:

    第一站:8:20分乌鲁木齐扬子江路全季酒店门前(红十月文化宫站附近)

    第二站:8:30分红山南航明珠酒店门前

    第三站:8:40分新医路医科大学门前天桥下

    第四站:8:50分铁路局北京路二宫体育馆门前

    第五站:9:00卡子湾52路公交车停车场警务室旁河滩路边。

    返程时间:17:00左右稍事休息返回乌鲁木齐。18:30左右抵达乌鲁木齐红山南航明珠国际酒店散团

  3. 活动出发的前一天晚19点到22点之间导游会电话或者手机短信通知活动的坐车车号、上车时间、上车地点等信息,到时请保持电话畅通或者留意手机短信。如果过了晚上22点30分仍然没有收到旅行社或者导游的任何通知,请打电话或者微信联系报名领队。

  4. 跟团需要确定的问题:

    [x] 22号周五有团不?天天有

    [x] 多少钱?168元

    [x] 哪里出发?几点出发?

    [x] 几点回程?17:00

    [x] 退票怎么扣钱?

班车

公众号:“天山行新疆公路客运”,点“在线购票”,始发站选“高铁汽车站”,目的地选择“天池往返”。

发车时间有09:30和10:30两个,09:30的车是18:00回,实际上可能会延迟半小时。

往返是坐统一辆车,需记住车牌。

起点:乌鲁木齐高铁国际汽车客运站(高铁站对面)。备注:从红山公园去这个汽车站,11公里,打车约花费20元,耗时18分钟。

路程:68km

耗时:1.5h

票价:60元/人,往返。

其他:座位是先到先得,不会按订单座位坐。

哪里买门票

线下

凭身份证现场购买。

线上

公众号:“玩转天山天池”、“天山零距离”

公众号玩转天山天池买票细节:(1)游玩当天17:00前可预定;(2)门票分为3个时间段,08:00-11:30、11:30-14:30、14:30-19:00

小程序:“寻梦天山 做客天池”

网站:www.xjtstc.com

门票多少钱

门票价格:旺季(4月1日~10月31日):95元/人。淡季(11月1日~3月31日):45元/人。

区间车:60元。

区间车分两段,第一段是门票包含的,坐40min。第二段区间车需要单独购买,坐12min,不建议坐,用走代替。

门票和区间车是一起收的。所以咱们11月去就是收105元/人。

怎么玩

池边走走

大门口买票->第一段区间车上山->第一个下车点(民族风情园)徒步走到天山天池->打卡天池石碑->飞龙涧瀑布->西王母神庙->返回第一个下车点等区间车回大门口->大门口,全程用时4h。

环天池走一圈,约3到4小时。

登顶

马牙山半腰到山顶,可以看云海、天池全貌、博格达峰。

下索道后到山顶仍有一段距离,需要走路。

220元/人,往返。

游船

100元/人,往返,20min。

邮轮

40元/人,往返

注意事项

雨雪天气,道路结冰,闭园。

最近一次是11月14号不开园,11月15号积雪清理完毕开园。

去之前可以打官方客服电话咨询,400-8706-110

电话卡

  1. 马来西亚打中国

    13300+86+对方手机号(座机号码前0去掉)如:中国座机0755-12345678则需要拨打133008675512345678

    中国手机13812345678则需拨打133008613812345678

  2. 中国打马来西亚

    0060+对方手机号码(号码首位0去掉)如:马来西亚手机0172328222则需拨打0060172328222

  3. 套餐内容

    digi,7天30G流量,马打中60分钟,马本土接听免费。

    查话费余额*126#,更换中文服务*128*1*1#,流量使用情况*200*1*1#

银行卡

  1. 境外取款知识

    个人持境内银行卡在境外提取现金,本人名下银行卡(所有银行,含信用卡、附属卡)合计每个自然年度不得超过等值10万元人民币。超过年度额度的,本年及次年将被暂停持境内银行卡在境外提取现金。

    每卡每日额度统一为等值1万元人民币。

    银联卡境外ATM每卡每日可累计取现10笔,超过将无法取现成功。

    境外取款时,ATM机所属银行可能还会收取附加服务费。

  2. 平安银行境外取款手续费

    通过银联网络,15元人民币每笔。

  3. 本人平安银行信息

    日累计限额5000元。

  4. 本人招商银行信用卡信息

    累计限额8000元。

  1. 项目级build.gradle

    classpath 'com.android.tools.build:gradle:8.1.2'
  2. gradle/wrapper/gradle-wrapper.properties

    gradle-8.0-bin.zip
  3. 模块级build.gradle

    android{
        namespace 'xxx.xxx.xxx'
    }
  4. gradle.properties

    org.gradle.jvmargs=-Xms1024m -Xmx1024m -Xmx4000M
    android.defaults.buildfeatures.buildconfig=true
    android.nonTransitiveRClass=false
    android.nonFinalResIds=false
  5. cocos2d目录下的build.gradle。cocos2d\cocos\platform\android\libcocos2dx

    android{
        namespace 'org.cocos2dx.lib'
        buildFeatures {
        aidl true
    }
    }

其他

打开广告SDK的日志

LogUtils.setDebug(true);
SDKAgent.setDebug(true);

1瓶三得利无糖乌龙茶。

我做的土豆牛肉焖饭。一是水放多了,二是煮久了,洋葱什么的变得不好吃了。

吃的杀猪粉那家的饭。今天从DDG那里得知拆骨肉就是猪头肉。

问题描述

写一段代码,删除C++文件里的注释。包含单行注释、多行注释,需要正确处理换行的字符串,如:

std::string s = "ni hao \
shi jie";

解决思路

  1. 读入代码文件,得到字符串。遍历字符串,根据字符和字符之间的关系来判断是否遇到了注释。

如果第一个字符遇到了/,然后判断第二个字符是/*

如果第二个字符是/,接下来就判断是否遇到了换行符。

如果第二个字符是*,接下来就判断是否遇到了*,如果是就继续判断是否遇到了/

第一版:处理标准格式的单行注释和多行注释

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>

std::string f(const std::string & str)
{
	std::string ret;
	int state = 0;
	for (char c : str)
	{
		if (0 == state)
		{
			if ('/' == c)
			{
				//状态0中遇到/,说明可能会遇到注释,则进入状态1
				state = 1;
			}
			else
			{
				ret += c;
			}
		}
		else if (1 == state)
		{
			if ('*' == c)
			{
				//状态1中遇到*,说明进入多行注释,则进入状态2
				state = 2;
			}
			else if ('/' == c)
			{
				//状态1中遇到/,说明进入单行注释,则进入状态4
				state = 4;
			}
			else
			{
				//状态1中没有遇到*或/,说明/是除号,则恢复状态0
				ret += '/';
				ret += c;
				state = 0;
			}
		}
		else if (2 == state)
		{
			if ('*' == c)
			{
				//状态2中遇到*,说明多行注释可能要结束,则进入状态3
				state = 3;
			}
			else
			{
				//状态2中不是遇到*,说明多行注释还在继续,则维持状态2
			}
		}
		else if (3 == state)
		{
			if ('/' == c)
			{
				//状态3中遇到/,说明多行注释结束,则恢复状态0
				state = 0;
				//删除注释后补个换行
				ret += '\n';
			}
		}
		else if (4 == state)
		{
			if ('\n' == c)
			{
				//状态4中遇到换行符,说明单行注释结束,则进入状态0
				state = 0;
				//删除注释后补个换行
				ret += '\n';
			}
			else
			{
				//维持状态4
			}
		}
	}
	return ret;
}

int main()
{
	std::ifstream fin("input.cpp");
	std::ofstream fout("output.cpp");

	if (!fin.is_open())
	{
		std::cerr << "Open input file failed." << std::endl;
		return 0;
	}

	if (!fout.is_open())
	{
		std::cerr << "Open output file failed." << std::endl;
		return 0;
	}

	std::string str_in;
	std::string str_line;

	while (getline(fin, str_line))
	{
		str_in += str_line;
		str_in += '\n';
	}

	std::cout << str_in << std::endl;

	std::string str_out = f(str_in);

	std::cout << str_out << std::endl;

	fout.write(str_out.c_str(), str_out.size());

	fin.close();
	fout.close();

	system("pause");
	return 0;
}

第二版:处理特殊格式的多行注释

当state由0->1->2->3时,也就是遇到了/**之后,下一个字符不一定就是/,举例说明,如:/*abc**//*abc*d*//**a/*/

所以,需要在 else if (3 == state) {} 的大括号里加如下代码。如果不加会得到什么结果,可自行测试。

else if (3 == state)
{
	if ('/' == c)
	{
		//状态3中遇到/,说明多行注释结束,则恢复状态0
		state = 0;
		//删除注释后补个换行
		ret += '\n';
	}
	else if ('*' == c)
	{
		//状态3中继续遇到*,说明多行注释可能要结束,维持状态3
	}
	else
	{
		//状态3中不是遇到/或*,说明多行注释只是遇到*,还要继续,则恢复状态2
		state = 2;
	}
}

第三版:处理字符串常量

如果有代码std::string str_test = "//nihao";,会得到std::string str_test = ",这显然是错误的。

所以我们需要增加对字符串常量的处理,修改方法:在if (0 == state){}的大括号里增加对双引号的判断。

if (0 == state)
{
	if ('/' == c)
	{
		//状态0中遇到/,说明可能会遇到注释,则进入状态1
		state = 1;
	}
	else if ('\"' == c)
	{
		//状态0中遇到",说明进入字符串常量中,则进入状态7
		state = 7;
		ret += c;
	}
	else
	{
		ret += c;
	}
}
else if (7 == state)
{
	if ('\"' == c)
	{
		//状态7中遇到"字符,说明字符串常量结束,则恢复状态0
		state = 0;
	}
	ret += c;
}

上面的修改还不行,没有对字符串常量含有反斜杠的情况(即转义字符)做特殊处理,假如有个双引号的转义字符,如std::string test = "ni\"//hao";,程序会在遇到第二个双引号时认为字符串常量读取完毕了。所以继续修改如下:

else if (7 == state)
{
	/*在状态7中,遇到反斜杠、双引号需要特殊处理
	反斜杠代表下一个字符是转义字符,直接跳过判断
	双引号代表字符串结束
	除上述两种情况外,不做任何处理*/
	if ('\\' == c)
	{
		//状态7中遇到\,说明字符串常量里遇到转义字符,则进入状态8
		state = 8;
		ret += c;
	}
	else if ('\"' == c)
	{
		//状态7中遇到"字符,说明字符串常量结束,则恢复状态0
		state = 0;
		ret += c;
	}
	else
	{
		ret += c;
	}
}
else if (8 == state)
{
	//状态8中遇到任何字符,都恢复状态7
	//即转义字符结束
	state = 7;
	ret += c;
}

第四版:处理双引号这个特殊的字符常量

测试代码:

char ch1 = '\"';
//test
char ch2 = '\"';

如果没有增加对转义双引号这个字符的处理的话,上面代码两个双引号中间的代码会被认为属于字符串常量。

修改方法:在if (0 == state){}的大括号里增加对单引号的判断

if (0 == state)
{
	if ('/' == c)
	{
		//状态0中遇到/,说明可能会遇到注释,则进入状态1
		state = 1;
	}
	else if ('\'' == c)
	{
		//状态0中遇到',说明进入字符常量中,则进入状态5
		state = 5;
		ret += c;
	}
	else if ('\"' == c)
	{
		//状态0中遇到",说明进入字符串常量中,则进入状态7
		state = 7;
		ret += c;
	}
	else
	{
		ret += c;
	}
}
else if (5 == state)
{
	if ('\\' == c)
	{
		//状态5中遇到\,说明遇到转义字符,则进入状态6
		state = 6;
	}
	else if ('\'' == c)
	{
		//状态5中遇到',说明字符常量结束,则进入状态0
		state = 0;
	}
	else
	{
		//进到这里说明正在读取那个不是转义字符的字符,维持状态5
	}
	ret += c;
}
else if (6 == state)
{
	//状态6中遇到任何字符,都恢复状态5
	//即转义字符结束
	state = 5;
	ret += c;
}

总结

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>

std::string f(const std::string & str)
{
	std::string ret;
	int state = 0;
	for (char c : str)
	{
		if (0 == state)
		{
			if ('/' == c)
			{
				//状态0中遇到/,说明可能会遇到注释,则进入状态1
				state = 1;
			}
			else if ('\'' == c)
			{
				//状态0中遇到',说明进入字符常量中,则进入状态5
				state = 5;
				ret += c;
			}
			else if ('\"' == c)
			{
				//状态0中遇到",说明进入字符串常量中,则进入状态7
				state = 7;
				ret += c;
			}
			else
			{
				ret += c;
			}
		}
		else if (1 == state)
		{
			if ('*' == c)
			{
				//状态1中遇到*,说明进入多行注释,则进入状态2
				state = 2;
			}
			else if ('/' == c)
			{
				//状态1中遇到/,说明进入单行注释,则进入状态4
				state = 4;
			}
			else
			{
				//状态1中没有遇到*或/,说明/是除号,则恢复状态0
				ret += '/';
				ret += c;
				state = 0;
			}
		}
		else if (2 == state)
		{
			if ('*' == c)
			{
				//状态2中遇到*,说明多行注释可能要结束,则进入状态3
				state = 3;
			}
			else
			{
				//状态2中不是遇到*,说明多行注释还在继续,则维持状态2
			}
		}
		else if (3 == state)
		{
			if ('/' == c)
			{
				//状态3中遇到/,说明多行注释结束,则恢复状态0
				state = 0;
				//删除注释后补个换行
				ret += '\n';
			}
			else if ('*' == c)
			{
				//状态3中继续遇到*,说明多行注释可能要结束,维持状态3
			}
			else
			{
				//状态3中不是遇到/或*,说明多行注释只是遇到*,还要继续,则恢复状态2
				state = 2;
			}
		}
		else if (4 == state)
		{
			if ('\n' == c)
			{
				//状态4中遇到换行符,说明单行注释结束,则进入状态0
				state = 0;
				//删除注释后补个换行
				ret += '\n';
			}
			else
			{
				//维持状态4
			}
		}
		else if (5 == state)
		{
			if ('\\' == c)
			{
				//状态5中遇到\,说明遇到转义字符,则进入状态6
				state = 6;
			}
			else if ('\'' == c)
			{
				//状态5中遇到',说明字符常量结束,则进入状态0
				state = 0;
			}
			else
			{
				//进到这里说明正在读取那个不是转义字符的字符,维持状态5
			}
			ret += c;
		}
		else if (6 == state)
		{
			//状态6中遇到任何字符,都恢复状态5
			//即转义字符结束
			state = 5;
			ret += c;
		}
		else if (7 == state)
		{
			/*在状态7中,遇到反斜杠、双引号需要特殊处理
			反斜杠代表下一个字符是转义字符,直接跳过判断
			双引号代表字符串结束
			除上述两种情况外,不做任何处理*/
			if ('\\' == c)
			{
				//状态7中遇到\,说明字符串常量里遇到转义字符,则进入状态8
				state = 8;
				ret += c;
			}
			else if ('\"' == c)
			{
				//状态7中遇到"字符,说明字符串常量结束,则恢复状态0
				state = 0;
				ret += c;
			}
			else
			{
				ret += c;
			}
		}
		else if (8 == state)
		{
			//状态8中遇到任何字符,都恢复状态7
			//即转义字符结束
			state = 7;
			ret += c;
		}
	}
	return ret;
}

int main()
{
	std::ifstream fin("input.cpp");
	std::ofstream fout("output.cpp");

	if (!fin.is_open())
	{
		std::cerr << "Open input file failed." << std::endl;
		return 0;
	}

	if (!fout.is_open())
	{
		std::cerr << "Open output file failed." << std::endl;
		return 0;
	}

	std::string str_in;
	std::string str_line;

	while (getline(fin, str_line))
	{
		str_in += str_line;
		str_in += '\n';
	}

	std::cout << str_in << std::endl;

	std::string str_out = f(str_in);

	std::cout << str_out << std::endl;

	fout.write(str_out.c_str(), str_out.size());

	fin.close();
	fout.close();

	system("pause");
	return 0;
}

问题描述

地毯元素,怎么实现类似液体一样的连接效果?

实现效果图

图片素材

备注:一个格子是140*140

  1. 左上角:footcloth_angle,其他几个角可以通过旋转得到。

  2. 底部:footcloth_bar_down

  3. 左边:footcloth_bar_left

  4. 右边:footcloth_bar_right

  5. 顶部:footcloth_bar_top

  6. 中心:footcloth_center

  7. 桥:footcloth_bridge

  8. 凹陷进去的角:footcloth_inner

代码

#ifndef __CARPET_NODE_H__
#define __CARPET_NODE_H__

#include "cocos2d.h"

struct CarpetBridge
{
	CarpetBridge(cocos2d::Vec2 a0, cocos2d::Vec2 a1);
	bool is_same(CarpetBridge st);
	cocos2d::Vec2 p0;
	cocos2d::Vec2 p1;
};

struct CarpetInner
{
	CarpetInner(cocos2d::Vec2 a0, cocos2d::Vec2 a1, cocos2d::Vec2 a2);
	bool is_same(CarpetInner st);
	cocos2d::Vec2 p0;
	cocos2d::Vec2 p1;
	cocos2d::Vec2 p2;
};

class CarpetNode : public cocos2d::Node
{
public:
	static CarpetNode * create(float af_cell_width, std::vector<std::vector<bool>> av_grid);
	void updateWithGrid(std::vector<std::vector<bool>> av_grid);
protected:
	bool init(float af_cell_width, std::vector<std::vector<bool>> av_grid);
	void initGrid();
	void drawGrid();
	void drawCell(int x, int y);
	void cleanCell(int x, int y);
	void drawInner();
	void drawBridge();
	void drawCellLeftTop(int x, int y);
	void drawCellRightTop(int x, int y);
	void drawCellRightBottom(int x, int y);
	void drawCellLeftBottom(int x, int y);
private:
	bool isInGrid(int x, int y);
	bool isSelectedCell(int x, int y);
	void addInner(CarpetInner st);
	void addBridge(CarpetBridge st);
private:
	float m_cell_width;
	// 棋盘数据,每个格子都是0和1两种状态
	std::vector<std::vector<bool>> m_data_arr;
	// 每个格子的中心放一个节点,从来显示四个角落的精灵
	std::vector<std::vector<cocos2d::Node*>> m_ui_arr;
	std::vector<CarpetInner> m_inner_arr;
	cocos2d::Node* m_inner_root;
	std::vector<CarpetBridge> m_bridge_arr;
	cocos2d::Node* m_bridge_root;
};

#endif
#include "CarpetNode.h"

CarpetBridge::CarpetBridge(cocos2d::Vec2 a0, cocos2d::Vec2 a1)
{
	p0 = a0;
	p1 = a1;
}

bool CarpetBridge::is_same(CarpetBridge st)
{
	if (p0 == st.p0 && p1 == st.p1)
	{
		return true;
	}

	if (p1 == st.p0 && p0 == st.p1)
	{
		return true;
	}

	return false;
}

CarpetInner::CarpetInner(cocos2d::Vec2 a0, cocos2d::Vec2 a1, cocos2d::Vec2 a2)
{
	p0 = a0;
	p1 = a1;
	p2 = a2;
}

bool CarpetInner::is_same(CarpetInner st)
{
	std::vector<cocos2d::Vec2> v;
	v.push_back(st.p0);
	v.push_back(st.p1);
	v.push_back(st.p2);

	bool b_found_same = false;

	for (auto it = v.begin(); it != v.end(); it++)
	{
		if (p0 == *it)
		{
			b_found_same = true;
			v.erase(it);
			break;
		}
	}

	if (!b_found_same)
	{
		return false;
	}

	b_found_same = false;

	for (auto it = v.begin(); it != v.end(); it++)
	{
		if (p1 == *it)
		{
			b_found_same = true;
			v.erase(it);
			break;
		}
	}

	if (!b_found_same)
	{
		return false;
	}

	if (p2 != v[0])
	{
		return false;
	}

	return true;
}

CarpetNode * CarpetNode::create(float af_cell_width, std::vector<std::vector<bool>> av_grid)
{
	auto p = new (std::nothrow) CarpetNode();
	if (p && p->init(af_cell_width, av_grid))
	{
		p->autorelease();
		return p;
	}
	delete p;
	p = nullptr;
	return nullptr;
}

bool CarpetNode::init(float af_cell_width, std::vector<std::vector<bool>> av_grid)
{
	if (!cocos2d::Node::init())
	{
		return false;
	}

	m_cell_width = af_cell_width;
	m_data_arr = av_grid;
	// 给每个格子添加一个根节点
	initGrid();
	// 创建一个显示凹陷拐角的节点
	m_inner_root = cocos2d::Node::create();
	this->addChild(m_inner_root);
	// 创建一个显示桥形连接的节点
	m_bridge_root = cocos2d::Node::create();
	this->addChild(m_bridge_root);
	// 绘制棋盘
	drawGrid();

	return true;
}

void CarpetNode::updateWithGrid(std::vector<std::vector<bool>> av_grid)
{
	assert(m_data_arr.size() == av_grid.size());
	for (int i = 0; i < av_grid.size(); i++)
	{
		assert(m_data_arr.at(i).size() == av_grid.at(i).size());
	}
	m_data_arr = av_grid;
	drawGrid();
}

void CarpetNode::initGrid()
{
	m_ui_arr.clear();
	for (int x = 0; x < int(m_data_arr.size()); x++)
	{
		std::vector<cocos2d::Node*> vec;
		for (int y = 0; y < int(m_data_arr.at(x).size()); y++)
		{
			auto lab = cocos2d::Label::create();
			lab->setString(cocos2d::StringUtils::format("(%d,%d)", x, y));
			lab->setPosition(cocos2d::Vec2(m_cell_width * (x + 0.5f), m_cell_width * (y + 0.5f)));
			this->addChild(lab);
			auto node = cocos2d::Node::create();
			node->setPosition(cocos2d::Vec2(m_cell_width * (x + 0.5f), m_cell_width * (y + 0.5f)));
			this->addChild(node);
			vec.push_back(node);
		}
		m_ui_arr.push_back(vec);
	}
}

void CarpetNode::drawGrid()
{
	m_inner_arr.clear();
	m_bridge_arr.clear();

	for (int x = 0; x < int(m_data_arr.size()); x++)
	{
		for (int y = 0; y < int(m_data_arr.at(x).size()); y++)
		{
			cleanCell(x, y);
			if (m_data_arr[x][y])
			{
				drawCell(x, y);
			}
		}
	}

	drawInner();
	drawBridge();
}

void CarpetNode::drawCell(int x, int y)
{
	// 根据x坐标和y坐标,绘制左上角、右上角、右下角、左下角
	drawCellLeftTop(x, y);
	drawCellRightTop(x, y);
	drawCellRightBottom(x, y);
	drawCellLeftBottom(x, y);
}

void CarpetNode::cleanCell(int x, int y)
{
	assert(m_ui_arr.at(x).at(y));
	auto nod = m_ui_arr.at(x).at(y);
	nod->removeAllChildren();
}

void CarpetNode::drawInner()
{
	m_inner_root->removeAllChildren();

	for (auto st : m_inner_arr)
	{
		float xmin = st.p0.x;
		float ymin = st.p0.y;
		xmin = std::min(xmin, st.p1.x);
		ymin = std::min(ymin, st.p1.y);
		xmin = std::min(xmin, st.p2.x);
		ymin = std::min(ymin, st.p2.y);

		float xmax = st.p0.x;
		float ymax = st.p0.y;
		xmax = std::max(xmax, st.p1.x);
		ymax = std::max(ymax, st.p1.y);
		xmax = std::max(xmax, st.p2.x);
		ymax = std::max(ymax, st.p2.y);

		assert(xmax - xmin == 1);
		assert(ymax - ymin == 1);

		float rotation = 0;
		std::vector<cocos2d::Vec2> vec_temp;
		vec_temp.push_back(st.p0);
		vec_temp.push_back(st.p1);
		vec_temp.push_back(st.p2);
		cocos2d::Vec2 check_point(xmin, ymin);
		if (vec_temp.end() == std::find(vec_temp.begin(), vec_temp.end(), check_point))
		{
			rotation = 270;
		}
		check_point = cocos2d::Vec2(xmin, ymax);
		if (vec_temp.end() == std::find(vec_temp.begin(), vec_temp.end(), check_point))
		{
			rotation = 0;
		}
		check_point = cocos2d::Vec2(xmax, ymax);
		if (vec_temp.end() == std::find(vec_temp.begin(), vec_temp.end(), check_point))
		{
			rotation = 90;
		}
		check_point = cocos2d::Vec2(xmax, ymin);
		if (vec_temp.end() == std::find(vec_temp.begin(), vec_temp.end(), check_point))
		{
			rotation = 180;
		}

		auto spr_inner = cocos2d::Sprite::create("TestFootcloth/footcloth_inner.png");
		spr_inner->setRotation(rotation);
		spr_inner->setPosition(cocos2d::Vec2(m_cell_width * xmax, m_cell_width * ymax));
		m_inner_root->addChild(spr_inner);
	}
}

void CarpetNode::drawBridge()
{
	m_bridge_root->removeAllChildren();

	for (auto st : m_bridge_arr)
	{
		float rotation = 0;
		auto p0 = st.p0;
		auto p1 = st.p1;
		// 往右上
		if (p0.x + 1 == p1.x && p0.y + 1 == p1.y)
		{
			rotation = 90;
		}
		// 往右下
		if (p0.x + 1 == p1.x && p0.y - 1 == p1.y)
		{
			rotation = 0;
		}
		// 往左下
		if (p0.x - 1 == p1.x && p0.y - 1 == p1.y)
		{
			rotation = 90;
		}
		// 往左上
		if (p0.x - 1 == p1.x && p0.y + 1 == p1.y)
		{
			rotation = 0;
		}
		int xmax = std::max(p0.x, p1.x);
		int ymax = std::max(p0.y, p1.y);

		auto spr_bridge = cocos2d::Sprite::create("TestFootcloth/footcloth_bridge.png");
		spr_bridge->setRotation(rotation);
		spr_bridge->setPosition(cocos2d::Vec2(m_cell_width * xmax, m_cell_width * ymax));
		m_bridge_root->addChild(spr_bridge);
	}
}

void CarpetNode::drawCellLeftTop(int x, int y)
{
	assert(m_ui_arr.at(x).at(y));
	auto nod = m_ui_arr.at(x).at(y);

	bool a = false;
	int xa = x - 1;
	int ya = y;
	a = isSelectedCell(xa, ya);

	bool b = false;
	int xb = x - 1;
	int yb = y + 1;
	b = isSelectedCell(xb, yb);

	bool c = false;
	int xc = x;
	int yc = y + 1;
	c = isSelectedCell(xc, yc);

	if (false == a && false == b && false == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_angle.png");
		spr->setAnchorPoint(cocos2d::Vec2(1, 0));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(0);
		nod->addChild(spr);
	}

	if (false == a && false == b && true == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_bar_left.png");
		spr->setAnchorPoint(cocos2d::Vec2(1, 0));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(0);
		nod->addChild(spr);
	}

	if (false == a && true == b && false == c)
	{
		addBridge(CarpetBridge(cocos2d::Vec2(x, y), cocos2d::Vec2(x - 1, y + 1)));
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_angle.png");
		spr->setAnchorPoint(cocos2d::Vec2(1, 0));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(0);
		nod->addChild(spr);
	}

	if (true == a && false == b && false == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_bar_top.png");
		spr->setAnchorPoint(cocos2d::Vec2(1, 0));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(0);
		nod->addChild(spr);
	}

	if (false == a && true == b && true == c)
	{
		addInner(CarpetInner(cocos2d::Vec2(x - 1, y + 1), cocos2d::Vec2(x, y + 1), cocos2d::Vec2(x, y)));
	}

	if (true == a && false == b && true == c)
	{
		addInner(CarpetInner(cocos2d::Vec2(x, y + 1), cocos2d::Vec2(x, y), cocos2d::Vec2(x - 1, y)));
	}

	if (true == a && true == b && false == c)
	{
		addInner(CarpetInner(cocos2d::Vec2(x, y), cocos2d::Vec2(x - 1, y), cocos2d::Vec2(x - 1, y + 1)));
	}

	if (true == a && true == b && true == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_center.png");
		spr->setPosition(cocos2d::Vec2(0 - m_cell_width / 4.0f, 0 + m_cell_width / 4.0f));
		spr->setRotation(0);
		nod->addChild(spr);
	}
}

void CarpetNode::drawCellRightTop(int x, int y)
{
	assert(m_ui_arr.at(x).at(y));
	auto nod = m_ui_arr.at(x).at(y);

	bool a = false;
	int xa = x;
	int ya = y + 1;
	a = isSelectedCell(xa, ya);

	bool b = false;
	int xb = x + 1;
	int yb = y + 1;
	b = isSelectedCell(xb, yb);

	bool c = false;
	int xc = x + 1;
	int yc = y;
	c = isSelectedCell(xc, yc);

	if (false == a && false == b && false == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_angle.png");
		spr->setAnchorPoint(cocos2d::Vec2(1, 0));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(90);
		nod->addChild(spr);
	}

	if (false == a && false == b && true == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_bar_top.png");
		spr->setAnchorPoint(cocos2d::Vec2(0, 0));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(0);
		nod->addChild(spr);
	}

	if (false == a && true == b && false == c)
	{
		addBridge(CarpetBridge(cocos2d::Vec2(x, y), cocos2d::Vec2(x + 1, y + 1)));
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_angle.png");
		spr->setAnchorPoint(cocos2d::Vec2(1, 0));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(90);
		nod->addChild(spr);
	}

	if (true == a && false == b && false == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_bar_right.png");
		spr->setAnchorPoint(cocos2d::Vec2(0, 0));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(0);
		nod->addChild(spr);
	}

	if (false == a && true == b && true == c)
	{
		addInner(CarpetInner(cocos2d::Vec2(x + 1, y + 1), cocos2d::Vec2(x + 1, y), cocos2d::Vec2(x, y)));
	}

	if (true == a && false == b && true == c)
	{
		addInner(CarpetInner(cocos2d::Vec2(x + 1, y), cocos2d::Vec2(x, y), cocos2d::Vec2(x, y + 1)));
	}

	if (true == a && true == b && false == c)
	{
		addInner(CarpetInner(cocos2d::Vec2(x, y), cocos2d::Vec2(x, y + 1), cocos2d::Vec2(x + 1, y + 1)));
	}

	if (true == a && true == b && true == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_center.png");
		spr->setPosition(cocos2d::Vec2(0 + m_cell_width / 4.0f, 0 + m_cell_width / 4.0f));
		spr->setRotation(0);
		nod->addChild(spr);
	}
}

void CarpetNode::drawCellRightBottom(int x, int y)
{
	assert(m_ui_arr.at(x).at(y));
	auto nod = m_ui_arr.at(x).at(y);

	bool a = false;
	int xa = x + 1;
	int ya = y;
	a = isSelectedCell(xa, ya);

	bool b = false;
	int xb = x + 1;
	int yb = y - 1;
	b = isSelectedCell(xb, yb);

	bool c = false;
	int xc = x;
	int yc = y - 1;
	c = isSelectedCell(xc, yc);

	if (false == a && false == b && false == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_angle.png");
		spr->setAnchorPoint(cocos2d::Vec2(1, 0));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(180);
		nod->addChild(spr);
	}

	if (false == a && false == b && true == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_bar_right.png");
		spr->setAnchorPoint(cocos2d::Vec2(0, 1));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(0);
		nod->addChild(spr);
	}

	if (false == a && true == b && false == c)
	{
		addBridge(CarpetBridge(cocos2d::Vec2(x, y), cocos2d::Vec2(x + 1, y - 1)));
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_angle.png");
		spr->setAnchorPoint(cocos2d::Vec2(1, 0));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(180);
		nod->addChild(spr);
	}

	if (true == a && false == b && false == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_bar_down.png");
		spr->setAnchorPoint(cocos2d::Vec2(0, 1));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(0);
		nod->addChild(spr);
	}

	if (false == a && true == b && true == c)
	{
		addInner(CarpetInner(cocos2d::Vec2(x + 1, y - 1), cocos2d::Vec2(x, y - 1), cocos2d::Vec2(x, y)));
	}

	if (true == a && false == b && true == c)
	{
		addInner(CarpetInner(cocos2d::Vec2(x, y - 1), cocos2d::Vec2(x, y), cocos2d::Vec2(x + 1, y)));
	}

	if (true == a && true == b && false == c)
	{
		addInner(CarpetInner(cocos2d::Vec2(x, y), cocos2d::Vec2(x + 1, y), cocos2d::Vec2(x + 1, y - 1)));
	}

	if (true == a && true == b && true == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_center.png");
		spr->setPosition(cocos2d::Vec2(0 + m_cell_width / 4.0f, 0 - m_cell_width / 4.0f));
		spr->setRotation(0);
		nod->addChild(spr);
	}
}

void CarpetNode::drawCellLeftBottom(int x, int y)
{
	assert(m_ui_arr.at(x).at(y));
	auto nod = m_ui_arr.at(x).at(y);

	bool a = false;
	int xa = x;
	int ya = y - 1;
	a = isSelectedCell(xa, ya);

	bool b = false;
	int xb = x - 1;
	int yb = y - 1;
	b = isSelectedCell(xb, yb);

	bool c = false;
	int xc = x - 1;
	int yc = y;
	c = isSelectedCell(xc, yc);

	if (false == a && false == b && false == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_angle.png");
		spr->setAnchorPoint(cocos2d::Vec2(1, 0));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(270);
		nod->addChild(spr);
	}

	if (false == a && false == b && true == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_bar_down.png");
		spr->setAnchorPoint(cocos2d::Vec2(1, 1));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(0);
		nod->addChild(spr);
	}

	if (false == a && true == b && false == c)
	{
		addBridge(CarpetBridge(cocos2d::Vec2(x, y), cocos2d::Vec2(x - 1, y - 1)));
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_angle.png");
		spr->setAnchorPoint(cocos2d::Vec2(1, 0));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(270);
		nod->addChild(spr);
	}

	if (true == a && false == b && false == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_bar_left.png");
		spr->setAnchorPoint(cocos2d::Vec2(1, 1));
		spr->setPosition(cocos2d::Vec2(0, 0));
		spr->setRotation(0);
		nod->addChild(spr);
	}

	if (false == a && true == b && true == c)
	{
		addInner(CarpetInner(cocos2d::Vec2(x - 1, y - 1), cocos2d::Vec2(x - 1, y), cocos2d::Vec2(x, y)));
	}

	if (true == a && false == b && true == c)
	{
		addInner(CarpetInner(cocos2d::Vec2(x - 1, y), cocos2d::Vec2(x, y), cocos2d::Vec2(x, y - 1)));
	}

	if (true == a && true == b && false == c)
	{
		addInner(CarpetInner(cocos2d::Vec2(x, y), cocos2d::Vec2(x, y - 1), cocos2d::Vec2(x - 1, y - 1)));
	}

	if (true == a && true == b && true == c)
	{
		auto spr = cocos2d::Sprite::create("TestFootcloth/footcloth_center.png");
		spr->setPosition(cocos2d::Vec2(0 - m_cell_width / 4.0f, 0 - m_cell_width / 4.0f));
		spr->setRotation(0);
		nod->addChild(spr);
	}
}

bool CarpetNode::isInGrid(int x, int y)
{
	if (x < 0 || y < 0)
		return false;
	if (x >= int(m_data_arr.size()))
		return false;
	if (y >= int(m_data_arr.at(x).size()))
		return false;

	return true;
}

bool CarpetNode::isSelectedCell(int x, int y)
{
	if (!isInGrid(x, y))
		return false;

	return m_data_arr.at(x).at(y);
}

void CarpetNode::addInner(CarpetInner st)
{
	bool flag = false;

	for (auto st0 : m_inner_arr)
	{
		if (st0.is_same(st))
		{
			flag = true;
			break;
		}
	}

	if (!flag)
	{
		m_inner_arr.push_back(st);
	}
}

void CarpetNode::addBridge(CarpetBridge st)
{
	bool flag = false;

	for (auto st0 : m_bridge_arr)
	{
		if (st0.is_same(st))
		{
			flag = true;
			break;
		}
	}

	if (!flag)
	{
		m_bridge_arr.push_back(st);
	}
}
#pragma once
#ifndef __TEST_FOOTCLOTH_SCENE_H__

#include "cocos2d.h"
#include "CarpetNode.h"

class TestFootclothScene : public cocos2d::Scene
{
public:
	static TestFootclothScene* create();
	virtual bool init() override;
	void initGridData();
	void initBackground();
	bool onTouchBegan(cocos2d::Touch * t, cocos2d::Event * e);
private:
	int m_grid_num;
	float m_cell_w;
	std::vector<std::vector<bool>> m_d_arr;
	std::vector<std::vector<cocos2d::Sprite*>> m_spr_arr;
	CarpetNode* m_carpet_node;
};

#endif // !__TEST_FOOTCLOTH_SCENE_H__
#include "TestFootclothScene.h"

TestFootclothScene * TestFootclothScene::create()
{
	auto p = new (std::nothrow) TestFootclothScene();
	if (p && p->init())
	{
		p->autorelease();
		return p;
	}
	delete p;
	p = nullptr;
	return nullptr;
}

bool TestFootclothScene::init()
{
	if (!cocos2d::Scene::init())
	{
		return false;
	}

	// 棋盘为5行5列
	m_grid_num = 5;
	// 棋盘单元格的宽高是140像素
	m_cell_w = 140;
	// 生成棋盘数据(二维数组),即给 m_d_arr 赋值
	initGridData();
	// 生成棋盘背景图
	initBackground();
	// 创建地毯节点,传入单元格的边长和棋盘数据
	m_carpet_node = CarpetNode::create(m_cell_w, m_d_arr);
	this->addChild(m_carpet_node, 1);
	// 添加触摸响应
	auto listener = cocos2d::EventListenerTouchOneByOne::create();
	listener->onTouchBegan = CC_CALLBACK_2(TestFootclothScene::onTouchBegan, this);
	_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

	return true;
}

void TestFootclothScene::initGridData()
{
	m_d_arr.clear();
	for (int i = 0; i < m_grid_num; i++)
	{
		std::vector<bool> vec_row;
		for (int j = 0; j < m_grid_num; j++)
		{
			vec_row.push_back(false);
		}
		m_d_arr.push_back(vec_row);
	}
}

void TestFootclothScene::initBackground()
{
	m_spr_arr.clear();
	for (int x = 0; x < m_grid_num; x++)
	{
		std::vector<cocos2d::Sprite*> vec_row;
		for (int y = 0; y < m_grid_num; y++)
		{
			std::string str1 = "TestFootcloth/map_cell_1.png";
			if ((x % 2 == 1 && y % 2 == 0) || (x % 2 == 0 && y % 2 == 1))
			{
				str1 = "TestFootcloth/map_cell_2.png";
			}
			auto spr = cocos2d::Sprite::create(str1);
			spr->setAnchorPoint(cocos2d::Vec2::ZERO);
			spr->setPosition(cocos2d::Vec2(x * 140, y * 140));
			this->addChild(spr);
			vec_row.push_back(spr);
		}
		m_spr_arr.push_back(vec_row);
	}
}

bool TestFootclothScene::onTouchBegan(cocos2d::Touch * t, cocos2d::Event * e)
{
	auto world_pos = t->getLocation();

	for (int i = 0; i < m_grid_num; i++)
	{
		for (int j = 0; j < m_grid_num; j++)
		{
			auto spr = m_spr_arr.at(i).at(j);
			float sprw = spr->getContentSize().width;
			float sprh = spr->getContentSize().height;
			auto node_pos = spr->convertToNodeSpace(world_pos);
			float posx = node_pos.x;
			float posy = node_pos.y;

			if (0 < posx && posx < sprw && 0 < posy && posy < sprh)
			{
				cocos2d::log("click(%d %d)", i, j);
				m_d_arr.at(i).at(j) = !m_d_arr.at(i).at(j);
				m_carpet_node->updateWithGrid(m_d_arr);
				return false;
			}
		}
	}
	return false;
}

新版本的Android Studio在新建工程时,没法选择Java语言,默认是kotlin。可以通过下面的方法来选择Java语言。

步骤

  1. 在新建 project 的时候不要选 Empty Activity,会默认启用 kotlin,无法选择 java。

    选择 No Activity 或 Empty Views Activity 来新建项目,前者没有 activity,后者有默认的 main acitivty。

  2. 如果想要使用旧版的 build.gradle,就按照下图选择。

  3. 在运行的时候,遇到了下面的错误:

    Caused by: org.gradle.workers.internal.DefaultWorkerExecutor$WorkExecutionException: A failure occurred while executing com.android.build.gradle.internal.tasks.CheckAarMetadataWorkAction

    解决办法是把 implementation 'androidx.appcompat:appcompat:1.7.0' 改成 implementation 'androidx.appcompat:appcompat:1.3.0'

https://developers.google.com/admob

Android->RewardedAd->测试广告ca-app-pub-3940256099942544/5224354917->加载广告失败,提示信息如下:

{
  "Code": 0,
  "Message": "Unable to obtain a JavascriptEngine.",
  "Domain": "com.google.android.gms.ads",
  "Cause": "null",
  "Response Info": {
    "Response ID": "null",
    "Mediation Adapter Class Name": "",
    "Adapter Responses": [],
    "Response Extras": {}
  }
}

是广告拦截器拦截了广告,在手机里修改如下设置:

0%