Cocos2dx学习笔记——Ref对象管理之保留与释放

在Cocos中,我们一切的智能类都继承于Ref引用类。方便内存的优化与管理。这是推荐的自定义类方法。
而推荐的创建(对象实例化)方法是在头文件中使用CREATE_FUNC(__TYPE__)方法来创建。创建的时候需要配上一个自定义init()来对类数据进行初始化。

这里需要注意一点。那就是对象的自动释放:
pRet->autorelease();
cocos在CREATE_FUNC宏中配置自动释放的机制。这个方法使得内存的管理变得很方便。因为很多时候一些数据只需要调用一次。
我们来看看autorelease()方法的说明:

Ref * autorelease ()
在下一帧自动释放 Ref 对象的所有权。

那么如果当我们需要让这个类能够长久的存在下去、比如全局管理类。那么这个方法就会很明显的影响到代码的逻辑实现。因为在下一帧以后数据都被自动释放掉了。如果我们还想访问的话就会报错。因为此时地址都指向0xfeeefeee(该指针指向的对象已经被释放,地址就会指向0xfeeefeee)。

解决方案:在该对象初始化的时候接管对象的所有权。即保留该对象不让它被自动释放。

如在init()函数中声明:this->retain();
当需要释放的时候手动释放:this->this->retain();

我们来看一下这两个方法的说明

void retain ()
保留 Ref 对象的所有权。 会将 Ref 对象的引用计数 +1。

void release ()
释放 Ref 对象的所有权。 会将 Ref 对象的引用计数 -1

注意:多层对象需要每个都进行保留处理。
比如如下结构:

1
2
3
4
5
class Test: public Ref{
public:
Ref* a;
Ref* b;
}

我们在一个Test中存了a,b两个对象的地址。那么我们对内存进行管理的时候需要把每个都进行retain()方法。

1
2
3
this->retain();
a->retain();
b->retain();

如果仅仅执行this->retain();操作。那么只会保留a,b两个对象的引用不被释放。而a和b里面可以被自动释放的引用都会被自动释放。
为什么要这么做?如果一个Node* node对象没有立刻(这一帧)中被addChild。那么在下一帧以后进行addChild就会失败因为addChild会判定该对象的父节点是否为空。如果不为空则不能被添加。在代码中的判定是node->_parent == nullptr。即node->_parent地址是否为0,而我们都知道释放后的地址会指向0xfeeefeee。因此会出现bug。

Cocos2dx学习笔记——编译器提示LINK1104无法打开文件“libcocos2d_2013.lib”的问题

在编译项目的时候可能会出现这样的错误:

LINK1104无法打开文件“libcocos2d_2013.lib”

这是因为VS无法找到这个库的原因。
解决方案有两个:

  • 如果你的项目是带有完整源代码的版本,找到main.cpp文件。找到一段代码,删掉:

    #if _MSC_VER > 1800
    #pragma comment(lib,”libcocos2d_2015.lib”)
    #pragma comment(lib,”libbox2d_2015.lib”)
    #pragma comment(lib,”libSpine_2015.lib”)
    #pragma comment(lib,”librecast_2015.lib”)
    #pragma comment(lib,”libbullet_2015.lib”)
    #else
    #pragma comment(lib,”libcocos2d_2013.lib”)
    #pragma comment(lib,”libbox2d_2013.lib”)
    #pragma comment(lib,”libSpine_2013.lib”)
    #pragma comment(lib,”librecast_2013.lib”)
    #pragma comment(lib,”libbullet_2013.lib”)
    #endif

    这是VS请求连接原始版本cocos应对不同版本的预编译vs依赖库。在源代码版本的项目中是没有这些文件的。在第一次生成的时候会生成对应vs的库文件。

  • 如果你的项目是预编译版本的项目工程文件。则右键项目—–>属性—->链接器——>常规 ——-> 附加库目录。添加原始cocos文件已经编译好的预编译库文件路径到新的一行。如果不知道文件的目录可以直接用windows自带的文件名搜索libcocos2d_2013.lib文件。其他同理

