sandbox games - how???

Blitz3D Forums/Blitz3D Beginners Area/sandbox games - how???

how do you make a sandbox game, without it lagging to death over all the variables???

this is what I have so far :
SeedRnd MilliSecs()
SetBuffer BackBuffer()
Type sand

Field x
Field y
Field colors
End Type 

Graphics3D 1024, 768, 32, 1

Repeat
RenderWorld()

If MouseDown(1) Then

s.sand = New sand 
s\x = MouseX()
s\y = MouseY()
s\colors = Rnd(0, 100000)

EndIf 

For s.sand = Each sand

LockBuffer FrontBuffer()
WritePixel s\x, s\y, s\colors
UnlockBuffer FrontBuffer()

s\y = s\y + 1


If s\y > 1023 Then Delete s

Next 





Flip 
Cls 
If KeyHit(57) Then Cls 



Until KeyHit(1)

End 


how do I make it go fast when under larger amounts of "sand grains"

Lock/unlock your buffer outside of the For...Next loop & use WritePixelFast. (EDIT: Pixel work will never operate objectively 'fast' under B3D but you can at least make it less slow.)

doh!

i feel like an idiot now, thanks :)

but there's one more problem, I'm getting a mem access error if i click while the game is running in windowed mode.

furthermore, sandbox games often can handle hundreds of thousands of sand co-ords, I start lagging up around 1000 grains,

I'm getting a mem access error if i click while the game is running in windowed mode

Switch to locking/unlocking the backbuffer instead of the frontbuffer.

furthermore, sandbox games often can handle hundreds of thousands of sand co-ords, I start lagging up around 1000 grains

http://dbfinteractive.com/index.php?topic=2112.msg30640#msg30640

?

I didn't get it either...

Writepixelfast() isn't fast at all so you will find your programs slowing down long before you can write a screen's worth of pixels at contemporary resolutions -- the link simply offers an explanation why. You might even find some links to faster pixel libraries in that thread.

While I'm posting I'll also mention that, these days, calling a game 'sandbox' means something very specific that does not involve grains of sand.

Yeah - that's what I thought chwaga meant when I read the title...

I was talking about sand-dropping games :)

also, it's not the drawing time that's slowing it down, look at this:

Graphics 1024, 768, 32, 1

LockBuffer FrontBuffer()
Repeat

WritePixelFast Rnd(2, 1022), Rnd(2, 766), Rnd(0, 10000)

Until KeyHit(1)
UnlockBuffer FrontBuffer()


it seems that the amount of types in the scene is what's bogging it down.

it seems that the amount of types in the scene is what's bogging it down.

I'm not sure what the code you posted is supposed to prove. Of course the more type instances you have [to iterate through] the longer it's going to take, but a writepixelfast() operation for each instance is only going to slow things even further. It's an expensive operation:

Graphics 800,600,0,2
SetBuffer BackBuffer()

Type dot
	Field xPos%
	Field yPos%
	Field col%
End Type
Global currentDot.dot=Null


For i%=1 To 1000000
	currentDot=New dot
	currentDot\xPos=Rand(0,GraphicsWidth()-1)
	currentDot\yPos=Rand(0,GraphicsHeight()-1)
	currentDot\col=0 Shl 24 Or Rand(100,255) Shl 16 Or Rand(100,255) Shl 8 Or Rand(100,255) Shl 0
Next

Text 10,10,"Short initialisation delay..."
Flip
Cls
Delay 5000

Text 10,10,"Test 1..."
Flip
Cls
startTime%=MilliSecs()
For currentDot=Each dot

Next
result1%=MilliSecs()-startTime


Text 10,10,"Test 2..."
Flip

startTime=MilliSecs()
LockBuffer BackBuffer()
	For currentDot=Each dot
		WritePixelFast currentDot\xPos,currentDot\yPos,currentDot\col
	Next
UnlockBuffer BackBuffer()
result2%=MilliSecs()-startTime

Cls
Text 10,10,"Iterating through list:                               "+result1+" millisecs."
Text 10,20,"Iterating through list with writepixelfast operation: "+result2+" millisecs."
Flip
WaitKey


