权限认证,也就是访问控制,即在应用中控制谁能访问哪些资源
在权限认证中,最核心的三个要素是:权限,角色和用户 (资源也算一个要素,但不是最核心的)
权限,即操作资源的 权限,比如访问某个页面,以及对某个模块的数据的添加,修改,删除,查看的权利(整合以后,其实就是一些对URL请求的权限)
角色,是权限的集合,一种角色可以包含多种权限(将权限赋给角色)
用户,在Shiro中,代表访问系统的用户,即Subject(将角色赋给用户)
英文好的,可以去看官方文档介绍: http://shiro.apache.org/authorization.html
首先配置ini文件:
1 2 3 4 5 |
|
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
|
演示结果自己跑一遍就出来啦
配置ini文件:
1 2 3 4 5 6 7 8 9 10 11 |
|
测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
|
讲了几个org.apache.shiro.subject.Subject的函数。
其实官方文档都有介绍的
更加详细的介绍可以去官网查看: http://shiro.apache.org/authorization.html
首先你的Java版本5+才能集成shiro的注解
RequiresAuthentication注解需要在当前会话中对当前的Subject进行身份验证,以便访问或调用该注解的类/实例/方法。
也就是要求当前Subject已经在当前的Session中被验证通过才能被访问或调用
比如:
1 2 3 4 5 6 |
|
基本等同于下面的代码:
1 2 3 4 5 6 7 8 |
|
要求当前的Subject是一个'guest'(游客),也就是说,必须是在之前的session中没有被验证或被记住才能被访问和调用
例如:
1 2 3 4 5 6 |
|
基本等价于下面的代码:
1 2 3 4 5 6 7 8 9 10 11 |
|
RequiresPermissions注解要求当前Subject允许一个或多个权限来执行带注释的方法。
也就是说,必须有这个权限才能访问
例如:
1 2 3 4 5 6 |
|
基本等价于:
1 2 3 4 5 6 7 8 9 |
|
RequiresRoles注解要求当前Subject拥有所有指定的角色。如果它们没有所有的角色,则不会执行该方法,并抛出AuthorizationException
例如:
1 2 3 4 5 |
|
基本等同于以下代码:
1 2 3 4 5 6 7 8 9 |
|
RequiresUser注解 需要当前的Subject是一个应用程序的用户 才能被所注解的类/实例/方法访问或者调用。
一个"应用程序用户"被定义一个拥有已知身份,或在当前session中通过验证被确认,或者在之前的session中的"RememberMe"服务被记住
也就是说,必须是某个用户
例如:
1 2 3 4 5 6 |
|
基本等同于下面代码:
1 2 3 4 5 6 7 8 9 10 11 |
|
必须添加shiro-web.jar
在jsp页面中引入:
1
|
|
用户没有身份验证时显示相应信息,即游客访问信息
例如:
1 2 3 |
|
在这里<shiro:guest>标签内的文字,如果用户没有登录才会显示出来,也就是游客
只有在当前Subject被认为是“用户”时,用户标记才会显示其包装内容。
在这个上下文中,“用户”被定义为一个具有已知身份的主题,要么是成功的身份验证,要么是来自“记住我”的服务。
注意,这个标记与经过身份验证的标记有语义上的不同,它比这个标记更加严格。
例如:
1 2 3 |
|
user标签和guest标签逻辑相反
仅当当前用户在当前会话中成功验证时才显示正文内容。
它比“用户”标签更具限制性。它在逻辑上与“notAuthenticated”标记相反。
只有在当前Subject在当前会话中成功验证的情况下,经过身份验证的标记才会显示其包装内容。
它是一个比用户更严格的标记,用来保证敏感工作流中的标识。也就是说,通过记住我登录的无法访问到!!!
例如:
1 2 3 |
|
如果当前Subject在当前会话中尚未成功验证,则未验证标记将显示其包装内容。
也就是用户没有身份验证通过,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证这个notAuthenticated标签!
例如:
1 2 3 |
|
输出用户信息,会调用toString()方法
例如:
1
|
|
相当于调用以下代码:
1
|
|
如果你不想获取所有的,比如在用户名和用户id之间,我想获取用户id,可以通过下面这种方式:
1
|
|
等同于:
1
|
|
但是,当遇到复杂的情况时,上面的就不行了,毕竟可能不止一个Integer,这个时候就可以通过属性名了。
通过getter方法获取的
例如:
1
|
|
相当于下面的代码:
1
|
|
或者说,可以结合type属性:
1
|
|
也就是如下代码的逻辑:
1
|
|
只有当当前Subject被分配指定角色时,hasRole标记才会显示其包装内容
例如:
1 2 3 |
|
如果当前Subject没有分配指定的角色,则将显示其包装内容。
1 2 3 |
|
lacksRole标签与hasRole标签的逻辑相反。
如果当前Subject从一个由逗号分隔的角色名称列表中具有了任一指定的角色,那么hasAnyRole标记将显示其包装内容。
1 2 3 |
|
只要有其中一个角色,即显示主体内容
如果当前Subject有权限则显示其包装的内容
1 2 3 |
|
如果当前Subject没有该权限则显示其包装的内容
1 2 3 |
|
lacksPermission标签与hasPermission标签的逻辑相反
例如: queryPrinter权限-查询权限
1
|
|
基本等同于:
1
|
|
第二种方式基本不用,用第一种方式即可
下面使用":“用于分隔权限字符串下一部分的特殊字符。
1 2 3 |
|
即可配置多个权限
也可以用多值来配置:
1
|
|
验证查询权限:
1
|
|
比如我们有这些权限:
1
|
|
相当于:
1
|
|
使用第二种方法使用通配符比显式地列出动作要更好,因为如果以后向应用程序添加了一个新操作,则不需要更新在该部分中使用通配符的权限。
还可以在通配符权限字符串的任何部分使用通配符令牌
1
|
|
所有资源的view权限
也就是说对“foo:view”(或其他的:view)的任何权限检查将返回true
通配符权限的另一个常见用法是建立实例级访问控制列表。
在这个权限中,您将使用三个部分——第一个是域,第二个是动作,第三个是被执行的实例(标识)。
1 2 |
|
比如你拥有printer的query权限,打印机的id为lp7200,也就是拥有这类printer的query权限
如果您将这些权限授予用户,那么它们就可以在特定的实例上执行特定的行为。然后你可以在代码中做一个检查:
1 2 3 |
|
1
|
|
也就是说,具有所有printer的print权限,相当于前面的单个资源的多个权限
1
|
|
1
|
|
1
|
|
query和print之间用逗号隔开
在实际开发中,基本上用不到实例级别的权限控制
关于权限分配的最后一件事是:末尾丢失的部分意味着用户可以访问与该部分对应的所有值。换句话说,
1 2 3 |
|
1 2 3 |
|
但是注意!
1 2 3 4 |
|
因为这不是末尾的*
虽然权限分配使用通配符构造相当多(“printer:*”=打印到任何printer),但在运行时的权限检查应该始终基于可能的最特定的权限字符串。
比如:如果用户有一个用户界面,他们想要打印一个文档到lp7200打印机,你应该检查用户是否允许执行这个代码
1 2 3 |
|
这个检查非常具体,并且明确地反映了用户在那个时候正在尝试做什么。
但是,如下代码是不对的:
1 2 3 |
|
因为第二个示例说“您必须能够打印到任何打印机,以便执行以下代码块”。但请记住,“printer:print”等同于“printer:print:*”!
因此,这是一个不正确的检查。
如果当前用户没有能力打印到任何打印机,但他们确实有打印的能力,比如lp7200和epsoncolor打印机。
然而,上面的第二个例子永远不会允许他们打印到lp7200打印机,即使他们已经获得了这种能力!
因此,经验法则是在执行权限检查时使用最特殊的权限字符串。
当然,如果您真的只想执行代码块,如果用户被允许打印到任何打印机(可能),那么第二个方法可能是应用程序中的另一个有效的检查。
您的应用程序将决定什么检查是有意义的,但是一般来说,越具体越好。
为什么运行时权限检查应该尽可能具体,但是权限分配可以更通用一些呢?
这是因为权限检查是由隐含逻辑计算的,而不是平等检查。
也就是说,如果用户被分配给"user:“权限,这意味着用户可以执行"user:view"操作。字符串"user:"显然不等于"user:view",但前者暗示后者。"user:*"描述了由"user:view"定义的功能的超集。
为了支持隐含规则,所有权限都被翻译到实现org.apache.shiro.authz的对象实例的权限接口中。
这就是说,隐含逻辑可以在运行时执行,而且隐含逻辑通常比简单的字符串等式检查更复杂。
本文档中描述的所有通配符行为实际上都是由org.apache.shiro.authz.permission.WildcardPermission类实现
下面是一些通配符的权限字符串,它显示了访问的含义:
1
|
|
暗指还能删除用户的能力:
1
|
|
但是:
1
|
|
也就是说,还可以使用实例12345更新用户帐户:
1
|
|
1 2 3 |
|
授权其实就是查看有没有权限,有就授权给它
授权步骤:
1 2 3 4 5 6 7 |
|
有兴趣的可以去官网看看:http://shiro.apache.org/authorization.html
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
Subject认证主体包含两个信息:
Principals: 身份,可以是用户名,邮件,手机号码等等,只要能用来标识一个登陆主体身份的东西都可以
Credentials: 凭证(比如你说你叫张三,你凭什么说叫张三,你这个时候会拿出身份证说你就是叫张三,这个凭证和身份证差不多),常见有密码,数字证书等等
细节可以自己去官网链接查看: http://shiro.apache.org/authentication.html
1.身份凭证登录:.login(token)
2.SecurityManager - 管理者
3.4.涉及安全数据。在这里涉及到了Realm(意思是域),Shiro从Realm中获取验证数据(或者叫安全数据);
Realm有很多种类,例如常见的jdbc realm,jndi realm,text realm(上节的博客就是text Realm).
我们可以去Shiro的源码查看:
可以看到还是有比较多的。
本节讲解jdbc Realm。
既然是数据库操作,首先当然是去建数据库和表啦
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
直接拷贝进数据库运行即可(数据库文件在项目src\sql目录下)
注意事项:
表名一定要是: users
用户名列名必须是: userName(大小写不区分) **
jdbc_realm.ini配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
“;"为ini文件的注释
测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
如果验证失败会报异常,可以自己测试
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
百度百科上的介绍:
Apache Shiro(日语“堡垒(Castle)”的意思)是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理功能,可为任何应用提供安全保障 - 从命令行应用、移动应用到大型网络及企业应用。
Shiro为解决下列问题(我喜欢称它们为应用安全的四要素)提供了保护应用的API:
认证 - 用户身份识别,常被称为用户“登录”;
授权 - 访问控制;
密码加密 - 保护或隐藏数据防止被偷窥;
会话管理 - 每用户相关的时间敏感的状态。
Shiro还支持一些辅助特性,如Web应用安全、单元测试和多线程,它们的存在强化了上面提到的四个要素。
Apache Shiro官网的介绍链接:http://shiro.apache.org/introduction.html
Shiro targets what the Shiro development team calls “the four cornerstones of application security” - Authentication(身份认证), Authorization(权限控制), Session Management(Session管理), and Cryptography(加密):
Authentication: Sometimes referred to as ‘login’, this is the act of proving a user is who they say they are.
Authorization: The process of access control, i.e. determining ‘who’ has access to ‘what’.
Session Management: Managing user-specific sessions, even in non-web or EJB applications.
Cryptography: Keeping data secure using cryptographic algorithms while still being easy to use.
前面四个是核心的。
还具有Web支持,缓存,并发,伪装,"记住我"等
本节实例使用Maven,如不熟悉Maven的,建议先去学习Maven
引入Shiro的Jar包:
1 2 3 4 5 |
|
配置配置文件(放在resource文件下):
最简单的账户密码形式
1 2 3 |
|
Java-HelloWord类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
重载流插入和提取运算符的运算符函数,不能作为类的成员函数,只能作为普通函数
流插入运算符"<<“和流提取运算符”>>“也可以被用来重载。
我们可以使用cout对一个int,string等等类型的数据进行输出,我们却不可以对我们自己定义的一个类的对象进行直接输出,因为我们这个类是没有"<<“运算符的。
“<<"运算符是有两个操作数的,它是一个双目运算符,平时貌似只给了它一个操作数,形如cout<<a;我们只知道a是一个变量,是它的一个操作数,还有一个操作数其实是cout!
cout也是它的一个操作数,cout是一个在ostream类里面已经定义好了的对象,ostream类还为我们定义好了系统中已经存在的类型的输出,如int,double…..这个对象作为了它的左操作数。显然cout这个对象是不属于我们新声明的类的,但是它又需要作为第一个参数,它是没有办法调用我们这个类的成员函数的,所以只能将"<<“运算符的重载声明为友元函数。
可以为CTime类定义重载的流插入和流提取运算符。
重载之后就可以直接对CTime对象进行输入和输出:
1 2 |
|
重载流插入和提取运算符的运算符函数,不能作为类的成员函数,只能作为普通函数 这是一个规定,没有为什么
“<<"和”>>“重载的函数声明如下:
1 2 |
|
istream和ostream分别是输入流类和输出流类。cin和cout就分别是istream和ostream的对象。
注意:
重载"<<“流插入运算符的函数第一个参数和返回类型必须是ostream&类型。
重载”>>“流提取运算符的函数第一个参数和返回类型必须是istream&类型。
第二个参数是用户自定义的类
1 2 3 4 5 |
|
1 2 3 4 5 6 7 |
|
1
|
|
在重载完流插入和提取运算符后,我们就可以对该类使用<<输出数据,使用>>输入数据。这样是非常直观的。
1 2 3 4 5 6 7 8 9 10 |
|
在为CTime类重载+运算符后,我们就可以对两个CTime对象使用+运算符进行操作。
但仍然不能使用+运算符将一个CTime对象和一个int类型相加。为了实现它,我们可以先将int类型转换为一个CTime的临时对象,然后在进行相加。
如下: time + CTime(3)
CTime(3)这种形式很类似于强制类型转换,将int类型转换为CTime类型。之所以可以进行此种转换,是因为已经为CTime对象定义了具有一个int类型参数的构造函数。因此具有一个参数的构造函数可以用来做类型转换,称之为转换构造函数
有了类型转换函数,在需要CTime类型参数的地方可以使用int类型代替
1 2 3 4 5 6 |
|
如果我们期望避免这种转换,我们可以在含有一个参数的构造函数前面加上声明explicit
如:
1
|
|
这样,我们使用前面的func(10),CTime time4 = 20;的时候,编译器就会报错
类型转换函数用以将类的对象转换另一种数据类型的函数。
类型转换函数没有参数,没有返回类型。它是成员函数。
如 可以将CTime类对象转换int类型。
1
|
|
类型转换函数的声明形式:
1
|
|
下面定义一个类型转换函数:
1 2 3 4 |
|
1 2 |
|
最后面的那行输出 6:3:3的秒数
类型转换函数在平时比较少见,在这里只介绍了一下如何使用的。
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
双目运算符就是具有两个操作数的运算符。如 +、-、==等。
对双目运算符而言,成员函数重载运算符的函数参数表中只有一个参数,而用友元函数重载运算符函数参数表中含有两个参数。
1 2 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
1 2 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 6 7 8 |
|
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
被重载的运算符必须是已经存在的C++运算符,不能重载自己创建的运算符。
运算符被重载之后,原有功能仍然保留。只是扩展了原有功能。
重载不能改变运算符运算对象的个数。
+运算符具有两个操作数,在+运算符函数作为类(例如上个例子中的CTime)的成员函数的时候,有一个参数是隐含的,也就是当前的对象,使用this指针来引用。
另一个参数通过函数参数指定。
可以重载的运算符:
1 2 3 4 5 6 7 |
|
不能重载的运算符:
1 2 3 4 5 |
|
不需要重载的运算符
1
|
|
因为编译器会为每个类自动实现一个默认的赋值运算符/取地址符的成员函数
当然,我们可以重写这个默认的成员函数。
1
|
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
友元函数的运算符重载
1 2 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
赋值函数
普通函数和类的成员函数都可以作为类的友元,但什么时候应该使用普通函数,什么时候应该使用成员函数方式呢?
普通函数形式的运算符函数一般都声明为类的友元函数,用以访问类的私有数据成员。
这样可以减低开销,但破坏封装性。因此建议尽量使用成员函数形式。
一般将单目运算符重载为成员函数,将双目运算符重载为友元函数
成员函数方式要求左侧的参数要与类的类型相同。而普通函数则要求实参顺序与形参类型顺序一致。
如
有的运算符必须定义为类的成员函数
1 2 3 |
|
有的运算符不能定义为类的成员函数,只能定义为类的友元
1
|
|
运算符重载可以在函数内执行任意的操作,比如可以将+定义成两个对象相减的操作
但是这样违背我们日常使用的习惯,容易使用误用,减低程序可读性,因此必须保证重载的运算符与该运算符应用于标准数据类型时所具有的功能。
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
纹理图集(Texture)也称为精灵表(Sprite Sheet)
使用纹理图集的优点:
1、减少文件读取次数,读取一张图片比读取一推小文件要快
2、减少OpenGL ES绘制调用并且加速渲染
OpenGL ES 1.1仅仅能够使用2的n次幂大小的图片(即宽度或者高度是2、4、8、64…)。
如果采用小图片OpenGL ES1.1会分配给每个图片2的n次幂大小的内存空间,即使这张图片达不到这样的宽度和高度也会分配大于此图片的2的n次幂大小的空间。那么运用这种图片集的方式将会减少内存碎片。
虽然在Cocos2d-x v2.0后使用OpenGL ES2.0,它不会再分配2的几次幂的内存块了,但是减少读取次数和绘制的优势依然存在。
3、减少内存消耗。
4、Cocos2d-x全面支持Zwoptex和TexturePacker,所以创建和使用纹理图集是很容易的
这样一张大图,可以让美工来完成,但是记得需要记下坐标,图集中小图的左上角坐标是多少,宽和高是多少,这是需要知道的。
这是很耗时的。实际上这是可以由软件(Zwoptex和TexturePacker)来完成的。
做出来的纹理图集由两部分构成。一部分是存有纹理的,也就是大图文件。另一部分就是里面精灵/小图的坐标等信息文件
plist文件是属性列表文件,一种xml文件。每一个小图称为帧(frame),每一个frame包含了该帧的名(key),坐标,高宽。是否旋转等。这是给程序读的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
GITHUB源码下载地址:【点我进行下载】
精灵帧缓存是缓存的一种,缓存有如下几种:
1、纹理缓存(TextureCache)
使用纹理缓存可以创建纹理对象
2、精灵帧缓存(SpriteFrameCache)
和纹理图集相对应,把plist文件读到内存,到文件里面创建精灵帧缓存,然后再从精灵帧缓存中获得精灵对象,反复使用精灵对象时候,使用精灵帧缓存可以节省内存消耗
将一个图读到精灵帧缓存中,同时也会加载到纹理缓存中
3、动画缓存(AnimationCache)
动画缓存主要用于精灵动画,精灵动画中的每一帧是从动画缓存中获取的
1 2 3 4 5 6 7 |
|
清空或移除精灵帧的缓存函数:
1 2 3 4 |
|
建议初学者不要轻易使用清除缓存函数!
现在还做不了太复杂的项目,在目前这个阶段
项目描述:
我们有这样一个场景,一个背景草地,山,和一个精灵牛仔(还没学帧动画,先做个静态的)。 把这三个精灵放到一个场景中
利用精灵帧缓存完成
背景没有放到精灵图集中去,这是因为背景是不需要透明的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
魔窗官网:http://www.magicwindow.cn/
魔窗介绍就不重复了,想去了解的可以去官网看看、
1 2 3 4 |
|
可以这么理解,通过浏览器访问某一链接(可以带参数),直接在本机上打开安装的应用(通过scheme),通过配置或者参数跳转到不同的场景
首先当然是去注册账号咯。
然后进入到管理后台,也就是http://mgnt.magicwindow.cn
填写产品信息:
这里的微信分享AppID,是你集成微信分享(微信会分配给你一个appid)后需要填写的。
填写APP信息:
iOS应用的填写先不管,这里讲的是安卓。
包名就是你的项目AndroidManifest.xml里面的包名:
URL Scheme其实填写的是你的应用的唯一标识,你可以自定义,记住后面需要加://
下载地址是你没有安装应用时,访问链接后跳转的链接,一般填写应用下载地址
魔窗位信息:
不需要填写,直接点完成即可。
下面就是选择添加mLink服务,选择好产品之后,点击添加mLink服务
接下来就是填写信息了:
mLink服务名称自定义。可以有中文。
mLink服务key: 页面key只能包含英文字母,数字和下划线,且只能以英文字母或者下划线开头,且长度不得大于50
也就是mLink的唯一标识
iOS URL我现在不管。
Android URL: 第一个参数mLinkHello我是随便写的(可以自定义为其他的),我到现在都不明白配置这个有什么用。
官方文档解释为:
貌似这是一个动态参数,我没用到这个,不管,我随便填写的。
?问号后面的也是动态参数,这是我比较熟悉的传参。id和name为参数名。记得中间需要填写的是=:
这两个符号不能分开写。
点击保存即可。
不出意外的话,会这样:
现在配置完了,直接看代码吧。
首先你需要创建一个启动页(Cocos2d-x开发的游戏也可以),记得是启动页而不是首页。
在AndroidManifest.xml中配置启动页:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
首页:
1 2 3 4 5 |
|
需要跳转的页面:
1 2 3 4 5 6 7 |
|
ParaSetActivity类上的注解的值为mLink的key
实例说明,没有集成微信分享,想测试的,可以直接用mLink短链接带上参数,例如:https://aevcir.mlinks.cc/A0dY?id=1&name=chx
在浏览器中直接访问,即可跳转到ParaSetActivity页面,参数值也可在app中读出
实例中的MW_APPID请替换为自己的魔窗App Key,可以在产品管理中看到:
更多的理解,可以通过下面的实例(使用android studio开发)去看看。也可以直接下载官方的DEMO
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
创建精灵对象有多种方式,其中常用的函数如下:
1 2 3 4 5 6 7 8 9 10 |
|
无论是计算机中的CPU还是GPU,做运算做处理,它不是对图片进行处理。图片读入到计算机里,需要对图片进行解码。最后,在计算机放的东西,就可以叫做纹理!
实际上,纹理就是由图片或者计算机本身用绘图工具绘画出来的对象。这个东西本身最后的目的是为了放在图片上面,这个过程叫纹理贴图。
在实际中,我们有时候是把纹理叫成图片的。或者图片叫成纹理。一般而言,在游戏里叫纹理或纹理图片,这是没问题的
场景设计:
两个精灵(具体几个,看美工给几张图咯):
草地图片:
树图片:
这张图上有三棵树,实际上我们不需要全部用到,所以不能简单的把树图片放到草地图片上面。
而且摆放位置也不同。对于第二种图片,我们可以先读到内存里,形成一个纹理对象,然后从这个纹理对象中截图
从里面裁剪出来来创建精灵对象。
裁剪有两种方式,一是通过它的纹理缓存来裁剪。也可以从大图文件直接进行裁剪。
不管是哪种方式,我们都需要去量树的坐标,Rect的参数是一样的!
去画图工具中量坐标:
我们需要的参数是:左上角坐标,还有宽和高
从纹理中创建tree精灵:
1 2 3 4 |
|
1 2 3 4 5 6 7 |
|
平时我们玩游戏的时候,遇到游戏中loading的画面时,基本上就是在缓存纹理,经过这个步骤后,我们玩游戏会快很多。因为不会去临时加载图片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
SpringMVC-Spring-MyBatis框架
数据库:SQL SERVER 2008
以前都是用的MySQL数据库,没有出现这个问题,现在换成sql server了,结果事务没有起作用了。
经过一番测试:
排除以下几个问题:
1.数据库原因,不存在的。MySQL中只有InnoDB引擎支持事务。SqlServer2008的企业版作为收费数据库,不可能不支持事务操作。
2.异常类型不是unchecked异常,我写的异常是1/0,为了保险起见,我还抛出RuntimeException试了,结果也是没有回滚。
3.是不是配置文件的没配置好,比如Bean,比如:
1 2 3 4 5 6 7 |
|
检查几遍,排除这个原因。 4.还有一种情况,因为我以前写的都是对一个数据库的操作,现在是一个数据源多个数据库操作,当时有点怀疑我是不是少配置了什么,导致多数据库时无法启动事务,于是便还原到一个数据库,结果事务还是无效,排除此问题
经过一番折腾,在网上找到一篇文章,说原因是applicationContext.xml的父容器先于Servlet的子容器生效,将Service提前加载了。
于是验证了一下,首先去掉Service实现类的@Service注解,在spring.xml(也就是applicationContext.xml,我起名是spring.xml),配置该类的Bean:
1
|
|
结果运行之后,事务起作用了。
原因如下:
Spring容器优先加载由ServletContextListener(对应applicationContext.xml,我这里是spring.xml)产生的父容器,而SpringMVC(对应spring-mvc.xml)产生的是子容器。
子容器Controller进行扫描装配时装配的@Service注解的实例是没有经过事务加强处理,即没有事务处理能力的Service,而父容器进行初始化的Service是保证事务的增强处理能力的。如果不在子容器中将Service exclude掉,此时得到的将是原样的无事务处理能力的Service。
所以我们要在扫描的时候在子容器中将Service exclude掉就好了。
也就是在spring-mvc.xml中进行如下修改:
1 2 3 4 5 6 7 |
|
注意: 请将@Transactional注解写在实现类的方法或类上!不建议写在接口类中!
Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。
在以上解决方法中,若将@Transactional 注解写在接口上,则无法实现事务。所以请将 @Transactional 注解写在实现类中!
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
运算符重载就是对已有的运算符赋予新的含义,实现新的功能。
运算符重载,如“+”,它可以对int、float、string类型进行加法运算。
“<<"是C++中的左移运算符,但是在输出操作中与cout配合被称为流插入运算符,可以进行输出。
”>>“是右移运算符,与cin配合使用被称为流提取运算符。
它们都被称为运算符重载。
我们也可以根据我们的需要对C++中现有的运算符进行重载,来赋予这些运算符新的含义。
如CTime类,重载+运算符,实现两个CTime对象的相加。
介绍运算符重载前,我们看下如何来实现两个CTime对象相加。
CTime重载+运算符实现两个CTime对象的相加,
time1 + time2
首先需要定义一个重载的运算符函数,此后在执行被重载的运算符时,系统将自动调用该运算符函数。
运算符重载实际上是函数的重载。
运算符重载的格式:返回类型 operator运算符(参数列表)
1
|
|
重载的运算符函数可以作为一般的函数,也可以作为类的成员函数。
1
|
|
下面通过代码来看吧 普通的,通过函数来相加:
1
|
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
+号运算重载:
1
|
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
在CTime类内部定义+号重载运算符
1
|
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
1 2 3 4 5 6 7 8 9 10 |
|
结果和前面的是一样的。
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
三个表,权限表(Permission),权限组表(PermissionGroup),权限组与权限的关系表(PermissionPermissionGroupKey)
实体类就不写上来了。
原出错映射文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
这是因为主表和明细表的id字段名相同造成的。
问题的关键在于resultMap中如果不定义类似主键之类的能够区分每一条结果集的字段的话,会引起后面一条数据覆盖前面一条数据的现象。
解决方法一:
修改主表或者明细表的id名,保证不一致就行
解决方法二:
查询结果起别名
修改映射文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
如上两种方法均能解决这个问题,希望对你有帮助
有知道出现这个问题的原理的大佬欢迎在评论区解释下,O(∩_∩)O谢谢
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
CSDN博客导出工具
之前一直想把CSDN的博客导入到自己的网站中,可是由于博客比较多,后面受朋友老郭启发,就找了个时间用Java开发了这款小工具。
Had been trying to CSDN blog into their website, but because of the blog is more, inspired by my friend guo behind, will find a time this kind of small tools with Java development.
直接下载CSDNBlogExport.7z解压使用即可。
Direct download CSDNBlogExport.7z decompression can be used.
经过测试,667篇博客,开50个线程,在54秒左右可以全部导出到文件。
Tested, 667 blog, open 50 threads, in 54 seconds can all exported to a file.
博客文件导出的存储规则是:
软件运行目录\blog\年-月\年-月-日 博客标题名.markdown
Blog file exported storage rule is:
Software running directory/blog/year-month/year-month-day blog title name.markdown
CSDNBlogExport目录下是完整的程序代码
使用了WebMagic爬虫框架,本来自己写HttpURLConnection工具类也能实现的,只是比较耗时,偷个小懒,既然别人有更好的工具,为什么不用呢
技术含量呢,可以说基本没有什么,但是也是花了大半天时间做的。
中间还遇到部分玩家无法导出博客的情况,因为CSDN对于用户的链接命名分了2种情况,当时写的时候没有发现,是测试别人博客的时候发现的,经过半小时解决了这个问题。
虽然很想把这个程序完善,但是由于时间限制还是不能做太多事。
不保证本版本一直能使用下去,如果某天本程序不能使用了(肯定是CSDN对返回的数据进行了处理或者进行了权限控制),请留言或者联系我QQ:619699629或者邮箱:uifuture@uifuture.com
我会利用空闲时间跟上csdn对博客的升级,以保证能继续使用
此版本为1.0版本,希望用的朋友遇到bug,在这里留言或联系我,我会及时修复。
也欢迎朋友加入进来与我一起完善本程序。
本小程序可导出任意CSDN用户的博客,但是仅供学习使用。 免责声明:如果导出博客侵犯他人权益,引起纠纷的,一概与本人无关。
CSDNBlogExport directory is a complete program code
Used WebMagic crawler frame, original, write their own HttpURLConnection tools can be achieved only takes time, steal a little lazy, now that people have a better tools, why not
Technical content, it was basically have no what, but also spent most of time to do.
And in case of some players cannot export blog because CSDN links named points to the user for two kinds of circumstances, then write not found, is to test others while on a blog, solved the problem after half an hour.
Although very want to send this application is perfect, but due to time constraints or can’t do too many things.
Does not guarantee that this version has been able to use, if one day can’t use this program (must be CSDN on the returned data processing or access control), please leave a message or contact me QQ: 619699629 or email: uifuture@uifuture.com
I will use free time keep up with the CSDN on updating the blog, to ensure that can continue to use
This version is 1.0 version, hope to meet with friends bug, leave a message or contact me here, I’ll repair in time.
Also welcome friends to join in with me in perfect this procedure.
This small program can export any CSDN user’s blog, but only for the use of learning.
Disclaimer: if the export blog infringement of rights and interests of others, cause disputes, all has nothing to do with himself.
2017.7.31:
修复html编辑器写完博客后导出博客不全的bug
现在版本 v1.1
感谢CSDN博主[三名狂客]提出的Bug
2017.8.16:
进行版本升级,因为CSDN把一个分页的bug给堵上了,原来的版本不能使用,请下载最新版本2.0
现在版本 v2.0
感谢CSDN博主[龙腾四海365]提出的Bug
本次bug修复后,时间会延长一点,因为我在里面把分页的线程写死了,50个线程,有兴趣的可以自己扩展。
经过测试,在输入50线程时,668篇博客的爬取时间为92S。
2017.9.6:
进行版本升级,部分拥有两个id的CSDN用户无法备份博客,已进行修复,请下载最新版本2.1
现在版本 v2.1
感谢CSDN博主[沐雨浩]提示的Bug
GITHUB项目地址:【点我进行访问】
如果无法访问,请翻墙哦
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
错误如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
出错代码的MyBatis中查询语句为:
1 2 3 4 |
|
其实这是因为top后面不能跟占位符'?'号的原因,可以看调试的sql语句,mybatis为了防止注入,会先使用?号占位符。
错误解释如下:
在Java中对数据库查询时经常使用“Select Top ? * From 表名 Where 列名 = ?”的SQL语句,此时的问号是PreparedStatement预编译对象的参数占位符,需要使用setXX()系列方法对其赋值后再执行。但是,Top后面是不允许使用问号占位符的,此处的错误就是由此引起的。
解决方法:
使用$
代替#,使用#传入参数是,sql语句解析是会加上"“,当成字符串来解析,会加入占位符?,再使用setXX()方法后赋值再执行,#{}传参能防止sql注入。
而${}
这种方式 是直接传值!在这里无法使用占位符的情况下,可以使用$
,但是自己写好防范哦,以免被注入了
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
Menu - 菜单
MenuItem - 菜单项
菜单分类实际上是按照菜单项分类的
菜单和菜单项的继承关系图:
文本菜单,精灵菜单,图片菜单和开关菜单其实准确来讲,应该是:
文本菜单项,精灵菜单项,图片菜单项和开关菜单项
继承MenuItemLabel的菜单其实都是文本菜单
精灵菜单:MenuItemSprite的子类是图片菜单MenuItemImage
开关菜单:MenuItemToggle
文本菜单是菜单项只是显示文本
文本菜单类包括了MenuItemLabel、MenuItemFont和MenuItemAtlasFont。MenuItemLabel是个抽象类,具体使用的时候是使用MenuItemFont和MenuItemAtlasFont两个类。
文本菜单类MenuItemFont,它的其中一个创建函数create定义如下:
1 2 3 |
|
cocos2d帮我们做了一个宏来帮助我们传递回调函数的参数,CC_CALLBACK_n,n为回调的参数个数
1 2 3 4 5 |
|
文本菜单类MenuItemAtlasFont是基于图片集的文本菜单项,它的其中一个创建函数create定义如下:
1 2 3 4 5 6 7 8 |
|
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
GITHUB源码下载地址:【点我进行下载】
创建函数create定义:
1 2 3 4 5 6 7 |
|
创建函数create定义:
1 2 3 4 5 |
|
精灵菜单和图片菜单都有三种状态,也就是正常状态,选中状态,还有禁用状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
|
小提示:这里图片的UI坐标可以通过画图工具或者PhotoShop获得坐标
GITHUB源码下载地址:【点我进行下载】
开关菜单有两种状态,这两种状态可以用任何的图片来替代(比如精灵-只要是菜单项就可以)
函数创建:(也是菜单项)
1 2 3 4 5 |
|
简单形式的文本类型的开关菜单:
1 2 3 4 5 6 7 8 |
|
这里只是简单的文本菜单,当然也可以是精灵菜单,也可以是图片菜单…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
|
先是创建On和Off图片惨淡项->创建开关菜单->Menu
Menu 放入 Layer
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
[TOC]
const char是C风格的字符串
std::string是C++风格的字符串,它封装了const char
初始化std::string对象:
1 2 3 4 |
|
std::string 指针类型
1 2 3 4 5 |
|
把std::string 转化为const char*类型
1 2 |
|
1 2 3 4 5 6 7 8 9 |
|
(注意是两个英文下划线)
源自于Objective-C的NSString
在coco2d-x里面,凡是有两个下划线开头的,都是过渡Objective-C过来的(内存管理采用引用计数管理)
现在Cocos2d-x在慢慢去除Objective-C化
创建它的主要的静态create函数如下(工厂设计模式)
1 2 3 |
|
cocos2d::__String 转换为const cahr*类型,这种转换还是用的比较多的
1 2 |
|
const cahr* 转换为cocos2d::__Stirng类型
1 2 |
|
std::string转换为cocos2d::__String类型
1 2 |
|
cocos2d::__String转换为int类型
1 2 3 |
|
默认情况下Windows中文环境是采用GBK编码,源程序文件HelloWorldScene.cpp编码默认也是GBK,如果源程序代码中有中文,它的字符集是GBK,我们需要将中文符GBK编码转换为UTF-8编码。
源文件保存为UTF-8(不带签名的)
文件->高级保存选项
存储完之后编译,会出现这样的问题
这是由于Visual Studio对于Unicode(UTF-8无签名)识别有误,我们一般在后面添加一些英文字符,或者“啊”等特殊的中文字符。
建议不要用这种解决方式
转码GBK->UTF-8
1 2 3 4 5 6 7 8 9 10 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
其实还可以用文本文件来解决中文乱码,就是字符串从xml文件或者json中读取(注意,文本需要是UTF-8编码),然后传值,这样不会出现乱码问题
可以把标签理解为一个控件
此处的大家好和中间的COCOS2DX图片就是标签
一种是COCOS2DX这样的,可以叫美工做张图片然后放上去就可以了,静态的
另外一种是"大家好"这样的动态文字
TTF基于系统字库
1 2 3 4 5 6 7 8 9 |
|
create函数的完整定义:
1 2 3 4 5 6 |
|
const std::string& string 要显示的字符串
const std::string& fontName 字体的名字
float fontSize 字体的大小
const Size& dimensions = Size::ZERO 尺寸-放在这个所定义的矩形的大小里面
TextHAlignment hAlignment = TextHAlignment::CENTER 水平方向的中心对齐
TextVAlignment vAlignment = TextVAlignment::TOP 垂直方向的顶对齐
后面三个参数可省略,都会有默认值
在cocos2d X3.01时,认为create已经过时了,但是这种用法还是能用,可能以后会去掉
基于图集的标签
继承了:LabelProtocol-纯虚函数,相当于Java中的接口
显示的abcd的那些字母,放在一张图中了
1 2 3 4 |
|
位图字体标签,需要添加字体文件:包括一个图片集(.png)和一个字体坐标文件(.fnt)
LabelBMFont比LabelTTF快很多。LabelBMFont中的每个字符的宽度是可变的
.png很容易,叫美工做好图片就行
.fnt:
这个就不是自己能手写出来的了~~ 那么我们就需要借助工具了
(大家可以简单的学习一下工具)
创建并初始化标签
1 2 3 |
|
效果:
Cocos2d-x 3.x后推出了新的标签类Label,这种标签通过使用FreeType(开源字体引擎)来使它在不同的平台上有相同的视觉效果。
由于使用更快的缓存代理,它的渲染也将更加快速。Label还提供了描边和阴影等特效。
前面三个标签在3.0或者说3.1之后已经过时了,但是还可以用(不推荐使用了)。
推荐使用该标签类Label,该类替换了前面的三个标签类
创建Label类静态create函数常用的有如下几个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
使用实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
解决方法一:保存文件为Unicode(UTF-8无签名)
(不推荐使用)
解决方法二:写工具类,将字符串编码转换为UTF-8
参考前面的Win32平台下中文乱码问题
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
在类体中使用friend关键字对友元函数进行声明:
将非成员函数/一般函数声明为友元:
friend void func(); //func为非成员函数,不属于任何类
将其他类的成员函数声明为友元:
friend void CTime::getNum();//getNum为CTime类的成员。
在类体中使用friend关键字将某类声明为自己的友元类。
friend CTime;
好处就是方便,可以在其他类或方法直接访问私有成员
缺点:
面向对象的基本原则包括封装性和信息隐藏,而由于友元可以访问其他类的私有成员,这是对封装原则的一个破坏。因此使用友元的时候要特别慎重。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
UI坐标就是Android和iOS等应用开发的时候使用的二维坐标系。它的坐标原点是在左上角的。
UI坐标也叫视图坐标,它是和我们的OpenGL坐标是不一样的。OpenGL坐标是基于左下角的
OpenGL坐标是一种3D坐标,OpenGL是一个渲染的标准,渲染标准的坐标系是一种3D坐标系。
所以OpenGL主要是给3D世界来做渲染,但是cocos2d觉得OpenGL速度快,所以就把OpenGL拿过来了做为一个引擎,这样的话,cocos2d就使用OpenGL坐标作为默认坐标
OpenGL坐标在二维世界里,并没有什么太大的问题,不过就是Z轴基本不用。但是有时候也会用到,就是在绘制的顺序的时候,就需要Z轴了。
比如绘制两个精灵在一个位置,精灵之间会有遮挡的问题,这个就和z轴的绘制顺序有关了。
其实就是左上角,左下角之间的转换。
屏幕的高度 - OpenGL坐标 = UI坐标
屏幕的高度 - UI坐标 = OpenGL坐标
1 2 |
|
touch是触摸点(Touch)对象
在3D坐标系里,有两种坐标。一种是Z轴指向外面的坐标,一种是Z轴指向内部的坐标,如上图
指向外面的坐标称为右手坐标系
指向内部的坐标称为左手坐标系
大家用左右手演示一下就明白了。
注意大拇指指向X轴正方向,食指向上,中指弯曲
OpenGL属于右手坐标!
微软平台的Direct3D是左手坐标!
这两个是类似的技术
由于OpenGL坐标有可以分为:世界坐标和模型坐标,所以Cocos2d-x的坐标也有世界坐标和模型坐标。
举一个例子:
比如你去问路,可能有人会告诉你先向南走1000米,再向东走500米、
也可能会有人告诉你,先向右走1000米,再向左走500米、
世界坐标:
先向南走1000米,再向东走500米、也就是说以地球为参照物
模型坐标(也叫本地坐标):
先向右走1000米,再向左走500米、这里是以自身为参照物
所谓模型是什么,就是这个物体,这个精灵,也就是称为模型。
虽然cocos2d画的是2D对象,但是实际上是以3D技术来绘制的,因此还是叫模型坐标
世界坐标的整个坐标的参考系在第三方!也就是不是本身
比如:
看上图,坐标系上有ABC三个点,C是坐标原点,A参考C,B也参考C,那么,C的坐标就是A和B坐标的坐标系
所以我们把以C为参考的坐标(也就是以第三方为参考系的坐标)称为世界坐标
所以A的坐标是(5,5),B的坐标是(6,4)
采用A的模型坐标来描述B的位置:
我们也可以这么说,B相对于A的坐标是(1,-1),这样B就把A作为它的参考系,A就是模型坐标了!
也就是B在A这个模型坐标里所在的位置是(1,-1)
通过Node对象如下函数实现:
1 2 3 4 5 6 7 8 9 10 |
|
Node1和Node2的像素是(300,100)
所以很容易得出:
A(100,400)
C(200,300)
C相对于A:(100,-100)
B(400,500) C相对于B:(-200,-200)
Node2的世界坐标转换为相对于Node1的模型坐标:
1 2 3 4 5 |
|
所以得出的结果就是:
1 2 3 4 5 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
GITHUB源码下载地址:【点我进行下载】
在游戏场景中有两个Node对象,其中Node1的坐标是(400,500),大小是300100像素
Node2是放置在Node1中的,它对于Node1的模型坐标是(0,0),大小是150150像素
Node2相对于Node1的模型坐标转换的世界坐标:
1 2 |
|
(150,50)为Node2的宽高
A点的坐标 = (400,500) - (150,50) = (250,450)
上面的是没加上锚点的,如果加上锚点,是相对于锚点的坐标
加上锚点之后,Node1的锚点是B点,所以Node2相对于Node1的锚点的坐标是:
1 2 |
|
Vec2 point2 得到的其实就是B点的坐标,也就是A点坐标,加上Node1锚点的坐标相对于A点的坐标。也就是(250,450)+(150,50) = (400,500)
也就是我们说的Node2的世界坐标!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
1 2 3 |
|
上面代码是使用node1模型坐标来设置位置的
也可以用世界坐标描述
1 2 3 |
|
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
首先来看一张图
这个图反应了Node与Node的层级架构
所谓层级架构其实就是树形结构/层次结构,从图上可以看出来,树的根是Scene(场景),然后是层,层里面又包含了精灵,菜单,粒子系统,瓦片地图
所有这些元素,都有一个共同的父类,就是Node
这个树形结构,其实就是一种包含关系
这2个文件共同定义了一个HelloWorld的层
class HelloWorld : public cocos2d::Layer
我们自己自定义了一个类HelloWorld继承了Layer,层最后要放到场景里去
1 2 3 4 5 6 7 8 9 10 11 |
|
创建场景以及HelloWord这个层,然后把层放到场景里
通过addChild这个方法,把子节点加到父节点里面去
以此类推,可以把Layer添加到Scene里,也可以这样把精灵,菜单等添加到层里
1 2 3 4 5 |
|
代码在HelloWord.cpp中可以看到
所以,最开始的图上的层次结构,是通过add的这个方法添加上来的
既然有添加,那么就有移除方法,后面再介绍。
主要是树形结构,需要注意的就是添加的顺序和个数
一般来说,一个场景会有多个层,我们建立的HelloWord实例中,场景和层是一对一的关系
也就是场景中只放了一个层。实际上场景与层是一对多的关系
为了减少绘制的次数,不要建立太多的层,那样很消耗cpu
层与精灵也是一对多的关系,然后层与菜单,粒子系统,瓦片地图都是一对多的关系
菜单与菜单项是一对多的关系,一个菜单里会有多个菜单项
当cocos2d启动一个场景的时候,场景就会加载层,层会加载菜单等等,菜单会加载菜单项。就是这样一种树形结构
由于场景、层、菜单、精灵…都是继承的Node,所以它们有一些共同的属性和方法
1
|
|
1
|
|
第一个参数是添加的节点;第二个参数是添加的Node的z轴的顺序(添加节点的时候会有顺序的,相当于绘制的时候的先后顺序);第三个参数是Tag/标签,可以理解成id,通过这个tag来操作node对象
附带第二个参数的英文介绍:
1 2 3 4 5 |
|
addChild有4个方法
1 2 3 4 |
|
1
|
|
1
|
|
1
|
|
1
|
|
1
|
|
Node两个非常重要的属性:
position和anchorPoint
position是指的位置,anchorPoint是指的锚点
位置(坐标)很好理解,就是比如放在(5,5),x=5,y=5.但是精灵图片是有大小的,这个时候就需要锚点了。
我们用图来理解吧
1.anchorPoint为(0.5,0.5),这个是默认值
第一个参数0.5,是锚点距离左边边线的距离和图片整个的宽度的比例,也就是1/2
第二个参数0.5,是锚点距离底边高度和整个高度的比值,也就是1/2
2.anchorPoint为(0,0),也就是精灵图片的左下角
3.anchorPoint为(1.0,1.0),也就是精灵图片的右上角
4.anchorPoint为(0.66,0.5),这个具有普遍性
每一个游戏程序都有一个循环在不断运行,它是有导演对象来管理和维护。
如果需要场景中的精灵运动起来,我们可以在游戏循环中使用定时器(Scheduler)对精灵等对象的运行进行调度。
因为Node类封装了Scheduler类,所以我们也可以直接使用Node中调用函数。
Node中调用函数主要有:
1 2 3 4 5 6 7 8 9 |
|
GITHUB源码下载地址:【点我进行下载】
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】
导演类Director(v3.0之前是CCDirector)用于管理场景对象。
(所以3.0版本和以前的最大区别(我们看到的最大区别)就是类前面的CC,3.0版本是把所以的类前缀CC都去掉了)
采用单例设计模式!(不多解释啦,不知道的朋友请搜索)
1
|
|
访问和改变场景
访问Cocos2d-x的配置信息
暂停、继续和停止游戏
转换坐标
上面只是导演对象的职责其中一部分,还有其他很多,但我们不需要让导演做很多事情(其他的事被隐藏了),我们用的最多的应该就是访问和改变场景、暂停、继续和停止游戏和转换坐标
场景类Scene(v3.0之前是CCScene)是构成游戏的界面,类似于电影中的场景。
像导演、场景、包括层,精灵等这些游戏的概念,其实都是从电影行业中过渡过来的。
那么,电影行业,我们知道有场景,有导演。
场景就是我们拍这场戏,我们布置的景 比如打斗的场景等
场景中会有男主角,女主角,那么男女主角就相当于我们这里的精灵了,包括道具什么的(精灵),这些东西在一起,就构成了层
所以场景里面也会放一些层
展示类场景。播放视频或简单的在图像上输出文字,来实现游戏的开场介绍、胜利和失败提示、帮助介绍
选项类场景。主菜单,设置游戏参数等(比如开始,暂停,继续菜单)
游戏场景。这是游戏的主要内容
Scene类图:继承图
层是我们写游戏的重点,我们大约99%以上的时间是在层上实现我们游戏内容。
层的管理类似于Photoshop中的图层,它也是一层一层叠在一起
我们一般写的很多类都是层,然后在层上面添加精灵等.然后把层放到场景里
场景包含层,层包含精灵,菜单等对象
理论上来说,层的层数越多(层与层之间有覆盖的问题,后面的层会覆盖先绘制的层),需要绘制的深度越深,越耗CPU
大家可以打开Photoshop,用里面的图层来理解,这样更加直观
精灵类Sprite(v3.0之前是CCSprite)是游戏中非常重要的概念,它包括了敌人、玩家控制的对象、静态物体、地图和背景等
通常情况它会进行运动,运动方式包括了:移动、旋转、放大、缩小和动画等
菜单在游戏中时非常重要的概念,它提供操作的集合,在Cococ2d-x中菜单类是Menu
Menu中包含菜单项
MenuItem,它有三个子类:
MenuItemLabel、MenuItemSprite和MenuItemToggle
之前的HelloWord中的关闭按钮其实就是一个菜单项
我们也可以用精灵来实现,但是菜单项封装了一些触摸事件,你不需要关心它事件处理的细节问题
本文章由[谙忆]编写, 所有权利保留。 欢迎转载,分享是进步的源泉。
]]>转载请注明出处:http://chenhaoxiang.cn
本文源自【人生之旅_谙忆的博客】