如何获取TexturePacker 1年免费软件授权

怎么说呢。非常感谢TexturePacker以及Andreas Loew提供的免费1年授权。为我们这些独立游戏开发者提供了方便。
TexturePacker是一款非常好用的图集打包程序。能够将多个零散的图片打包成一个大图来使用。降低了游戏图形渲染的效率。支持多种格式的输出。在游戏开发特别是cocos2d引擎的开发中收到了广泛的应用。

现在记录一下申请1年免费授权的过程:
首先需要满足如下条件:

Bloggers and framework developers can get a free 1-year-license for my tools.

My requirements to you are:

  • You write your own blog about game/software/web development
  • Your blog has
    • 10 recent blog posts (2015/2016) about game / web development
    • at least 1000 words/post
    • own content, no copy / scraping from other blogs
  • No Facebook, no Twitter, no Weibo — except you have 10.000 followers

I would be happy if you do a small blog post about my tools in return - but this is not a requirement.

  • 拥有一个关于游戏/网页开发的博客。博客的内容不得少于10篇(近两年),至少有1000+字,完全原创的博文。
  • 这个博客不能是facebook、Twitter、微博除非有10000以上关注。

满足以上条件即可申请免费的1年授权。申请的网站如下
https://www.codeandweb.com/request-free-license

按照表单填入相关信息以后静等一天(因为有时区的关系不可能马上回复),不建议使用qq邮箱因为在国外的支持并不好(我使用的是hotmail)。当然此时会收到自动回复的邮件。内容如下:

You signed up for the newsletter on www.codeandweb.com. The newsletter contains: Getting started with the free blogger license for TexturePacker, SpriteIlluminator and PhysicsEditor..
Please ignore this mail if you did not signup for the newsletter. You only receive the newsletter if you confirm the subscription by clicking on the button below.
You can unsubscribe from receiving mails at any time.
Best
Andreas

过了一段时间会收到如下邮件:

Hi ####,
you’ve requested a license for TexturePacker.
Congratulations: Your blog qualifies for a free license!
Please verify that this is really your blog by adding the following code somewhere on the blog page.
TP:#####
You can remove the code in about 1-4 days. Click on the button below after you’ve added the code.
Best
Andreas

他需要你在你的博客上添加一段字符串来表示你是这个博客的主人。添加完后按下他给的链接更新你的数据。
注意:建议将代码添加到网页的首页。如底部栏之类的。否则别人不一定马上能知道。我就放在了别的地方结果第二天TexturePacker用繁体中文翻译了一遍又发了一遍邮件=-=

末了,会收到邮件:

Hi ####,
you requested a license for TexturePacker:
TexturePacker: TP-####-####-####-####
Have fun with the license. I would be happy if you would write blog post about my tools in return.
Please let me know if you write a tutorial or review - we might link back from our tutorials page.
Kind regards Andreas Loew

恭喜你成功收到TexturePacker的序列号了。尽情享用它吧!

Cocos2dx学习笔记——节点与层的父子坐标区别

在cocos2d中,我们一切ui的基础——节点的坐标系起始坐标依赖于父节点的坐标。当我们在一个node对象中使用addChild方法后,子节点的坐标是依赖于父节点。
也就是说如下代码:

1
2
3
4
5
6
7
auto parent = Node::create();
parent->setPosition(Vec2(10,20));
addChild(parent);

auto child = Node::create();
child->setPosition(Vec2(5,10));
parent->addChild(child);

child个人坐标系的位置是(5,10),然而因为是parent的子节点。所以child的世界坐标系位置应该加上父节点的坐标,也就是(5+10,10+20)。
通过这个原理我们就能很方便的控制子节点与父节点的坐标关系。

而其中layer和一般的节点不同。虽然layer继承于node,可以成为另一个node的子节点,但是当layer成为一个node的子节点后。其坐标起始点并不会改变。因为在源码中:

