当前位置: 首页 > 工具软件 > Node-Lua > 使用案例 >

cocos2d-lua基础

姜玉泽
2023-12-01

cocos2d-lua

一.核心概念

  1. 场景:scene,在特定时间、特定地点发生的事件的集合,可以看作是一个容器,包含各种游戏的元素
  2. 层:图层(一个场景可以有多个层,一个场景至少有一个层)
  3. 精灵:sprite,在屏幕上移动的对象,它能够被控制。通常是可移动、能被控制的图片动画等。
  4. Ui组件:界面上的元素
  5. 导演:director,游戏的总控,是一个共享的单例对象,可以在代码中的任何地方调用
  6. 节点****:node类,凡是可以显示的都是节点(节点是cocos2dx中最为重要的根类,被广泛的继承

二.坐标系

坐标系基本规则:x正方向向右、y正方向向上、z正方向向屏幕外(笛卡尔坐标系)

1.绝对坐标系和相对坐标系

绝对坐标系:是游戏引擎中的抽象概念,他是远点固定在屏幕左下角的cocos2d-lua坐标系

相对坐标系:是节点相关联的坐标系,每个节点都有独立的坐标系,以节点的左下角为原点遵循坐标系的基本规则,当节点移动时,坐标系也会随之移动

2.锚点

​ 将一个节点添加到父级节点中,需要设置其在父级节点上的位置,本质上是将节点的锚点设置在父级节点坐标系上的位置,同时锚点也是旋转一个节点时的中心点

在cocos2d-lua中,luyer的锚点默认值为(0,0)sprite的默认值为(0.5,0.5)

3.ZOrder与渲染顺序

​ 在cocos2d-lua开发2d游戏,z轴的值并不影响物体显示在屏幕上的远近,它只与渲染顺序有关,z轴值小的node最先被渲染

三.文本标签

TTF文本标签:TTF(True Type Font)是一种字库规范,是苹果公司和Microsoft公司共同推出的字体文件格式,随着windows的流行,TTF变成最常用的一种字体文件格式

  1. display中的TTF接口

display.newTTFlabel(params)对TTF创建进行了统一的封装和简化

参数功能
text显示的文本
font字体名或字体路径名
size字体大小
color文字颜色,默认为白色(可选)
align文字的水平对齐方式(可选)
valign文字的垂直对齐方式(可选)
dimensions文本显示区域的尺寸用cc.size()创建(可选)
xx坐标(可选)
yy坐标(可选)
--创建一个TTF文本
local ttfLabel = display.newTTFLabel({
        text = "bandari",
        font = "CreteRound-Italic.ttf",
    	size = 30,
        align = cc.TEXT_ALLGNMENT_CENTER,
        x = display.cx,
        y = display.cy + 400
    })
self:addChild(ttf;abelSys)

四.按钮

不同于文本标签,按钮是图形显示与用户触摸控制的整合抽象。它影响用户触摸,做出显示上的反馈,并触发回调事件,对于普通按钮的实现使用ccui.Button,对于复选框按钮的实现使用ccui.CheckBox

  1. ccui.Button的创建

    创建:ccui.Button:create(A,B,C,D)

    参数说明

    A:普通状态下显示的图片(可选)

    B:按下状态下显示的图片(可选)

    C:禁用状态下显示的图片(可选)

    D:图片来源,0从文件,1从精灵帧缓存

  2. 创建文本按钮

    创建文本按钮,就扣四个参数都不需要传值

    local btn = ccui.Button:create()
    btn:setTitleText('bandari')
    btn:setTitleFontSize(24)
    btn:addTo(self)
    btn:addTouchEventListener(funtion(ref,eventType)		--设置触摸监听函数
    	print('bandari is vary cool')
    	end
    end)
    
  3. ccui.CheckBox的创建

    ccui.CheckBox:create(A,B,C,D,E,G)

    A:图片状态下显示的背景图片(可选)

    B:按下状态下显示的背景图片(可选)

    C:勾选图片图片状态(可选)

    D:禁用状态下显示的背景图片(可选)

    E:勾选图片禁用状态(可选)

    F:图片来源,0从文件,1从精灵帧缓存(可选)

    local btnCB = ccui.CheckBox:create("btn1.png","btn2.png","btn3.png","btn4.png","btn5.png",0)
    btnCb:setSekected(true)	
    btnCB:addEventListener(function(sender,eventType)		--设置触摸监听函数
        if eventType then
            print('1')
        else
            print('2')
        end)
    

五.场景转换

​ 一个游戏可能拥有多个场景,但在同一时刻只有一个场景是出于激活状态的
​ 当游戏在不同场景之间切换时,为了避免场景切换突兀,程序员往往需要在切换时加入一定的动画衔接效果
​ 场景转换:display.wrapSceneWithTransition(scene,transitionType,time,more)有四个参数,具体作用如下

  1. scene:目标场景

  2. transitionType:指定场景切换使用的动画效果,参数如下

    参数效果
    coressFade淡入淡出
    fade淡出当前场景到指定颜色,默认为cc.c3b(0,0,0)可用more参数设定反转颜色
    fadeBL从左下角开始淡出
    fadeDown从底部开始的淡出
    fadeTR从右上角开始淡出
    fadeUp从顶部开始淡出
    flipAngular当前场景倾斜后反转成下一场景,默认从左边开始反转,more参数可以修改反转方式

    更多的参见书中61页…

  3. time:转场动画的持续时间

  4. more:参数2可能需要额外的参数

通常用封装好的display.replaceScene完成同样的功能
如: display.replaceScene(nextScene,"fade,0.5,cc.c3b(255,0,0))

六.动作

动作是用来面熟游戏节点行为规范的一个类,其中Action类是所有动作的基类,动作作用于Node,因此每个动作都需要由Node对象执行,它本身并不是一个能在屏幕中显示的对象

1.瞬时动作

指的是能够在下一帧立刻执行并完成的动作,这中间不产生任何动画效果

  1. Place

    该动作用于将节点放置在某个指定位置,作用与setPosition相同

    local place = cc.Place:create(cc.p(10,10))
    
  2. FilpX 和 FilpYwer

    这两个动作只能用于Sprite,他们分别将Sprite沿X轴或Y轴反转显示,其作用与setFlippedX或setFlippedY相同

    local flipxAction = cc.FlipX:create(true)
    --参数true表示翻转,false的话为不翻转
    
  3. Show 和 Hide

    分别用于显示和隐藏节点,作用与setVisible相同

    local hideAction = cc.hide:create()
    
  4. RemoveSelf

    将自己从父节点上一处,通产用在顺序执行的符合动作的最后一个动作,以实现特效播放完毕后自动移除节点

    local removeAction = cc.RemoveSelf:create()
    
  5. CallFunc

    函数动作CallFunc用在符合动作中判断某个哥动作是否执行结束,然后启用其他逻辑

    local callback = cc.CallFunc:create(function()print ("bandari")end)
    

2.有限时间动作

连续的动作需要至少一个游戏帧来完成

  1. MoveTo 与 MoveBy

    使节点从当前目标匀速直线运动到目标点

    local moveTo = cc.MoveTo:create(2,cc.p(0,0))
    --参数1:运动的总时间
    --参数2:moveTo是目标重点,moveBy是相对偏移向量
    
  2. JumpTo 与 JumpBy

    使节点以一定的轨迹匀速条约到指定位置,用法如下

    local jumpTo = cc.JumpTo:create(2,cc.p(10.0),50,2)
    --参数1:运动总时间
    --参数2:JumpTo是目标点,JumpBy是相对偏移向量
    --参数3:跳跃高度
    --参数4:跳跃次数
    
  3. BezierTo 与 BezierBy

    使节点沿贝塞尔曲线运动,每条贝塞尔曲线都包含一个起点和一个终点,在一条曲线中,起点和终点各自包含一个控制点,而控制点到端点的连线称作控制线,控制点决定了曲线的形状,包含角度和长度两个参数,用法如下

    local action = cc.BezierTo:create(2,{cc.p(display.right,display.top),cc.p(200,200),cc.p(200,200)})
    --参数1:运动总时间
    --参数2:包含贝塞尔曲线数据的table,依次是:
    --a.控制点1的坐标
    --b.控制点2的坐标
    --c.BezierTo是目标点,BezierBy是相对偏移量
    
  4. ScaleTo 与 ScaleBy

    使节点的缩放系数随时间线性变化。用法如下:

    local action = cc.ScaleTo:create(2,0.5)
    --参数1:持续时间
    --参数2:ScaleTo是最终缩放系数,ScaleBy是相对缩放系数
    
  5. RotateTo 与 RotateBy

    使节点围绕锚点旋转,用法如下:

    local action =  cc.rotateTo:create(2,180)
    --参数1:持续的时间
    --参数2:ScaleTo是最终角度,RotateBy是相对缩放系数
    
  6. FadeIn 、FadeOut 和 FateTo

    FadeIn:淡入,透明度变化范围为0~255

    fadeOut:淡出,透明度变化范围为255~0

    local action = cc.FadeIn:create(2)
    --参数:持续时间
    

    FadeTo:从节点当前透明度变化到指定透明度

    local action = cc.FateTo:create(2,110)
    --参数1:持续时间
    --参数2:目标透明度
    
  7. TintTo 与 TintBy

    使节点着色,用法如下

    local action = cc.TintTo:create(1,0,255,0)
    --参数1:持续时间
    --参数2:TintTo为目标red值,TintBy为相对red变化值
    --参数3:TintTo为目标green值,TintBy为相对green变化值
    --参数4:TintTo为目标blue值,TintBy为相对blue变化值
    
  8. Blink

    使节点闪烁,内部是设置节点透明度为0或255来实现闪烁效果。用法如下:

    local action = cc.Blink:create(1,2)
    --参数1:持续时间
    --参数2:闪烁次数
    
  9. Animation

    序列帧动画也叫逐帧动画,在时间轴的每帧上逐帧绘制不同的内容,使其连续播放而成动画

3.复合动作

cocos2d-lua提供了一套动作的符合机制,允许组合各种基本动作,产生更为复杂和生动的效果。

复合动作是一类特殊的动作,因此它也需要使用Node的renAction方法执行。而他的特殊之处在于,作为动作容器,符合动作可以把许多动作组合成一个复杂的动作。因此,通常会是使用一个或多个动作在创建复合动作,再把动作交给节点执行。复合动作十分灵活,这是由于复合动作本身也是动作,因此也可以作为一个普通的动作嵌套在其他复合动作中。

  1. DelayTime

    DelayTime表示什么都不做,用来表示动作序列里的一段空白期,通过占位的方式将不同的动作段串接在一起。

    cc.DelayTime:create(delay)
    --参数delay表示需要延时的时间
    
  2. Repeat 与 RepeatForever

    有些情况下动作只需要执行一次,但还常常遇到一个动作反复执行的情况。对于一些重复的动作,可以通过Repeat与RepeatForever这两个方式重复执行

    cc.Repeat:create(action,times)
    cc.RepeatForever:create(action)
    --RepeatForever是无限重复执行动作,Repeat重复执行times次的动作
    --Repeat动作不能嵌入其他复合动作内使用,它应该是最外层的动作。嵌入其他复合动作会导致不能正确重复动作
    
  3. Spawn

    使一个Node同时执行一批动作,并列动作必须是能够同时执行并继承自FiniteTimeAction的动作,合并之后,动作执行完成时间按照最大的一个动作执行时间计算。

    cc.Spawn:create(action1,...)
    
  4. Sequence

    除了让动作同时并列执行,更常遇到的情况是顺序执行一系动作。Sequence提供了一个动作队列,它会顺序执行一系列。

    cc.Sequence:create(action1,...)
    
  5. Follow

    Follow是一个节点跟随另一个节点的动作。Follow的创建方法如下

    cc.Follow:create(followedNode,rect)
    --作用是创建一个跟随的动作
    --参数1:跟随的目标
    --参数2:跟随范围,离开范围就不再跟随
    

4.变速动作

游戏开发过程中有时候需要速度变化的动作,如模拟汽车起步加速的过程等。

  1. Speed

    可调整速度动作Speed不是一个独立的哦你工作,可以把他理解为是对目前动作的“包装”,经过这个“包装”以后,就可以实现慢动作和快进的效果,使用Speed来处理很方便,创建方法如下

    cc.Speed:create(action,speed)
    --作用是让目标动作运行速度改变
    --参数1:目标动作
    --参数2:倍速
    
  2. ActionEase

    Speed虽然能改变动作的速度,但是只能按照比例改变目标动作的速度,如果要实现动作由快到慢,速度随时间改变的变速运动,需要不停的修改它的speed属性才能实现,ActionEase系列动作通过使用内置的多种自动速度变化来解决这一问题,该内包含了:指数缓冲、sine缓冲、弹性缓冲、跳跃缓冲和回震缓冲,每类运动运动都包含了in、out、inout 三个不同的的变化

    in:表示动作执行先慢后快

    out:表示动作执行先快后慢

    inout:表示动作执行慢-快-慢

5.节点与动作相关的接口

所有动作都由Action创建,最终这些Action是由节点来执行的

node:runAction(action)	--执行

如果节点多次调用runAction运行不同的动作,那么这些动作会同时运行,效果叠加,既然有运行接口,就会有停止接口:

node:stopAllAction()		--停止所有动作
node:stopAction(action)		--停止某个指定的action对象
node:stopActionByTag(tag)	--停止某个tag的action对象

action类也是从node继承而来,也可以为action设置tag标签

node:setTag(tag)		--node设置tag为整数
action:setTag(tag)		--naction设置tage为整数

使用tag来获取或停止一个动作

node:getActionByTag(tag)
node:stopActionByTag(tag)

七.序列帧动画

序列帧动画也叫逐帧动画简称帧动画,动画的每一帧都有独立的数据保存,连续播放这些帧而形成了动画。

1.精灵表单

精灵表单由一张存储了多个精灵纹理的大图和一个对应的描述文件组成,描述文件用于记录每个精灵纹理在大图上的位置区域。

cocos2d-lua中使用display.addSpriteFrames(A,B,C)方法从指定的SpriteSheet导入精灵帧,三个参数如下

A:plistFilename数据文件,string类型

B:image纹理文件,string类型

C:handler回调函数,function类型

八.调度器

cocos2d-lua引擎中的调度器是用来周期执行某个函数或延时执行某个函数的。

1.全局调度器

在游戏中,经常需要周期性的处理事务,并且这些事物不会因为某个节点的销毁而取消。

cocos2d-lua框架默认不会加载全局调度器模块,需要手动加载:

local scheduler = require(cc.PACKAGE_NAME..".scheduler")

全局调度器模块提供了如下三种调度器:

  1. 全局帧调度器

    游戏的每一帧都会出发的调度器,主要用在碰撞检测等每一帧都需要计算的地方。

    全局调度器不需要依赖任何场景,因此可以在整个游戏范围内实现比较精确的全局记时。

    local scheduler = require(cc.PACKAGE_NAME..".scheduler")
    local function onInterval(dt)
        print("bandari")
    end
    scheduler.scheduleUpdateGlobal(onInterval)
    --dt是两次调度之间的时间间隔
    
  2. 全局自定义调度器

    全局帧调度器是全局自定义调度器的特例,自定义调度器可以指定调度时间,提供更高的灵活性。

    自定义时间间隔应在1/60s以上(引擎默认每秒刷新60帧)

    local scheduler = require(cc.PACKAGE_NAME..".scheduler")
    local function onInterval(dt)
        print("bandari")
    end
    scheduler.scheduleUpdateGlobal(onInterval,0.5)
    --dt是两次调度之间的时间间隔
    
  3. 全局延时调度器

    在游戏中的某些场合,只想实现一个单次的延迟调用,这就需要延迟调度器。scheduler.performWithDelayGlobal()会在等待指定时间后执行一次回调函数,然后自动取消该scheduler

    local scheduler = require(cc.PACKAGE_NAME..".scheduler")
    local function onInterval(dt)
        print("bandari")
    end
    scheduler.performWithDelayGlobal(onInterval,0.5)
    

2.节点调度器

Node是coco2d-lua引擎中的基础类,他封装了很多基础方法和属性,其中调度器就是Node提供的方法之一。Node中的调度器只能在Node中使用,Node负责管理调度器的生命周期,当Node销毁的时候,会自动注销节点名下的所有调度器,游戏项目中大多时候会使用节点调度器

节点调度器同样提供了三种调度器

  1. 节点帧调度器:节点帧调度器属于节点帧事件(在事件分发机制中介绍)

  2. 节点自定义调度器

    自定义时间间隔应在1/60s以上(引擎默认每秒刷新60帧)

    local action = node:schedule(function()
        print('bandari')
    end,1.0)
    --schedule函数内部使用动作系统来实现的,如果需要提前停止节点调度器,可以用停止动作的方式实现
    node:stopAction(action)
    
  3. 节点延时调度器

    节点延时调度器等待指定事件后执行一次回调函数。

    node:performWithDelay(function()
        print('bandari')
    end,1.0)
    --提前停止节点延迟调度器的方法依然是使用stopAction()
    

九.事件分发机制

事件按照功能和用途分为

  1. 节点事件
  2. 帧事件
  3. 键盘事件
  4. 加速计时间
  5. 触摸事件

1.节点事件

节点事件在一个Node对象进入和退出场景时触发

node:addNodeEventListener(cc.NODE_EVENT,function(event)
	print(event.name)
end)
--启用
node:setNodeEventEnabled(true)

--注:如果使用display.newScene()创建的场景,默认开始了节点事件。如果是其他节点,需要主动调用setNodeEventEnabled开启节点事件监听。

参数event只有name属性,介绍如下

解释
enter加载场景
exit退出场景
enterTransitionFinish转场特效结束
exitTransitionStart转场特效开始
cleanup场景被完全清理并从内存删除

2.帧事件

每帧都会执行的事件

local node = display.newNode()
self:addChild(node)
--注册事件
node:addNodeEventListener(cc.NODE_ENTER_FRAME_EVENT,function(dt)
    print(dt)
end)
--启用帧事件
node:shduleUpdata()
--0.5s后,停止帧事件
node:performWithDelay(function()
    --禁用帧事件
    node:unscheduleUpdate()
    print("stop")
    
    --在等0.5s,重新启动帧事件
    node:peformWithDelay(function()
            --再次启动帧事件
            node:scheduleUpdate()
    end,0.5))
end,0.5)

3.键盘事件

监听键盘事件的方法如下

self:setKeypadEnabled(true)
self:addNodeEventListener(cc.KEYPAD_EVENT,function(event)
    print("TestKeypadEvent = "..event.key)
end)

event为table,有以下属性值

解释
code按键对应的编码:数值
key按键对应的字符串:字符串
type按键事件类型:字符串

Android设备可以响应Menu和Back按键事件,对应的key值如下:

menu:菜单键 back:返回键

type按键事件类型有如下的值

解释
Pressed键盘按键按下事件
Released键盘按键谈起事件

4.加速计事件

现在手机都配备了加速计,用于测量设备静止或匀速运动时所受的重力方向

重力感应来自移动设备的是加速计

通常是支持X、Y、Z三个方向的加速度感应(三向加速计)

可以根据三个方向的力度来计算手机倾斜的角度和方向

self:addNodeEventListener(cc.ACCEKEROMETER_EVENT,function(event)
    print("AccelerateData:",event.x,event.y,event.z,event.timestamp)
end)
self:setAccelerometerEnabled(true)

--event属性如下
--1.event.x,event.y,event.z:设备在x、y、z轴上的角度
--2.event.timestamp:测量值更新时间

5.触摸事件

在介绍触摸事件之前首先要理解显示层级和触摸区域两个概念,显示层级和触摸区域

1.显示层级

​ 游戏的画面是由一些列的Node、Scene、Layer和Sprite等对象构成的,这些对象都是由Node基类继承,可以将Node成为显示节点,一个游戏画面就是许多显示节点构成的树结构,越向上的node显示层级就越高,从画面白哦线上来说,node是背景,上面的node是建筑,那么建筑就会挡住下面的背景,从而构成了显示层级的关系

2.触摸区域

​ 所谓触摸区域,就是一个Node即其所有子Node显示内容占据的屏幕空间。

​ 这个屏幕空间包括了图片的透明部分

3.单点触摸事件

单点触摸事件一个时刻只相应一个触摸点
通过setTouchMode设置Node的触摸监听模式,然后通过addNodeEventListener设置触摸事件监听回调函数。

node:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)	--设置单点触摸可以不写,默认就是单点触摸
node:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
    printf("sprite: %s x,y: %0.2f.%0.2f",event.name,event.x,event.y)
    if event.name == "brgan" then
        return true
    end
