Shooting a gun

I am creating a 2d zombie game and i’m having a problem .

I started creating the game in storyboard and after a while I stopped . When I started to make the game again, I decided to create it in composer . My problem is when I was creating the game in storyboard, I tapped on the gun to shoot it and it fired one bullet which is what I wanted . And when the bullet hit the zombie the user would get 5 points . Now that I’m doing it in composer when I tap the gun to fire the bullet three come out and the users score goes up by 120 . Can someone help me fix this problem ? Thanks

storyboard :

function scene:createScene(event) local screenGroup = self.view local background = display.newImageRect("images.png",display.contentWidth,display.contentHeight) background.x = display.contentCenterX background.y = display.contentCenterY screenGroup:insert(background) centerX = 230 centerY = 60 round = 1 roundTxt = display.newText( "Round: "..round, centerX, centerY, native.systemFontBold, 20 ) gun = display.newImage("pistol.gif") gun.x = 50 gun.y = 300 screenGroup:insert(gun) cart = display.newImage("cart.png") cart.x = 100 cart.y = 70 screenGroup:insert(cart) end local bullet = {} local bCounter = 1 local function shootBullet(event) if event.phase == "ended" then bullet[bCounter] = display.newImage( "bullet4.png",gun.x, gun.y, 6, 6 ) bullet[bCounter].value = bCounter physics.addBody( bullet[bCounter], "dynamic" ) bullet[bCounter].gravityScale = 0 bullet[bCounter].myName = "bullet" bullet[bCounter]:setLinearVelocity( 2100, -20 ) bCounter = bCounter + 1 end end Coins = 0 centerX = 350 centerY = 60 CoinsTxt = display.newText( "Coins: "..Coins, centerX, centerY, native.systemFontBold, 20 ) local onCollision=function( event ) if event.phase =="began" then Coins = Coins + 5 CoinsTxt.text="Coins: "..Coins end end function scene:enterScene(event) Runtime:addEventListener("collision", onCollision) gun:addEventListener( "touch", shootBullet ) end function scene:exitScene(event) Runtime:removeEventListener("collision", onCollision) end

Composer :

function scene:create(event) local screenGroup = self.view local background = display.newImageRect("images.png",display.contentWidth,display.contentHeight) background.x = display.contentCenterX background.y = display.contentCenterY screenGroup:insert(background) centerXTxt = 230 centerYTxt = 60 round = 1 roundTxt = display.newText( "Round: "..round, centerXTxt, centerYTxt, native.systemFontBold, 20 ) gun = display.newImage("pistol.gif") gun.x = 50 gun.y = 300 screenGroup:insert(gun) cart = display.newImage("cart.png") cart.x = 100 cart.y = 70 screenGroup:insert(cart) end local bullet = {} local bCounter = 1 local function shootBullet(event) if event.phase == "ended" then bullet[bCounter] = display.newImage( "bullet4.png",gun.x, gun.y, 1, 6 ) bullet[bCounter].value = bCounter physics.addBody( bullet[bCounter], "dynamic" ) bullet[bCounter].gravityScale = 0 bullet[bCounter].myName = "bullet" bullet[bCounter]:setLinearVelocity( 2100, -20 ) bCounter = bCounter + 1 end end local Coins = 0 local centerX = 350 local centerY = 60 local CoinsTxt = display.newText( "Coins: "..Coins, centerX, centerY, native.systemFontBold, 20 ) local onCollision=function( event ) if event.phase =="began" then Coins = Coins + 5 CoinsTxt.text="Coins: "..Coins end end function scene:show(event) Runtime:addEventListener("collision", onCollision) gun:addEventListener( "touch", shootBullet ) end function scene:hide(event) Runtime:removeEventListener("collision", onCollision) end

Thanks a lot .

I’d suggest starting without composer.* or any other scene framework.

i.e. Create a module that does all the work.

This module should have at least two functions:

  • mod.create( group ) - Creates game content and places it in the ‘passed in’ group.
  • mod.destroy() - Stops and destroys the game.

