Not drawing multiple images.
BlitzMax Forums/BlitzMax Beginners Area/Not drawing multiple images.| 
 | ||
| So after defeating the nefarious level editor I'm now working on the primary game, I have it pulling the actual level information, everything is going well except for drawning my enemies. If I make it draw a rectangle for each enemy it works fine, but when I try to have it draw the actual "Villain" image it only draws the first one and leaves the rest blank. This tells me that my DrawSprite() is probably the issue, but I can't see the problem. SuperStrict
Include "openlevel.bmx"
AppTitle="Platform Game"
Const  gwidth:Int = 1280
Const  gheight:Int = 1024
Graphics gwidth, gheight
Global scn_left:Int = 0
Global scn_top:Int = 0
Global Spritelist:TList = CreateList()
For Local x:Int = 0 To mapx-1
	For Local y:Int = 0 To mapy-1
		For Local z:Int = 0 To mapz-1
			If map[x,y,4] > -1 Then Global H:hero = Hero.Create("images/hero.png",(x*tsize)-scn_left,(y*tsize) - scn_top)
			If map[x,y,3] = 0 Then Global E:Enemy = Enemy.Create("images/Villain.png",(x*tsize)-scn_left,(y*tsize) - scn_top)
		Next 
	Next
Next
Repeat
	
	Cls
	
	For Local H:Hero = EachIn Spritelist
		H.UpdateSprites()
	Next 
	
	For Local a:Sprite = EachIn Spritelist
		a.DrawSprites()
	Next 
	
	Flip
Until AppTerminate() Or KeyHit(Key_escape)
Type Sprite
	Field x:Int
	Field y:Int
	Field I:TImage
	
	Method DrawSprites()
		DrawImage I,x,y
	End Method
	
End Type
	
Type Hero Extends Sprite	
	Function Create:Hero(File:String,xstart:Int,ystart:Int)
		Local H:Hero = New Hero
			H.x=xstart
			H.y=ystart
			H.I=LoadImage(file)
			
			ListAddLast Spritelist, H
		Return H
	End Function
	
	Method UpdateSprites()
		If KeyDown(key_left) Then x = x - 5
		If KeyDown(key_right) Then x = x + 5
	End Method
End Type 
	
Type Enemy Extends Sprite
	Function Create:Enemy(File:String,xstart:Int,ystart:Int)
		Local E:Enemy = New Enemy 
			E.x=xstart
			E.y=ystart
			E.I=LoadImage(file)
			
			ListAddLast Spritelist, E
		Return E
	End Function
	
	Method UpdateSprites()
		
	End Method
End Type
End   | 
| 
 | ||
| Change your looping and dont create Globals in a loop ;) 
Global H:Hero
' Dont need Global E:Enemy
For Local x:Int = 0 To mapx-1
	For Local y:Int = 0 To mapy-1
		For Local z:Int = 0 To mapz-1
			If map[x,y,4] > -1 Then H = Hero.Create("images/hero.png",(x*tsize)-scn_left,(y*tsize) - scn_top)
			If map[x,y,3] = 0 Then Enemy.Create("images/Villain.png",(x*tsize)-scn_left,(y*tsize) - scn_top)
		Next 
	Next
Next
Last edited 2012 | 
| 
 | ||
| I would replace For Local H:Hero = EachIn Spritelist H.UpdateSprites() Next For Local a:Sprite = EachIn Spritelist a.DrawSprites() Next with 'both types extend from sprite, so we can use that 'that way we replace a loop of a maybe-big-list with type checks 'use such style if MORE THAN ONE hero is possible in the list For Local a:Sprite = EachIn Spritelist if Hero(a) <> null then Hero(a).UpdateSprites() a.DrawSprites() Next or better: 'we stored hero as global - no need to look for it. H.UpdateSprites() For Local a:Sprite = EachIn Spritelist a.DrawSprites() Next To check the images/drawimage-part - replace: Type Sprite Field x:Int Field y:Int Field I:TImage Method DrawSprites() DrawImage I,x,y End Method End Type with Type Sprite Field x:Int Field y:Int Field I:TImage Method DrawSprites() if I<>null DrawImage(I,x,y) else DrawRect(x,y,20,20) 'print "missing sprite image XYZ drawn at x="+x+" y="+y endif End Method End Type Hope that helps a bit. bye Ron PS: if you know that enemies share images, make a TMap with Sprites and access them that way and not with LoadImage(url) multiple times. - create map - check existance of object by url as key - insert object (Timage) to map with url as key You can do the same with other resources in your application. | 
| 
 | ||
| Okay so I did everything suggested (aside from the Tmap, I need to learn more about those) and it's working, almost too well. Now for some reason it's drawing multiple images of the Hero sprite, only one of which actually exists as an object created by the hero type, if I remove H from the Spritelist then it deletes the sprite that I have control over and just leaves a static image that's standing at the starting XY coordinates. Edit: I tested the sprites for the enemies and they aren't affected by this issue, so it's just an issue with the hero for some reason. Last edited 2012 | 
| 
 | ||
