Скорость игры увеличивается при каждом перезапуске - Corona

Пытаюсь сделать джетпак-концепт-джойрид на короне. Прежде всего, в отличие от других SDK, где, когда вы меняете сцену, предыдущая сцена автоматически удаляется, в короне вы должны удалить каждый и объект и функционировать самостоятельно.

Через неделю я наконец смог удалить объекты при смене сцены, но теперь я столкнулся с новой проблемой. Каждый раз, когда я меняю сцены и возвращаюсь к игровому экрану, скорость лазеров и ракет увеличивается каждый раз (может быть, вдвое?). Как я могу сбросить его скорость? Я даже добавил другую переменную "gameStatus", чтобы удалить прослушиватель событий, и попытался распечатать его, но на самом деле статус игры никогда не возвращался "окончен", он всегда "работал". Вот игровой экран, где все происходит


РЕДАКТИРОВАТЬ: я только что заметил, например, если 3 объекта уже появились, то после перезагрузки экрана только первые 3 объекта кажутся быстрыми, и это нормально с четвертого.

local composer = require( "composer" )
local scene = composer.newScene()
local physics = require( "physics" )
physics.start()

local image, text1

local function onSceneTouch( self, event )
    if event.phase == "began" then      
        composer.gotoScene( "startScreen", "fade", 400  )       
        return true
    end
end

