Blitzmax game suddenly slow

BlitzMax Forums/BlitzMax Beginners Area/Blitzmax game suddenly slow

kronholm(Posted 2006) [#1]
So I read the "Blitzmax SLOW SLOW SLOW" thread, and to my surprise discovered I was running a very old Blitzmax. Something like 1.09 or something. "Woah great" I thought, and immediately updated (yes, remembering to uninstall and delete all instances of old blitzmax).

PROBLEM!
The crappy laptop I use to test my builds on (Windows, celeron 2000ish), to see if they're not too slow, now runs my game at a crawl. It's not even 4 fps. Before, it was smooth even with 4000+ balls on the screen (breakout clone). The other laptop I'm using to code and test on (Pentium M-1.6) runs it just fine.

Edit: On yet another machine, it used to run very slow, but it ran. Now it just shows the console window and closes it. (Windows 600mhz)

What happened guys? It worked fine with 1.09 and now with 1.16 it's crawling. I'm having the exact opposite problem of the guy in the "Blitzmax SLOW SLOW SLOW" thread..


tonyg(Posted 2006) [#2]
Maybe the exact opposite is true with your system?
Maybe the card is crap with DX (or the DX driver is a problem)?
Try using the GL driver again and checking the difference.


kronholm(Posted 2006) [#3]
I've tried both DX and GL, and there's no difference. It's still slow.


tonyg(Posted 2006) [#4]
Can you post some code?


kronholm(Posted 2006) [#5]
Hmm okay, don't see how that could help but alright. Careful or you might go blind from my n00b coding:

Strict
(whole lot of incbin's removed here, to save space)
Graphics 800,600,0
SetClsColor 100,100,100
SetMaskColor 255,255,255'White

AutoMidHandle True
(more image loading removed)

Include "powerup.bmx"
Include "particles.bmx"

Type obj
	Field x#, y#
	Field speed# = 0.1
	Field height#
	Field width#
EndType

Type tball Extends obj 'note: ball image must be 100x100 pixels
	Field oldx# = 0, oldy# = 0
	Field offsetx#
	Field dir# = 0
	Field radius# = 10
	Field oldspeed# = 0
	Field sticky = 0
	Function newball(radius)
		Local ball:tball = New tball
		ball.radius = radius
		balllist.addlast(ball)	
	EndFunction
	Method moveball()
		oldx# = x
		oldy# = y
		x#:+ Sin(dir)*speed*time
		y#:+ Cos(dir)*speed*time
	EndMethod
	Method collide()
		If x <= radius-3 Or x >= 646-radius Then x = oldx ; dir = (180 - dir) + 180 ' left wall and right wall collide check
		If y <= radius-3 Then y = oldy ; dir = 180 - dir ' top wall and bottom wall collide check
		Local paddleh# = paddle.height/2
		If y+radius >= paddle.y - paddleh	' check if ball is below paddle y
			Local paddlew# = paddle.width/2
			If x+radius > paddle.x-paddlew And x-radius < paddle.x+paddlew Then 'check if ball is between paddle in x
				If paddle.sticky = 1
					If sticky = 0 Then ' set the ball as sticky if it isn't, making it stop etc.
						sticky = 1
						oldspeed = speed
						speed = 0
						offsetx = x-paddle.x
						If x > paddle.x Then dir = 180 - (x - paddle.x)/2
						If x < paddle.x Then dir = 180 + (paddle.x - x)/2
					EndIf
					x = MouseX() + offsetx
					y = paddle.y - paddleh - radius	'fix the ball height if it's below the paddle
					If MouseHit(1) Then								For Local ball:tball = EachIn balllist 'make sure we release all balls from paddle when mousehit
							If ball.sticky = 1 Then 
								If ball.speed = 0 Then ball.speed = ball.oldspeed ; ball.oldspeed = 0
								ball.sticky = 0
							EndIf
						Next
					EndIf
				Else
					If x > paddle.x Then dir = 180 - (x - paddle.x)/2
					If x < paddle.x Then dir = 180 + (paddle.x - x)/2
				EndIf	
			Return
			EndIf
		EndIf
		If y >= 600 Then die()
	EndMethod
	Method draw()
		Local ratio# = radius / 100 * 2
		SetScale ratio,ratio
		DrawImage(ballimg, x, y)
		SetScale 1,1
	EndMethod
	Method die()
		balllist.remove(Self)
	EndMethod
EndType

Type TBrick Extends obj
	Field strength = 1
	Field r,g,b
	Field powerup = 0
	Field number# = 0
	Function create(x=200,y=200,h=20,w=70,r=200,g=200,b=255,str=1,powerup=0)
		Local newbrick:tbrick = New tbrick
		newbrick.x = x
		newbrick.y = y
		newbrick.height = h
		newbrick.width = w
		newbrick.r = r
		newbrick.g = g
		newbrick.b = b
		If randompowerups = True
		    Local random = Rand(1,5)
			If random = 1 Then newbrick.powerup = getrandomeffectnumber()
		EndIf
		bricklist.addlast(newbrick)
	EndFunction
	Method collide()
		For Local ball:tball = EachIn balllist
			Local brickw = width / 2
			If ball.x# + ball.radius => x# - brickw Then
				If ball.x# - ball.radius =< x# + brickw Then
					Local brickh = height / 2
					If ball.y# + ball.radius => y# - brickh Then
						If ball.y# - ball.radius =< y# + brickh Then
							If ball.oldy < y - brickh Then ball.dir = 180 - ball.dir ; ball.y = ball.oldy ; die() ; Return
							If ball.oldy > y + brickh Then ball.dir = 180 - ball.dir ; ball.y = ball.oldy ; die() ;  Return
							If ball.oldx < x - brickw Then ball.dir = 360 - ball.dir ; ball.x = ball.oldx ;  die() ; Return
							If ball.oldx > x + brickw Then ball.dir = 360 - ball.dir ; ball.x = ball.oldx ;  die() ; Return
						EndIf
					EndIf
				EndIf
			EndIf		
		Next
	EndMethod
	Method draw()
		If powerup > 0 Then
			r = 255
			g = 255
			b = 10	
		EndIf
		SetColor r,g,b
		DrawImage(brick1img, x, y)
		Select strength
			Case 1 DrawImage(cracked_3,x,y)
			Case 2 DrawImage(cracked_2,x,y)
			Case 3 DrawImage(cracked_1,x,y)
		EndSelect
	EndMethod
	Method die()
		If strength = 1 And powerup > 0 Then tpowerup.spawn(x,y,powerup)
		If strength = 1 Then bricklist.remove(Self)	 ; 'PlaySound explodesnd ; player1.score:+25
		If strength = 1 Then explode(x,y, width/2, height/2,r,g,b)
		If strength > 1 Then strength:-1 ; 'PlaySound pop ; player1.score:+10
	EndMethod
EndType

Type TPaddle Extends obj
	Field width# = 190
	Field leftwidth# = 15
	Field rightwidth# = 15
	Field height# = 17
	Field x = 0
	Field y = 580
	Field sticky = 0
	Method move()
		x = MouseX()
	EndMethod

	Method draw()
		Local realwidth = width - leftwidth - rightwidth
		Local halfwidth = realwidth/2 
		SetColor 255,255,255
		Local MouseX = MouseX()
		If MouseX < 15 + halfwidth Then MouseX = 15 + halfwidth
		If MouseX > 630 - halfwidth Then MouseX = 630 - halfwidth
		MoveMouse MouseX, 550
		DrawImage(paddle_leftimg, MouseX-halfwidth-7, 580)
		SetScale realwidth,1
		DrawImage(paddle_middleimg, MouseX, 580)
		SetScale 1,1
		DrawImage(paddle_rightimg, MouseX+halfwidth+8, 580)
	EndMethod
EndType

Type player
	Field lives = 3
	Field score = 0
EndType

Type background Extends obj
	Method draw()
		SetColor 255,255,255
		TileImage(tileimg,x,y)
		x#:+.4*time
		y#:+.5*time
	EndMethod
EndType

Global balllist:TList = CreateList()
Global bricklist:TList = CreateList()
Global sparklist:TList = CreateList()
Global state$ = "menu"
Global ball_hold = 1
Global newbackground:background = New background
Global player1:player = New player
Global time# = 1
Global paddle:tpaddle

Repeat
	If state = "menu" Then menu()
	If state = "started" Then started()
	If state = "started" And ListIsEmpty(balllist) Then die()
	If state = "started" And ListIsEmpty(bricklist) Then die()
	If state = "gameover" Then gameover()
	Flip; Cls
'	FlushMem -- this did not work with 1.16
Until KeyDown(Key_Escape)

Function die()
	If player1.lives = 0 Then state = "gameover" ; Return
	player1.lives:-1
	tball.newball(10)
	ball_hold = 1
EndFunction

Function gameover()
	If KeyHit(key_space) state = "menu" ; Return
	SetBlend(alphablend)
	newbackground.draw()
	SetRotation Cos(number)*20
	SetScale Cos(number)*1, Cos(Cos(number)*1)*1.2
	number:+1
	SetColor 0,0,0
	SetAlpha 0.1
	DrawImage(gameoverimg,400,400)
	SetColor 255,255,255
	SetAlpha 1
	DrawImage(gameoverimg,400,300)
	SetRotation 0
	SetColor 0,0,0
	SetScale 1,1
	DrawText "Press SPACE for menu", 200,550
EndFunction

Function menu()
	SetBlend(alphablend)
	newbackground.draw()
	SetAlpha .1
	DrawImage(logo_shadowimg, 400, 150)
	SetAlpha 1
	SetColor 255,255,255
	DrawImage(logoimg, 400, 100)
	SetColor 0,0,Rand(100,200)
	DrawText "Press SPACE to start a new game", 290,300
	If KeyHit(key_space) Then newgame()
EndFunction


Function newgame()
	tball.newball(10)
	paddle = New tpaddle
	player1.lives = 3
	player1.score = 0
	balllist.clear()
	bricklist.clear()
	poweruplist.clear
	debrislist.clear()
	Include "level1.bmx"
	state = "started"
EndFunction

Function started()
		newbackground.draw()
		For Local brick:tbrick = EachIn bricklist
			brick.collide()
			brick.draw()
		Next
		For Local particle:tparticle = EachIn particlelist
			particle.move()
			particle.draw()
		Next
		For Local debris:tdebris = EachIn debrislist
			debris.move()
			debris.draw()
		Next

		For Local ball:tball = EachIn balllist
			ball.moveball()
			ball.collide()
			ball.draw()
		Next

		For Local powerup:tpowerup = EachIn poweruplist
			powerup.move()
			powerup.collide(paddle.width)
			powerup.draw()
		Next

		paddle.move()
		paddle.draw()

		drawstatusbar()''		drawvalues()

		If ball_hold = 1
			ballhold()
		Else	
			If MouseDown(2) Then matrix() Else time = 1 ; SetAlpha 1
			If KeyHit(key_e) Then state = "edit"

			'If KeyHit(key_down) Then paddle.width:-50
			'If KeyHit(key_up) Then paddle.width:+50

			If KeyHit(key_down) Then For Local ball:tball = EachIn balllist ; ball.radius:-30 ; Next
			
			If KeyHit(key_up) Then For Local ball:tball = EachIn balllist ; ball.radius:+30 ; Next

			If KeyHit(key_x) Then For Local brick:tbrick = EachIn bricklist ; brick.die() ; Next

			If KeyHit(key_4) Then tbrick.create(Rand(40,600), Rand(20,700))
			If KeyHit(key_5) Then createballs(5, Rand(4,20))
			If KeyHit(key_6) Then Include "level1.bmx"
			If KeyHit(key_0) Then createballs(100, Rand(1,3))
			If KeyHit(key_space) Then 
				For Local ball:tball = EachIn balllist
					If ball.speed <> 0
						ball.speed = 0
					Else
						ball.speed = 5
					EndIf
				Next
			EndIf
		EndIf
EndFunction


Function matrix()
	DrawText "MATRIX MODE ON",700,580
	time = 0.1
EndFunction




Function ballhold()
	For Local ball:tball = EachIn balllist
		ball.speed = 0
		ball.y = MouseY()'550
		ball.x = MouseX()
	Next
	If MouseHit(1) Then launchball()
EndFunction


Function launchball()
	ball_hold = 0
	For Local ball:tball = EachIn balllist
		ball.speed = 6
		ball.dir = Rand(135,225)
	Next	
EndFunction

Function drawstatusbar()	SetColor 0,0,0
	DrawRect 645,0,5,600
	SetColor 201,203,219
	DrawRect 650,0,600,800
	SetColor 255,255,255
EndFunction

Function drawvalues()
	SetColor 0,0,0
	DrawText "Number of balls : "+balllist.Count(), 20, 40
	DrawText "Number of bricks : "+bricklist.Count(), 20, 20
	DrawText "Score: "+player1.score, 660,100
	DrawText "Lives: "+player1.lives, 660,120
EndFunction




tonyg(Posted 2006) [#6]
don't see how that could help

You're absolutely right.
Without any images (or the chance to sub them for my own) or the include code I have no chance of running this and providing feedback on whether I see the issue on my machines, what their spec is, add debug/timing/memory usage code etc and help you out.
So...
Why don't you add debug messages to your code so you can determine which function/method is causing the slowdown?


kronholm(Posted 2006) [#7]
Gah, I'm an idiot. Turns out I had to put in
SetGraphicsDriver GLMax2DDriver()
to actually force it to run in opengl mode. Turns out it runs perfectly now with this mode on my slow test-laptop.


kronholm(Posted 2006) [#8]
"Why don't you add debug messages to your code so you can determine which function/method is causing the slowdown?"

Guess you didn't read my initial post. There is no change to the code between the computers, the only change was the difference in BMax versions. Why would I start adding more debug messages when that's not the issue? This was also the reason why I couldn't see a reason to post my code. I omitted the content inclusions because they'll just provide further spam in this thread.


Dreamora(Posted 2006) [#9]
How many images and how large images do you load?
One reason might be that the drawing has been modified to support more hardware things (T'n'L especially was might not make much of different for regular usage but there are some uses for it).
Also the default flags for loading have changed, you might check the BRL.D3D7Max2D implementation to see in the history how that changed and set it for you manually (especially not using filtered images for example)

One thing that might help is that you change to manuall GC mode on slow systems like your 600mhz system as automatic GC has an overhead (GCSetMode I think and then GCCollect where you used flushmem before).


kronholm(Posted 2006) [#10]
Most of the images are very small, not over 50x50. Only the logo and game_over logo are bigger, and they're about 400x300 or something.

I will never ever code for D3D, because I can't use it on other platforms.. What do you mean by filtered images, and that I must not use them - do you mean images with alpha/transparency?

I have no idea what GC mode means or even is, so I will read up on that later when I sit down to code again :) Thanks Dreamora!

Here's the images..

Incbin "images\ball.png"
Incbin "images\paddle.png"
Incbin "images\paddle_left.png"
Incbin "images\paddle_right.png"
Incbin "images\paddle_middle.png"
Incbin "images\tile.png"
Incbin "images\brick_1.png"
Incbin "images\cracked_1.png"
Incbin "images\cracked_2.png"
Incbin "images\cracked_3.png"
Incbin "images\logo.png"
Incbin "images\gameover.png"
Incbin "images\logo_shadow.png"

Incbin "images\powerup\_tile.png"
Incbin "images\powerup\_glass.png"
Incbin "images\powerup\faster.png"
Incbin "images\powerup\slower.png"
Incbin "images\powerup\magnet.png"
Incbin "images\powerup\multi3x.png"
Incbin "images\powerup\multi5x.png"
Incbin "images\powerup\multi9x.png"
Incbin "images\powerup\multi15x.png"
Incbin "images\powerup\multix2.png"
Incbin "images\powerup\multix3.png"
Incbin "images\debris\debris001.png"
Incbin "images\debris\debris002.png"
Incbin "images\debris\debris003.png"
Incbin "images\debris\debris004.png"
Incbin "images\debris\debris005.png"
Incbin "images\debris\debris006.png"
Incbin "images\debris\debris007.png"
Incbin "images\debris\debris008.png"
Incbin "images\debris\debris009.png"
Incbin "images\debris\debris010.png"
Incbin "images\debris\debris011.png"
Incbin "images\debris\debris012.png"
Incbin "images\debris\debris013.png"
Incbin "images\debris\debris014.png"
Incbin "images\debris\debris015.png"
Incbin "images\debris\debris016.png"
Incbin "images\debris\debris017.png"

Global tileimg:Timage=LoadImage("incbin::images\tile.png")
Global ballimg:Timage=LoadImage("incbin::images\ball.png")
Global paddle_leftimg:Timage=LoadImage("incbin::images\paddle_left.png")
Global paddle_middleimg:Timage=LoadImage("incbin::images\paddle_middle.png")
Global paddle_rightimg:Timage=LoadImage("incbin::images\paddle_right.png")

Global logoimg:Timage=LoadImage("incbin::images\logo.png")
Global gameoverimg:Timage=LoadImage("incbin::images\gameover.png")
Global logo_shadowimg:Timage=LoadImage("incbin::images\logo_shadow.png")

Global brick1img:Timage=LoadImage("incbin::images\brick_1.png")
Global cracked_1:Timage=LoadImage("incbin::images\cracked_1.png")
Global cracked_2:Timage=LoadImage("incbin::images\cracked_2.png")
Global cracked_3:Timage=LoadImage("incbin::images\cracked_3.png")
Global tile:Timage=LoadImage("incbin::images\powerup\_tile.png")
Global glass:Timage=LoadImage("incbin::images\powerup\_glass.png")
Global faster:Timage=LoadImage("incbin::images\powerup\faster.png")
Global slower:Timage=LoadImage("incbin::images\powerup\slower.png")
Global magnet:Timage=LoadImage("incbin::images\powerup\magnet.png")
Global multi3x:Timage=LoadImage("incbin::images\powerup\multi3x.png")
Global multi5x:Timage=LoadImage("incbin::images\powerup\multi5x.png")
Global multi9x:Timage=LoadImage("incbin::images\powerup\multi9x.png")
Global multi15x:Timage=LoadImage("incbin::images\powerup\multi15x.png")
Global multix2:Timage=LoadImage("incbin::images\powerup\multix2.png")
Global multix3:Timage=LoadImage("incbin::images\powerup\multix3.png")



tonyg(Posted 2006) [#11]
First, what is the status of the problem?
Does it run OK in either DX and/or GL mode on Bmax 1.16?
Second, adding the debug messages would show if it was a general slowdown or a specific area of code which slowed down. If, for example, some functions were slower than before you coulc the similarity of commands and usen them to review changes in Bmax source code.
Third, posting your code allows other people to feedback on whether they see the same problems. If they do then more people are available to diagnose the problem and/or make suggestions and/or give advice.
Make sense?


FlameDuck(Posted 2006) [#12]
Careful or you might go blind from my n00b coding:
At least you indent. :o>


kronholm(Posted 2006) [#13]
tonyg, as I said above, it's fixed. I simply run it OpenGL on 1.16, which is what I want to use anyway, since it's multiplatform. Turns out 1.16 defaulted to D3D, and 1.09 defaulted to OpenGL. So that was the problem.

If anyone wants, feel free to comment on my code in other areas.. I'd be very happy if you did, it can only be improved from here. I'm a newbie at this, so there's probably a lot of rules and laws I've carelessly stepped on.


Dreamora(Posted 2006) [#14]
I would not use that many program scope globals.
Instead I would use them in a scoped manner like:

Type TEffectImages
  Global brick1img:Timage=LoadImage("incbin::images\brick_1.png")
  Global cracked_1:Timage=LoadImage("incbin::images\cracked_1.png")
  Global cracked_2:Timage=LoadImage("incbin::images\cracked_2.png")
  Global cracked_3:Timage=LoadImage("incbin::images\cracked_3.png")
  Global tile:Timage=LoadImage("incbin::images\powerup\_tile.png")
  Global glass:Timage=LoadImage("incbin::images\powerup\_glass.png")
  Global faster:Timage=LoadImage("incbin::images\powerup\faster.png")
  Global slower:Timage=LoadImage("incbin::images\powerup\slower.png")
  Global magnet:Timage=LoadImage("incbin::images\powerup\magnet.png")
  Global multi3x:Timage=LoadImage("incbin::images\powerup\multi3x.png")
  Global multi5x:Timage=LoadImage("incbin::images\powerup\multi5x.png")
  Global multi9x:Timage=LoadImage("incbin::images\powerup\multi9x.png")
  Global multi15x:Timage=LoadImage("incbin::images\powerup\multi15x.png")
  Global multix2:Timage=LoadImage("incbin::images\powerup\multix2.png")
  Global multix3:Timage=LoadImage("incbin::images\powerup\multix3.png")
end type


You can access them using TEffectImages.multix3 for example.

Might look useless bu perhaps you are later going to implement some effect classes which then can extend TEffectImages and straight accessing them like local images.


But there is nothing "eye killing noobish" in your code at all :-)


kronholm(Posted 2006) [#15]
Ahh I see your point, but don't you mean to make them local within the class then? Otherwise it would still work my old way, with adding the effect classes if they were global ; the effects classes would be able to see them anyway, without a class.


Dreamora(Posted 2006) [#16]
No local is of no use as then every instance of the class would hold a reference to them. The way above they only exist for all instances of the class and extended classes (-> only 1 reference per image to take care off)

Only only thought encapsulate them might help keeping the application "global free" if the images are not really needed to be global at all.
But this logically only makes sense if you create effect classes. Otherwises it would be a useless "more work" :-)


Defoc8(Posted 2006) [#17]
ouch! some indenting from hell...easy there :p ;)
- damned thing nearly had my eye out :]


Psychotronic(Posted 2006) [#18]
Hi. I'm new to BlitzMax. I was looking over this thread, and ran across Dreamora's advice to couch global image declarations in a Type. I tried to convert the graphics in my current project to that system. It looks like Dreamora's example, but now I get a compile error: "Type global initializers must be constant." Can anyone tell me what the problem is?


Kuron(Posted 2006) [#19]
I will never ever code for D3D, because I can't use it on other platforms..
To be honest, in my experience D3D doesn't even work well amongst the various Windows versions. OpenGL in BMax blows away the D3D performance.

Just an FYI, but if you are used to using an older version of BMax, the flush mem stuff has changed too ;c)


Dreamora(Posted 2006) [#20]
Psychotronic: You haven't updated to BM 1.16 then.
This error comes up if you do

Type test
global img:TImage = loadimage(...)

end type

If you insist on staying on the outdated version you must do the following

type test
global img:timage

method new()
if img = null then img = loadimage(..)
...
end method
end type


kronholm(Posted 2006) [#21]
"ouch! some indenting from hell...easy there :p ;)"

What's wrong with my indenting? I use 4space, but seems this site decided to make them 10 spaces or so. Other than that, what's wrong?


Psychotronic(Posted 2006) [#22]
Dreamora: Thank you. I figured since I just downloaded BlitzMax, I would have the most updated version, but I'm all fixed up now.