• cocos2dx 3.2之Lua打飞机项目


    1          创建lua打飞机项目

    cocos new T32Lua -dE:Installedcocos2d-x-3.2cocos2d-x-3.2projects -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)

     

        -- 加菜单button

        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) .. " ")

        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

    执行结果:



  • 相关阅读:
    python-TCP传输模型
    python-锁机制
    python-生产者消费者模式
    python-Lock锁线程同步和互斥
    python-Event事件线程同步和互斥
    python-thread封装类创建线程
    python-fifo管道文件通信
    python-thread多线程
    Sublime一些设置
    gdb的user-define command
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/7211741.html
Copyright © 2020-2023  润新知