Challenge #25 - High Performance 8 Direction Scroller (8 by 8 tile size)

Started by kevin, March 23, 2012, 02:41:35 AM

Previous topic - Next topic

kevin





Challenge #25 - High Performance 8 Direction Scroller (8 by 8 tile size)


   This is a challenge for the more experienced PlayBASIC programmers.  Those that are similar with PlayBASIC know that creating an 8 direction scrolling screen,  as seen in virtually any 2D platform game,  is trivial.    That's not the challenge here.  

  This is a challenge of performance (thinking outside of the box really),  what you have to do. is create a world that's 1024*1024  tiles/blocks wide and high.  Each tile is to be 8 by 8 pixels in size with at least 2 unique tiles.  Giving us a world size in pixels of 8192x*8192y.   The player should be able to scroll in any of the 8 directions, so  Left -> Right -> Up -> Down and their diagonal combination's

  Extra Brownie points will award to submissions over 500fps.  on my test system.



Submission

 * Submissions can be written in any version of PlayBASIC
 
 * Submission can only be accepted in Source Code form only.

 * Authors can use external Media (images/music) provided you created the media/and or have permission to distribute the includes media or the Media is in the public domain.

* Zip up your Submissions and please try to keep it smaller than 500K !

 * Authors automatically give consent for their submission(s) to distributed and used for promotional purposes via UnderwareDesign.com, PlayBasic.com code tank.

* Authors can submit as many times as they like.

 * To make a submission, zip up your projects source code + media and either post it in this thread, or create your own thread in either the Source Codes or Show Case forums and post a link bellow.



Dead Line

    Anytime before the next ice age



Prizes

    * The best submissions will be periodically highlighted through the PlayBasic IDE news service/News Letters/ FaceBook or on Twitter



kevin

  Struggling, here's some motivation :) .... The attached piccy shows a demo that converts the Animal picture into a block map 8 times it's size. So each pixel becomes an 8*8 block, just thought it'd make an interesting scene, rather than some random colours.  The user can scroll around the world using the arrows...  The routine runs between 500->700fps (in a window), so around a 2 millisecond refresh.


monkeybot


kevin

 Runs around 500fps here, so you can have a nice shiny brownie point

Now obviously, you're on the right track..  The main tip I can give would be to 'manage' the size of the cache image(s).   So find a size that's not too small, or too large.. and you can win even out performance.    

It's interesting you're using an emulated 2D array.  While it doesn't really matter in this particular example,  the approach is slower than a 2D array.  But you can even it out,  by calculating the row and using and Xlp as the inner offset.  Which makes it about the same as a 2D array write performance,  In PB1.64 at least.   Suspect it'd work better if you had to lots of reads from the array.  

PlayBASIC Code: [Select]
   Width      =256
Height =256

Dim Map1D(Width*Height)
Dim Map2D(Width,Height)


do
cls

frames++

; Emulated 2D array
t=timer()
For ylp=0 to Height-1
for xlp=0 to Width-1
Map1D(xlp+(width*ylp))=Colour
next
next
tt1#+=timer()-t
print tt1#/frames

; Emulated 2D array, writing to rows with loop offset
t=timer()
RowOffset=0
For ylp=0 to Height-1
for xlp=0 to Width-1
Map1d(RowOffset+xlp)=Colour
next
RowOffset+=Width
next
tt2#+=timer()-t
print tt2#/frames


; normal 2d array
t=timer()
For ylp=0 to Height-1
for xlp=0 to Width-1
Map2d(xlp,ylp)=Colour
next
next
tt3#+=timer()-t
print tt3#/frames

Sync
loop




   

 It's slightly quicker if you have to read/write from the same array cell

PlayBASIC Code: [Select]
   ; This version adds the colour to each array cell.  So it's reading + writing to the cell

Width =256
Height =256

Dim Map1D(Width*Height)
Dim Map2D(Width,Height)

Colour =1

do
cls

frames++

; Emulated 2D array
t=timer()
For ylp=0 to Height-1
for xlp=0 to Width-1
Address=xlp+(width*ylp)
Map1D(Address)+=Colour
next
next
tt1#+=timer()-t
print tt1#/frames

; Emulated 2D array, writing to rows with loop offset
t=timer()
RowOffset=0
For ylp=0 to Height-1
for xlp=0 to Width-1
Map1d(RowOffset+xlp)+=Colour
next
RowOffset+=Width
next
tt2#+=timer()-t
print tt2#/frames


; normal 2d array
t=timer()
For ylp=0 to Height-1
for xlp=0 to Width-1
Map2d(xlp,ylp)+=Colour
next
next
tt3#+=timer()-t
print tt3#/frames

Sync
loop








monkeybot

woot!! a brownie point,i will clear some space in my trophy cabinet.
the reason i kept the read and write apart was just for flexibility i was messing around with the array data in other read routines.

monkeybot

Kevin,
when i run my  above program with fastpoint it crashes,please could you tell me where i have gone wrong.

Cheers.

kevin

PlayBASIC Code: [Select]
   RendertoIMage MyIMage
Lockbuffer
For ylp=0 to Height-1
For xlp=0 to Width-1
ThisPixel = Point(xlp,ylp)
next
next
unLockbuffer



  If you swapped point for fastpoint in a loop like this, then that won't work.   Why ? - FastPoint doesn't have any nanny code in it.  Where regular graphics commands like Point will fill in the internal current surface structure every time they're called, FastPoint doesn't, it just uses whatever the pointer was last set to.   The internal structure is stuff like the address & pitch and of the image data in memory, so it's happily die when it's not pointing at something that's not an image.  

  So before using any "FastPoint"  or "FastDot"  we need to make sure the address/pitch are seeded,  one way is to read a dummy point from the surface before entering the loop.  Like so

PlayBASIC Code: [Select]
   RendertoIMage MyIMage
Lockbuffer
ThisPixel=Point(0,0)
For ylp=0 to Height-1
For xlp=0 to Width-1
ThisPixel = Point(xlp,ylp)
next
next
unLockbuffer




monkeybot

ahhhhh i see,thanks.

from the Manual

QuoteNote: Before you can use FastPoint correctly. After you lock the draw surface, it's hihgly recommended you read a pixel from this surface using Point(). This will ensure the address of the surface is seeded for FastPoint

i should look harder

kevin