• 文章介绍
  • 评价建议
  •  

    教程名称:薛老师cocos2d游戏开发34天视频教程

     

     

    cocos2d-x课程大纲(基础部分)

     

    I. 第一章 基础1.1 前言

    1.1.1 cocos2d-x介绍

    • cocos2d-x是一个手机游戏开发引擎,使用C++开发,可以很方便的移植到各个平台,目前cocos2d-x支持Android,IOS,windows,mac,linux等系统。" u) ~+ N9 s* }/ e/ G7 @
      早先由阿根廷人开发Python版本,后来苹果手机流行之后,阿根廷人又用OC改写了cocos2d,并称之为cocos2d-iphone。
      后来由国人将cocos2d-iphone用C++改写,并称之为cocos2d-x,这样使用cocos2d-x开发的游戏很容易被移植到各个平台。5 j' e6 m, J+ w! O* p

    8 B! C+ o6 y% o+ U7 ?- j2 x. a

    • cocos2d-x框架图1 P0 H( e3 X& f: I. D* t# G

    1.1.2 基础阶段学习目标和作品演示

    • 了解cocos2dx

    • 实现飞机大战

    1.1.3 环境搭建

    • 安装python2.7和配置python路径

    • 安装vs2013

    • 解压cocos2dx到某目录,比如d:\\\\cocos\\\\cocos2d-x

    • 命令行进入cocos2d-x目录,执行setup.py

    1.1.4 介绍cocos2dx开发包目录

    • build 工程目录

    • cmake makefile目录

    • cocos cocos2dx核心源代码目录

    • docs 文档目录

    • extensions 拓展代码目录,主要是GUI部分

    • external 外部开源库

    • licenses 外部开源库licenses

    • plugin 插件

    • templates 创建工程模板,创建工程使用的模板工程

    • tests 测试项目cpp-test代码在这里

    • tools 工具,创建工程的脚本就在这里

    1.2 第一个工程

    万丈高楼平地起

    1.2.1 创建工程

    • cocos new ProjectName -l cpp' \\\\6 ^* J4 M! N( V7 r9 k0 P
      在当前目录下创建一个工程名字为ProjectName

    • cocos new ProjectName -l cpp -d d:\\\\cocos
      在d:\\\\cocos目录下创建一个名字为ProjectName的工程

    • cocos new ProjectName -l cpp -d d:\\\\cocos -p com.Orgnization.ProjectName
      在d:\\\\cocos目录下创建一个工程名为ProjectName,包名为com.Orgnization.ProjectName的工程

    • cocos new9 J! m- W8 E( y- _
      查看cocos new命令的帮助

    • 使用vs2013打开工程目录中的解决方案文件,对第一个工程进行编译和运行! M/ N, o, Y4 O8 j# |1 D

    1.2.2 介绍工程目录

    • Classes 跨平台游戏逻辑代码

    • cocos2d cocos引擎代码

    • proj.xxxx 平台相关的代码和工程文件

    • Resources 资源文件(图片、声音、脚本)

    1.2.3 介绍详细代码

    • 程序入口和AppDelegate% g& ?. X0 o/ x  t
      main函数通过虚函数调用到AppDelegate::applicationDidFinishLaunching

    • AppDelegate::applicationDidFinishLaunching()) Z4 N  H( H8 R8 u3 ~3 O
      这个是真正的入口函数,负责游戏的初始化,包括创建第一个场景

    • HelloWorld::init()
      场景层的初始化,负责显示场景的信息

    • HelloWorld::menuCloseCallback(Ref*)9 ?5 w2 A3 R8 a
      退出菜单的回调函数,负责程序退出

    • 头文件和命名空间
      cocos引擎定义cocos2d.h头文件中,并且使用了命名空间cocos2d,因此我们写的程序都应该包含cocos2d头文件,并且需要使用cocos2d命名空间,

    #include "cocos2d.h"USING_NS_CC;// #define USING_NS_CC using namespace cocos2d

    e USING_NS_CC using namespace cocos2d

    • 初始化的调用过程3 R5 ?% K: l# M5 \\\\+ r; ?, ^8 O

    1.2.4 cocos设计理念

    cocos2dx的设计者将游戏划分为一个个片段组成:每个片段由Scene负责组织;片段内部的模块划分由Layer负责组织;Scene和Layer虽然是游戏组织的一部分,但是它们一般并不可见、可见的部分如英雄、怪物、道具由精灵负责抽象。! n' C2 i8 _* W8 r
    Director负责推动游戏进程的发展,切换场景是由导演来负责的, ~$ H. s1 }8 C

      _5 A. g: M5 N* x4 M$ |* j) s
    1.3 精灵

    Sprite,游戏的灵魂& V4 h/ ~; ~4 M1 H9 b

    1.3.1 精灵的创建

    精灵可以通过图片、纹理或者精灵帧作为参数来创建  x/ x5 h: S0 P9 Z

    • Sprite::create()

    • Sprite::createWithTexture()

    • Sprite::createWithSpriteFrame()5 q1 v  b& w% `% {! L. B

    cocos2dx使用create函数来创建对象,create函数调用了new,init,autorelease等方法,对对象管理! R* \\\\, p* N) f/ i( m2 z: _0 R

    1.3.2 精灵的属性

    • 位置 Sprite::setPosition()

    • 锚点 Sprite::setAnchorPoint()

    • 旋转 Sprite::setRotation()

    • 缩放 Sprite::setScale()

    • 颜色 Sprite::setColor()

    • 可见 Sprite::setVisible()

    • 透明度 Sprite::setOpacity()

    • X翻转Sprite::setFlippedX()

    • Y翻转 Sprite::setFlippedY()

    • X扭曲 Sprite::setRotationSkewX()

    • Y扭曲 Sprite::setRotationSkewY()

    • 名字 Sprite::setName()

    • 标签 Sprite::setTag()

    • 精灵帧 Sprite::setSpriteFrame()

    • 纹理 Sprite::setTexture()

    • 纹理矩形 Sprite::setTextureRect()

    • 用户数据 Sprite::setUserData()

    • 用户对象 Sprite::setUserObject()

    • 获取包含精灵的矩形 Sprite::getBoundingBox()

    • ZOrder setLocalZOrder, setGlobalZOrder

    1.3.3 自定义精灵类(派生)

    为什么要派生精灵的子类?因为不同的精灵有不同的额外的属性和动作,从面向对象角度来说,额外的属性需要通过派生子类来加入。派生子类需要注意,在子类的init函数中,调用父类的init函数,Sprite提供了一些列init函数,供我们在子类中调用,我们可以选择一个合适的init函数使用。( Q: @, t" v* L

    • 初始化空精灵 Sprite::init()

    • 通过文件初始化精灵 Sprite::initWithFile()

    • 通过纹理初始化精灵 Sprite::initWithTexture()

    • 通过精灵帧初始化精灵 Sprite::initWithSpriteFrame()% v7 s* A6 r! m' a" K, u

    1.3.4 纹理和精灵帧

    • 纹理) x1 u, r9 K% I
      对应的类叫做Texture2D,在2D的概念中,纹理其实就是指图片了。图片在加载到内存之后,做进一步的处理,将数据格式转换成适合opengl渲染的格式,这个格式的数据我们称之为纹理。+ Q. [+ C% m0 d: {, E

      • 加载纹理方法:Director::getInstance()->getTextureCache()->loadImage("test.png");

    • 精灵帧
      对应的类叫做SpriteFrame,有时候一张大的纹理包括很多小图,我们只需要纹理的一部分来创建精灵,我们可以理解精灵帧是纹理的一部分。6 y) F  g) L1 @6 K" }

      • SpriteFrame* frame = SpriteFrame::create(filename, rect);

      • SPriteFrame* frame = SpriteFrame::createWithTexture(texture, rect);

      • SpriteFrameCache::getInstance()->addSpriteFramesWithFile(plistFile)1 H4 g, ^/ [3 y) c3 ~; v! q/ a& R3 ^6 K
        通过plist文件加载一些列精灵帧,这个将来在缓存时细说! `. a7 e  b; V. w" a$ ~% X# {8 t

    1.4 坐标体系和锚点

    要做到胸有成竹,必须要清楚坐标体系6 p3 ~- N2 Z2 [/ T

    1.4.1 坐标体系概念

    • cocos2dx坐标体系# Q6 [1 t& |% P+ l6 v! k! @2 s


    游戏中使用的是cocos2dx坐标体系,也叫GL坐标体系

    1.4.2 精灵的锚点

    • setAnchorPoint

    • 调用精灵的setPosition时的对齐点

    • 锚点范围为(0, 0) ~ (1, 1)

    • 使用相对坐标,非绝对坐标

    • 是setRotation的中心点

    1.5 单点触摸处理

    触摸处理是游戏控制的基础

    1.5.1 设置触摸监听

    • 创建EventListenerTouchOneByOne对象

    • 设置回调函数

      • onTouchBegan
        返回值true表示该监听器接受并处理这次触摸,并且后续函数会得到调用,否则返回false

      • onTouchMoved9 B* }  Q4 U& S- q
        触摸移动时被调用

      • onTouchEnded; u6 e, g# Z- h$ I9 m
        触摸结束时(松手时)被调用

      • onTouchCancelled8 T# G/ s+ {4 @' y$ X
        取消触摸(比如来电导致游戏切入后台)时被调用5 C/ Q0 w, q* w7 `& W- r; h

    • 将监听对象加入到事件分发器* j1 J: K. O& `- I4 j

      • _eventDispatcher

      • addEventListenerWithSceneGraphPriority

      • addEventListenerWithFixedPriority: T9 _4 I4 S1 ]6 A$ l7 G$ v+ |

    • 将监听对象删除

      • removeEventListener

      • removeAllEventListeners) r# o) M/ ?0 }7 X5 b: n! h

    1.5.2 Touch对象

    每个触摸函数都有两个参数,Touch和Event,其中Event可以忽略,Touch对象中带着一些触摸信息需要我们了解

    • Touch::getLocation
      返回触摸当前坐标,该坐标是世界体系的坐标,不论监听的对象是精灵还是层,返回坐标都是世界坐标,该函数可以在began、moved、ended、cancelled函数中调用获取当前触摸的位置

    • Touch::getDelta
      返回触摸偏移量,该函数一般在moved中调用才有意义

    • Touch::getStartLocation
      返回触摸开始时位置,该函数在began时和getLocation一样,在moved和ended时,可以调用该函数返回当初触摸开始时位置

    1.5.3 lambada表达式和应用

    • Lambada表达式

      • 与普通函数代码块相同

      • 一般省略,lambada表达式的返回值代表了返回类型

      • 与普通参数列表相同! J: I7 X3 x/ b& v

      • [] 不捕获

      • [=] 捕获外部所有常量,以传值方式

      • [&] 捕获外部所有变量,以引用方式

      • [&a, b] 以引用方式捕获a,以传值方式捕获b

      • [&a, =] 以引用方式捕获a,其他变量传值捕获

      • 捕获列表一般使用[&],即可

      • 捕获列表可以捕获的参数范围为lambada表达式可见的变量,包括之前定义的局部变量,this指针,全局变量,但是捕获局部变量是一个危险的行为,因为lambada表达式被调用时,局部变量可能已经不存在了.4 i, Q. L  g' H! ~

      • [capture list](parameter list)->return type{function body}

      • [capture list]和{function body}是必须的,其他是可选的

      • 基本语法:7 k2 H$ a) _  P% A2 H

      • 捕获列表 capture list' Y: F) A3 j1 d9 Y1 K. l

      • 参数列表 parameter list! b- R  ]9 D; ]; E" I

      • 返回类型 return type( G! Y  e3 Q6 F( q* q7 a8 ^" c

      • 代码块 function body' Z, N9 Q! p: e) f1 S; p: c

    Lambada表达式是一个匿名函数,由捕获列表,参数列表和代码块组成。捕获列表的存在使得我们可以在定义函数时,给函数传递参数,使得函数定义和调用更加灵活。! [$ v2 ]0 f5 t1 f1 J

    • 使用lambada表达式作为触摸处理的回调函数

    EventListenerTouchOneByOne* ev = EventListenerTouchOneByOne::create();ev->onTouchBegan = [](Touch* touch, Event* ev){return true; };ev->onTouchMoved = [&](Touch* touch, Event* ev){    streak->setPosition(touch->getLocation());    sprite->setPosition(touch->getLocation());};_eventDispatcher->addEventListenerWithSceneGraphPriority(ev, this);1.5.4 练习:使用触摸移动精灵

    • 创建精灵

    • 设置触摸

    • 在moved函数中,使用setPosition移动精灵

    1.6 定时器

    定时器是自动控制(AI)的基础

    1.6.1 帧定时器

    • Node::scheduleUpdate

    1.6.2 自定义定时器

    • Node::schedule5 N9 i+ N) b, X- z

    1.6.3 定时器回调函数的参数

    • void Node::update(float dt)  z3 i8 A& ]  E* w$ i
      参数dt表示超时时间间隔,以秒为单位,一般这个值是有误差的,而且一般大于设定的值,比如设置超时时间为1秒,那么dt可能是1.000111秒/ K0 O) x9 M  H# B% Y: l. o- x

    1.6.4 取消和干预定时器

    • 节点释放时,它自动会取消该节点拥有的定时器。

    • 节点未释放时,可以调用Node::unschedule取消某个定时器

    • 通过重新调用schedule可以改变定时器时间间隔

    1.6.5 练习:通过定时器实现动画

    • 创建精灵

    • 启动定时器

    • 在定时器里切换精灵的精灵帧3 c1 A, z0 x1 k+ ?. v

      • setSpriteFrame1 V( e& A: `7 x- e1 W$ O1 X

    1.6.6 练习:通过定时器实现精灵运动

    • 创建精灵

    • 启动定时器

    • 在定时器里设置精灵的位置

    1.7 内存管理

    cocos使用了引用计数器自动管理内存,不理解它,等着程序跑飞吧

    1.7.1 Ref类

    Ref类几乎是所有cocos类的父类,在2.2.3版本里,这个类叫做CCObject,该类有一个主要的功能,就是实现了对象的引用计数器

    1.7.2 管理引用计数器

    • 构造函数:构造函数将引用计数器初始化为1

    • retain:将计数器加1

    • release:将计数器减1,如果减去1之后等于0,则执行delete this,自己删除自己" k9 ?4 J' L. n* q

    1.7.3 静态的create方法

    • cocos采用静态的create函数来创建对象,在静态的create函数里,除了创建对象之外,还调用该对象的init函数来对对象进行初始化,最后调用了autorelease将该对象加入内存管理池,纳入自动管理。

    • cocos的这种创建对象的方法,参考了ObjectC,从C++设计角度来说,这样创建对象也是合理的,构造函数负责数值初始化,而init负责逻辑初始化。0 q( z7 k( U+ X$ V( j/ M5 W

    1.7.4 内存管理池

    • 当对象调用autorelease时,它将自己加入内存管理池,该内存管理池会在一次帧循环结束时,调用池子里所有对象的release,这样如果对象在这个帧循环内,没有被其他对象引用的话,该对象会被自动销毁。

    • 如果该对象被别的对象引用了,那么别的对象要不再引用该对象时,要调用该对象的release函数。

    大部分时候,我们只需要create对象,然后将它加入到父节点即可,Ref的release、retain、autorelease函数,其实是内部调用的。但是理解机制很重要,某些场合下,需要我们自己去release对象

    1.8 数组容器Vector

    敌人很多,得拿个东西装起来

    1.8.1 Vector

    • Vector是cocos里定义的容器类,它只能将Ref或者Ref的子类对象加入到该数组中。

    • 当一个Ref对象被加入到该数组时,Ref对象的引用计数器会自动增加1

    • 当Ref对象从数组中移除时,Ref对象的引用计数器会自动减少1

    • 数组访问

      • 增加对象 Vector::pushBack

      • 删除对象 Vector::erase, Vector::eraSEObject

      • 遍历对象

    1.8.2 与std::vector的区别

    • std::vector是标准C++库提供的容器,它可以将任何类型数据加入到数组,但是它不会自动给元素增加引用计数器

    1.9 碰撞检测

    战斗要打响了,麻烦也来了/ L" m4 J, [$ h

    1.9.1 矩形碰撞检测

    • 矩形和矩形:Rect::intersectsRect(Rect)

    • 矩形和圆:Rect::intersectsCircle(Vec2, float)

    • 矩形和点:Rect::containsPoint(Vec2)8 G! N0 p; k; Z. C% V- l5 n' [% {

    1.9.2 圆形碰撞检测

    • 转化为圆心距离是否超过两个圆半径之和5 _+ O* w6 s* V. m# F" e' O, z3 g

    1.9.3 点与圆碰撞检测

    • 转化为圆心到点的距离是否小于半径7 f5 T4 {9 x& k# Z+ q

    1.9.4 线段碰撞检测

    • ccpSegmentIntersect

    1.10 文本显示

    在不显眼的角落,它们扮演着很重要的角色

    1.10.1 systemFont

    • Label::createWithSystemFont()% y( I& f, a8 I  I4 s

    1.10.2 altas

    • Label::createWithCharMap()

    1.10.3 BMFont

    • Label::createWithBMFont()

    1.10.4 TTF(TrueTypeFont) Label

    • Label::createWithTTF()" R  r+ k6 X6 p' l$ r9 _

    1.10.5 Label的锚点也是Label文字的对齐方式1.11 菜单

    菜单,其实是触摸封装

    1.11.1 菜单实现

    • Menu类和MenuItem类

      • Menu类,负责响应触摸,是Layer的派生类

      • MenuItem类,负责展示菜单项目

    • 为菜单项设置回调函数 MenuItem::setCallback

    • 自动排列菜单项 Menu::alignItemsVertically

    • 移动菜单项位置,菜单的坐标体系原点在屏幕中间  h/ b2 k7 B+ J: p

    1.11.2 菜单项介绍

    • MenuItemFont

    • MenuItemLabel

    • MenuItemSprite

    • MenuItemImage

    • MenuItemToggle

    补充知识:设计分辨率,getFrameSize,getWinSize,getVisibleSize

    1.12 场景切换

    战斗结束了…

    1.12.1 场景介绍

    • 场景是独立的游戏逻辑

    • 场景是导演调度单位

    • 场景是组织游戏元素的根节点

    • 显示在游戏界面上的元素,都是以场景为根节点的节点树的节点

    1.12.2 场景替换 replaceScene

    • 替换场景接口

    Scene* scene = Scene::create();Director::getInstance()->replaceScene(scene);

    • 替换场景行为

      • 删除原来活动的场景

      • 新场景为活动场景– M  a. d3 E, u8 B& B3 Q7 N

    1.12.3 场景入栈和出栈 pushScene

    • 场景压栈– t& X6 {7 `! C( ]' U5 J7 V

    Scene* scene = Scene::create();Director::getInstance()->pushScene(scene);

    • 场景压栈行为; l2 f+ z: Q/ J: f; |, }% d. `' l1 h) x

      • 原来的活动场景保存在栈中

      • 新场景为活动场景

    • 场景出栈

    Director::getInstance()->popScene();

    • 场景出栈行为1 ?9 b1 v  P! b+ K7 h  C; c

      • 当前活动场景出栈并删除

      • 出栈之后当前栈定场景为活动场景

    1.12.4 总结

    • 在cocos中,导演对象有一个场景栈来保存所有的场景,栈顶的场景为当前活动的场景,非栈顶的场景为暂停的场景。

    • runWithScene是第一次往栈中增加场景

    • replaceScene是替换栈顶的场景

    • pushScene是往栈中增加场景

    • popScene是从栈中删除一个场景,如果popScene后,栈为空,也就是说pop最后一个场景后,程序将退出

    • 在游戏中,慎用pushScene,因为会导致内存暴增,除非自己很清楚必须这样做。

    • 场景切换效果/ O4 y$ {' J0 B# N, E0 ]

      • 只有replace可以有切换效果

    1.13 截取屏幕

    拍照留念可以不* s4 n$ h* W3 P2 N  C

    1.13.1 使用RenderTexture抓屏

    • 流程

      • RenderTexture::begin

      • 被抓取对象::visit

      • RenderTexture::end  r7 b- S, o8 c

    1.13.2 使用utils::captureScreen抓屏

    • 在3.2中引入+ C2 K2 B, V# k/ z+ X

    1.14 声音

    没声音,再好的戏也出不来

    1.14.1 cocos2dx跨平台音频引擎cocosdension

    • cocos2dx的音频引擎为各个平台提供统一的接口

    • 头文件 #include "SimpleAudioEngine.h"

    • 需要使用命名空间 CocosDenshion0 k( k$ z7 f& u, J4 o% i. t

    1.14.2 背景音乐

    • 播放背景音乐

      • 循环播放0 n  M* w( t2 B; n  W: v9 N3 f

    • 停止背景音乐$ e5 |, s, c/ p( I6 C3 x5 C

    1.14.3 音效

    • 播放音效

    • 停止音效; b) k- ~- P5 R: J5 L0 t

    1.14.4 干预

    • 设置音量

    • 暂停

    • 继续– G' a: D# d: x" [' ~( Q

    1.14.5 提高效率:预加载音乐1.14.6 背景音乐的生命周期1.14.7 程序进入后台的处理

    补充:学习cppTest代码,从cppTest代码获得知识1 G+ q- _7 }& [, s0 S; o. {

    1.15 实现飞机大战案例

    一切准备就绪,让我们来设计游戏吧8 C  H& g+ D4 u8 `& D' C/ N

    1.15.1 设计目标

    • 划分模块,简化模块逻辑,逐步实现! U/ ~$ L! y3 L/ e( m" P0 V2 Y

    1.15.2 控制层实现

    • 英雄战机的移动控制

    • 发射子弹

    • 引爆炸弹

    1.15.3 AI层实现

    • 敌机产生

    • 敌机自动移动控制

    • 子弹自动移动控制

    • 炸弹道具产生2 C3 E4 |: z  n) J

    1.15.4 碰撞检测

    • 敌机和子弹的碰撞检测

    • 敌机和英雄战机的碰撞检测9 x( c1 w3 K3 X  m/ W' c

    1.15.5 记分实现

    • 创建Label

    • 敌军飞机死掉时,给Label更新分数. w' s! ?+ Y% d# P4 R5 ]

    1.15.6 实现游戏暂停

    • 添加暂停按钮

    • 在暂停按钮的处理程序中9 R) ^% o; h0 E4 B

      • 截取屏幕

      • 压入暂停场景

    • 在暂停场景中' L) X7 s8 F+ D! `# q$ @

      • 将游戏截图显示在场景中

      • 弹出继续游戏界面7 U/ S( H5 t8 k/ M3 w6 x

    1.15.7 进入分数场景