| Try this (also I added the TMap stuff that Derron talked about and I added some code so I code actually run (eg mapx, mapy etc): SuperStrict
AppTitle="Platform Game"
Const WIDTH:Int = 1280
Const HEIGHT:Int = 1024
Graphics WIDTH, HEIGHT
Global scn_left:Int = 0
Global scn_top:Int = 0
Global sprite_list:TList = CreateList()
Global mapx:Int = 20
Global mapy:Int = 20
Global mapz:Int = 20
Global tsize:Int = 30
Global map:Int[,,]
Global h:THero 
Global images:TImageBank = New TImageBank
LoadImages()
PopulateMap()
Local heroCreated:Int = False
For Local x:Int = 0 To mapx - 1
	For Local y:Int = 0 To mapy - 1
		For Local z:Int = 0 To mapz - 1
			If map[x,y,4] > -1 And Not heroCreated Then
				h = THero.Create(images.Get("hero"),(x*tsize)-scn_left,(y*tsize) - scn_top)
				heroCreated = True
			EndIf
			If map[x,y,3] = 0 Then TEnemy.Create(images.Get("Villain"),(x*tsize)-scn_left,(y*tsize) - scn_top)
		Next 
	Next
Next
Repeat
	Cls
	h.UpdateSprite()
	For Local a:TSprite = EachIn sprite_list
		a.DrawSprite()
	Next 
	
	Flip
Until AppTerminate() Or KeyHit(KEY_ESCAPE)
Function LoadImages()
	images.Load("images/hero.png")
	images.Load("images/Villain.png")
EndFunction
Function PopulateMap()
	map = New Int[mapx, mapy, mapz]
	
	For Local x:Int = 0 To mapx - 1
		For Local y:Int = 0 To mapy - 1
			For Local z:Int = 0 To mapz - 1
				map[x, y, z] = Rand(0, 10)
			Next
		Next
	Next
EndFunction
Type TSprite
	Field x:Int
	Field y:Int
	Field image:TImage
	
	Method DrawSprite()
		DrawImage image,x,y
	End Method
End Type
	
Type THero Extends TSprite	
	Function Create:THero(image:TImage, xstart:Int, ystart:Int)
		Local h:THero = New THero
		h.x = xstart
		h.y = ystart
		h.image = image
		sprite_list.AddLast(h)
		Return h
	End Function
	
	Method UpdateSprite()
		If KeyDown(key_left) Then x = x - 5
		If KeyDown(key_right) Then x = x + 5
	End Method
End Type 
	
Type TEnemy Extends TSprite
	Function Create:TEnemy(image:TImage, xstart:Int, ystart:Int)
		Local e:TEnemy = New TEnemy 
		e.x = xstart
		e.y = ystart
		e.image = image
			
		sprite_list.AddLast(e)
		Return e
	End Function
	
	Method UpdateSprite()
		
	End Method
End Type
Type TImageBank Extends TMap
	Method Load(name:String)
		Local i:TImage = LoadImage(name)
		If i = Null Then RuntimeError "Error - Cannot load image "+name
		Insert(StripAll(Upper(name)), i)
	EndMethod
	
	Method Get:TImage(name:String)
		Local i:TImage = TImage(ValueForKey(Upper(name)))
		If i = Null Then RuntimeError "Error - Cannot find image "+name
		Return i
	EndMethod
	
EndType
End  
Last edited 2012 Last edited 2012 | 
| 
 | ||
| @therevills [bbcode] Global h:THero ... Local heroCreated:Int = False ... If map[x,y,4] > -1 And Not heroCreated Then h = THero.Create(images.Get("hero"),(x*tsize)-scn_left,(y*tsize) - scn_top) heroCreated = True EndIf [/bbcode] could be stripped by... [bbcode] Global h:THero = Null ... If map[x,y,4] > -1 And h = null h = THero.Create(images.Get("hero"),(x*tsize)-scn_left,(y*tsize) - scn_top) EndIf [/bbcode] Think a "null" check is not that work intensive :D @awesome Try to get some code which you can post here for us to test. Another hint: instead of calling a type's method "UpdateSprites" you should consider calling it "Update" and "Draw" and the object containing the list can then have a function (methods if instances) like "UpdateAll". If you run into problems like "but Hero extends sprite and has to have a method 'draw' too" try something like : [bbcode] Type THero field sprite:TSprite field name:string="My Hero" ... Method Draw() self.sprite.Draw() End Method End Type [/bbcode] That's needed as you won't be able to extend a class and overwrite the parents methods in Blitzmax (for adding further parameters and so on). Extend types if they share something - so eg. Renderables but do not extend from attributes they have. [bbcode] 'object having some values associated but needs some nifty helpers Type TCoord field x:float field y:float ... Method IsSame(otherTCoord) ... Method IsSameXY(x:float,y:float) ... End Type Type TRenderable field coord:TCoord ... 'abstract methods are defined in all the ancestors Method Draw() abstract ... End Type Type TSprite extends TRenderable field image:TImage ... Method Draw() DrawImage(self.image, self.coord.x, self.coord,y) ... End Method End Type Type THero field sprite:TSprite 'here we can store the coord of last cycle 'or before we started some moving action - a backup :D 'but this won't be that easy if extending the things field lastCoord:TCoord Method Draw(additionalParameterLikeOverwriteSomething:int = 0) self.sprite.Draw() End Method End Type 'do the same for Type TEnemy 'but this time you can extend different Enemies... TFireElemental extends TEnemy 'then just change sprites, or update-behaviour Type TLevel field blocksAndEntityList... field enemiesList:TList ... End Type Type TGame field hero:THero field currentLevel:TLevel ... Method Update() hero.update() for local enemy:TEnemy = eachin self.currentLevel.enemiesList enemy.update() next End Method ... 'same for Method Draw()... End Type ... [/bbcode] Ok it's not tested as I wrote it now and I might be run into offtopic or some kind of tutorial for "oop in BlitzMax" ... think I finish my posting here :D bye Ron |