【http 请求中 post 与get的区别:】
get提交的时候数据 放到URL后面,
post放在HTTP协议 消息体中。
【lua函数中:和.的区别】:
function a:foo()
//这里可以直接用self
print(self.x)--输出a.x的值
end
function a.fool()
//这里不能直接用self 必须 在参数里显示地传入self
// function a.foo(self)
print(self.x)
end
end
【lua的基本数据类型】:number(双精度浮点数),bol(true和false),
string(‘’或者“”,字符,字符串),nil,function(方法),table(表),thread(线程),userdata(用户自定义类型).
【lua 模拟类的写法】:使用table和function模拟类,table描述对象属性、function 表示行为方法。
cocos2d-lua引擎自己封装了类class:
cocos-lua的继承:一共有三种继承(
1、类继承自方法:
local classA = class(“classA”,function() return cc.Scene:create()
end)
2、类继承自原生c++类:
local classB = class("classB",cc.Node)
3、类继承自lua纯table
local classC = class("classC",{a=1})
)
【lua面向对象编程】:元表 metatable,对table的一系列预定义操作(使用元方法操作table,怎么添加元方法呢,setmetatable)
元方法:重要代表__index和__newindex。
__index的使用:(在查找表元素时)
1、在表中找,找到返回元素,没找到进行2;
2、判断表是否有元表,如果有则进行3,没有返回空;
3、判断元表中有没有__index方法;没有返回nil;如果__index方法传入的是一个table,则重复步骤123;若__index传入的是function 则返回函数的返回值。
【c++数组的优缺点:】
数组定义:固定大小的相同类型的元素的顺序集合
优点:通过键值查找 和遍历方便。(总结访问方便)
缺点:增加和删除速度慢;占用的内存地址是连续的,不能过长;长度固定不能改变;C++中元素类型必须统一;通过值查找速度慢。
【热更新核心思想】
1、读取本地的配置文件 (配置文件为所有游戏资源文件的MD5值,可以是任意文件格式的);
2、从服务 器下载配置文件和本地对比;
3、下载更新文件并写入本地;
4、设置搜索路径的优先级。(更新文件地址中的文件具有优先级)
5、更改md5表单为最新。
【cocos动作实现机制】
基类:CCAction(抽象类)
派生类:CCFiniteTimeAction(大部分动作实现)
由CCFiniteTimeAction派生的两个主要类:
(CCActionInstant、CCActionInterval)
瞬时动作类:CCActionInstant
⬇
主要的派生类(CCFlipX,CCShow,CCHide,CCCallFunc);
持续性动作类:CCActionInterval
⬇
主要的派生类(CCMoveTo,CCMoveBy,CCScaleTo,CCDelayTime);
动作执行过程:
当一个CCNode执行runAction(CCAction*action )方法时。会调用ActionManager的addAction方法,ActionManager 会将新的CCAction和对应的目标节点CCNode,添加到其管理的【动作表中】。将动作添加到动作队列后,对该CCAction调用成员函数startWithTarget(CCNode*pTarget)来绑定该动作的执行者。
ActionManager的初始化在CCDirector的初始化里执行。
【在里面通过CCSchedule定时调度器为ActionManager注册了一个定期更新任务】
所以:
以上准备完之后,在每一帧刷新时,ActionManager都会遍历其【动作表】中的动作,并调用该动作的step(ccTimedt)方法。step中主要负责计算m_elapsed(动作执行的时间),并调用update(float time),来完成动作的实现。
注意;在update执行过程中。会检测该动作的生命周期,isDone()
bool Repeat::isDone(void) const
{
return _total == _times;
};如果时间到了就从动作列表中删除。
总结:计算刷新次数 是根据update 的参数(0--1),如果等于1就停止刷新。所以在瞬时动作中update的参数总是1。(不需要多次刷新);CCRepeatForever 动作的 isDone 函数始终返回 false。
【【【在Director的 init中ActionManager向Schedule注册了一个最高优先级的回调。然后每一帧回调更新_scheduler->update(_deltaTime);
都会调用ActionManager的update方法。】】】
【事件机制】
Event(EventCustom)
EventListener(EventListenerCustom)
EventDispatcher(与节点绑定)
Event 事件EventCustom:new(data)(data中包含Name和其他的数据)
EventListener事件监听器(一个回调函数、一个订阅者类型type,以及一个listenerlD(custom自定义是EventName))
EventListenerCustom:new(name,callbacks)
EventDispatcher (增加或删除Listener
例如:增加: EventDispatcher:addEventListenerWithFixPriority 或者 WithGraphPriority
删除:EventDispatcher:removeCustomEventListeners(evtName)
EventDispatcher:removeEventListener(handler))
EventDispatcher (方法dispatchEvent 触发事件 eventDispatcher.dispatchEvent(event),触发之后完成回调(执行回调函数,传递data))
【调度管理器】
cocos2d-x引擎启动后Director类会创建一个默认的调度管理器,所有的Node类默认都会引入Director的调度管理器,调度管理器会在Director的 mainLoop里的 drawscene方法里被每一帧都调度
“单例模式 ”
Director TextureCache(纹理缓存)
UserDefault(用户信息)
cc.UserDefault:getInstance()
SpriteFrameCache(精灵帧缓存工具)
cc.SpriteFrameCache:getInstance()
FileUtils(文件管理工具)
cc.FileUtils:getInstance()
ActionManager PoolManager (代码内)
“简单工厂模式” (create方法)
“观察者模式” (事件机制, 监听与派发)
“二段构建模式” (create 方法内 先new()分配内存,在init初始化内容,并顺带进行了内存管理)
“装饰者模式”
【cocos2d-x如何实现跨平台】
cocos工程中封装了各个平台的入口文件,通过接口转换,最终运行到CCAplication的run方法
主类CCApplicationProtocol(定义)
↓
主类 CCAplication (继承)
↓
AppDelegate app (继承并实现)
在创建app对象时 调用其构造函数 以及父类构造函数
在AppDelegate 中实现applicationDidFinishLaunching()方法
在父类CCApplication 中run()开始,就调用了子类的APPDelegate中的同名方法。
简单说来:applicationDidFinishLaunching 是由 CCApplicationProtocol 定义,CCApplication 继承, AppDelegate 实现的 ~)
【新的渲染流程】
现在,一个渲染流程是这样的:
(1)drawScene开始绘制场景
(2)遍历场景的子节点,调用visit函数,递归遍历子节点的子节点,以及子节点的子节点的子节点,以及…
(3)对每一个子节点调用draw函数
(4)初始化QuadCommand对象,这就是渲染命令,会丢到渲染队列里
(5)丢完QuadCommand就完事了,接着就交给渲染逻辑处理了。
(6)是时候轮到渲染逻辑干活干活,遍历渲染命令队列,这时候会有一个变量,用来保存渲染命令里的材质ID,遍历过程中就拿当前渲染命令的材质ID和上一个的材质ID对比,如果发现是一样的,那就不进行渲染,保存一下所需的信息,继续下一个遍历。好,如果这时候发现当前材质ID和上一个材质ID不一样,那就开始渲染,这就算是一个渲染批次了。
Ref* Ref::autorelease()
{
PoolManager::getInstance()->getCurrentPool()->addObject(this);
return this;
}
_managedObjectArray(Object对象集合)
void AutoreleasePool::addObject(Ref* object)
{
_managedObjectArray.push_back(object);
}
_releasePoolStack(autoreleasePool对象集合)
void PoolManager::push(AutoreleasePool *pool)
{
_releasePoolStack.push_back(pool);
}
MainLoop(主循环)
↓
void DisplayLinkDirector::mainLoop()
{
if (_purgeDirectorInNextLoop)
{
_purgeDirectorInNextLoop = false;
purgeDirector();
}
else if (! _invalid)
{
drawScene();
// release the objects
(获得当前_releasePoolStack的releaPool进行clear操作)
PoolManager::getInstance()->getCurrentPool()->clear();
}
}
↓(clear操作)
void AutoreleasePool::clear()
{
对当前autoreleasePool中的所有ref元素进行release操作
【cocos2d-x屏幕适配】
屏幕适配 函数
----//屏幕实际分辨率(并非设备长宽,游戏内只讨论分辨率,不考虑实际尺寸)
frameSize = director:getFrameSize()
宽高分别是FW,FH
设计分辨率宽高分别是DW,DH
屏幕分辨率与设计分辨率的比值:scaleX = FW/DW scaleY = FH/DH
setDesignResolutionSize(设计后width, 设计后height,resolutionPolicy_type)
第一种,EXACT_FIT(不等比例缩放,可能会变形)
第二种,NO_BORDER (无黑边,以设备分辨率与设计分辨率 比例大的进行缩放 Fwidth/Dwidth)
第三种,SHOW_ALL(全屏幕显示,以比例小的进行缩放,可能有黑边)
----------------------
以下两种:屏幕长宽比 与 设计分辨率长宽比 无拉伸变形
第四种:FIXED_HEIGHT(固定设计高度,(固定比例为)scaleX = scaleY,
传入高度DH,传入宽度DW = FW/scaleX,屏幕与设计分辨率的比值)
第五种:FIXED_WIDTH(固定设计宽度,(固定比例为)scaleY = scaleX
传入高度DH = FH/sacleY,传入宽度DW)
【assert】断言断言
assert(arg1,arg2)
assert(a==b,print("============="))
断言arg1是条件 当arg1是false时执行arg2
【纹理 优化内存】
写到这里才发现,其实只需要下面一句话就可以搞定。
这类图片会不会同时出现多个,同时出现时,内存开销是否无法接受, 如果确实无法接受,则使用GPU纹理,否则,优先考虑JPG,JPG+ALPHA,或者PNG8。就是说,首先要减小安装包大小,如果内存有无法接受的情况,才需要用GPU纹理进行优化。
---------------------
提示与技巧:
1、一帧一帧载入游戏资源
2、减少绘制调用,打包大图
3、载入纹理时按照从大到小的顺序
4、避免高峰内存使用
5、使用载入屏幕预载入游戏资源
6、需要时释放空闲资源
7、收到内存警告后释放缓存资源
8、使用纹理打包器优化纹理大小、格式、颜色深度等
9、使用JPG格式要谨慎
10、请使用RGB4444颜色深度16位纹理
11、请使用NPOT纹理,不要使用POT纹理
12、避免载入超大纹理
13、推荐1024*1024 NPOT pvr.ccz纹理集,而不要采用RAW PNG纹理
---------------------
【忽略锚点】:
Ignore Anchor Point全称是ignoreAnchorPointForPosition,作用是将锚点固定在一个地方;
如果设置其值为true,则图片资源的Anchor Pont固定为左下角,否则即为所设置的位置。
关于ccTouchBegan的返回值
true:
本层的后续Touch事件可以被触发,并阻挡向后层传递
false:
本层的后续Touch事件不能被触发,并向后传递
【排序笔记】
冒泡排序: 重点是 每次遍历取出一个最大/最小值,放在末尾
选择排序:每次排序 取出一个最大/最小值,放在开头
(排好序的值在哪里 很关键,意味着遍历的结束条件)
【C++创建对象】
构造函数:先基类 再派生类
析构函数:先派生类 再基类
【父类 指针指向子类对象】
例: void foo1 ();
virtual void foo2();
Parent *p1 = new Child();
delete p1;
构造函数 函数调用 :{ 先调用父类构造 ,再调用子类构造 };
析构函数:
第一种情况:
{ 父类析构函数不是虚函数,则 此情况只会调用父类析构函数,不调用子类析构};
第二种情况:
{ 父类析构函数是虚函数,则 先调用子类析构函数,再调用父类析构函数
}
【方法调用】
p1->foo1;
p1->foo2;
结果:
parent foo1
Child foo2
结论:如果父类函数不是虚函数,则调用父类;如果是虚函数 ,则调用子类实现;
【子类对象】
Child c1;
c1.foo1();
c1.foo2();
构造:先父类再子类;析构 先子类再父类;
方法:都只调用 子类方法;
【总结】
{
如果基础类和衍生类定义了相同名称的成员函数,那么通过对象指针调用成员函数时,到底调用哪个函数
要根据【指针的原型】来确定,而不是根据指针实际指向的对象类型确定。
}
{
在父类指针指向子类对象做对象销毁时,由于析构函数不是虚函数,则delete时,父类指针只能调用父类自己的析构函数, 这就造成了上述对象部分销毁的错误状况;
}
【引用和指针的区别】
Parent *p1 = new Parent();
Parent *p2 = new Parent();
Parent& q = *p1;
q = *p2;
1.引用只能在定义时初始化一次,之后不能改变指向其它变量(从一而终);指针变量的值可变。(上例中q并没有等于*p2)
2. 引用必须指向有效的变量,指针可以为空。(引用必须初始化)
3. sizeof指针对象和引用对象的意义不一样。sizeof引用得到的是所指向的变量的大小,而sizeof指针是对象地址的大小。
4. 指针和引用自增(++)自减(-–)意义不一样。
5. 相对而言,引用比指针更安全。