Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
How Do I Make an if Touching instance? — Gideros Forum

How Do I Make an if Touching instance?

MinstrelMinstrel Member
edited June 2015 in General questions
Hello Forums. This is going to be my last post for a while (and this time I mean it).

I've nearly got a playable game with score hiScore etc., but there's still one more thing I need to know: How do I make an if touching instance. By this I mean if my 'bullet' sprite is touching my invadersLayer layer it will register it the bulllet will be removed and placed in the pool (which i've already made so you don't need to bother with that) and my score variable will increase by one.
Here is my entire code as I don't know which bit I should give you (better safe than sorry!)
local sound = Sound.new("MakoBeamNCSGiderosCompRemix(-32Db).wav")
local channel = sound:play()
 
application:setFps(60)
 
hiScore= 0
score = 0
 
layerstartDir = "LTR" --(Left to right) This defines which way the layer is  going to start off moving
 
 
Pool = Core.class(bullet)
 
function Pool:init()
    self.pool = {}
end
 
function Pool:createObject()
    local b
 
    if #self.pool > 0 then
		b = table.remove(self.pool)
    else
        b = Bitmap.new(Texture.new("bullet.png", true))
    b:setScale(0.2)
	b:setPosition(0,0)
	b:setRotation(-90)
	end
 
    return b
end
 
function Pool:destroyObject(b)
    b:removeFromParent()
    table.insert(self.pool, b)
end
 
bullets = {}
counter  = 1 
 
application:setBackgroundColor(0x0)
 
width = application:getContentWidth()
 
local username = ""
 
local textInputDialog = TextInputDialog.new("Player1", 
	"Enter Name Player1", username, "Cancel", "Save")
 
backgroundtexture = Texture.new("BGComp.png")
backgroundtexture = Bitmap.new(backgroundtexture)
stage:addChild(backgroundtexture)
backgroundtexture:setAnchorPoint(0.5,0.5)
backgroundtexture:setRotation(90)
backgroundtexture:setPosition(239,160)
backgroundtexture:setScaleX(1.75)
backgroundtexture:setScaleY(1.75)
 
local retrofont = TTFont.new("8-BIT WONDER.TTF", 20, true) 
local text = TextField.new(retrofont,username)
text:setPosition(0, 20)
stage:addChild(text)
text:setTextColor(0xffffff) 
 
stage:addEventListener(Event.ENTER_FRAME, function()
	text:setTextColor(text:getTextColor()+3)
 
end) 
 
 
local rec = Shape.new()
rec:setFillStyle(Shape.SOLID, 0xffffffff, 0.3)
rec:setLineStyle(3, 0x00000, 1)
rec:beginPath()
rec:moveTo(0,0)
rec:lineTo(0,100)
rec:lineTo(200,100)
rec:lineTo(200,0)
rec:lineTo(0,0)
rec:endPath()
stage:addChild(rec)
rec:setPosition(-10, 224)
rec:setScaleX(3)
 
local firetext = TextField.new(retrofont,"fire")
stage:addChild(firetext)
firetext:setPosition(397,310)
firetext:setTextColor(0x00000)
 
 
if score > hiScore then
hiScore = score
 
end
 
scoreText = TextField.new(retrofont, "Score: " .. score)
scoreText:setPosition(4,290)
stage:addChild(scoreText)
hiScoreText = TextField.new(retrofont, "Hi-Score: " .. hiScore)
hiScoreText:setPosition(4,270)
stage:addChild(hiScoreText)
 
firebutton = Bitmap.new(Texture.new("Button.png"))
stage:addChild(firebutton)
firebutton:setScale(0.6)
firebutton:setAnchorPoint(0.5,0.5)
firebutton:setPosition(430,260) 
 
playership1 = Bitmap.new(Texture.new("ship.png"))
stage:addChild(playership1)
playership1:setAnchorPoint(0.39,0.39)
playership1:setPosition(200,260)
 
 
function firebutton:onClick(e)
	if self:hitTestPoint(e.x, e.y) then
		self:setScale(0.5)
	end
end
 
function firebutton:onRelease(e)
	if self:hitTestPoint(e.x, e.y) then
		self:setScale(0.6)
	end
