Player character not moving using external module and storyboard

Hi guys, 
I’ve recently started using Corona again after a long lay off, and I’ve been messing about with a Pac-Man style game idea. I’m using storyboard to transition between scenes, and my prototype was about 60% complete when I decided to start using external modules to separate my file and make the code easier to read. And that’s when things went pear shaped!
 
I have a player.lua, enemy.lua, play.lua, and level1.lua. I can get my player on screen, but the function I have to move the player is giving me “attempt to perform arithmetic on field ‘x’ (a nil value)”.
 
Any ideas or suggestions would be appreciated.
 
Thanks.
 
Here’s my code

[lua]

– play.lua ------

local storyboard = require( “storyboard” )

local scene = storyboard.newScene()

local physicsData = (require “shapedefs”).physicsData(1.0)

local enemy = require “enemy”

local level1 = require “level1”

local player = require “player”

local lives = 3

local barrier1

local livesText

local scoreText

local background

local bottomWall

local topWall

local rightWall

local leftWall

speed =3

local up

local down

local right

local left

local buildLevel = {}

local update = {}

local bounce = {}

local removeBrick = {}

local SCORE_CONST = 100 --the amount to add to the score when a brick is hit

local score = 0 --stores the current score

–local bricks = display.newGroup() --holds all the level bricks

local xSpeed = 5

local ySpeed = -5

local xDir = 1 – x direction

local yDir = 1

local gameEvent = ‘’ --stores game events (win, lose, finished)

local currentLevel = 1

local levelTime = 5000                  


– FUNCTIONS GO HERE


    local function leftMove()

        motionx = -speed;

        print “left”

    end

    

    local function rightMove()

         motionx = speed;

    end

    local function upMove()

         motiony = -speed;

    end

     local function downMove()

         motiony = speed;

     end

 local function moveguy (event)

         player1.x = player1.x + motionx;

         player1.y = player1.y + motiony;

    end

  

local function stop (event)

         if event.phase ==“ended” then

             motionx = 0;

             motiony = 0;

         end

end

  

local function removeBrick(e)

            if(e.other.name == ‘brick’) then

                ySpeed = ySpeed * -1

                e.other:removeSelf()

                e.other = nil

                bricks.numChildren = bricks.numChildren - 1

                – Score

                print (bricks.numChildren)

                score = score + 1

                scoreText.text = "Score: " …score * SCORE_CONST

                scoreText:setReferencePoint(display.CenterLeftReferencePoint)

                scoreText.x = 54 

            

            elseif e.other.name  == “enemy” then

                lives = lives-1

                livesText.text = "Lives: " … lives 

                livesText:setReferencePoint(display.CenterLeftReferencePoint)

                livesText.x = 380 

                print “hit the enemy” )

            end

            

            – Check if all bricks are destroyed

            

            if(bricks.numChildren < 0) then

                gameEvent = ‘win’

                print “Yay”

            end

end

– Called when the scene’s view does not exist:

function scene:createScene( event )

        local group = self.view

        

        – --------------------------------------------------------------------------------------------------------------------

– DISPLAY OBJECTS GO HERE


        bottomWall = display.newRect (0,0,screenWidth, 100)

        bottomWall:setFillColor ( 255, 0, 0 )

        bottomWall:setReferencePoint(display.TopLeftReferencePoint)

        bottomWall.x = 0

        bottomWall.y=256

        physics.addBody ( bottomWall, “static” )

        bottomWall.alpha=.01

        group:insert(bottomWall)

        background = display.newImage(  “backgroundGUI.png” )

        background.x = centerX

        background.y = centerY

        group:insert(background)

        scoreText = display.newText ( "Score: " … score, 0, 0, “Cabin Sketch”, 18 )

        scoreText.x = 90

        scoreText.y = 15

        scoreText:setTextColor ( 25, 28, 83  )

        scoreText:setReferencePoint(display.CenterLeftReferencePoint)

        group:insert(scoreText)

        livesText = display.newText ( "Lives: " … lives, 0, 0, “Cabin Sketch”, 18 )

        livesText.x =380

        livesText.y = 15

        livesText:setTextColor ( 25, 28, 83  )

        livesText:setReferencePoint(display.CenterLeftReferencePoint)

        group:insert(livesText)

        level1coins = level1.new ( levels[1]) 

        group:insert (level1coins)

        enemy1 = enemy.new ( 45, 47 )

        enemy1:setReferencePoint(display.TopLeftReferencePoint)

        enemy1.name = “enemy”

        group:insert(enemy1)

        player1 = player.new (startX, startY)

        player1.name = “player”

        group:insert(player1)

        

        barrier1 = display.newImage(“shape1_1.png”)

        barrier1:setReferencePoint(display.TopLeftReferencePoint)

        barrier1.x = 60

        barrier1.y = 60

        barrier1.myName = “barrier1”

        physics.addBody( barrier1, “static”,  physicsData:get(“shape1_1”) )

        group:insert(barrier1)

        barrier1.objectName = “barrier”

        left = display.newImage(group, “arrow_left.png”)

        left.x = 60

        left.y = 275

        right = display.newImage(group, “arrow_left.png”)

        right.x = 130

        right.y = 275

        right.xScale = -1

        up = display.newImage(group, “arrow_up.png”)

        up.x = 340

        up.y = 275

        down = display.newImage(group, “arrow_up.png”)

        down.x = 390

        down.y = 275

        down.yScale = -1