1
2
3
4
5
6
bool Layer::init()
{
Director * director = Director::getInstance();
setContentSize(director->getWinSize());
return true;
}

规定了layer必须占满屏幕。所以不管父节点的坐标。layer必定占满整个屏幕。因此想通过父节点的坐标来控制子layer的坐标是办不到的。

Cocos2dx学习笔记——CCLog无法使用的问题

在cocos2dx中我们拥有多种调试输出日志的方法:

  • CCLog
  • CCLOG
  • log
    然而在实际使用中会报错,如:
1
错误	46	error LNK2019: 无法解析的外部符号 "__declspec(dllimport) void __cdecl cocos2d::CCLog(char const *,...)" (__imp_?CCLog@cocos2d@@YAXPBDZZ),该符号在函数 "public: bool __thiscall XMLParser::initWithFile(char const *)" (?initWithFile@XMLParser@@QAE_NPBD@Z) 中被引用	G:\Study\Cocos\gfxz\proj.win32\XMLParser.obj

我们来看一下为什么。
首先CCLOG是一个宏指令。定义如下:
#define CCLOG(format, ...) cocos2d::log(format, ##__VA_ARGS__)
也就是说CCLOG与log等价。

而CCLog是一个独立的函数。在CCDeprecated.h中可以看到:

1
2
/** use log() instead */
CC_DEPRECATED_ATTRIBUTE void CC_DLL CCLog(const char * pszFormat, ...) CC_FORMAT_PRINTF(1, 2);

Cocos在注释中已经声明了使用log命令来代替使用。

我们来研究一下这条命令。
CC_DEPRECATED_ATTRIBUTE是一条宏语句。他的定义如下

1
2
3
4
5
6
7
#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)))
#define CC_DEPRECATED_ATTRIBUTE __attribute__((deprecated))
#elif _MSC_VER >= 1400 //vs 2005 or higher
#define CC_DEPRECATED_ATTRIBUTE __declspec(deprecated)
#else
#define CC_DEPRECATED_ATTRIBUTE
#endif

在vs2005以上版本使用__declspec约定方式调用后面的函数。

__declspec主要是用于说明DLL的引出函数的,在某些情况下用__declspec(dllexport)在DLL中生命引出函数,比用传统的DEF文件方便一些.在普通程序中也可以用__declspec(dllimport)说明函数是位于另一个DLL中的导出函数。

显示声明该函数是在另一个dll中而新版本cocos默认不引入该dll(被否定)因此会报错LNK2019。该错误常见于没有在项目中引入相关的dll。解决方案是引入相关dll或直接引入完整的源码文件(不建议)。

建议的解决方案:在新版cocos2d中使用log指令代替CCLog指令

新型钓鱼网站骗术

今天玩儿游戏。又日常看见钓鱼网站。打进去研究了一下。差点吓坏我。这个钓鱼网站做的厉害。现在我就来揭露一下这种钓鱼网站的原理。
首先这种网站是一个仿照正规官网域名的假域名。比如QQ写为OO。不注意的话很容易上当,界面直接复制官网的css然后修改敏感信息比如登陆框。然后要求你登陆。通过获取你登陆时候的输入传输表单到他们服务器的后台数据库中进行记录。然后返回一个成功登陆的响应。当然为了让用户能自主登陆会伪造一些虚假信息比如抽奖啊领福利啊之类的
当然这不是我今天要说的内容。因为以上的只是传统的骗术。有一定上网经验的人都能发现,并不上当,所以这种方法的成功率并不高。
今天我发现一种新的网站。他们不抄袭界面。而是使用了frame框架。什么是frame框架?就是在这个frame中相当于一个独立的浏览器窗口。一切的点击、跳转行为都在这个frame中而不会刷新网页。简单的说。进行跳转不会影响外部的界面。在frame中点击链接并不会改变整个窗口的url指向。那么当这个frame指向了一个游戏的官网呢?
这是一个社会工程学上的问题。当你看到一个网页上已经登陆,显示的是正确的个人信息的时候。你潜意识的会认为这是一个正常的网页,而非钓鱼网站。因为钓鱼网站是无法直接获取你的个人信息的。
那么问题来了。假如这个frame的连接指向的是一个正规的网站呢?当你通过这个网站发送的信息呢?数据会传到哪里?答案是钓鱼网站。因为js传输表单的时候默认的相对路径是浏览器窗口url为标准的。在frame中的操作是正规的,也的确是正常的官方网站。但是数据却是传到钓鱼网站的。
就算我一开始知道是钓鱼网站。我都差点上当。何况是普通用户。可见这种钓鱼方式的可怕。希望网民在上网浏览的时候能够保持一定的警戒心。不要随意打开陌生网站。