end
 
 
firebutton:addEventListener(Event.MOUSE_DOWN, firebutton.onClick, firebutton)
firebutton:addEventListener(Event.MOUSE_UP, firebutton.onRelease, firebutton)
 
 
local function onComplete(e)
	--if e.buttonIndex then
		username = e.text
		text:setText(username)
	--end
end
 
textInputDialog:addEventListener(Event.COMPLETE, onComplete)
textInputDialog:show()
left = false
right = false
 
shipX=width/2
playerDir=0
bDir=0
by= 1
 
bullets = {}
counter  = 1
 
bpool = Pool.new()
 
function gameloop(e)
 
local layerX = invadersLayer:getX() --This finds the actual position of the layer
 
 if layerstartDir == "LTR" and layerX<= 70 then 
   invadersLayer:setX(layerX+1.5) -- where 1 is the pixel speed at which layer moves Left to right
 else --we reached the limit, change direction
	layerstartDir = "RTL"  --right to left
 end	
 
 if layerstartDir == "RTL" and layerX>= -40 then -- -50 is my choice, it's the x position where layer direction should reverse at the left of the screen when moving RTL
   invadersLayer:setX(layerX-1.5) -- same as before, but negative
 else --do...
	layerstartDir = "LTR"  -- (left to right again)
 end
 
	shipX=shipX + (playerDir* 5)
 
	if shipX<14 then
		shipX = 14
	elseif
		shipX>(width-55) then
		shipX = width - w
	end	
 
		playership1:setX(shipX)
 
	--you need to update the position of each bullet in bullets array
	for bb in pairs(bullets) do --for any entry of bullets, where bb is index 
		local bp = bullets[bb]:getY() --bulletPosition: each bullet has its own
		if bp < -100 then --this is what I decided is enough outside screen boundaries to remove the bullet (in pixels, same scale as setX, setY...)
			bpool:destroyObject(bullets[bb]) --place bullet in pool
			bullets[bb] = nil --remove entry from array so that next time it won't be processed
			print("bullets removed:", bb) --tell me that you did it
		else --I am still inside the screen, so:
			local by=bp+(bDir*8) --add the increment to this bullet bp
			bullets[bb]:setY(by) --set the increment to this bullet
		end
	end
 
 
end
 
stage:addEventListener(Event.ENTER_FRAME,gameloop)
 
stage:addEventListener(Event.KEY_DOWN,function(e)
	if e.keyCode==KeyCode.LEFT then
		left=true
		playerDir=-1
	elseif e.keyCode==KeyCode.RIGHT then
		right=true
		playerDir=1
	elseif e.keyCode==KeyCode.Z then
 
	print("fire")
	bx,by=playership1:getPosition()
	bullets[counter] = bpool:createObject()
	stage:addChild(bullets[counter])
	bullets[counter]:setPosition(bx,by)
	bDir=-1
 
	counter = counter+1
 
	end
 
end)
 
stage:addEventListener(Event.KEY_UP,function(e)
	if e.keyCode==KeyCode.LEFT then
		left=false
		if right then
			playerDir=1
		else
			playerDir=0
		end
 
	elseif e.keyCode==KeyCode.RIGHT then
		right=false
		if left then
			playerDir=-1
		else
			playerDir=0
		end
	end
end)
 
Invader = Core.class(Sprite)
 
function Invader:init() 
 
local anim1 = {}
anim1[1] = Bitmap.new(Texture.new("invader2.png"))
anim1[2] = Bitmap.new(Texture.new("invader.png"))
 
local anim1 = MovieClip.new{
{1,20, anim1[1]},
{20,40, anim1[2]},
anim1[1]:setScale(0.3)
}
 
anim1:setPosition(0,-5)
self:addChild(anim1) 
anim1:setGotoAction(40, 1)
 
anim1:gotoAndPlay(1)
end
 
local maxInvaders  = 10
 
 
local invaders = {} 
invadersLayer = Sprite.new() 
stage:addChild(invadersLayer)
 
local paddx = 75 
for i=1, maxInvaders do 
invaders[i] = Invader.new()
invaders[i]:setX(paddx*i) 
invadersLayer:addChild(invaders[i]) 
invadersLayer:setScale(0.5)
invadersLayer:setPosition(0 ,25)
 
end
Thanks for your help, support and time! :D