I would also suggest it have these functions:

  • mod.start() - Separates the starting logic from the creation logic which is cleaner.
  • mod.stop() - Separates stopping from destruction which may be useful to you later.

Then, if you can get your game (in a module) working with these tests, you’ll be ready to use that same module in composer.*

Test 1

local mod = require "mod" -- or whatever you named the module file. mod.create( display.currentStage ) timer.performWithDelay( 1000, mod.destroy ) -- If this doesn't crash you're ready for the next test.

Test 2

local mod = require "mod" -- or whatever you named the module file. mod.create( display.currentStage ) timer.performWithDelay( 1000, mod.start ) -- assuming you have a start() timer.performWithDelay( 2000, mod.stop ) -- assuming you have a stop() timer.performWithDelay( 3000, mod.destroy ) -- If this doesn't crash you're ready for the next test.

Test 3

Now, play your game for a while, and further tweak the module.  Later, when you think it is time to move to composer.* run test 1 and 2 again.

I see a lot of folks write their code directly in a composer.* scene and it often goes terribly wrong because they don’t have a good grasp of scope, display group rules, etc.  

So again, I suggest starting of in the simplest modular setting ( i.e. A single module) then move on to composer.*, game interfaces, etc.

Note I give this advice, because if you follow it, then writing the composer.* game scene is as easy as this:

local mod = require "mod" function scene:create(event) mod.create( self.view ) end function scene:show(event) if (event.phase == "did") then mod.start() end end function scene:hide(event) if (event.phase == "will") then mod.stop() end end function scene:destroy(event) mod.destroy() end

Sorry for the multiple answer, but I wanted to also suggest making a few simple examples using composer.*  before using it for game work. 

You need to have a solid grasp of how it works and when the various functions are called as well as the concept of will and did phases for show() and hide().

When you fully understand these things, using composer.* will make a lot more sense and be less mysterious.

At this time I can see you’re totally ignoring or not aware of the will/did phases.  This leads me to believe you’re treating composer.* exactly like storyboard.* and they are two very different beasts.

This is a great place to start:

https://docs.coronalabs.com/guide/system/composer/index.html

I just tried this example on the corona docs :

-- example1.lua local M = {} print( "example1.lua has been loaded" ) return M -- main.lua local ex1 = require( "example1" ) ex1.testvar = "Hello World!"

That worked . I got example1.lua has been loaded in the simulator .

I tried the first test you gave me and this is what I did :

Main.lua : local M = {} local example1 = require "example1" -- or whatever you named the module file. example1.create( display.currentStage ) timer.performWithDelay( 1000, example1.destroy ) -- If this doesn't crash you're ready for the next test. return M

example1.lua :

– example1.lua

  

local M = {}

return M

I’m getting this error :

main.lua:8: attempt to call field 'create' (a nil value)

This is line 8 :

example1.create( display.currentStage )

When I tried the code in main.lua and example1.lua the other way around I get this error :

loop or previous error loading module 'example1'

am I suppose to only use one file for all of the code ? If so which file ?

@brandon,

Let me put together a small example of what the module should look like and I’ll post it so you can use it as a framework to scaffold your code onto.

-Ed

PS - Welcome back.  I know you’re in and out of the forums and I sense you’ve been struggling and a bit frustrated at times.  This time I think you’ll make some progress and get some satisfaction out of the experience.

Posting back in a bit…

Thanks a lot Ed . I will try harder than I did before .

@brandon

Here is the code: https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2017/12/brandon.zip

In this zip file are three folders:

  • 001_starter - A bare bones module with create(), start(), stop(), destroy() functions and some basic parts I think you should always have.
  • 002_sample_game - OK, not really a game, but more like a tech demo showing how to make something very simple with the module.  Go into main.lua and experiment with the start, stop, destroy calls too.
  • 003_integrated_in_composer  - Basically 002 put into a composer scene.
    • Warning: This composer.* scene uses my custom format to separate the will and did phases of show() and hide() into separate function calls.  So be aware it is a little different from the default sample you see on the Corona site.

