首页 > 代码库 > cocos2dx 3.2之Lua打飞机项目

cocos2dx 3.2之Lua打飞机项目

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

运行结果:



 

cocos2dx 3.2之Lua打飞机项目