1 创建lua打飞机项目
cocos new T32Lua -dE:\Installed\cocos2d-x-3.2\cocos2d-x-3.2\projects -l lua
2 项目代码
Common.lua |
--用于打印日志信息 function cclog(...) print(string.format(...)) end function createBackMenu(node, callback) -- 获得窗口的大小 local winSize = cc.Director:getInstance():getWinSize() -- 创建菜单 local menu = cc.Menu:create() -- node中加入菜单 node:addChild(menu) --local function startGame() -- cc.Director:getInstance():replaceScene(SceneMenu()) --end -- 加菜单项 local menuItem = cc.MenuItemImage:create("btn_back_normal.png", "btn_back_press.png") -- 菜单中添加菜单项 menu:addChild(menuItem) -- 注册处理函数 menuItem:registerScriptTapHandler(callback) -- 注册处理函数 -- menu的锚点默认是在屏幕正中间的,将它设置在屏幕右下角 menuItem:setAnchorPoint(cc.p(1, 0)) -- 重新设置菜单项的位置 menuItem:setPosition(winSize.width/2, -winSize.height/2); -- 设置缩放,在2.3中x方向和y方向上的缩放比例必须相同,但是在3.2中没有限制 menuItem:setScale(2) end -- 设置触摸事件 function regTouch(node, onTouchBegan, onTouchEnded, onTouchMoved) local evListen = cc.EventListenerTouchOneByOne:create() evListen:registerScriptHandler(onTouchBegan, cc.Handler.EVENT_TOUCH_BEGAN) -- 如果onTouchEnded不为空 if onTouchEnded ~= nil then evListen:registerScriptHandler(onTouchEnded, cc.Handler.EVENT_TOUCH_ENDED) end -- 如果onTouchMoved不为空 if onTouchMoved ~= nil then evListen:registerScriptHandler(onTouchMoved, cc.Handler.EVENT_TOUCH_MOVED) end -- 如果 local evDisp = node:getEventDispatcher() evDisp:addEventListenerWithSceneGraphPriority(evListen, node) end |
LayerScrollBackground.lua 滚动的背景 |
require "Common" function LayerScrollBackground() local layer = cc.Layer:create() -- 获得屏幕的大小 local winSize = cc.Director:getInstance():getWinSize() -- 加背景 local bg = cc.Sprite:create("background.png") -- 层中添加作为背景的精灵 layer:addChild(bg) -- 设置精灵的锚点 bg:setAnchorPoint(0, 0) -- 需要两个动作,一个动作向下移动,一个动作设置位置 local action1 = cc.MoveBy:create(10, {x=0, y=-winSize.height}) local action2 = cc.Place:create({x=0, y=0}) local action = cc.Sequence:create(action1, action2) -- 执行动作 bg:runAction(cc.RepeatForever:create(action)) return layer end |
SceneMenu.lua 菜单 |
require "Common" require "LayerScrollBackground" require "SceneGame" function SceneMenu() local scene = cc.Scene:create() local winSize = cc.Director:getInstance():getWinSize() -- 滚动的背景 local bgLayer = LayerScrollBackground() scene:addChild(bgLayer) -- ScrollView cc.SpriteFrameCache:getInstance():addSpriteFrames("chooselevel.plist") local node = cc.Node:create() for i = 1, 5 do local spriteName = "ChooseLevel" .. i .. ".png" local spriteFrame = cc.SpriteFrameCache:getInstance():getSpriteFrame(spriteName) local sprite = cc.Sprite:createWithSpriteFrame(spriteFrame) node:addChild(sprite) sprite:setPosition(winSize.width/2 + winSize.width*(i-1), winSize.height/2) sprite:setTag(1000+i) end local scrollView = cc.ScrollView:create(winSize, node) scene:addChild(scrollView) scrollView:setContentSize(winSize.width*5, winSize.height) scrollView:setDirection(0) -- 增加Touch处理 local function onTouchBegan(touch, event) return true end local function onTouchEnded(touch, event) local sLoc = touch:getStartLocation() local dLoc = touch:getLocation() local d = {x=sLoc.x - dLoc.x, y=sLoc.y-dLoc.y} local pt = node:convertToNodeSpace(sLoc) if d.x*d.x+d.y*d.y < 25 then for i=1, 5 do local sprite = node:getChildByTag(1000+i) local rc = sprite:getBoundingBox() if cc.rectContainsPoint(rc, pt) then cc.Director:getInstance():replaceScene(SceneGame(i)) cclog("start new game " .. i) end end end end regTouch(scene, onTouchBegan, onTouchEnded) local function Back() cc.Director:getInstance():replaceScene(SceneStart()) end createBackMenu(scene, Back) return scene end |
SceneStart.lua |
require "SceneMenu" require "Common" function SceneStart() local scene = cc.Scene:create() local winSize = cc.Director:getInstance():getWinSize() cclog(winSize.width .. winSize.height) -- 加背景图片 local bg = cc.Sprite:create("background.png") scene:addChild(bg) bg:setPosition(winSize.width/2, winSize.height/2) -- 加菜单按钮 local menu = cc.Menu:create() scene:addChild(menu) local function startGame() cc.Director:getInstance():replaceScene(SceneMenu()) end -- 加菜单项 local menuItemStart = cc.MenuItemImage:create("btn1_normal.png", "btn1_push.png") menu:addChild(menuItemStart) menuItemStart:registerScriptTapHandler(startGame) -- 注册处理函数 return scene end |
SceneGame.lua |
require "Common" require "LayerScrollBackground" function SceneGame(idx) --创建 local scene = cc.Scene:create() local winSize = cc.Director:getInstance():getWinSize() -- 滚动的背景 local bgLayer = LayerScrollBackground() -- 场景中加上层 scene:addChild(bgLayer) -- 数据结构,子弹的数组和敌机的数组 local bullets = {} -- 添加敌机 local enemys = {} -- 创建英雄战机 local plane = cc.Sprite:create("Player" .. idx .. ".png") -- 场景中添加飞机 scene:addChild(plane) -- 设置飞机的位置 plane:setPosition(winSize.width/2, plane:getBoundingBox().height) -- 设置plane的ZOrder plane:setLocalZOrder(100) ----- 加载战斗机的属性 local vm = cc.FileUtils:getInstance():getValueMapFromFile("planeinfo.xml"); plane.damage = tonumber(vm["planedamageamount" .. idx]) plane.hp = tonumber(vm["plane" .. idx .. "_hp"]) plane.cd = tonumber(vm["planeshootspeedrate" .. idx]) plane.curCD = 0; cclog(plane.damage .. " " .. plane.hp .. " " .. plane.cd) -- 显示分数和血的Label local labelScore = nil local labelHP = nil local function createLabels() -- 设置label labelHP = cc.Label:createWithSystemFont("" .. plane.hp, "Arial", 50) -- 设置Label的锚点 labelHP:setAnchorPoint(cc.p(1, 1)) -- 设置锚点的位置 labelHP:setPosition(winSize.width, winSize.height) scene:addChild(labelHP) labelHP:setLocalZOrder(1010) labelScore = cc.Label:createWithSystemFont("0", "Arial", 50) labelScore:setAnchorPoint(cc.p(0, 1)) labelScore:setPosition(0, winSize.height) scene:addChild(labelScore) labelScore:setLocalZOrder(1010) end createLabels() -- 移动飞机 -- 增加Touch处理 local function onTouchBegan(touch, event) return true end local function onTouchMoved(touch, event) local x, y = plane:getPosition() local d = touch:getDelta() plane:setPosition(x+d.x, y+d.y) end local function onTouchEnded(touch, event) end regTouch(scene, onTouchBegan, onTouchEnded, onTouchMoved) ------------------- shoot -- angle参数代表的发射角度,delta表示子弹发射的起始位置和英雄战机的位置的偏移 local function shootOne(angle, delta) cc.SimpleAudioEngine:getInstance():playEffect("m/bullet.wav") local bullet = cc.Sprite:create("Bullet.png") scene:addChild(bullet) local x, y = plane:getPosition() bullet:setPosition(x+delta.x, y+delta.y) bullet:setRotation(angle) -- math.rad(角度) 把角度转换成弧度 local dx = math.sin( math.rad(angle) ) * winSize.height local dy = math.cos( math.rad(angle) ) * winSize.height local moveBy = cc.MoveBy:create(5, cc.p(dx, dy)) bullet:runAction(moveBy) -- 子弹保存在数组里 table.insert(bullets, bullet) end local function Shoot() local sizePlane = plane:getContentSize() if idx == 1 then shootOne(0, cc.p(0, sizePlane.height/2)) elseif idx == 2 then shootOne(0, cc.p(0, sizePlane.height/2)) shootOne(0, cc.p(-sizePlane.width/4, sizePlane.height/4)) shootOne(0, cc.p(sizePlane.width/4, sizePlane.height/4)) elseif idx == 3 then shootOne(0, cc.p(0, sizePlane.height/2)) shootOne(-30, cc.p(0, sizePlane.height/2)) shootOne(30, cc.p(0, sizePlane.height/2)) elseif idx == 4 then shootOne(0, cc.p(0, sizePlane.height/2)) shootOne(180, cc.p(0, -sizePlane.height/2)) shootOne(90, cc.p(sizePlane.width/2, 0)) shootOne(270, cc.p(-sizePlane.width/2, 0)) elseif idx==5 then shootOne(45, cc.p(0, 0)) shootOne(45+90, cc.p(0, 0)) shootOne(45+180, cc.p(0, 0)) shootOne(45+270, cc.p(0, 0)) end end local function tickShoot() plane.curCD = plane.curCD + 1 if plane.curCD >= plane.cd then Shoot() plane.curCD = 0 end end local tickShootID = cc.Director:getInstance():getScheduler():scheduleScriptFunc(tickShoot, 0, false) -- 检查子弹是否飞出窗口外 local function checkBulletAndEnemy() -- 得到子弹数量 local n = table.getn(bullets) for i = n, 1, -1 do local bullet = bullets[i] -- 判断bullet是不是出了窗口 local x, y = bullet:getPosition() if x<0 or y<0 or x>winSize.width or y > winSize.height then bullet:removeFromParent() table.remove(bullets, i) -- 从bullets数组中,删除下标为i的元素 cclog("bullet is out of window") end end n = table.getn(enemys) for i = n, 1, -1 do local enemy = enemys[i] -- 判断enemy是不是出了窗口 local x, y = enemy:getPosition() if y < -enemy:getContentSize().height/2 then enemy:removeFromParent() table.remove(enemys, i) -- 从enemys数组中,删除下标为i的元素 end end end local tickCheckBullet = cc.Director:getInstance():getScheduler():scheduleScriptFunc(checkBulletAndEnemy, 0, false) -- 产生敌机的定时器 local function genEnemy(type) -- 创建敌机精灵,加入到数组,加入渲染树 -- 增加敌机属性 -- 随机设置位置 local enemy = cc.Sprite:create("Enemy" .. type .. ".png") table.insert(enemys, enemy) scene:addChild(enemy) -- 敌军飞机的额外属性 local hp = {10, 30, 100} enemy.hp = hp[type] local score = {1000, 3000, 10000} enemy.score = score[type] local speed = {150, 100, 50} enemy.speed = speed[type] enemy.type = type -- 设置初始位置 local sizePlane = enemy:getContentSize() math.randomseed(os.time()) local x = math.random(sizePlane.width/2, winSize.width-sizePlane.width/2) local y = winSize.height + sizePlane.height/2 enemy:setPosition(x, y) -- 设置飞机飞行动作 local distance = winSize.height + sizePlane.height + 5 local moveBy = cc.MoveBy:create(distance*1.0/enemy.speed, cc.p(0, -distance)) enemy:runAction(moveBy) end local function genEnemy1() genEnemy(1) end local function genEnemy2() genEnemy(2) end local function genEnemy3() genEnemy(3) end local tickGenEnemy1 = cc.Director:getInstance():getScheduler():scheduleScriptFunc(genEnemy1, 1, false) local tickGenEnemy2 = cc.Director:getInstance():getScheduler():scheduleScriptFunc(genEnemy2, 3, false) local tickGenEnemy3 = cc.Director:getInstance():getScheduler():scheduleScriptFunc(genEnemy3, 10, false) local function loadBoomAnimation() local spriteFrameCache = cc.SpriteFrameCache:getInstance() spriteFrameCache:addSpriteFrames("PFBoom.plist") -- CCArray* arr = CCArray:create() local spriteFrames = {} for i = 1, 18 do local spriteFrame = spriteFrameCache:getSpriteFrame("Boom_" .. i .. ".png") table.insert(spriteFrames, spriteFrame) end local animation = cc.Animation:createWithSpriteFrames(spriteFrames, 0.05) cc.AnimationCache:getInstance():addAnimation(animation, "ENEMYBOOM") end loadBoomAnimation() local function removeEnemy(node, tab) node:removeFromParent() end local function enemyBoom(idx) local enemy = enemys[idx] cc.SimpleAudioEngine:getInstance():playEffect("m/enemy" .. enemy.type .. "_down.wav") -- 增加分数 local score = labelScore:getString() score = tonumber(score) + enemy.score labelScore:setString("" .. score) table.remove(enemys, idx) -- 执行爆炸动画,然后再调用removeFromParent local animation = cc.AnimationCache:getInstance():getAnimation("ENEMYBOOM") local animate = cc.Animate:create(animation) local callfunc = cc.CallFunc:create(removeEnemy) local seq = cc.Sequence:create(animate, callfunc) enemy:runAction(seq) -- enemy:removeFromParent() end local function collision() local nEnemy = table.getn(enemys) local rcPlane = plane:getBoundingBox() for i = nEnemy, 1, -1 do local enemy = enemys[i] local rcEnemy = enemy:getBoundingBox() local bEnemyBoom = false -- 如果敌机和英雄战机碰撞, rcEnemy, rcPlane if cc.rectIntersectsRect(rcEnemy, rcPlane) then plane.hp = plane.hp - enemy.hp labelHP:setString("" .. plane.hp) if plane.hp <= 0 then cc.Director:getInstance():replaceScene(SceneMenu()) break end enemyBoom(i) bEnemyBoom = true end -- 跟子弹进行碰撞检测 if bEnemyBoom == false then local nBullet = table.getn(bullets) for j = nBullet, 1, -1 do local bullet = bullets[j] -- 如果子弹和敌机碰撞 local ptBullet = cc.p( bullet:getPosition() ) if cc.rectContainsPoint(rcEnemy, ptBullet) then bullet:removeFromParent() table.remove(bullets, j) enemy.hp = enemy.hp - plane.damage; if enemy.hp <= 0 then enemyBoom(i) break -- 表示这个敌机不再和下一个子弹做碰撞检测 end end end end end end local tickCollisionID = cc.Director:getInstance():getScheduler():scheduleScriptFunc(collision, 0, false) local function Back() cc.Director:getInstance():replaceScene(SceneMenu()) end createBackMenu(scene, Back) -- 注销定时器 local function onNodeEvent(event) if "enter" == event then cclog("OnEnter") cc.SimpleAudioEngine:getInstance():playMusic("m/game_music.wav", true) end if "exit" == event then cc.SimpleAudioEngine:getInstance():stopMusic() cc.Director:getInstance():getScheduler():unscheduleScriptEntry(tickShootID) cc.Director:getInstance():getScheduler():unscheduleScriptEntry(tickCheckBullet) cc.Director:getInstance():getScheduler():unscheduleScriptEntry(tickGenEnemy1) cc.Director:getInstance():getScheduler():unscheduleScriptEntry(tickGenEnemy2) cc.Director:getInstance():getScheduler():unscheduleScriptEntry(tickGenEnemy3) cc.Director:getInstance():getScheduler():unscheduleScriptEntry(tickCollisionID) end end scene:registerScriptHandler(onNodeEvent) return scene end |
main.lua |
--引入lua的方式是通过require require "Cocos2d" require "Cocos2dConstants" -- cclog 打印日志的方式 cclog = function(...) print(string.format(...)) end -- for CCLuaEngine traceback lua中连接字符串的方式是通过 .. 实现的 function __G__TRACKBACK__(msg) cclog("----------------------------------------") cclog("LUA ERROR: " .. tostring(msg) .. "\n") cclog(debug.traceback()) cclog("----------------------------------------") return msg end local function main() collectgarbage("collect") -- avoid memory leak collectgarbage("setpause", 100) collectgarbage("setstepmul", 5000) -- initialize director lua中定义局部变量的是通过local的方式 local director = cc.Director:getInstance() local glview = director:getOpenGLView() if nil == glview then glview = cc.GLView:createWithRect(‘HelloLua‘, cc.rect(0,0,768/2,1280/2)) director:setOpenGLView(glview) end -- 设置设计分辨率,这个就是图片的实际大小 glview:setDesignResolutionSize(768, 1280, cc.ResolutionPolicy.NO_BORDER) --turn on display FPS director:setDisplayStats(true) --set FPS. the default value is 1.0/60 if you don‘t call this director:setAnimationInterval(1.0 / 60) -- 设置加载的文件包 cc.FileUtils:getInstance():addSearchPath("src") cc.FileUtils:getInstance():addSearchPath("res") --support local targetPlatform = cc.Application:getInstance():getTargetPlatform() if (cc.PLATFORM_OS_IPHONE == targetPlatform) or (cc.PLATFORM_OS_IPAD == targetPlatform) or (cc.PLATFORM_OS_ANDROID == targetPlatform) or (cc.PLATFORM_OS_WINDOWS == targetPlatform) or (cc.PLATFORM_OS_MAC == targetPlatform) then cclog("result is ") --require(‘debugger‘)() end ----------------------------------------------- -- 自定义的文件的require必须在 addSearchPath之后,2.2.3没有这个问题 require "SceneStart" cc.Director:getInstance():runWithScene(SceneStart()) end local status, msg = xpcall(main, __G__TRACKBACK__) if not status then error(msg) end |
运行结果: |