Surface Problems

Superfly1611

Well-known member
Joined
Feb 17, 2004
Messages
66
Location
UK
Hello
Im building a 2D game that runs in a full screen resolution of 640*480 using vb.net and directdraw
But i have a problem.
What i want to do is create a surface in memory that stores the images that make up my level (walls, floor, etc).
Then create another surface in memory and draw (based on a 2D string array) my level to that surface.
This new surface would then be drawn to my backbuffer before flipping my surfaces.

Here is what ive got in my graphics class(This is based on tutorials @ Directx4.Net....

Code:
    Private targetform As Form = Nothing
    Private dddevice As Device = Nothing DirectDraw Device
    Private psurface As Surface = Nothing Primary Surface
    Private ssurface As Surface = Nothing Backbuffer
    Private LevelSurface As Surface = Nothing Background surface
    Private StructuresSurface As Surface = Nothing Surface containing bitmaps of all differnt objects(walls,floors etc)

    Private FullScreenRect As New Rectangle(0, 0, 640, 480) Rect to draw to the screen with

    Private clip As Clipper = Nothing
    Private needrestore As Boolean = False

    Private StructureFrames(3) As Rectangle Rect for each structure bitmap

    Variables for FPS limiter - not relevant
    Private thisTick As Integer
    Private lastTick As Integer = Environment.TickCount
    Private sinceLastTick As Integer
    Private Const fps As Integer = 9

    Map informationn
    Private height, width As Integer
    Private MapArray(9, 9) as integer

    Public Sub New(ByVal frm As Form)
        targetform = frm
        InitDevice()
        LoadLevelSurface()
    End Sub

    Public Sub InitDevice()
        Create Device
        dddevice = New Device
        Give device full control of the screen
        dddevice.SetCooperativeLevel(targetform, CooperativeLevelFlags.FullscreenExclusive)
        Set display resolution and color depth
        dddevice.SetDisplayMode(640, 480, 32, 85, False)
        Create Surfaces
        InitSurfaces()
    End Sub

    Private Sub InitSurfaces()
        Create Primary and Secondary Game Surfaces
        Dim sdesc As New SurfaceDescription
        clip = New Clipper(dddevice)
        clip.Window = targetform
        sdesc.SurfaceCaps.PrimarySurface = True
        sdesc.SurfaceCaps.Flip = True
        sdesc.SurfaceCaps.Complex = True
        sdesc.BackBufferCount = 1
        psurface = New Surface(sdesc, dddevice)
        psurface.Clipper = clip
        sdesc.Clear()
        sdesc.SurfaceCaps.BackBuffer = True
        ssurface = psurface.GetAttachedSurface(sdesc.SurfaceCaps)
        sdesc.Clear()

        Craete Surface with the 4 structure images in it
        StructuresSurface = New Surface("images/levelstructures.bmp", sdesc, dddevice)

        Create Level Surface which we will build the level graphics on to
        LevelSurface = New Surface(sdesc, dddevice)
    End Sub

    Private Sub LoadLevelSurface()
        CreateStructureFrames()
        Dim i, j As Integer
        For each row in array
        For i = 0 To mapheight - 1
            for each column in that row
            For j = 0 To mapWidth - 1
                Draw the Appropriate structure in the coresponding position (determined by the value in the MapArray array
                LevelSurface.DrawFast((j * 64), (i * 48), StructuresSurface, StructureFrames(mapArray(j,i)), DrawFastFlags.Wait)
            Next
        Next
    End Sub

    Private Sub CreateStructureFrames()
        Dim x As Integer
        For x = 0 To 3
            Each image in the bitmap is 64*48 pixels
            StructureFrames(x) = New Rectangle((x * 48), 0, 64, 48)
        Next
    End Sub

    Public Sub FlipSurface()
        If dddevice.TestCooperativeLevel = False Then if the device is not ready
            needrestore = True indicate that there is a need to restore surfaces
            Return return
        End If
        If needrestore Then if need to restore
            needrestore = False turn the flag to false
            dddevice.RestoreAllSurfaces() restore surfaces
        End If

        Try
            Fill Background
            ssurface.ColorFill(Color.Black)
            Draw LevelSurface surface to back buffer
            [color=red][b]ssurface.DrawFast(0, 0, LevelSurface, FullScreenRect, DrawFastFlags.Wait)[/b][/color]
            Flip Surfaces
            psurface.Flip(ssurface, FlipFlags.Wait)
            Limit the FPS
            LimitFPS()
        Catch ex As Exception
            MsgBox(ex.ToString(), MsgBoxStyle.OKOnly)
            Dispose()
            End
        End Try
    End Sub

    Public Sub Dispose()
        Dispose of objects in memory
        dddevice.Dispose()
        psurface.Dispose()
        ssurface.Dispose()
        StructuresSurface.Dispose()
        LevelSurface.Dispose()
        clip.Dispose()
    End Sub

    Private Sub LimitFPS()
        Simple FPS Limiter
        thisTick = Environment.TickCount
        sinceLastTick = thisTick - lastTick
        lastTick = thisTick
        If sinceLastTick < (1000 / fps) Then
            System.Threading.Thread.Sleep((1000 / fps) - sinceLastTick)
        End If
    End Sub

The error i get is when i try and draw the structuresurface to the back buffer simply points out the line it occured on (highlighted in red)
Can someone tell me where im going wrong?
Do i need to set some kind of property on the surface?
 
I have attached the project that i am working from hoping that you guys might take a look at it.

I have to admit i dont know what im doing wrong.
Whilst im no expert on this i certainly dont se any problems with my code.
 

Attachments

Perhaps someone could show me how to do what i want?

Load a bitmap of 4 frames into memory, then build another surface the size of teh screen(640*480) in a 10*10 grid using those frames.
Then draw this surface to the backbuffer for every flip surface

Because i really cant see anything wrong with my code

Thanx
 
I dont see you putting anything onto the LevelSurface surface, but you are accessing it with a Fullscreen rect... the surface (i think) is initialized to the previous surfaces size... which is the tile map... and is much smaller than fullscreen.

Usually, I would just use a For Loop and draw directly onto your surface.
Something like this:
Code:
RectFast = [COLOR=Blue]New[/COLOR] Rectangle(0, 0, 64, 48)  [COLOR=Teal]Width and height
[/COLOR][COLOR=Blue]For[/COLOR] iy = 0 [COLOR=Blue]To[/COLOR] 479 [COLOR=Blue]Step[/COLOR] 48  [COLOR=Teal]Height of your tile.[/COLOR]
  [COLOR=Blue]For[/COLOR] ix = 0 [COLOR=Blue]To[/COLOR] 639 [COLOR=Blue]Step[/COLOR] 64  [COLOR=Teal]Width of tileDuring these loops, ix and iy will go through every candidate drawing position
on the screen.[/COLOR]
    RandomNum = Ri.Next(0, 3)
    RectFast.Left = RandomNum * 64 [COLOR=Teal](or shift left 6)
Generate a random 0, 64, 128, or 196... really it picks a random tile from
the tileset to draw.[/COLOR]
    RectFast.Right = RectFast.Left + 64
[COLOR=Teal]The top and bottom of the rect should stay the same.[/COLOR]
    BackupSf.DrawFast(ix, iy, TileSf, RectFast, [COLOR=Red]DrawFastFlags.Whatever[/COLOR])
[COLOR=Teal]Draw it at our candidate location, from the tileset surface TileSf...
our RectFast is bounding the tile that we want to draw.[/COLOR]
  [COLOR=Blue]Next
Next[/COLOR]
 
In the source code i included there is a sub called LoadLevelSurface in the graphics class.
At the moment (because its dumbed down for easy reading) all it does is tile the first frame of the structures bitmap.

OK let me put another question to you.

Is it possible to...
Preloader....
  • Load a bitmap into a surface -contains 4 frames
  • Create a new surface (not backbuffer) and build the background from the previous surface onto this new surface in a 10*10 grid
Game Loop....
  • Draw this new background surface to the backbuffer
  • Draw other items(characters, objects etc) to the back buffer
  • Flip Surfaces

This seems like such a simple task but its causing me a rediculous amount of problems
 
LevelSurface.DrawFast((j * 64), (i * 48), StructuresSurface, StructureFrames(0), DrawFastFlags.Wait)
You are drawing the first frame everytime in the loop.
You could make a random number from 0 to 3 and use that there instead. :)
 
I know - i actually do something a little more structured than that i simply made it "structureFrames(0)" to make it easier to read.
But this is all useless at the moment as my application doesnt work...

So is what im trying to do possible?
Am i going about it the wrong way?
Someone please put me out of my misery
 
Im sure what you are trying to do is possible, but Im trying to see how that error occurs... maybe Ill be able to figure it out on the weekend when I get back to my home computer :).

What is on my mind is that I think you have to specify a size for your LevelSurface, but Im not sure.
 
i thought that by drawing the contents captured by the rectangle you were in effect defining the size?
 
No, the size of levelsurface would be defined when it is created (when you are not using a fullscreener or a surface from file). I believe that there are parameters that you must set in the SurfaceDescription to specify Width and Height. (And besides, its not good practice to omit a size :) )
If the surface is not large enough to take the rectangle, then DX9 will probably give you an indescriptive error. :(
 
Last edited by a moderator:
OK - it is a bit slack i admit
and... i found sdesc.height & sdesc.width
Perhaps i need to specify the purpose of the surface aswell? Although im not sure how id do that. Ill try and explore the surfacedescription object
Im going to re-write it again as i think my desperation for a solution has thrown my code into dissaray.

Will report back by end of day.
 
Woot!

YIPEEEEEEEEEEEEEEEEEEEEEEEEEEEEeeee
It works!!!
OMG!!!
Iceplug - Big thanks to you for your input on this!

Now i can start on the hard bits ;)
 
Back
Top