function scene:create( event )
    local sceneGroup = self.view

    -- Variable
    ---------------------------------------
    sW = display.contentWidth
    sH = display.contentHeight

    -- trying to reset gameStatus on restart
    gameStatus = "ended"
    gameStatus = "running"


    --------------------------------------------------------
    backgroundTiles = {}

    drawBackground = function()
        cieling = display.newRect( 0, 0, 2 * sW, sH * 0.05)
        physics.addBody( cieling, "static", { density=0, friction=0, bounce=0 } )
        cieling.x, cieling.y = cieling.contentWidth / 4, cieling.contentHeight * 0.25
        cieling.alpha = 0
        cieling.name = "ceiling"

        ground = display.newRect( 0, sH, 2 * sW, sH * 0.05)
        physics.addBody( ground, "static", { density=3, friction=1, bounce=0.1 } )
        ground.x, ground.y = ground.contentWidth / 4, sH - ground.contentHeight * 0.25
        ground.alpha = 0
        ground.name = "ground"

    end

    drawBackground()
    --------------------------------------------------------


    --------------------------------------------------------
    drawBird = function()
        bird = display.newImageRect( "a/img/hero/hero.png", 80, 58)
        bird.x, bird.y = 0 - sW * 0.1, ground.y - ground.contentHeight - 10
        bird.isFixedRotation = true; bird.angularVelocity = 0;
        physics.addBody( bird, { density=1, friction=0.5, bounce=0.1 } )
        bird.name = "bird"
        sceneGroup:insert( bird )

        bird:addEventListener( "collision", onCollision )
    end

    coinsCollected, tokensCollected = 0, 0

    birdFlight = function()
        if ( gameStatus == "running" ) then
            transition.to(bird, {
                y = bird.y - 75,
                transition = easing.outQuad,
                onComplete = function() end
            })
            function birdFlight()
                --transition.to( bird, { rotation=-45, time=300 } )
            end
            birdFlight()
            function birdFall()
                --transition.to( bird, { rotation=90, time=300 } )
            end
            timer.performWithDelay(700, birdFall, 1)
        end
    end
    display.currentStage:addEventListener( "tap", birdFlight )

    function onCollision(event)
        if event.phase == "began" then
            if event.other.name == "coin" then
                coinsCollected = coinsCollected + 1
            end
            if event.other.name == "token" then
                tokensCollected = tokensCollected + 1
            end
            if event.other.name == "missile" or event.other.name == "laser" or event.other.name == "rod" then
               -- game ended
            end
        end
    end

    drawBird()

    function atFrame(event)
        if gameStatus == "running" then
            bird.x,bird.y = sW / 3,bird.y + 9
            if ( bird.y > sH - 70) then bird.y = sH - 70 end
            if ( gameStatus == "ended" ) then bird.y = bird.y + 15 end
        end
    end
    Runtime:addEventListener( "enterFrame", atFrame )

    --------------------------------------------------------



    --------------------------------------------------------
    missile, missileAlert, missileMoving = {}, {}, {}

    function removeMissile(i)
        local onEnterFrame = function( event )
            if missile[i] ~= nil and missile[i].x ~= nil and gameStatus == "running" then
                if missile[i].x < -100 then
                    display.remove( missile[i] )
                    missile[i] = nil
                end
            end
        end
        Runtime:addEventListener( "enterFrame", onEnterFrame )

        print(gameStatus)

        if gameStatus == "ended" then
            Runtime:removeEventListener( "enterFrame", onEnterFrame )
        end 
    end


    function flyMissile(i)
        local onEnterFrame = function( event )
            if missile[i] ~= nil and missile[i].x ~= nil and missile[i].y ~= nil and gameStatus == "running" then
                if missileMoving[i] == true then
                    missile[i].y = bird.y
                end
                missile[i].x = missile[i].x - 5
                if missileAlert[i] ~= nil then
                    if missileMoving[i] == true then
                        missileAlert[i].y = bird.y
                    end                 
                    if missile[i].x < sW then
                        display.remove( missileAlert[i] )
                        missileAlert[i] = nil
                    end                 
                end
            end
        end
        Runtime:addEventListener( "enterFrame", onEnterFrame )

        print(gameStatus)

        if gameStatus == "ended" then
            Runtime:removeEventListener( "enterFrame", onEnterFrame )
        end 
    end


    function holdMissile(i)
        local onEnterFrame = function( event )
            if missile[i] ~= nil and missile[i].x ~= nil and gameStatus == "running" then
                if missile[i].x < sW * 1.5 then
                    if missileAlert[i] ~= nil then
                        missileAlert[i]:setFillColor(1,1,0)
                    end
                    missileMoving[i] = false
                end
            end
        end
        Runtime:addEventListener( "enterFrame", onEnterFrame )

        print(gameStatus)

        if gameStatus == "ended" then
            Runtime:removeEventListener( "enterFrame", onEnterFrame )
        end 
    end


    function spawnMissile(i)

        missile[i] = display.newRect( sW*2, sH/2, 80, 80 )
        missileAlert[i] = display.newRect( sW-80, bird.y, 80, 80 )
        physics.addBody(missile[i],"kinematic",{isSensor=true})
        missile[i].name = "missile"
        sceneGroup:insert( missile[i] )
        sceneGroup:insert( missileAlert[i] )

        missileMoving[i] = true

        flyMissile(i)
        removeMissile(i)
        holdMissile(i)

    end

    spawnMissile(1)
    --------------------------------------------------------


    --------------------------------------------------------
    laser = {}

    function moveAndRemovelaser(i)
        local onEnterFrame = function( event )
            if laser[i] ~= nil and laser[i].x ~= nil and gameStatus == "running" then               
                laser[i].x = laser[i].x - 5
                if laser[i].x < 0 - sW / 2 then
                    display.remove( laser[i] )
                    laser[i] = nil
                end
            end
        end
        Runtime:addEventListener( "enterFrame", onEnterFrame )

        print(gameStatus)

        if gameStatus == "ended" then
            Runtime:removeEventListener( "enterFrame", onEnterFrame )
        end 
    end

    function spawnlaser(i)

        laserSize = math.random(1,2)
        laserPosition = math.random(1,3)
        laserRotation = math.random(1,4)

        if laserSize == 1 then
            laser[i] = display.newRect( 100,100,50,sH/3 )
        else
            laser[i] = display.newRect( 100,100,50,sH/2 )
        end

        sceneGroup:insert( laser[i] )

        laser[i].x = sW * 2
        laser[i].y = sH / 2
        laser[i].name = "laser"

        if laserPosition == 1 and laserRotation ~= 4 then
            laser[i].y = sH * 0.05 + 12
            laser[i].anchorY = 0
        elseif laserPosition == 3 and laserRotation ~= 4 then
            laser[i].y = sH * 0.95 - 12
            laser[i].anchorY = 1
        end

        if laserPosition == 1 and laserRotation == 4 then
            laser[i].y = sH * 0.05 + laser[i].contentHeight / 2
        elseif  laserPosition == 3 and laserRotation == 4 then
            laser[i].y = sH * 0.95 - laser[i].contentHeight / 2
        end

        if laserRotation == 1 then
            laser[i].rotation = -45
        elseif laserRotation == 2 then
            laser[i].rotation = 0
        elseif laserRotation == 3 then
            laser[i].rotation = 45
        elseif laserRotation == 4 then
            local onEnterFrame = function( event )
                if laser[i] ~= nil and laser[i].rotation ~= nil then
                    laser[i].rotation = laser[i].rotation + 5
                end
            end
            Runtime:addEventListener( "enterFrame", onEnterFrame )
        end

        laser[i]:setFillColor(1,1,0)
        physics.addBody(laser[i],"kinematic",{isSensor=true})

        moveAndRemovelaser(i)
    end

    spawnlaser(1)
    --------------------------------------------------------




    image = display.newRect (100,100,100,100)
    image.x = display.contentCenterX
    image.y = display.contentCenterY

    sceneGroup:insert( image )

    image.touch = onSceneTouch

    text1 = display.newText( "Game Screen", 0, 0, native.systemFontBold, 24 )
    text1:setFillColor( 255 )
    text1.x, text1.y = display.contentWidth * 0.5, 50
    sceneGroup:insert( text1 )