end

– Called BEFORE scene has moved onscreen:

function scene:willEnterScene( event )

        local group = self.view

end

– Called immediately after scene has moved onscreen:

function scene:enterScene( event )

        local group = self.view

       

–Listeners for controls

Runtime:addEventListener(“enterFrame”, moveguy)

Runtime:addEventListener(“touch”, stop )

left:addEventListener ( “touch”, leftMove )

right:addEventListener ( “touch”, rightMove )

up:addEventListener ( “touch”, upMove )

down:addEventListener ( “touch”, downMove )

player1:addEventListener(“collision”, removeBrick)

end

[/lua]

[lua]

– player.lua

local player = {}

local player_mt = { __index = player }

    

– CONSTRUCTOR FUNCTION –    

function player.new ( x, y )

    newPlayer = display.newImage(“player.png”)

    newPlayer.x = x

    newPlayer.y = y

    newPlayer:setReferencePoint(display.TopLeftReferencePoint)

    physics.addBody ( newPlayer, “dynamic”, { radius=5 } )

    return setmetatable( newPlayer, player_mt )

end

return player

[/lua]

[lua]

– main.lua

physics = require (“physics”)

physics.start()

physics.setGravity( 0, 0 )

_w = display.contentWidth/2

_h = display.contentHeight/2

 --Constants

centerX = display.contentCenterX

centerY = display.contentCenterY

screenX = display.screenOriginX

screenY = display.screenOriginY

screenWidth = display.contentWidth - screenX * 2

screenHeight = display.contentHeight - screenY * 2

screenLeft = screenX

screenRight = screenX + screenWidth

screenTop = screenY

screenBottom = screenY + screenHeight

display.contentWidth = screenWidth

display.contentHeight = screenHeight

motionx=0

motiony=0

startX = centerX-3

startY = centerY-19

local storyboard = require(“storyboard”)

storyboard.gotoScene ( “play”, {effect=“slideUp”} )

[/lua]

First, to help debug that problem, I would remove any code that does not have to do with the player (so, you clean your code, making it easy to identify the problem).

That error should be happening because the property .x does not exist, so it is nil and when your move code try to sum .x with other number, lua will give you an error because you are trying to sum a nil value.

I never used metatable as you use in the player file, so I cannot help you on that, but I would guess that your player.lua is not returning the objecting that you expected. Try to print the value that is returned by the new() function to check it.

Renato

Hi Renato,

I’m not entirely sure how to print the value returned by the new() function. Is it print (player), and where do I  run that?

Also, the metatable part of the player code was found in a tutorial. Maybe I used it incorrectly. Here is the link:http://www.coronalabs.com/blog/2011/09/29/tutorial-modular-classes-in-corona/

I removed that and the line: local player_mt = { __index = player }

Instead, I put the newPlayer into a display group and returned it. The player now displays and moves around the screen. BUT … the associated physics no longer work. No collisions happen with any other physics object. 

 

Here is the player file:

[lua]

local player = {}

local playerGroup = display.newGroup ( )

– CONSTRUCTOR FUNCTION –    

function player.new ( x, y )

    

    newPlayer = display.newImage(“player.png”)

    newPlayer.x = x

    newPlayer.y = y

    newPlayer:setReferencePoint(display.TopLeftReferencePoint)

    physics.addBody ( newPlayer, “dynamic”, { radius=5 } )

    newPlayer.name = “player”

    playerGroup:insert(newPlayer)

    return playerGroup

end

return player

[/lua]

Hummm. I think it is related to a group thing.

Collision only happens when groups are with the same position, so usually it is easier to have all objects that collide in the same group. I think you are changing the player group position when moving the player, so it will not collide with a object that is not inside the player group or in a group that is with the same position of the player.

Another thing that may be related, you are adding the collision listener to the player group not the player object. I don’t know if that may also cause some problem.

Hi @Megatronic Games,