该网站链接:http://qq.mhoap.com/(请注意这个不是一个正规的网站,也随时可能失效。一切敏感操作请不要通过该网站的连接进行)

Cocos2dx学习笔记——C++的一些约定

关于C++使用的时候,为了防止出现头文件相互嵌套的问题,有两点原则:

第一个原则应该是,如果可以不包含头文件,那就不要包含了。这时候前置声明可以解决问题。如果使用的仅仅是一个类的指针,没有使用这个类的具体对象(非指针),也没有访问到类的具体成员,那么前置声明就可以了。因为指针这一数据类型的大小是特定的,编译器可以获知。

第二个原则应该是,尽量在CPP文件中包含头文件,而非在头文件中。假设类A的一个成员是是一个指向类B的指针,在类A的头文件中使用了类B的前置声明并便宜成功,那么在A的实现中我们需要访问B的具体成员,因此需要包含头文件,那么我们应该在类A的实现部分(CPP文件)包含类B的头文件而非声明部分(H文件)。

简单的说就是最好在声明中包含头文件。在头文件包含前置声明。为了防止头文件相互依赖相互引用出现的空内存现象。

参考资料:*http://www.cnblogs.com/MuyouSome/p/3388242.html*

Cocos2dx学习笔记——引擎版本号的选择

Cocos2d作为一款开源游戏引擎来说。是非常好的一款引擎。但是不得不说。他的学习成本比较高。为什么说他的学习成本比较高呢?因为其各个版本间的兼容性很差,架构迭代很快。早年我学使用unity。仅仅在unity4到unity5之间经历了一次大的api更新。然而小版本之间兼容性非常强。一个代码能够很容易在各个小版本之间交叉使用。然而Cocos2d并不能。Cocos2d之间API更新非常快。同样是3.X版本。我照着3.4的教程写着3.10的基础代码。居然还能出现一些很神奇的bug。这点是我非常反对的。调试与翻源码翻了3小时以上的时间后我选择了放弃。
新版本与旧版本差异大。导致市面上的教程都处于一个落后的阶段。新的教程很难跟上引擎的更新速度。其学习基本处于和大多数缺少完善文档,缺少视频和文字教程的开源项目一样基本完全靠程序员个人的素质与逻辑能力。这无疑对新手来说是非常不友好的。
因此我建议下载引擎的时候最好不要选择最新版本的游戏引擎。最好是找到一个适合自己或自己感兴趣的教程。去下载配套的引擎版本。在熟悉了以后再去跟进新的版本进行学习。这样才会比较好。

Cocos2dx学习笔记——cocos-ext头文件编译问题

开始学习的过程中遇到一个问题。就是跟着教程学习使用如何使用TableView的时候,为使用当时引入了一个名为cocos-ext.h的头文件而产生了大量的报错。我当时很诧异因为我一切步骤都是按照教程的步骤来的。后来我发现了原因所在。因为我为了更好的研究代码使用的是cocos2d的源码生成的项目。而不是使用预编译的版本。而环境搭建时对于基本头文件的路径有所优化,而源码中仍旧使用的是老版本的路径方式。所以解决方案如下:
不断循环编译。在编译报告中点开关于无法打开源文件extensions\...的报错项目。将其改为如#include "ExtensionExport.h"这样的格式。再重新生成直到没有报错为止。