Comments

  • piepie Member
    I think that there are many ways to do this, but basically you need to check if any bullet collides with any Invader.

    The first that comes to mind is to use a for loop and Sprite:collidesWith() by ar2rsawseen.
    copy the function at the beginning of your file: it adds collidesWith() as a method of Sprite.
     
    function Sprite:collidesWith(sprite2)
    	local x,y,w,h = self:getBounds(stage)
    	local x2,y2,w2,h2 = sprite2:getBounds(stage)
     
    	return not ((y+h < y2) or (y > y2+h2) or (x > x2+w2) or (x+w < x2))
    end

    Since collidesWith is a method of Sprite, you would need that your bullets were Sprites too (now these are Bitmaps, while Invaders already are Sprites): you need to add the bitmap to a Sprite instance for this to work.
    --excerpt of Pool:createObject() 
    else
    --rename the current b in something else, since you need to return a Sprite
            local c = Bitmap.new(Texture.new("bullet.png", true)) --create the bitmap
            c:setScale(0.2)
         c:setPosition(0,0)
    	c:setRotation(-90)
     
            b = Sprite.new() -- create the sprite: b, because is what is going to be returned by the function
            b:addChild(c) --add bitmap to Sprite
    	end

    then you could insert another for in the for loop updating the bullets position:
    --you need to update the position of each bullet in bullets array
    	for bb in pairs(bullets) do --for any entry of bullets, where bb is index 
    		local bp = bullets[bb]:getY() --bulletPosition: each bullet has its own
    		if bp < -100 then --this is what I decided is enough outside screen boundaries to remove the bullet (in pixels, same scale as setX, setY...)
    			bpool:destroyObject(bullets[bb]) --place bullet in pool
    			bullets[bb] = nil --remove entry from array so that next time it won't be processed
    			print("bullets removed:", bb) --tell me that you did it
    		else --I am still inside the screen, so:
    			local by=bp+(bDir*8) --add the increment to this bullet bp
    			bullets[bb]:setY(by) --set the increment to this bullet
    		end
     
    for i in pairs(invaders) do --you already have bb, so check it against every invader
     if bullets[bb]:collidesWith(invaders[i]) then
      --kill Invader, remove bullet... do something else
     end
    end
     
     
     
    	end
    I didn't test it, and there may be better ways to do this :)
  • Is the for loop the first piece of code you sent?
  • Btw thanks for the piece of inspiration at the end: --kill Invader, remove bullet do something else.
  • also where do I put the code turning bullet into a sprite
  • piepie Member
    @Minstrel

    function Sprite:collidesWith(sprite2) -- goes at the beginning of your file

    --excerpt of Pool:createObject() goes in Pool:createObject()
    it's an update to existing code: where you had b = blah blah, now you have local c = blah blah, and then b = Sprite.new and b:addChild(c)

    --the last piece goes inside gameloop(), it's an update to the "bullet movement for loop": the added for loop is at the end and not aligned with previous code.


  • Ok all is well with the first and last pieces of code but on the second code area it says end expected on line 23 to close function lua: 21 near else. but if I put an end before the else it says of expected near else and anyway you can clearly see that the function is being ended to early. Here is the function in question(21 to 31)
    function Pool:createObject()
     
    else
    		local c = Bitmap.new(Texture.new("bullet.png",true))
    		c:setScale(0.2)
    	c:setPosition(0,0)
    		c:setRotation(-90)
     
    	b = Sprite.new()
    	b:addChild(c)
    end
    Thanks! :D
  • piepie Member
    edited June 2015
    It should be like this
    function Pool:createObject()
        local b
     
        if #self.pool > 0 then
    		b = table.remove(self.pool)
        else
    --rename the current b in something else, since you need to return a Sprite
            local c = Bitmap.new(Texture.new("bullet.png", true)) --create the bitmap
            c:setScale(0.2)
         c:setPosition(0,0)
    	c:setRotation(-90)
     
            b = Sprite.new() -- create the sprite: b, because is what is going to be returned by the function
            b:addChild(c) --add bitmap to Sprite
        end
     
        return b
    end
  • MinstrelMinstrel Member
    edited June 2015
    Ok So I can start up the game now (Woo Hoo) But when a bullet sprite hits invaders layer i get this error

    main.lua:216: attempt to index field '?' (a nil value)
    stack traceback:
    main.lua:216: in function


    I've checked the area no typos as far as I'm aware everything seems normal.

    function 202 is:
    function gameloop(e)
     
    	for bb in pairs(bullets) do --for any entry of bullets, where bb is index 
    		local bp = bullets[bb]:getY() --bulletPosition: each bullet has its own
    		if bp < -100 then --this is what I decided is enough outside screen boundaries to remove the bullet (in pixels, same scale as setX, setY...)
    			bpool:destroyObject(bullets[bb]) --place bullet in pool
    			bullets[bb] = nil --remove entry from array so that next time it won't be processed
    			print("bullets removed:", bb) --tell me that you did it
    		else --I am still inside the screen, so:
    			local by=bp+(bDir*8) --add the increment to this bullet bp
    			bullets[bb]:setY(by) --set the increment to this bullet
    		end
     
    for i in pairs(invaders) do --you already have bb, so check it against every invader
    if bullets[bb]:collidesWith(invaders[i]) then
    bpool:destroyObject(bullets[bb])
    score = score + 1
     
     end
    end
    I will check the collidesWith code but if not I know i've got you guys to back me up!
    :D :D :) ;) ;D
  • SinisterSoftSinisterSoft Maintainer
    @Minstrel, which line is 216?
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • if bullets[bb]:collidesWith(invaders[i]) then
    is line 216
  • SinisterSoftSinisterSoft Maintainer
    edited June 2015
    The problem is that you are checking for bullets when you might have made the bullet nil.

    Move the loop that checks for a bullet hitting an invader to the bit that increments the position of the bullet.
    function gameloop(e)
     
    	for bb in pairs(bullets) do --for any entry of bullets, where bb is index 
    		local bp = bullets[bb]:getY() --bulletPosition: each bullet has its own
    		if bp < -100 then --this is what I decided is enough outside screen boundaries to remove the bullet (in pixels, same scale as setX, setY...)
    			bpool:destroyObject(bullets[bb]) --place bullet in pool
    			bullets[bb] = nil --remove entry from array so that next time it won't be processed
    			print("bullets removed:", bb) --tell me that you did it
    		else --I am still inside the screen, so:
    			local by=bp+(bDir*8) --add the increment to this bullet bp
    			bullets[bb]:setY(by) --set the increment to this bullet
     
    for i in pairs(invaders) do --you already have bb, so check it against every invader
    if bullets[bb]:collidesWith(invaders[i]) then
    bpool:destroyObject(bullets[bb])
    score = score + 1
     
     
    		end
     -- don't do bullet collision check here as bullets[bb] might now be nil (doesn't exist any more)
     
     end
    end

    Likes: pie

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
    +1 -1 (+1 / -0 )Share on Facebook
  • MinstrelMinstrel Member
    edited June 2015
    Ok one more thing for some reason my text is not showing up (my score text) code:
    score = 0
    hiScore = 0
    scoreText = TextField.new(nil, "Score: " .. score)
    scoreText:setPosition(10,10)
    stage:addChild(scoreText)
    hiScoreText = TextField.new(nil, "Hi Score: " .. hiScore)
    hiScoreText:setPosition(200,10)
    stage:addChild(hiScoreText)
    also how would I make the score text go update to the new score or does that happen any way?
    Thanks for your time. :D
  • SinisterSoftSinisterSoft Maintainer
    edited June 2015
    Have you done this before a background was added to the stage? It should be done AFTER the background has been added other wise it will be drawn underneath the background.

    I personally would add score after all the objects have been added - so it's drawn on top.

    To set the score every game frame add:
    oldScore=-1
    oldHiscore=-1
    to the beginning of your code.

    Then in your gameloop event...
    if score~=oldScore then
       oldScore=score
       scoreText:setText("Score: "..score)
    end
    if score>hiscore then
       hiscore=score
    end
    if hiscore~=oldHiscore then
       oldHiscore=hiscore
       hiscoreText:setText("Hi Score: "..hiscore)
    end
    You can then edit your initial creation of the textfield to something like:
     TextField.new(nil,"")
    As it will get updated on the first gameloop to the correct text (no point having it in twice).
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
Sign In or Register to comment.