Here is the ‘game’ in action:

https://www.youtube.com/watch?v=0x2GxoWwDGU&feature=youtu.be

One last note.  I know I never answered your ORIGINAL question.

That was on purpose.  

I think the code for your gun is something you can solve.  The real problem is that I think you’re having some issues with scope and visibility as well as composer.* concepts. 

I think that if you use the module first approach you’ll self-solve the gun problem and be in a much better place for future work.

Cheers,

Ed

Okay this is what I did .

In my main.lua file I put what was in the example’s main.lua file :

local example1 = require "example1" local group = display.newGroup() example1.create( group ) timer.performWithDelay( 4000, function() example1.start() end ) timer.performWithDelay( 8000, function() example1.stop() end ) timer.performWithDelay( 12000, function() example1.destroy() end )

and in my example1.lua file I put what was in the example’s game.lua file :

local physics = require "physics" local cx, cy = display.contentCenterX, display.contentCenterY local fullw, fullh = display.actualContentWidth, display.actualContentHeight local isRunning = false local layers local game = {} function game.create( group ) game.destroy() layers = display.newGroup() layers.underlay = display.newGroup() layers.content = display.newGroup() layers.overlay = display.newGroup() -- group:insert( layers ) -- This group contains all layers layers:insert( layers.underlay ) -- Bottom layer. layers:insert( layers.content ) -- Middle layer layers:insert( layers.overlay ) -- Top layer end etc...

When I did that I got nothing . Nothing should up on the simulator or in the console . I’m guessing everything went well .

When I did this in my main.lua file : 

local example1 = require "example1" -- or whatever you named the module file. example1.create( display.currentStage ) timer.performWithDelay( 1000, example1.destroy ) -- If this doesn't crash you're ready for the next test.

and I left the game file the same, I don’t have any problems . Should I move on or should I be seeing something on my screen ? 

Or should I continue with test 2 and implement my game code ?

Please zip the whole project up and share it here.   You can use the ‘more reply options’ to attach the zip file to your post.

When you ran the app and did not destroy it, did it run properly?

If you feel your game is ready to play, then by all means move on to using composer.*

Okay the problem is fixed with the bullet .

So should I put everything in composer now ? Or develop the whole game and then put it in composer ?

I would develop as much of the game as I could without ever using composer.*  Then, when you’re satisfied, integrate it.

Over time you will get better and better at developing and you can integrate earlier.

However, let’s ask ourselves what composer.* is doing for us…

It is essentially giving us an easy way to create scenes, where we can have some of these scenes:

  • Splash screen
  • Home (main menu)
  • Options (maybe an overlay, maybe a normal scene)
  • Play (the place the game is actually played).  This is where the game module is most used.
  • Game Over (a place to show scores and ads, etc.)

As you can see, while you are developing a game and working on its mechanics, you don’t need any of that. 

So just use the game module for as long as possible directly from main.lua and save yourself a big headache and a lot of wasted effort. 

Do your interfaces later.

Alright thanks . 

I’m trying to transition my zombie because I can’t do spritesheets . I have this code :

zombie = display.newImage("zombie.gif") local w,h = display.contentWidth, display.contentHeight local function listener1( zombie ) print( "Transition 1 completed on object: " .. tostring( zombie ) ) end local function listener2( zombie ) print( "Transition 2 completed on object: " .. tostring( zombie ) ) end -- (1) move square to bottom right corner; subtract half side-length transition.to( zombie, { time=1500, alpha=0, x=(w-150), y=(h-300), onComplete=listener1 } ) -- (2) fade square back in after 2.5 seconds transition.to( zombie, { time=2000, delay=9500, alpha=1.0, onComplete=listener2 } )

But I don’t see the zombie at all and in the console it says the transitions were completed . What should I do ?