2.player走起
安装好Quick之后,我们先来开启player跑跑看,初窥一下Quick,也正好验证一下环境变量的配置是否争取了。
上面已经提到了安装完成后player所在的位置,毫不犹豫的点击运行,如果一切顺利,player就顺利启动了,点击示例标签你会看到如下界面:
这里包含了Quick提供的一些示例项目,单击某个示例将会启动一个新的player打开所选示例。你会看到新启动的player带了一个控制台窗口。这个控制台窗口是player的输出窗口,包括你打印的日志以及崩溃日志都会出现在这里,所以,一开始遇到bug,请同学们先去看看控制台里面是否有啥不正常的打印内容,即为报错内容,如果你要问问题,这个报错信息是很关键的!
3.Quick的基本目录结构
好了,player已经跑起来了,被太兴奋,先把player放着就是了,我们来看看Quick的基本目录结构。
打开Quick根目录,我们一个一个说:
-
build:build目录是Cocos2d-x的项目存放目录,可以不鸟
-
cocos:这是Cocos2d-x的主目录,核心代码基本都在这里了
-
docs:这个是Quick的文档目录,至于都有啥文档,自己去瞧瞧
-
extensions:这是cocos的一些扩展内容所在的目录,也可以先不鸟
-
external:同样是扩展内容,也先不鸟
-
licenses:这个就不说了
-
quick:这个是Quick的核心目录了,后面会详细介绍
-
tools:这里放的东东是用来做luabinding的工具,你肯定会用到,但现在还用不到,系列后面会有专门讲如何使用工具来导出自己定义的C++类
好了,目录结构就介绍完了,除了Quick目录,其他的目录你可以都先不鸟了,所以我们下面重点说下Quick目录。
进入Quick目录,内容如下:
-
bin:这里存放的基本都是Quick的工具脚本,包括binding脚本,加密脚本等,每个工具的使用以后会在用到的时候详细讲
-
cocos:这里存放的一大堆lua文件,绝大多数都是C++那边定义的一些常量以及一些封装的接口
-
framework:这个就是Quick框架的核心目录了,你后面基本都是在跟framework打交道
-
lib:这里放的是Quick的一些库
-
player:这里放的是player的工程文件,你可以在这里打开player的工程项目,对player进行修改,对于小白,就先算了,知道这事就好
-
samples:这里放着的是Quick示例的代码
-
templates:这里是Quick的项目模板,知道就行
-
welcome:这里是player启动界面的代码,也就是你打开player看到的第一个界面就是从这里加载构建的
以上就是Quick目录的基本内容,罗里吧嗦一大堆,估计你都迷糊了,别怕,现在开始,你只需要关注smpales和framework这两个目录,这将会是你Quick起飞的地方!
4.Quick的入门
Quick如何入门?其实很简单,打开player,跑示例,然后看代码,然后创建自己的项目,在项目里使用消化的示例内容来做一些自己的内容。
我们实际来做一下吧:
A.打开player,切换到示例,打开TOUCH示例
正常运行如上图,用鼠标在白色区域点点拖拖你会看到相应的变化。
你现在肯定想问代码在哪里呢?还记得前面提到的sample目录么?对的,现在就打开samples/touch/src/app/scenes/TestSingleTouche1Scene.lua
这里面就是上面的场景的构建代码了,代码中都有相关注释,对照player表现的内容,浏览代码,了解每行代码的意义。
Quick的入门也就大致如此了,如果这样你还不知道咋玩,那我只能说,哥们,别完了,去蓝翔吧,会比你写代码有前途!
开个玩笑,其实Quick已经让我们的开发很简单了,顺便调侃一下,前两天群里有个哥们说他正在做个不用写代码就可以做任何游戏的平台,你也可以期待一下!
Quick小白书系列(四)Quick中的Scene
Quick小白书系列(三)MyApp详解
Quick-Cocos2d-x 3.3中的CCStore使用说明
天我们来讲解Quick中的Scene,也就是场景,场景是构成一个游戏的基本概念。场景简单地理解就是一个舞台,你构建一个场景之后,就可以在场景上添加你的游戏元素了!
我们就以一个新建项目中得MainScene来逐步讲解Scene!
1. 打开你项目的MainScene,我们先来看最上面的MainScene的定义,代码如下:
1
2
3
|
localMainScene=
class
(
"MainScene"
,function()
return
display.newScene(
"MainScene"
)
end)
|
这片代码的意思就是定义一个名为MainScene的场景类,并赋值给local变量MainScene。为什么要赋值给一个local变量呢?我们后面会揭晓!
那么display.newScene方法是在哪里定义的呢?在src/framework/display.lua中:
1
2
3
4
5
6
7
|
functiondisplay.newScene(name)
localscene=cc.Scene:create()
scene:setNodeEventEnabled(
true
)
scene:setAutoCleanupEnabled()
scene.name=nameor
"<unknown-scene>"
return
scene
end
|
2.Scene的构造函数ctor
接着往下看你回看到MainScene的构造函数,如下:
1
2
3
4
5
6
|
functionMainScene:ctor()
cc.ui.UILabel.
new
({
UILabelType=2,text=
"Hello,World"
,size=64})
:align(display.CENTER,display.cx,display.cy)
:addTo(self)
end
|
ctor函数就是MainScene的构造函数,在这里,你可以对MainScene做初始化,比如上面的代码就是在场景中添加一个label,显示helloworld,总之可以做的事情so many!以后再论吧!
构造函数ctor在何时调用?看过上一篇文章的应该知道了,在你对一个Scene调用new来实例化的时候会调用,不晓得的童鞋就去看下上一篇文章就知道了!
3.Scene的一些方法
再往下看你回看到两个方法的定义:
1
2
3
4
5
|
functionMainScene:onEnter()
end
functionMainScene:onExit()
end
|
用过Cocos2d-x的C++版本的童鞋应该很熟悉这两个方法,onEnter方法是在进入场景的时候调用,onExit方法是在退出场景的时候调用,在C++中是通过重写父类方法产生作用的。那么在quick中是如何起作用的呢?我们来一步一步的找答案:
A. 在上面定义MainScene的时候我们说到调用了display.newScene方法,翻看上面的代码你回看到display.newScene方法中有这样一句:
1
|
scene:setNodeEventEnabled(
true
);
|
这句代码的意思是开启scene的node事件
B. 继续扒,打开src/framework/cocos2dx/NodeEx.lua,找到function Node:setNodeEventEnabled(enabled,listener)
代码太长,我就不贴了。首先NodeEx.lua中都是定义了一些对Node进行扩展的函数,因为Scene在底层是继承自Node的,所以对Node的这些扩展同样可以被Scene调用。
C. 再扒,看Node:setNodeEventEnabled中的这段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
if
notlistenerthen
listener=function(event)
localname=event.name
if
name==
"enter"
then
self:onEnter()
elseifname==
"exit"
then
self:onExit()
elseifname==
"enterTransitionFinish"
then
self:onEnterTransitionFinish()
elseifname==
"exitTransitionStart"
then
self:onExitTransitionStart()
elseifname==
"cleanup"
then
self:onCleanup()
end
end
end
|
这片代码在你们使用Node:setNodeEventEnabled的时候只传入第一个bool参数时,会向底层注册一些默认调用的函数,从而让你在自己的Scene中定义的onEnter等方法可以被调用。
常用的就是onEnter和onExit,一个是在进入场景的时候调用,你可以在这里做一些初始化的事情,个人更建议初始化的事情在ctor里做。而onExit就是在场景退出的时候调用,在这里你可以做一些清理工作,比如释放某些不用的资源,重置某些变量等。
至此,该扒的就都扒完了,至于更深层地的底层的东西,在你能熟练应用之后再去查看会更有收获!
4.最后的返回值
MainScene的最后一行是一个return MainScene语句,意思就是返回最上面定义的那个local MainScene。为何要写这一句呢?
当你在想要引用这个MainScene的时候,你需要这样写:
1
|
localMainScene=require(
"app.scenes.MainScene"
);
|
这样就把你定义的MainScene类返回给了前面的local变量MainScene。之后,你就可以调用MainScene.new()来实例化一个场景,然后调用display.replaceScene来切换到你实例化的这个新场景。
当然,看过前面的文章的童鞋就知道有更方便的方法,直接调用app:enterScene("MainScene")来进入一个新场景,因为app:enterScene方法帮你完成了场景的实例化等。
好了,现在你可以去构建一个属于自己的场景了,如MyScene
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
localMyScene=
class
(
"MyScene"
,function()
return
display.newScene(
"MyScene"
)
end)
functionMyScene:ctor()
cc.ui.UILabel.
new
({
UILabelType=2,MyScene"
,size=64})
:align(display.CENTER,display.cy)
:addTo(self)
end
functionMyScene:onEnter()
end
functionMyScene:onExit()
end
return
MyScene
|
Quick小白书系列(三)MyApp详解
来是计划从这篇开始做个用一个小游戏教程来讲解Quick的使用,但是发现很多童鞋对Quick的框架还真是不了解。
其实这种不了解源自于没有认真的阅读Quick的framework的代码,但无论是懒得读还是读不懂,结果都是会问各种基础的小白问题,于是我决定这个系列还继续讲解一些小白类的问题,而一些略微深入的使用以及我在做项目中得一些值得分享的东西我会单独开贴来写!
好了,进入今天正题,在上一篇内容中,我已经说明了Quick得项目启动过程中,看过的应该知道Quick启动中一个关键的类就是MyApp,所以本篇就来详细讲解下这个东西。
首先,打开自己新建项目的MyApp.lua文件,代码我就不贴了,下面开始逐步讲解!
1.通过一些文件进行framework的初始化
在MyApp.lua的最开始是3行require语句
1
2
3
|
require(
"config"
)
require(
"cocos.init"
)
require(
"framework.init"
)
|
在Lua中,require表示引入一个文件,那么上面的三个文件分别在哪里呢?
他们分别在:
-
root/src/config.lua
-
root/src/cocos/init.lua
-
root/src/framework/init.lua
其中root表示你项目的根目录。
通过require这三个文件后,将会对Quick的框架做一些初始化的事情。简单说下是如何初始化的,比如,require("config"),这句会加载root/src/config.lua文件,require加载文件的过程中会检查该文件的lua语法,以及完成文件内的一些变量的初始化,你打开config.lua文件,你回看到都是一些变量的初始化,这些都是全局变量,因为没有local,看过Lua语法的都晓得。require了之后,你就可以在任何地方引用这些变量,比如DEBUG变量。关于Lua的require更详细明确的讲解,请自行百度。这里,你就可以先理解为引入三个文件并且进行初始化。
2.MyApp的定义
回到MyApp文件,看这一行
1
|
localMyApp=
class
(
"MyApp"
,cc.mvc.AppBase)
|
这一行的意思是:定义一个MyApp类,它继承自cc.mvc.AppBase。
那么问题来了,cc.mvc.AppBase在哪里?在root/framework/cc/mvc/AppBase.lua
理解继承概念的童鞋一看则明,不了解何为继承的,可以简单的这样理解:MyApp继承了AppBase,那么MyApp就可以使用AppBase的所有变量和函数,就跟MyApp自己的一样,如何使用,下面会具体介绍
3.MyApp的构造函数
MyApp.super.ctor(self),这一行的意思是调用基类的构造函数,也就是AppBase的构造函数。
那么我们来看看AppBase的ctor函数都干了啥,打开AppBase,看ctor函数
1
|
cc(self):addComponent(
"components.behavior.EventProtocol"
):exportMethods()
|
这一行是给AppBase函数添加事件组件,至于事件组件是啥,后面会有专门对这个组件讲解,这里你知道是添加了事件组件就好
1
2
|
self.name=appName
self.packageRoot=packageRootor
"app"
|
这里就是简单地两个赋值,self就是AppBase自己
1
2
3
4
5
6
7
|
localeventDispatcher=cc.Director:getInstance():getEventDispatcher()
localcustomListenerBg=cc.EventListenerCustom:create(AppBase.APP_ENTER_BACKGROUND_EVENT,
handler(self,self.onEnterBackground))
eventDispatcher:addEventListenerWithFixedPriority(customListenerBg,1)
localcustomListenerFg=cc.EventListenerCustom:create(AppBase.APP_ENTER_FOREGROUND_EVENT,
handler(self,self.onEnterForeground))
eventDispatcher:addEventListenerWithFixedPriority(customListenerFg,1)
|
这几行内容是通过eventDispatcher注册两个监听事件,分别是AppBase.APP_ENTER_BACKGROUND_EVENT和AppBase.APP_ENTER_FOREGROUND_EVENT,这两个事件是你的游戏在切换到后台和从后台切换回来的时候触发后,会调用AppBase的两个方法onEnterBackground,onEnterForeground。这两个方法的定义在AppBase的下面,因为涉及到事件的东西,暂时用不到,所以不做详解。
1
2
3
|
self.snapshots_={}
--setglobalapp
app=self
|
这两行是初始化两个变量,注意app这个变量的初始化,app被定义为一个全局变量,并且赋值为self,也就是以后你使用app这个全局变量的时候它就是AppBase,或者继承自AppBase的MyApp。
4.run函数
1
|
cc.FileUtils:getInstance():addSearchPath(
"res/"
)
|
这一行是向搜索路径中添加res目录,何为搜索路径,就是你将来引用资源的时候能够查找的目录。
1
|
self:enterScene(
"MainScene"
)
|
这一句有童鞋会不理解,enterScene方法哪里来得,MyApp中没有定义啊,是得MyApp中没有定义,因为是在AppBase中定义的,而上面说了,通过继承可以直接访问基类的方法,所以MyApp可以直接使用enterScene方法。
在AppBase中找到enterScene方法的定义。
1
|
enterScene(sceneName,args,transitionType,
time
,more)
|
此函数接收4个参数,你可能比较奇怪,为啥前面MyApp里只传入了一个参数,看过lua语法的应该知道,lua中函数的参数可以少写或者多写,少写得话,对应位置的参数会赋值nil,多写的话会被省略,所以
1
|
self:enterScene(
"MainScene"
)等同于self:enterScene(
"MainScene"
,nil,nil)
|
在基本的使用中,你只需要传入sceneName即可:
1
2
3
|
localscenePackageName=self.packageRoot..
".scenes."
..sceneName
localsceneClass=require(scenePackageName)
localscene=sceneClass.
new
(unpack(checktable(args)))
|
这三句的意思是确定该场景所在的包名,引入该场景的文件,生成一个该场景的实例。
通过看scenePackageName的赋值你会看出,使用enterScene方法跳转场景是有限制的,该场景的定义文件一定要在root/scenes/这个文件夹中,比如root/scenes/MainScene.lua。
1
|
display.replaceScene(scene,more)
|
同样的逻辑你可以看下createView这个方法,这个方法是创建一个定义文件在root/views/这个目录下的view
5.用args给要切换到的场景传参
前面说过args传参需要是一个table类型,比如给MainScene传参可以这样写
1
|
self:enterScene(
"MainScene"
,{10,20})
|
那么如何在MainScene中接收这两个参数呢?需要这样改写MainScene的ctor定义
1
|
MainScene:ctor(arg1,arg2)
|
此时,arg1 = 10, arg2 = 20
Quick-Cocos2d-x 3.3中的CCStore使用说明
文简要介绍Quick-Cocos2d-x 3.3中针对iOS的iap功能封装的CCStore。
1. CCStore源码和导出的Lua的api在哪里
a)iaptest2/frameworks/runtime-src/Classes/quick-src/extra/store/CCStore.h
b)iaptest2/src/framework/cc/sdk/Store.lua
是的,iaptest2就是项目目录。
2. 首先,在当前版本中要想正常使用CCStore需要修改两个地方
a)图中标明的两处替换为cc.Store
b)图中三处变量添加cc前缀
修改完毕,现在就可以正常使用了
3. 关于iOS工程如何开启iap支持
可以参考下面的帖子的前面的部分,这里不做啰嗦,因为Quick的iOS工程终极也是iOS工程,没区别。参考帖子:http://www.tairan.com/archives/5515
4. 现在我假定看官们已经开启了iOS工程的iap支持,也在itunesconnect添加了测试商品以及测试账号
本文的代码如下:
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
|
functionMainScene:ctor()
--初始化商店
Store.init(handler(self,self.storeCallback))--function(event)self:storeCallback(event)end)
--载入商品
Store.loadProducts({
"com.originaljoy.iaptest.222coin"
,
"com.originaljoy.iaptest.11coin"
},handler(self,self.loadCallback))
--添加一个购买按钮
self.btn=cc.ui.UIPushButton.
new
(
"ui_btn_start.png"
)
:onButtonClicked(function(event)
print(
"购买商品"
)
Store.purchase(
"com.originaljoy.iaptest2.1111coin"
)
end)
:pos(display.cx,display.cy)
:addTo(self)
end
---商店的回调
functionMainScene:storeCallback(transaction)
--处理购买中的事件回调,如购买成功
if
transaction.transaction.state==
"purchased"
then
"buysuccess"
)
Store.finishTransaction(transaction.transaction)
end
end
---载入商品的毁掉
functionMainScene:loadCallback(products)
--返回商品列表
dump(products)
end
|
5.store的api使用
a)Store.init(listener)
初始化商店,并设置回调函数。回调函数用来处理各种store事件,接受一个参数event
event包含一个字段,transaction! transaction就是事件的完整内容,下图就是一次购买成功后回调的transaction
b)Store.loadProducts(productsId,listener)
载入商品列表,并设置回调
回调函数接受一个参数,就是商品列表,包括可用和不可用的商品,如图
c)Store.purchase(productId)
购买一个商品,传入商品id!购买事件将会在store的回调中接收
d)Store.finishTransaction(transaction)
移除一个事件。如果你购买一个商品成功后,不移除对应的事件,再次购买会有如下提示:
this in-app purchase has already been bought it will be restored for free