end

function scene:show( event )

    local phase = event.phase

    if "will" == phase then
        gameStatus = "ended"
    end

    if "did" == phase then
        print( "4" )
        composer.removeScene( "startScreen" )
        image:addEventListener( "touch", image )
        gameStatus = "running"
    end

end

function scene:hide( event )
    local phase = event.phase
    if "will" == phase then
        print( "5" )
        gameStatus = "ended"
        image:removeEventListener( "touch", image )
        Runtime:removeEventListener( "enterFrame", onEnterFrame )
    end
end

function scene:destroy( event ) 
    print( "6" )
end


scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )


return scene

2 ответа

Решение

Так что я закончил тем, что создал функцию и поместил все removeEventListeners в эту функцию и вызвал эту функцию, когда игра закончилась. Для дальнейшего использования всегда сохраняйте список всех созданных вами таймеров и слушателей событий в любом месте экрана и удаляйте их все вместе по окончании игры.

Вы получаете эту проблему, потому что вы регистрируете прослушиватель событий дважды.

Вы должны добавлять и удалять их только тогда, когда сцена входит и выходит. Правильное место для удаления игровых объектов: scene:destroy() и scene:hide()

Я советую вам попытаться реорганизовать свой код и следовать этим рекомендациям:

  • scene: create (): это происходит при первом использовании сцены. Вы хотите создать свои игровые объекты здесь. Это событие произойдет только один раз, если сцена не будет уничтожена, а затем использована снова.

  • scene: show (): здесь вы хотите зарегистрировать всех своих слушателей событий (коснуться и т. д.) и настроить свою игру. Эта функция вызывается каждый раз, когда отображается сцена. Каждый прослушиватель событий, который зарегистрирован здесь, должен быть незарегистрированным, чтобы предотвратить двойной запуск.

  • scene: hide (): Вы хотите отменить регистрацию всех слушателей событий здесь. Это предотвратит запуск следующей сцены на слушателях предыдущей сцены.

  • scene:destroy(): здесь вы хотите удалить все игровые объекты (изображения, текст, виджеты и т. д.). Сцена больше не нужна, и все должно быть очищено.

Чтобы лучше понять, как работает сцена, я рекомендую прочесть этот документ: http://coronalabs.com/blog/2014/01/21/introducing-the-composer-api-plus-tutorial/

Другие вопросы по тегам