A little bug I just cant seem to figure out.

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Shaddy
Prole
Posts: 5
Joined: Thu Apr 30, 2015 11:26 pm

A little bug I just cant seem to figure out.

Post by Shaddy »

So, for the past few days I have been working on a bit of a game engine of sorts for a project I will be doing next month. Everything was going relatively fine, until I found an odd bug in a section of code which I cant seem to figure out how to fix. The code itself: (Sorry its a little choppy, ill refine it later.)

Code: Select all

function love.load()  
  anim8 = require("anim8") --Animation program, not mine, props to Enrique Garcia Cota.
  
  playerAnimations = {bobus={}}  -- Table holding all animations for the playable characters of the game.
  
  --Bobus' Animations--
  playerAnimations["bobus"]["Idle"] = love.graphics.newImage("graphics/bobus3.png")
  playerAnimations["bobus"]["Attack1"] = love.graphics.newImage("graphics/bobus4.png")
  
  --Starting Character--
  playerAnim = playerAnimations["bobus"]["Idle"] --Redundant but here in case something else fails--
  playerID = "bobus" --Determines which character you are using, so it uses the correct sprites.--
  
  spellAnimations = {} -- Table holding all animations relating to attacks or spells or items used in the game.
  
  --Spirit Animation--
  bSpellAnimation = love.graphics.newImage("graphics/Spirit.png")
  gSpellAnimation = anim8.newGrid(80,100,320,100,0,0,0)
  spellAnimations["Spirit"] = anim8.newAnimation(gSpellAnimation("1-4",1),0.2)
  spellAnimations["Spirit"]:pauseAtStart()
  
  --Summoning Effect Animation--
  bSpellAnimation2 = love.graphics.newImage("graphics/summon2.png")
  gSpellAnimation2 = anim8.newGrid(100,120,1000,120,0,0,0)
  spellAnimations["SummonEffect"] = anim8.newAnimation(gSpellAnimation2("1-10",1),0.5)
  spellAnimations["SummonEffect"]:pauseAtStart()
  
  --Dark Explosion Animation--
  bSpellAnimation3 = love.graphics.newImage("graphics/darkExplode.png")
  gSpellAnimation3 = anim8.newGrid(80,100,1120,100,0,0,0)
  spellAnimations["DarkExplosion"] = anim8.newAnimation(gSpellAnimation3("1-14",1),0.2)
  spellAnimations["DarkExplosion"]:pauseAtStart()
  
  --Table storing all spells and things as they need to be on the field. Also stores special effects and things that dont really affect gameplay (though its subject to change)--
  spells={x={},y={},animation={},frame={},duration={},length={},graphic={},scaleX={},scaleY={},id={},numberEnd={},endSpells={}}
  
  --List of all possible summonable spells. Its rather large and unwieldy.--
  spellList={
            summonSkull=
				{number=2,
					[1]={id="summonSkull",endSpells={"skullExplosion"},duration=99999,delay=0,blocking=false,length=4,animation=spellAnimations["Spirit"],graphic=bSpellAnimation,type="summon",xOffset=20,yOffset=108,bomb=1,detonator=false},
                    [2]={id="summonEffect",numberEnd=0,endSpells={},duration=10,delay=0,blocking=false,length=10,animation=spellAnimations["SummonEffect"],graphic=bSpellAnimation2,type="summon",xOffset=-3,yOffset=71,bomb=false,detonator=false}
				},
			explodeSkulls=
				{number=1,
					[1]={id="explodeSkulls",endSpells={},duration=1,delay=0,blocking=false,length=nil,animation=nil,graphic=nil,type="activate",xOffset=nil,yOffset=nil,bomb=false,detonator=1}
				},
			skullExplosion=
			    {number=1,
					[1]={id="skullExplosion",endSpells={},duration=99999,delay=0,blocking=false,length=14,animation=spellAnimations["DarkExplosion"],graphic=bSpellAnimation3,type="summon",xOffset=0,yOffset=0,bomb=false,detonator=false}
				},
			}
  
  spellsCasting = {} --List of spells currently being used. Does not count buffs, but wards may be here.--
  
  playerSpells = {bobus={{spells="summonSkull",animation="Attack1",duration=1}}}
  
  spaceSpell = "summonSkull"
  shiftSpell = "explodeSkulls"
  
  --Set to loop through X spells to keep memory usage down and overwrite particles if there are too many instead of crashing the game or causing bugs--
  currentSpell = 1
  currentSpellCast = 1
  currentCheckCast = 1  
  
  --Set basic variables needed for gameplay not in the above categories.--
  animationRunTime = 0 --Used to allow attack animations to play until completed and not stick around.--
  player = {x=0,y=0,xVelocity=0,yVelocity=0,xMove=0,yMove=0,speed=5,friction=0.025} --Basic Player stats, everything needed goes here. Also has some other test variables.--
  
  xLocationList = {}
  
