Everything works fine now! Thank you for your help!
I’m just seeing this.
I’ll give it a real looking over Saturday. For now, I’m beat. Time to sleep.
On a side node, why are you making your own collision filters? You know I have an easier way to set up collisions right?
(Not likely the source of your issue, just asking.)
https://roaminggamer.github.io/RGDocs/pages/SSK2/libraries/cc/
Yes, I am aware of your collision calculator, however, I find these manual collision calculators to be easier for me. (I have studied binary, so I am familiar with how they function) Of course, I am not saying your collision calculator is flawed. But for now, I seem to like the way this is currently set up.
If they hinder the readability of my code, I will be happy to change them for the sake of this topic.
It’s all good. I just fine folks make more and subtler mistakes hand-calculating. That said, do it the way that works best for you.
I think all of your woes came down to setting up the collision listener incorrectly, but I’m not entirely sure.
-
Overall your code is looking really good. Congrats!
-
We talked about this before, don’t use listen() That is for Runtime events. You’re using a local listener so it is:
obj:addEventListener(“collision”)
-
I made major (although clear) changes to your code because you were doing several things that were inefficient.
** MAY CONTAIN TYPOS – SORRY IF IT DOES**
** I changed the indentation to 3 spaces as 2 is too hard for me to read… **
--explosion.lua -- Locals (need only define these once; doing it on each call to 'new' was a waste) local explosionInfo = require "sprite.lua.explosion" local explosionSheet = graphics.newImageSheet("sprite/png/explosion.png", explosionInfo:getSheet()) local explosionData = { name = "explosion", start = explosionInfo:getFrameIndex("explosion1"), count = 8, time = 500, loopCount = 1 } local M = {} function M.new( group, x, y, xScale, yScale, xOffset, yOffset) -- It is nice to provide defaults for those variables you might not always want to pass xScale = xScale or 1 yScale = yScale or 1 xOffset = xOffset or 0 yOffset = yOffset or 0 local explosion = display.newSprite(group, explosionSheet, explosionData) explosion.x, explosion.y = x + xOffset, y + yOffset explosion.xScale, explosion.yScale = xScale, yScale explosion:play() end return M
--bullet.lua -- Requires local explosion = require "other.explosion" -- Locals local bulletCollisionFilter = {categoryBits = 4, maskBits = 2} -- Localize math functions -- (FASTER execution; Makes typing function names EASIER; Makes code more LEGIBLE) local angle2Vector = ssk.math2d.angle2Vector local vecNorm = ssk.math2d.normalize local vecScale = ssk.math2d.scale local vecAdd = ssk.math2d.add -- Forward decalare common functions/methods local createBullet local collision1 -- needs a better name... local M = {} function M.new(group, object) object.bullets = {} object.bullets[1] = createBullet( group, object.x, object.y, bulletCollisionFilter, -26, -20) object.bullets[2] = createBullet( group, object.x, object.y, bulletCollisionFilter, 26, -20) for i = 1, #object.bullets do local bullet = object.bullets[i] local vx, vy = object:getLinearVelocity() local vec1 = angle2Vector( object.rotation + 180, true) vec1 = vecNorm( vec1 ) vec1 = vecScale( vec1, bullet.yOffset ) vec1 = vecAdd( vec1, object ) local vec2 = angle2Vector( object.rotation + 90, true ) vec2 = vecNorm( vec2 ) vec2 = vecScale( vec2, bullet.xOffset ) bullet.rotation = object.rotation - 90 -- RG: Why -90? bullet.x = vec1.x + vec2.x bullet.y = vec1.y + vec2.y bullet:setLinearVelocity(vx \* 4, vy \* 4) -- This is more compact and still 100% safe -- Compare it to your original to see that this is the same action. -- Also, there is no need to specify 1 as it is the default iteration count bullet.timer = display.remove timer.performWithDelay( 5000, bullet ) bullet.collision = collision1 -- RG INCORRECT (you are confusing listener types/categories; -- we talked about this in another thread) -- listen("collision", bullet) -- RG CORRECT bullet:addEventListener("collision") end end -- Define common functions (forward declared above) createBullet function (group, x, y, xOffset, yOffset) local bullet = display.newImageRect(group, "sprite/ship/Bullet.png", 32, 33) physics.addBody(bullet, "dynamic", {filter = bulletCollisionFilter}) bullet.x, bullet.y = x, y bullet.damage = 25 bullet:toBack() bullet.xOffset, bullet.yOffset = xOffset, yOffset return bullet end collision1 = function (self, event) if event and event.phase == "began" then -- RG notice how I'm putting the explision in the object's parent? That is the group the object -- is in. All objects are in a group even if you don't do it explicitly. -- The implied group is display.currentStage (top group) -- In your case, the group is the one you passed in. explosion.new( self.parent, self.x, self.y, 0.5, 0.5, math.random(-10, 10), math.random(-10, 10)) -- Tip: If you need the group to be something other than the 'ship' group, do this: --[[ship.bulletGroup = ... other group here ... then later explosion.new( self.bulletGroup, self.x, self.y, 0.5, 0.5, math.random(-10, 10), math.random(-10, 10))]] -- However, I think this will do what you want.. display.remove(self) end end -- Very last... return the module return M
--ship.lua local bullet = require "bullet" local function shoot() local vx, vy = ship:getLinearVelocity() if (vx \< -100 or vx \> 100) or (vy \< -100 or vy \> 100) then bullet.new(group, ship) end end local shootTimer = timer.performWithDelay(100, shoot, 0)
I hope this helps.!?
Here is a link to download the code above if you want (all in one file)
https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2017/10/sdktester15.zip
Warning! Code in zip is a little different from code above:
This was changed above and I did not update the zip file:
-- Define common functions (forward declared above) createBullet function (group, x, y, xOffset, yOffset) local bullet = display.newImageRect(group, "sprite/ship/Bullet.png", 32, 33) physics.addBody(bullet, "dynamic", {filter = bulletCollisionFilter})
Wow, thanks! I will start implementing right away!
Hi @roaminggamer, I am getting an error that says “Attempt to index global object (a nil value)” pointing to this line (in bullet.lua):
object.bullets = {}
Do note, that the code I have in the file is not the same as yours because some of it was giving me errors. (I did NOT copy and paste it in)
So here is what it looks like now:
local M = {} local explosion = require "other.explosion" local bulletCollisionFilter = {categoryBits = 4, maskBits = 2} local angle2Vector = ssk.math2d.angle2Vector local vecNorm = ssk.math2d.normalize local vecScale = ssk.math2d.scale local vecAdd = ssk.math2d.add function M.new(group, object) local function createBullet(x, y, xOffset, yOffset) local bullet = display.newImageRect(group, "sprite/ship/Bullet.png", 32, 33) physics.addBody(bullet, "dynamic", {filter = bulletCollisionFilter}) bullet.x, bullet.y = x, y bullet.damage = 25 bullet:toBack() bullet.xOffset, bullet.yOffset = xOffset, yOffset return bullet end local function bulletCollision(self, event) if event and event.phase == "began" then explosion.new(self.parent, self.x, self.y, 0.2, 0.2, math.random(-10, 10), math.random(-10, 10)) display.remove(self) end end end object.bullets = {} object.bullets[1] = createBullet(object.x, object.y, -26, -20) object.bullets[2] = createBullet(object.x, object.y, 26, -20) for i = 1, #object.bullets do local bullet = object.bullets[i] local vx, vy = object:getLinearVelocity() local vec1 = angle2Vector( object.rotation + 180, true) vec1 = vecNorm( vec1 ) vec1 = vecScale( vec1, bullet.yOffset ) vec1 = vecAdd( vec1, object ) local vec2 = angle2Vector( object.rotation + 90, true ) vec2 = vecNorm( vec2 ) vec2 = vecScale( vec2, bullet.xOffset ) bullet.x = vec1.x + vec2.x bullet.y = vec1.y + vec2.y bullet:setLinearVelocity(vx \* 4, vy \* 4) local removeTimer = timer.performWithDelay(5000, function() display.remove(bullet) end, 1) bullet.timer = display.remove timer.performWithDelay(5000, bullet) bullet.collision = bulletCollision bullet:addEventListener("collision") end return M
please edit above post and mark line of code it is complaining about
I do see one problem…
local removeTimer = timer.performWithDelay(5000, function() display.remove(bullet) end, 1) bullet.timer = display.remove timer.performWithDelay(5000, bullet)
should be
bullet.timer = display.remove timer.performWithDelay(5000, bullet)
I’m also just guessing, but maybe you aren’t passing in a group to new?
make this change and see what prints:
function M.new(group, object) print("bullet.new()", group, object)
Tip: The way to debug this is…
-
Identify line Corona is complaining about.
-
Add print statements BEFORE that line to see what the variables are set to. i.e. See if one is nil.
-
Back track the variable to where it is set or provided.
I noticed you completely ignored my advise against redefining the functions for each call of new. That is fine, but a waste and it makes the code more likely to have errors. i.e. It makes the definition of new long and easier to make mistakes in.
I forgot to place these outside the M.new function.
Alright, so now I have these two functions outside my .new() function.
createBullet = function(x, y, xOffset, yOffset) local bullet = display.newImageRect(group, "sprite/ship/Bullet.png", 32, 33) physics.addBody(bullet, "dynamic", {filter = bulletCollisionFilter}) --error line \<------ bullet.x, bullet.y = x, y bullet.damage = 25 bullet:toBack() bullet.xOffset, bullet.yOffset = xOffset, yOffset return bullet end bulletCollision = function(self, event) if event and event.phase == "began" then explosion.new(self.parent, self.x, self.y, 0.2, 0.2, math.random(-10, 10), math.random(-10, 10)) display.remove(self) end end
They have been forward declared above.
Also, when I tried out your print statement, this was returned:
bullet.new(): table: 0x60000086c9c0 table: 0x60000086cc00
Which I assume are nil values.
Currently, I am also receiving an “ERROR: table expected. If this is a function call, you might have used ‘.’ instead of ‘:’” error which is marked in the above code.
I have deduced that this error is occurring because the group is nil. Once I removed the group parameter from the line above,
local bullet = display.newImageRect(group, "sprite/ship/Bullet.png", 32, 33)
the bullets were offset greatly from the camera, but no error was returned.
They are not nil values. They will say nil if they are nil.
This tells me group and object are both being passed in.
Try this
local bob print ("bob is nil", bob)
Hey. I’m running out of time so I may be able to answer once more. However, I think you can find the problem using the step by step approach I mentioned.
Hmm…
Well, all I know is that it has something to do with that group parameter in the line before the error line.
Ok, I will try my best!
Whoops! Forgot the function was outside of the .new(), in the function group is nil, but in the .new() function group is not nil.