Cocos2dx-js VS Cocos2dx-lua
从效率上编译成字节码的Lua效率肯定比JS高,从坑方面来说,目前Lua几乎没有太大的坑,JS除非团队有牛人。从已经上线成功的产品来说,大多采用Cocos2dx-lua。JS目前没有比较成功的产品。从入门方面,Lua更为合适。对于小团队而言,目前Lua比JS更加合适。
Cocos2d-x官方主推JS的解决方案,因为JS可以跨越移动设备、桌面的限制,实现一套程序跑任意平台。不过对于HTML5的发展与强调体验的游戏来说,也许H5还需一段时间。
从市场来说,Lua明显是更为理性的选择,因为它更加成熟、安全且大作采用。
1.场景
准备资源文件
创建公共函数
$ vim app/Common.lua
-- 每个方块占32个像素
gridSize = 32
-- 场景宽度:10个方块共320px
sceneWidth = 8+2
-- 场景高度:18个方块
sceneHeight = 18
-- 方块坐标转换为屏幕坐标
function grid2pos(x, y)
local director = cc.Director:getInstance()
-- 获取可视区域宽高
local size = director:getVisibleSize()
-- 获取原点
local origin = director:getVisibleOrigin()
local posX = origin.x + size.width/2 + gridSize*x - sceneWidth/2*gridSize
local posY = origin.y + size.height/2 + gridSize*y - sceneHeight/2*gridSize
return posX, posY
end
创建场景
$ vim app/Scene.lua
require "app.Common"
function makeKey(x, y)
return x*1000 + y
end
-- 8*18
local Scene = class("Scene")
function Scene:ctor(node)
self.map = {}
for x=0, sceneWidth-1 do
for y=0, sceneHeight-1 do
local posX,posY = grid2pos(x,y)
local sprite = cc.Sprite:create("brick.png")
sprite:setPosition(posX, posY)
node:addChild(sprite)
local visible = (x==0 or x==sceneWidth-1) or y==0
sprite:setVisible(visible)
self.map[makeKey(x,y)] = sprite
end
end
end
function Scene:clear()
for y=1,sceneHeight-1 do
self:clearLine(y)
end
end
function Scene:clearLine(y)
for x=1,sceneWidth-2 do
self.set(x,y,false)
end
end
function Scene:set(x,y,value)
local sprite = self.map[makeKey(x,y)]
if sprite==nil then
return
end
sprite:setVisible(value)
end
function Scene:get(x, y)
local sprite = self.map[makeKey(x,y)]
if sprite==nil then
return
end
return sprite:isVisible()
end
return Scene
主场景中添加
$ vim app/scenes/MainScene.lua
local Scene = require "app.Scene"
local MainScene = class("MainScene", function()
return display.newScene("MainScene")
end)
function MainScene:ctor()
end
function MainScene:onEnter()
self.scene = Scene.new(self)
end
function MainScene:onExit()
end
return MainScene
$ vim app/Brick.lua
--[[
1. 方块的基本类型
2. 方块数据化
]]--
local brickArray= {
{
{
{1,1,1,0},
{0,1,0,0},
{0,0,0,0},
{0,0,0,0},
},
{
{0,1,0,0},
{1,1,1,0},
{0,0,0,0},
{0,0,0,0},
},
{
{0,1,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0},
},
{
{0,1,0,0},
{0,1,1,0},
{0,1,0,0},
{0,0,0,0},
}
},
{
{
{0,1,1,0},
{0,1,1,0},
{0,0,0,0},
{0,0,0,0},
}
},
{
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0},
},
{
{0,1,0,0},
{0,1,0,0},
{0,0,1,0},
{0,0,1,0},
}
},
{
{
{1,1,0,0},
{0,1,1,0},
{0,0,0,0},
{0,0,0,0},
},
{
{0,0,1,0},
{0,1,1,0},
{0,1,0,0},
{0,0,0,0},
}
},
{
initOffset = 1,
{
{0,0,0,0},
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
},
{
{0,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,1,0,0},
}
},
{
initOffset = 1,
{
{0,0,0,0},
{1,1,1,0},
{1,0,0,0},
{0,0,0,0},
},
{
{1,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,0,0,0},
},
{
{0,0,1,0},
{1,1,1,0},
{0,0,0,0},
{0,0,0,0},
},
{
{0,1,0,0},
{0,1,0,0},
{0,1,1,0},
{0,0,0,0},
}
},
{
initOffset = 1,
{
{0,0,0,0},
{1,1,1,0},
{0,0,1,0},
{0,0,0,0},
},
{
{0,1,0,0},
{0,1,0,0},
{1,1,0,0},
{0,0,0,0},
},
{
{1,0,0,0},
{1,1,1,0},
{0,0,0,0},
{0,0,0,0},
},
{
{0,1,1,0},
{0,1,0,0},
{0,1,0,0},
{0,0,0,0},
}
},
}
方块处理类
local Brick = class("Brick")
local initXoffset = sceneWidth/2 - 3
local function iterateBrick(index, trans, callback)
local transArray = brickArray[index]
local eachBrick = transArray[trans]
for y=1,#eachBrick do
local xData = eachBrick[y]
for x=1,#xData do
local data = xData[x]
if not callback(x, y, data~=0) then
return false
end
end
end
return true
end
function rawPlace(index, trans, scene, newX, newY)
local result = {}
local callback = function(x, y, b)
if b then
local finalX = newX + x
local finalY = newY - y
if scene:get(finalX, finalY) then
return false
end
table.insert(result, {x=finalX, y=finalY})
end
return true
end
if iterateBrick(index, trans, callback) then
for k,v in ipairs(result) do
scene:set(v.x, v.y, true)
end
return true
end
end
function Brick:ctor(scene, index)
self.x = initXoffset
self.y = sceneHeight
local offset = brickArray[index].initOffset
if offset then
self.y = self.y + offset
end
self.scene = scene
self.index = index
self.trans = 1
end
function Brick:move(deltaX, deltaY)
self:clear()
local x = self.x + deltaX
local y = self.y + deltaY
if rawPlace(self.index, self.trans, self.scene, x, y) then
self.x = x
self.y = y
return true
else
self.place()
return false
end
end
function Brick:rotate()
local offset = brickArray[self.index].initOffset
if offset and self.y==0 then
return
end
self:clear()
local transArray = brickArray[self.index]
local trans = self.trans + 1
if trans>#transArray then
trans = 1
end
if rawPlace(self.index, trans, self.scene, self.x, self.y) then
self.trans = trans
else
self:place()
end
end
function Brick:place()
return rawPlace(self.index, self.trans, self.scene, self.x, self.y)
end
function Brick:clear()
iterateBrick(self.index, self.trans, function(x,y,b)
local finalX = self.x + x
local finalY = self.y + y
if b then
self.scene:set(finalX, finalY, false)
end
return false
end)
end
return Brick
使用Texture对帧动画打包
动画帧数据文件 tex.plist
frames
brick0.png
frame
{{182,2},{32,32}}
offset
{0,0}
rotated
sourceColorRect
{{0,0},{32,32}}
sourceSize
{32,32}
brick1.png
frame
{{148,2},{32,32}}
offset
{0,0}
rotated
sourceColorRect
{{0,0},{32,32}}
sourceSize
{32,32}
brick2.png
frame
{{114,2},{32,32}}
offset
{0,0}
rotated
sourceColorRect
{{0,0},{32,32}}
sourceSize
{32,32}
brick3.png
frame
{{80,2},{32,32}}
offset
{0,0}
rotated
sourceColorRect
{{0,0},{32,32}}
sourceSize
{32,32}
bullet0.png
frame
{{36,2},{6,6}}
offset
{1,-1}
rotated
sourceColorRect
{{14,14},{6,6}}
sourceSize
{32,32}
bullet1.png
frame
{{36,86},{10,10}}
offset
{0,0}
rotated
sourceColorRect
{{11,11},{10,10}}
sourceSize
{32,32}
explode0.png
frame
{{2,240},{16,14}}
offset
{0,1}
rotated
sourceColorRect
{{8,8},{16,14}}
sourceSize
{32,32}
explode1.png
frame
{{36,64},{22,20}}
offset
{-1,1}
rotated
sourceColorRect
{{4,5},{22,20}}
sourceSize
{32,32}
explode2.png
frame
{{90,98},{26,24}}
offset
{-1,1}
rotated
sourceColorRect
{{2,3},{26,24}}
sourceSize
{32,32}
grass.png
frame
{{46,2},{32,32}}
offset
{0,0}
rotated
sourceColorRect
{{0,0},{32,32}}
sourceSize
{32,32}
home.png
frame
{{216,2},{30,26}}
offset
{0,0}
rotated
sourceColorRect
{{1,3},{30,26}}
sourceSize
{32,32}
mud.png
frame
{{2,206},{32,32}}
offset
{0,0}
rotated
sourceColorRect
{{0,0},{32,32}}
sourceSize
{32,32}
road.png
frame
{{2,172},{32,32}}
offset
{0,0}
rotated
sourceColorRect
{{0,0},{32,32}}
sourceSize
{32,32}
sign_bullet.png
frame
{{20,240},{10,24}}
offset
{0,-1}
rotated
sourceColorRect
{{11,5},{10,24}}
sourceSize
{32,32}
sign_tank_blue.png
frame
{{238,78},{16,18}}
offset
{0,-1}
rotated
sourceColorRect
{{8,8},{16,18}}
sourceSize
{32,32}
sign_tank_green.png
frame
{{238,58},{16,18}}
offset
{0,-1}
rotated
sourceColorRect
{{8,8},{16,18}}
sourceSize
{32,32}
steel0.png
frame
{{2,138},{32,32}}
offset
{0,0}
rotated
sourceColorRect
{{0,0},{32,32}}
sourceSize
{32,32}
steel1.png
frame
{{2,104},{32,32}}
offset
{0,0}
rotated
sourceColorRect
{{0,0},{32,32}}
sourceSize
{32,32}
steel2.png
frame
{{2,70},{32,32}}
offset
{0,0}
rotated
sourceColorRect
{{0,0},{32,32}}
sourceSize
{32,32}
steel3.png
frame
{{2,36},{32,32}}
offset
{0,0}
rotated
sourceColorRect
{{0,0},{32,32}}
sourceSize
{32,32}
tank_blue_fire0.png
frame
{{62,194},{26,28}}
offset
{-1,1}
rotated
sourceColorRect
{{2,1},{26,28}}
sourceSize
{32,32}
tank_blue_fire1.png
frame
{{46,226},{26,28}}
offset
{-1,1}
rotated
sourceColorRect
{{2,1},{26,28}}
sourceSize
{32,32}
tank_blue_run0.png
frame
{{36,98},{26,30}}
offset
{-1,1}
rotated
sourceColorRect
{{2,0},{26,30}}
sourceSize
{32,32}
tank_blue_run1.png
frame
{{206,58},{26,30}}
offset
{-1,1}
rotated
sourceColorRect
{{2,0},{26,30}}
sourceSize
{32,32}
tank_blue_run2.png
frame
{{174,36},{26,30}}
offset
{-1,1}
rotated
sourceColorRect
{{2,0},{26,30}}
sourceSize
{32,32}
tank_blue_run3.png
frame
{{142,36},{26,30}}
offset
{-1,1}
rotated
sourceColorRect
{{2,0},{26,30}}
sourceSize
{32,32}
tank_blue_run4.png
frame
{{110,36},{26,30}}
offset
{-1,1}
rotated
sourceColorRect
{{2,0},{26,30}}
sourceSize
{32,32}
tank_blue_run5.png
frame
{{78,36},{26,30}}
offset
{-1,1}
rotated
sourceColorRect
{{2,0},{26,30}}
sourceSize
{32,32}
tank_blue_run6.png
frame
{{46,36},{26,30}}
offset
{-1,1}
rotated
sourceColorRect
{{2,0},{26,30}}
sourceSize
{32,32}
tank_blue_run7.png
frame
{{216,30},{26,30}}
offset
{-1,1}
rotated
sourceColorRect
{{2,0},{26,30}}
sourceSize
{32,32}
tank_green_fire0.png
frame
{{88,130},{24,28}}
offset
{0,1}
rotated
sourceColorRect
{{4,1},{24,28}}
sourceSize
{32,32}
tank_green_fire1.png
frame
{{74,224},{24,28}}
offset
{0,1}
rotated
sourceColorRect
{{4,1},{24,28}}
sourceSize
{32,32}
tank_green_run0.png
frame
{{62,162},{24,30}}
offset
{0,1}
rotated
sourceColorRect
{{4,0},{24,30}}
sourceSize
{32,32}
tank_green_run1.png
frame
{{86,64},{24,30}}
offset
{0,1}
rotated
sourceColorRect
{{4,0},{24,30}}
sourceSize
{32,32}
tank_green_run2.png
frame
{{64,98},{24,30}}
offset
{0,1}
rotated
sourceColorRect
{{4,0},{24,30}}
sourceSize
{32,32}
tank_green_run3.png
frame
{{62,130},{24,30}}
offset
{0,1}
rotated
sourceColorRect
{{4,0},{24,30}}
sourceSize
{32,32}
tank_green_run4.png
frame
{{36,194},{24,30}}
offset
{0,1}
rotated
sourceColorRect
{{4,0},{24,30}}
sourceSize
{32,32}
tank_green_run5.png
frame
{{36,162},{24,30}}
offset
{0,1}
rotated
sourceColorRect
{{4,0},{24,30}}
sourceSize
{32,32}
tank_green_run6.png
frame
{{36,130},{24,30}}
offset
{0,1}
rotated
sourceColorRect
{{4,0},{24,30}}
sourceSize
{32,32}
tank_green_run7.png
frame
{{60,64},{24,30}}
offset
{0,1}
rotated
sourceColorRect
{{4,0},{24,30}}
sourceSize
{32,32}
water.png
frame
{{2,2},{32,32}}
offset
{0,0}
rotated
sourceColorRect
{{0,0},{32,32}}
sourceSize
{32,32}
metadata
format
2
realTextureFileName
tex.png
size
{256,256}
smartupdate
$TexturePacker:SmartUpdate:de153ba6091aa039f5da088c67aa2563$
textureFileName
tex.png
调整屏幕为横屏
$ app/config.lua
CONFIG_SCREEN_WIDTH = 960
CONFIG_SCREEN_HEIGHT = 640
显示坦克
创建对象类 app/Object.lua
- 对象类
local Object = class("Object")
-- 构造对象
function Object:ctor(node)
-- 创建精灵并添加到节点内
self.sprite = cc.Sprite:create()
self.node = node
self.node:addChild(self.sprite)
end
-- 判断对象是否有效
function Object:alive()
return self.sprite ~= nil
end
-- 销毁对象
function Object:destroy()
self.node:removeChild(self.sprite)
self.sprite = nil
end
return Object
创建坦克类 app/tank.lua
-- 加载对象
local Object = require "app.Object"
-- 坦克类派生自对象
local Tank = class("Tank", Object)
-- 构造函数
function Tank:ctor(node)
-- 父类初始化
Tank.super.ctor(self, node)
self.node = node
-- 临时代码
local director = cc.Director:getInstance()
-- 获取窗口大小
local size = director:getWinSize()
-- 设置精灵居中
self.sprite:setPosition(size.width/2, size.height/2)
-- 获取精灵甄
local spriteFrameCache = cc.SpriteFrameCache:getInstance()
local frame = spriteFrameCache:getSpriteFrame("tank_green_run0.png")
-- 设置精灵帧
self.sprite:setSpriteFrame(frame)
end
-- 析构函数
function Tank:destroy()
Tank.super.destroy(self)
end
return Tank
主场景加载并精灵帧并显示坦克app/scenes/MainScene.lua
local Tank = require "app.Tank"
local MainScene = class("MainScene", function()
return display.newScene("MainScene")
end)
function MainScene:ctor()
end
function MainScene:onEnter()
-- 加载游戏资源
local spriteFrameCache = cc.SpriteFrameCache:getInstance()
-- 加载精灵帧动画
spriteFrameCache:addSpriteFrames("res/tank/tex.plist")
-- 创建坦克
self.tank = Tank.new(self)
end
function MainScene:onExit()
end
return MainScene