end

function love.mousepressed(click_x,click_y,click_button)
  xClick = click_x
  yClick = click_y
  clicking = true
  button = click_button
end

function love.mousereleased(click_x,click_y,click_button)
  clicking = false
  button = click_button
end

function love.keypressed(type_key)
  key = type_key
  if key == "w" then
    wActive = true
  elseif key == "a" then
    aActive = true
  elseif key == "s" then
    sActive = true
  elseif key == "d" then
    dActive = true
  elseif key == " " then
    spaceActive = true
  elseif key == "lshift" then
    shiftActive = true
  end
  keyActive = true
end

function love.keyreleased(type_key)
  key = type_key
  if key == "w" then
    wActive = false
  elseif key == "a" then
    aActive = false
  elseif key == "s" then
    sActive = false
  elseif key == "d" then
    dActive = false
  elseif key == " " then
    spaceActive = false
  elseif key == "lshift" then
    shiftActive = false
  end
  keyActive = false
end

function love.update(dt)
  if spaceActive then
    spaceActive = false
    for i = 1,spellList[spaceSpell]["number"] do 
	  currentSpellCast = currentSpellCast + 1
	  if currentSpellCast > 1000 then
	    currentSpellCast = 1
	  end
      spellsCasting[currentSpellCast] = spellList[spaceSpell][i]
    end
  end
  if shiftActive then
    shiftActive = false
    for i = 1,spellList[shiftSpell]["number"] do 
	  currentSpellCast = currentSpellCast + 1
	  if currentSpellCast > 1000 then
	    currentSpellCast = 1
	  end
      spellsCasting[currentSpellCast] = spellList[shiftSpell][i]
    end
  end
  for i,v in pairs(spellsCasting) do
    spellsCasting[i]["delay"] = spellsCasting[i]["delay"] - 1
	if spellsCasting[i]["delay"] < 1 then
	  if spellsCasting[i]["type"] == "summon" then
	    currentSpell = currentSpell + 1
	    if currentSpell > 1000 then
	      currentSpell = 1
	    end
		writtenCast = spellsCasting[i]
	    spells.animation[currentSpell] = spellsCasting[i]["animation"]
		if spellsCasting[i]["xLocation"] then
		  spells.x[currentSpell] = spellsCasting[i]["xLocation"]+spellsCasting[i]["xOffset"]
	      spells.y[currentSpell] = spellsCasting[i]["yLocation"]+spellsCasting[i]["yOffset"]
		else
	      spells.x[currentSpell] = player.x+spellsCasting[i]["xOffset"]
	      spells.y[currentSpell] = player.y+spellsCasting[i]["yOffset"]
	    end
		spells.frame[currentSpell] = 1
	    spells.animation[currentSpell]:pauseAtStart()
        spells.animation[currentSpell]:resume()
	    spells.length[currentSpell] = spellsCasting[i]["length"]
	    spells.duration[currentSpell] = spellsCasting[i]["duration"]
	    spells.graphic[currentSpell] = spellsCasting[i]["graphic"]
		spells.id[currentSpell] = spellsCasting[i]["id"]
		spells.endSpells[currentSpell] = spellsCasting[i]["endSpells"]		
		spellsCasting[i] = nil
	  elseif spellsCasting[i]["type"] == "activate" then
	    if spellsCasting[i]["detonator"] then
		  for k,v in pairs(spells.id) do
		    if spellList[spells.id[k]] then
		      for o = 1,spellList[spells.id[k]]["number"] do
			    if spellList[spells.id[k]][o]["bomb"] == spellsCasting[i]["detonator"] then
			      spells.frame[k] = 9999999
			    end
			  end
			end
		  end
		end
	    spellsCasting[i] = nil
	  end
	end
  end
  for i,v in pairs(spells.x) do
	spells.animation[i]:update(dt)
	spells.frame[i] = spells.frame[i] + 1
    if spells.frame[i] > spells.duration[i] then
	  for k,v in pairs(spells.endSpells[i]) do
	    if spellList[v] then
	      for o = 1,spellList[v]["number"] do
		  	currentSpellCast = currentSpellCast + 1
		    if currentSpellCast > 1000 then
	          currentSpellCast = 1 
	        end
			spellsCasting[currentSpellCast] = spellList[v][o] 
            spellsCasting[currentSpellCast]["xLocation"] = spells.x[i]
			spellsCasting[currentSpellCast]["yLocation"] = spells.y[i]
		    writtenCast = spellsCasting[currentSpellCast]
			spells.x[i] = nil
			spells.y[i] = nil
		  end
	    end
	  end
	  spells.x[i] = nil
	  spells.y[i] = nil
	  spells.animation[i] = nil
	  spells.frame[i] = nil
	end
  end