To clarify on what Renato says:

  1. you can have colliding objects in different groups (quite necessary if you want z-index layering in a game). However, you can not move/shift the groups around independently of each other. You must keep them in the same coordinate orientation or collisions will not behave as expected.

  2. you can not apply a collision listener to an entire display group. You either need to apply collision listeners to individual objects, or use a Runtime collision listener to manage collisions between all objects in a the world.

EDIT: #2, I see you’re not applying the listener to a group, so scratch that. However, I see you are using different reference points on the player, which doesn’t play nice with physics. Try to use center reference with all physics objects.

Take care,

Brent

Thanks for the complement Brent.

 

@Megatronic Games is adding the collision listener to player1 variable. But player1 is the playerGroup returned by the new function, not the playerObj created in that same function.

Ah, I see now, I just didn’t follow the entire code through. So to summarize, no collision listeners on display groups. :slight_smile:

Brent

Hey guys, I think I might have fixed this, at least I hope I did!

I deleted the displayGroup in player.lua, and then returned the newPlayer object, and it seems to work. Thanks for your help.

[lua]

local player = {}

function player:new ( x, y )

    

    local newPlayer = display.newImage(“player.png”)

    newPlayer.x = x

    newPlayer.y = y

    physics.addBody ( newPlayer, “dynamic”)

    newPlayer.name = “player”

    return newPlayer

end

return player

[/lua]

First, to help debug that problem, I would remove any code that does not have to do with the player (so, you clean your code, making it easy to identify the problem).

That error should be happening because the property .x does not exist, so it is nil and when your move code try to sum .x with other number, lua will give you an error because you are trying to sum a nil value.

I never used metatable as you use in the player file, so I cannot help you on that, but I would guess that your player.lua is not returning the objecting that you expected. Try to print the value that is returned by the new() function to check it.

Renato

Hi Renato,

I’m not entirely sure how to print the value returned by the new() function. Is it print (player), and where do I  run that?

Also, the metatable part of the player code was found in a tutorial. Maybe I used it incorrectly. Here is the link:http://www.coronalabs.com/blog/2011/09/29/tutorial-modular-classes-in-corona/

I removed that and the line: local player_mt = { __index = player }

Instead, I put the newPlayer into a display group and returned it. The player now displays and moves around the screen. BUT … the associated physics no longer work. No collisions happen with any other physics object. 

 

Here is the player file:

[lua]

local player = {}

local playerGroup = display.newGroup ( )

– CONSTRUCTOR FUNCTION –    

function player.new ( x, y )

    

    newPlayer = display.newImage(“player.png”)

    newPlayer.x = x

    newPlayer.y = y

    newPlayer:setReferencePoint(display.TopLeftReferencePoint)

    physics.addBody ( newPlayer, “dynamic”, { radius=5 } )

    newPlayer.name = “player”

    playerGroup:insert(newPlayer)

    return playerGroup

end

return player

[/lua]

Hummm. I think it is related to a group thing.

Collision only happens when groups are with the same position, so usually it is easier to have all objects that collide in the same group. I think you are changing the player group position when moving the player, so it will not collide with a object that is not inside the player group or in a group that is with the same position of the player.

Another thing that may be related, you are adding the collision listener to the player group not the player object. I don’t know if that may also cause some problem.

Hi @Megatronic Games,

To clarify on what Renato says:

  1. you can have colliding objects in different groups (quite necessary if you want z-index layering in a game). However, you can not move/shift the groups around independently of each other. You must keep them in the same coordinate orientation or collisions will not behave as expected.

  2. you can not apply a collision listener to an entire display group. You either need to apply collision listeners to individual objects, or use a Runtime collision listener to manage collisions between all objects in a the world.

EDIT: #2, I see you’re not applying the listener to a group, so scratch that. However, I see you are using different reference points on the player, which doesn’t play nice with physics. Try to use center reference with all physics objects.

Take care,

Brent

Thanks for the complement Brent.

 

@Megatronic Games is adding the collision listener to player1 variable. But player1 is the playerGroup returned by the new function, not the playerObj created in that same function.

Ah, I see now, I just didn’t follow the entire code through. So to summarize, no collision listeners on display groups. :slight_smile:

Brent

Hey guys, I think I might have fixed this, at least I hope I did!

I deleted the displayGroup in player.lua, and then returned the newPlayer object, and it seems to work. Thanks for your help.

[lua]

local player = {}

function player:new ( x, y )

    

    local newPlayer = display.newImage(“player.png”)

    newPlayer.x = x

    newPlayer.y = y

    physics.addBody ( newPlayer, “dynamic”)

    newPlayer.name = “player”

    return newPlayer

end

return player

[/lua]