Notice there that I'm passing WritePixelFast a set of integers rather than floats (which is what rnd produces) also -- it's a good habit to minimise type conversion for speed critical operations.

this should be pretty fast:

SeedRnd MilliSecs()
SetBuffer BackBuffer()

Type sand
	Field x%
	Field y%
	Field colors%
End Type 

Graphics3D 640, 480, 32, 2

Repeat

   If MouseDown(1) Then
	s.sand = New sand 
	s\x = MouseX()
	s\y = MouseY()
	s\colors = Rnd(0, 100000)
   End If 

   If frame Mod 2 Then 
	LockBuffer BackBuffer()
	For s.sand = Each sand
		WritePixel s\x, s\y, s\colors
		s\y = s\y + 1
		If s\y > GraphicsHeight()-1 Then Delete s
	Next 
	UnlockBuffer BackBuffer()
	Flip False
	Cls 
   End If

   frame=frame +1
   If frame > 1 Then frame=0

Until KeyHit(1)

End 


cool, how'd you do it? (I'm not getting the code)

Flip False stops your code being constrained by the monitor's vertical refresh rate. All the speed increase in that code comes from flipping false.

The Frame gubbins is weird and, I presume, there as a method to slow the falling rate down without using a float for s\y (if SLotman was trying to draw every other frame of movement then that's not what his code does). Mod is expensive compared to a straightforward value comparison (=) I believe and I'm not sure why he opted for it.

Mod is not that expensive (at least not 1 MOD), and you can change it to MOD 3, MOD 5 or whatever. You could use "if frame=0", I guess I just wrote it pretty fast and MOD was the first thing on my mind.

This speed things up because it's not processing and drawing all the sand on every loop -- flip false was just an extra boost to it, as it was reducing the resolution to 640x480 ;)

This speed things up because it's not processing and drawing all the sand on every loop

Actually, because you only ever update the sand's position in the same conditional block that you draw it, you're really slowing things down very fractionally. You might've intended a frameskip but a frameskip that is not.

OK, now, how do I check if the pixel directly below the "sand grain" is black?

With ReadPixel(Fast) ? When I need to do this, I read a black pixel from the display, and store it in a variable, because the values of ReadPixel(Fast) could vary on different bitdepths.
Sort of like this:(pseudocode)
Graphics 800, 600, 0, 2
SetBuffer BackBuffer()

black = ReadPixel(0, 0)

.. other stuff..

(in main loop:)
   if ReadPixel(x, y) = black then .. etc
With the sand grain it would be something like (x, y + 1), where (x,y) is the grains position.

what is black on 32 bit?? For some reason on the code:

SeedRnd MilliSecs()
SetBuffer BackBuffer()

Type sand
	Field x%
	Field y%
	Field colors%
	Field kind
End Type 



Graphics3D 1280, 1024, 32, 1
Cls 
Global black = ReadPixel (0, 0)
Repeat
Line 100, 400, 540, 400
   If MouseDown(1) Then
	s.sand = New sand 
	s\x = MouseX()
	s\y = MouseY()
	s\kind = 1
	s\colors = Rnd(0, 100000)
   End If 

   If frame Mod 2 Then 
	LockBuffer BackBuffer()
	For s.sand = Each sand
		
		


		WritePixelFast s\x, s\y, s\colors
		If ReadPixelFast (s\x, s\y+1) = black Then 
		 s\y = s\y + 1
		
		Else If ReadPixelFast (s\x+1, s\y) = black Then 
		s\x = s\y+1
		
		ElseIf ReadPixelFast (s\x-1, s\y) = black Then 
		s\x = s\x-1
		
		EndIf 

		If s\y > GraphicsHeight()-1 Then Delete s
		
		
		

		
		 
	Next 
	UnlockBuffer BackBuffer()
	Flip False
	Cls 
   End If

   frame=frame +1
   If frame > 1 Then frame=0

For s.sand = Each sand
n=n+1
Next
	
	Text 0, 0, n
n=0


Until KeyHit(1)

End 


If you'll run it, you'll notice that when pressing the mouse, the dropping pixels are distributed between two points, one: the mouse co-ords, two: mousey, mousey

--????

Maybe it is safer to do this:
LockBuffer BackBuffer()
Global black = ReadPixelFast (0, 0)
UnlockBuffer BackBuffer()

About the two 'dropping points', there is a typo on this line:
		Else If ReadPixelFast (s\x+1, s\y) = black Then 
		s\x = s\y+1
It should be s\x=s\x+1
Oh .. and black seems to be -16777216 when I try it on 32-bit

lol, ok thanks

ok, take for example, this:

SeedRnd MilliSecs()
SetBuffer BackBuffer()

Type sand
	Field x%
	Field y%
	Field colors%
	Field kind
End Type 



Graphics3D 1280, 1024, 32, 1

Cls 

LockBuffer BackBuffer()
Global black = ReadPixel (0, 0)
UnlockBuffer BackBuffer()

Repeat
Line 100, 400, 540, 400
Line 100, 500, 800, 800
Line 800, 800, 1280, 600
   If MouseDown(1) Then

	s.sand = New sand 
	s\x = MouseX()
	s\y = MouseY()
	s\kind = 1
	s\colors = Rnd(0, 100000)
 

   End If 

   If frame Mod 2 Then 
	LockBuffer BackBuffer()
	For s.sand = Each sand
		
		


		WritePixelFast s\x, s\y, s\colors
		If ReadPixelFast (s\x, s\y+1) = black Then 
		 s\y = s\y + 1
		
		Else If ReadPixelFast (s\x+1, s\y) = black Then 
		s\x = s\x+1
		
		ElseIf ReadPixelFast (s\x-1, s\y) = black Then 
		s\x = s\x-1
		
		EndIf 

		If s\y > GraphicsHeight()-1 Then Delete s
		
		
		

		
		 
	Next 
	UnlockBuffer BackBuffer()
	Flip False
	Cls 
   End If

   frame=frame +1
   If frame > 1 Then frame=0

For s.sand = Each sand
n=n+1
Next
	
	Text 0, 0, n
n=0


Until KeyHit(1)

End 


when the sand grains reach the bottem of the triangle "pit", they simply dissappear, where are they going?

Don't worry about different bit-depths... black will always be $0 anyway.

Okay, a few things:

Read up on converting between integer and hex colour values here;

I can't run your example code because everything is hard-coded to a resolution my screen does not support. I'm guessing you're trying to do something similar to what I did here though. Should help.

OK, now, how do I check if the pixel directly below the "sand grain" is black?
As has been said, ReadPixel(Fast) is the boy. Seeing as I was tapping out an example while b32 snook in I'll post it anyway (some image buffer work in here too):
Graphics 800,600,0,2

iBuffer=CreateImage(GraphicsWidth(),GraphicsHeight())
SetBuffer ImageBuffer(iBuffer)

For x=0 To GraphicsWidth()-1
For y=0 To GraphicsHeight()-1
	WritePixel x,y,0 Shl 24 Or Rand(100,255) Shl 16 Or Rand(100,255) Shl 8 Or Rand(100,255) Shl 0,ImageBuffer(iBuffer)
Next
Next

SetBuffer BackBuffer()
Color 0,0,0
While Not KeyHit(1)
	col%=ReadPixel(MouseX(),MouseY(),ImageBuffer(iBuffer))
	r%=(col Shr 16) And $ff
	g%=(col Shr 8) And $ff
	b%=col And $ff

	DrawBlock iBuffer,0,0
	Text 10,10,"Red:   " + r
	Text 10,30,"Green: " + g
	Text 10,50,"Blue:  " + b
	
	Flip
	Cls	
Wend


:( sorry sledge ..

It wasn't that hard-coded, try this: (I modified 4 lines of code...)

SeedRnd MilliSecs()
SetBuffer BackBuffer()

Type sand
	Field x%
	Field y%
	Field colors%
	Field kind
End Type 



Graphics3D 1024, 768, 32, 2

Cls 

LockBuffer BackBuffer()
Global black = ReadPixel (0, 0)
UnlockBuffer BackBuffer()

Repeat
Line 0, 100, 200, 300
Line 200, 300, 400, 100
   If MouseDown(1) Then

	s.sand = New sand 
	s\x = MouseX()
	s\y = MouseY()
	s\kind = 1
	s\colors = Rnd(0, 100000)
 

   End If 

   If frame Mod 2 Then 
	LockBuffer BackBuffer()
	For s.sand = Each sand
		
		


		WritePixelFast s\x, s\y, s\colors
		If ReadPixelFast (s\x, s\y+1) = black Then 
		 s\y = s\y + 1
		
		Else If ReadPixelFast (s\x+1, s\y) = black Then 
		s\x = s\x+1
		
		ElseIf ReadPixelFast (s\x-1, s\y) = black Then 
		s\x = s\x-1
		
		EndIf 

		If s\y > GraphicsHeight()-1 Then Delete s
		
		
		

		
		 
	Next 
	UnlockBuffer BackBuffer()
	Flip False
	Cls 
   End If

   frame=frame +1
   If frame > 1 Then frame=0

For s.sand = Each sand
n=n+1
Next
	
	Text 0, 0, n
n=0


Until KeyHit(1)

End 


by the way, your supplied program (the hex one) can be generated in 92 millisecs with locked image buffers, up against 13115 millisecs without locked buffers...

Yep there's no buffer locking in the example for clarity, but you should lock and use the 'fast' pixel commands for release code. Personally I would indent between locking and unlocking so you don't forget to do the latter.

:( sorry sledge ..

:D

K...back to the original point of the thread...

Where do the grains go once they reach the bottom of the "pit"??

Has anyone ever posted a library routine that replaces WritePixelFast with something that writes REALLY fast?

Other programming languages apparently can write a screen-full of pixels fast (ie in real time), so why can't Blitz using an external dll?

the pixel drawing isn't what takes so long, It's the reading and transforming the pixels that takes so long

chwaga, not sure what sandbox style game is but it sounds like you have particles falling & collecting.

Is this what you want?

Jim

Kinda, It's like a sand-falling game where you can drop sand particles, kinda like this

any help??

This might be more like what you're looking for, unlike water that seeks the lowest path, this sand can be piled up in spots.

SeedRnd MilliSecs()
SetBuffer BackBuffer()

Type sand
	Field x%
	Field y%
	Field colors%
	Field kind
End Type 

Graphics3D 1024, 768, 32, 2

Cls 

LockBuffer BackBuffer()
Global black = ReadPixel (0, 0)
UnlockBuffer BackBuffer()

Repeat
Line 0, 100, 200, 300
Line 200, 300, 400, 100

;Line 100,200,400,200
   If MouseDown(1) Then

	s.sand = New sand 
	s\x = MouseX()
	s\y = MouseY()
	s\kind = 1
	s\colors = Rnd(0, 100000) 

   End If 

   If frame Mod 2 Then 
	LockBuffer BackBuffer()
	For s.sand = Each sand

		WritePixelFast s\x, s\y, s\colors
		
		If ReadPixelFast (s\x, s\y+1) = black Then 
		 s\y = s\y + 1
		EndIf
		
		If ReadPixelFast (s\x+1, s\y) = black And ReadPixelFast (s\x+1, s\y+1)=black Then 
		s\x = s\x+1:s\y = s\y + 1
		EndIf
		
		If ReadPixelFast (s\x-1, s\y) = black And ReadPixelFast (s\x-1, s\y+1)=black Then 
		s\x = s\x-1:s\y = s\y + 1
		EndIf 

		If s\y > GraphicsHeight()-1 Then Delete s
		 
	Next 
	UnlockBuffer BackBuffer()
	Flip False
	Cls 
   End If

   frame=frame +1
   If frame > 1 Then frame=0

For s.sand = Each sand
n=n+1
Next
	
	Text 0, 0, n
n=0

Until KeyHit(1)
End 


That kinda works, except, how do I prevent them from going into eachother?? I'll have like 1000 pixels with sand in them, but 8000 sand entities.

nevermind, just have to put a small delay in, still, it's happening, not on such a large scale though