--[[  if spaceActive then
    reset = true
	hold = false
  end
  if shiftActive then
    burst = true
  else
    burst = false
  end
  if reset == true and spaceActive == false then
    animationRunTime = 0
	currentSpell = currentSpell + 1
	if currentSpell > 1000 then
	  currentSpell = 1
	end
	spells.animation[currentSpell] = spellAnimations["Spirit"]
	spells.x[currentSpell] = player.x+20
	spells.y[currentSpell] = player.y+103
	spells.frame[currentSpell] = 1
	spells.animation[currentSpell]:pauseAtStart()
    spells.animation[currentSpell]:resume()
	spells.length[currentSpell] = 4
	spells.duration[currentSpell] = 999999
	spells.graphic[currentSpell] = bSpellAnimation
	currentSpell = currentSpell + 1
	spells.scaleX[currentSpell] = 1
	spells.scaleY[currentSpell] = 1
	if currentSpell > 1000 then
	  currentSpell = 1
	end
	spells.animation[currentSpell] = spellAnimations["SummonEffect"]
	spells.x[currentSpell] = player.x-3
	spells.y[currentSpell] = player.y+72
	spells.frame[currentSpell] = 1
	spells.animation[currentSpell]:pauseAtStart()
    spells.animation[currentSpell]:resume()
	spells.length[currentSpell] = 10
	spells.duration[currentSpell] = 10
	spells.graphic[currentSpell] = bSpellAnimation2
	spells.scaleX[currentSpell] = 1
	spells.scaleY[currentSpell] = 1
	if hold == false then
      reset = false
	end
  end
  for i,v in pairs(spells.x) do
	spells.animation[i]:update(dt)
	if burst and spells.graphic[i] == bSpellAnimation then
	  spells.frame[i] = 9999999
	end
	spells.frame[i] = spells.frame[i] + 1
    if spells.frame[i] > spells.duration[i] then
	  if spells.graphic[i] == bSpellAnimation then
		currentSpell = currentSpell + 1
		if currentSpell > 1000 then
		  currentSpell = 1
		end
		spells.animation[currentSpell] = spellAnimations["DarkExplosion"]
		spells.x[currentSpell] = spells.x[i]-60
		spells.y[currentSpell] = spells.y[i]-50
		spells.frame[currentSpell] = 1
		spells.animation[currentSpell]:pauseAtStart()
		spells.animation[currentSpell]:resume()
		spells.length[currentSpell] = 14
		spells.duration[currentSpell] = 14
     	spells.graphic[currentSpell] = bSpellAnimation3
		spells.scaleX[currentSpell] = 2
	    spells.scaleY[currentSpell] = 2
	  end
	  spells.x[i] = nil
	  spells.y[i] = nil
	  spells.animation[i] = nil
	  spells.frame[i] = nil
	  spells.scaleX[i] = nil
	  spells.scaleY[i] = nil
	end
  end
  if animationRunTime > 0 then
    playerAnim = playerAnimations[playerID]["Idle"]
  else
    playerAnim = playerAnimations[playerID]["Attack1"]
	animationRunTime = animationRunTime + 1
  end
 --]]
  if wActive and aActive then
    player.xVelocity = player.xVelocity - 0.2
	player.yVelocity = player.yVelocity - 0.2
  elseif wActive and dActive then
    player.xVelocity = player.xVelocity + 0.2
	player.yVelocity = player.yVelocity - 0.2    
  elseif sActive and aActive then
    player.xVelocity = player.xVelocity - 0.2
	player.yVelocity = player.yVelocity + 0.2
  elseif sActive and dActive then
    player.xVelocity = player.xVelocity + 0.2
	player.yVelocity = player.yVelocity + 0.2    
  elseif wActive then
    player.yVelocity = player.yVelocity - 0.4
  elseif aActive then
    player.xVelocity = player.xVelocity - 0.4    
  elseif sActive then
    player.yVelocity = player.yVelocity + 0.4    
  elseif dActive then
    player.xVelocity = player.xVelocity + 0.4    
  end
  player.xMove = player.xMove + player.xVelocity
  while math.abs(player.xMove) > 1 do
    player.xMove = player.xMove - math.abs(player.xMove)*1/player.xMove
	player.x =  player.x + math.abs(player.xMove)*1/player.xMove
  end  
  player.yMove = player.yMove + player.yVelocity
  while math.abs(player.yMove) > 1 do
    player.yMove = player.yMove - math.abs(player.yMove)*1/player.yMove
	player.y =  player.y + math.abs(player.yMove)*1/player.yMove
  end
  if aActive or dActive then else
    if math.abs(player.xVelocity) < player.friction then player.xVelocity = 0 else 
      player.xVelocity = player.xVelocity-player.friction*player.xVelocity
    end
  end
  if wActive or sActive then else
    if math.abs(player.yVelocity) < player.friction then player.yVelocity = 0 else 
      player.yVelocity = player.yVelocity-player.friction*player.yVelocity
    end
  end
  if math.abs(player.yVelocity) + math.abs(player.xVelocity) > player.speed then
    if math.abs(player.yVelocity) > math.abs(player.xVelocity) then
	  player.yVelocity = player.yVelocity - player.yVelocity*(math.abs(player.yVelocity)-(player.speed/2))/math.abs(player.yVelocity)
	else
	  player.xVelocity = player.xVelocity - player.xVelocity*(math.abs(player.xVelocity)-(player.speed/2))/math.abs(player.xVelocity)	  
	end
  end
end

function love.draw()
 love.graphics.draw(playerAnim,player.x,player.y)
 for i,v in pairs(spells.x) do
    frame = spells.frame[i]
	while frame > spells.length[i] do
	  frame = frame - spells.length[i]
	end
    spells.animation[i]:gotoFrame(frame)
    spells.animation[i]:draw(spells.graphic[i],spells.x[i],spells.y[i])
  end
  if writtenCast then 
    k = 0
    for i,v in pairs(writtenCast) do
      k = k + 1
	  love.graphics.print(tostring(i).." : "..tostring(v),10,20*k)
    end
  end
  if xLocationList then 
    k = 0
    for i,v in pairs(xLocationList) do
      k = k + 1
	  love.graphics.print("XLocation"..tostring(i).." : "..tostring(v),200,20*k)
    end
  end
end
(It uses Anim8 for the animations, although it isnt important as I see it. Ive been trying for a day or two now and this one is really bugging me.)
The bug itself is that when a spell is created upon the removal of another spell, it creates a xLocation and yLocation to show where to summon this next spell. The xLocation and yLocation seem to be created fine, but when a spell is created using them, it doesnt work quite right. Instead of summoning each one at its own location, it summons all of them at one random xLocation and yLocation. I found this much out by tracking the variables and using semi-transparent images. The problem is, I have no Idea how to fix it. It would seem the problem is isolated in the bit of code which creates the x and y coordinates of the spell using the xLocation and yLocation, as replicating the specifics while instead rending from player.x seems to work fine; however, I could be wrong. I was wondering if anyone could look through and see if they see any issues which could cause this behavior, and let me know so I could fix it up. Thank you.

Heres the love: https://drive.google.com/file/d/0B8Ox_E ... sp=sharing
Shaddy
Prole
Posts: 5
Joined: Thu Apr 30, 2015 11:26 pm

Please.

Post by Shaddy »

Does anyone know anything about this? Would you like me to edit something to make it easier to understand what I want? I just cant figure out what is causing this glitch. Its just causing everything to be created at the same location because of something that causes them to all have the same data when it reaches the exit of the loop that sets their offsets to where they are created. I dont know if its a flaw with the loop that sets them or some bug with the one that reads them or something else that I messed up I just cant find the error in my own coding that is causing the problem...any help is appreciated, thank you...
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: Please.

Post by s-ol »

Shaddy wrote:Does anyone know anything about this? Would you like me to edit something to make it easier to understand what I want? I just cant figure out what is causing this glitch. Its just causing everything to be created at the same location because of something that causes them to all have the same data when it reaches the exit of the loop that sets their offsets to where they are created. I dont know if its a flaw with the loop that sets them or some bug with the one that reads them or something else that I messed up I just cant find the error in my own coding that is causing the problem...any help is appreciated, thank you...
What steps exactly do I need to take to reproduce the problem?

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end
User avatar
BOT-Brad
Citizen
Posts: 87
Joined: Tue Dec 02, 2014 2:17 pm
Location: England

Re: A little bug I just cant seem to figure out.

Post by BOT-Brad »

I am presuming that when you cast multiple spells (SPACE), and have say 5 or 6 of them casted, when you press LSHIFT it should produce that cloud effect at each position, rather than them all clumping at that one position?

I would recommend however first turning the spells into objects, rather than accessing them via the massive spell object you have.

Right now in your update loop you have this;

Code: Select all

for i,v in pairs(spellsCasting) do
-snip-
 spells.frame[currentSpell] = 1
 spells.animation[currentSpell]:pauseAtStart()
 spells.animation[currentSpell]:resume()
 spells.length[currentSpell] = spellsCasting[i]["length"]
 spells.duration[currentSpell] = spellsCasting[i]["duration"]
 spells.graphic[currentSpell] = spellsCasting[i]["graphic"]
 spells.id[currentSpell] = spellsCasting[i]["id"]
 spells.endSpells[currentSpell] = spellsCasting[i]["endSpells"]
-snip-
end
Which is not only quite verbose, but also a little confusing. It would be better (in my opinion at least), to offload all these tables (spell.frame, spell.animation, spell.length, etc.) to actual variables inside a "spell" object.

Example

Code: Select all

for i=1, #spells do
 local spell = spells[i]
 spell.frame = 1
 spell.animation:pauseAtStart()
 spell.animation:resume()
 -- etc.
end
Where the "spells" table is just an array of spell objects which get added "array-wise" rather than "dictionary-like". This would not only massively trim down the amount of code you would need to write for all the nil-object checking you are doing each frame (as each object is 'guaranteed' to have a value of that name), but also make it easier to fix bugs like the one you have now. Let me know if you think my ramblings make any sense, I wouldn't mind helping you convert the code a little :nyu: .
Follow me on GitHub! | Send me a friend request on PSN!
Shaddy
Prole
Posts: 5
Joined: Thu Apr 30, 2015 11:26 pm

Re: A little bug I just cant seem to figure out.

Post by Shaddy »

Thanks for the help. Currently, I have a date to go on, but when I get back Ill try and rewrite it and see if that works better. (Though from what I see, it sounds like it would.)

Edit: Yup, updated it and now it works. The issue was an odd thing with tables which I recently realized from a different program I wrote. The thing you did, (plus a little addition lower down) has it working now though.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 3 guests