end)
node:setTouchEnabled(true)--开启节点的触摸事件监听,他必须在addNodeEventListener之后调用

event是一个table,具体信息如下

  1. event.name:事件类型

    解释
    began手指开始触摸屏幕,在began状态时,如果要继续接受该触摸事件的状态的话,需要处理函数返回true
    moved手指在屏幕上移动
    ended手指离开屏幕
    cancelled因其他原因取消触摸操作。通常情况下cancelled和ended是相同的处理逻辑
  2. event.x:触摸点x坐标

  3. event.y:触摸点y坐标

4.多点触摸

--先设置触摸模式为多点触摸
node:setTouchMode(cc.TOUCH_MODE_ALL_AT_ONCE)
--然后添加触摸事件回调函数
--注册触摸事件
node:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
    --event.name是触摸事件的状态:began、moved、ended、cancelled
    --event.point包含所有触摸点
    --按照event.point[id] = {x = ?,y = ?}的结构组织
    for id,point in paires(event.point) do
    	printf("event[%s] %s = %0.2f,%0.2f",event.name,id,point.x,point.y)
    end
    
    if event.name = "began" then
        return true
    end
end)

多点触摸时,事件状态的含义有所不同

解释
began此状态可以被触发多次,每一次代表一个或多个手指开始接触屏幕
moved由于多点触摸时可能只有部分触摸点移动,所以此时event.point中只包含所有变化的触摸点数据
ended当一个或多个触摸点消失时,出现ended状态。此时event.point中包含删除的触摸点数据
cancelled因其他原因导致触摸点被取消但手指不一定离开屏幕,此时event.point中包含了删除的触摸点数据

5.触摸事件吞噬

​ 默认情况下Node在响应触摸后(在began状态返回true表示要响应触摸),就会阻止事件继续传递给Node的父对象(更下层的Node),这种情况成为事件吞噬

​ Node:setTouchSwallowEnabled()可以改变这一行为,默认true吞噬事件,如果设置为false则Node响应触摸事件后仍然会将事件继续传递给父节点

 类似资料: