Go Back  Xtreme Visual Basic Talk > General Discussion > Tech Discussions > Dim sprite as what? ..best way to keep track of spritesheet related data..


Reply
 
Thread Tools Display Modes
  #1  
Old 08-16-2012, 07:24 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Dim sprite as what? ..best way to keep track of spritesheet related data..


After I submitted post #7 for the rpg inventory management thread I looked
around for a good example of managing sprites frames and spritesheet data
and I was somewhat disappointed at what I found (and didn't find).

I found this off forum thread ; "frames from sprite sheet in vb.net"..and based on
what I found in that thread I made a sample spritesheet frames test,
(see attachments below).

That sample uses arrays, but is that the ideal way to keep track
of sprite frames from a spritesheet?

Of course using a class comes immediately to mind.
There's a Render class as well as a some class code for
sprites (Sprite.vb) in the Xaracde GDI+ Project code (found here).

However giving a sprite class to a .Net newbie almost guarantees
a lot of explaining about how to use (and modify) class code.
Not that there is anything wrong with that..
However this thread is really about looking for possible alternatives to using a class to handle sprites

Some things that come to mind as possibilities:
1.) ImageList Class
2.) Dictionary(Of T Key, T Value) Class
3.) ArrayLists
4.) System.Collections.Generic.List(Of T) class
5.) Using a Structure

Looking around the internet I haven't found much in the way of
very good examples regarding using #1 thru #5 for "sprite-specific" or
"spritesheet-focused" purposes.

Does anyone have any links they would like to share.
A subject like this is really hard to get a good set of
google keyword search terms to narrow in a good set of
code for working with spritesheet frames

Dictionaries have a noticeable limitation:
they have to use primary keys that are unique.

I didn't find much when I search for "dictionary" in the
xvbt .Net Knowledgebase (but perhaps I missed some
code in one of the attachments).

Here's a few code snippets (so this thread doesn't end up all theory):
Code:
Dim Sprite As New List(of CSprite)
or possibly
Code:
Dim somesprites As New List(Of Sprite)
..as shown in this thread.
Code:
Dim Sprite As New Dictionary(string, Csprite)
or possibly..
Code:
Dim _Images As New Dictionary(Of String, Bitmap)
Of course ruling out classes the preferred favorite for me
would be Structure code:
Code:
Public Structure Sprite ' or "SpriteFrame" maybe?
     Public Image As Image
     Public Name As String
 End Structure
..or maybe..
Code:
Structure Sprite
 Dim Pos As Point
 Dim Dir As String
 Dim Frame As Integer
End Structure
..or some semi-kitchen-sink-inclusive structure like:
Code:
Structure Sprite
 'rect used with Contains method for mouse hit 
 'test..similar to using in VB6 the old PtinRect API
 Dim rect as Rectangle 
 Dim pos as Position
 Dim frame as Int16
 Dim selected as boolean
 ' why include a graphics path?
 ' perhaps for runtime created border-outline color highlighting 
 ' around sprite image on mousemove within containing rect
 ' or perhaps for a mouseover sprite surrounding "alpha-halo" effect 
 ' Note: My research regarding sprite outlining 
 ' using graphicspath found few useful links, but I did find this thread:
 ' "outline of an arbitrary shape as graphics path"
 Dim highlight_outline as GraphicsPath 
 Dim alpha as int16 'for ghosting or fading of dragged sprite images
End Structure
Anyway, whatever type of code is used,
my idea is that it should used in conjunction with a scenario that
draws an array of rectangles of screen,
(using a single form, panel, picbox etc)
then loads & places multiple random sprites from the spritesheet into
those rectangles (via DrawImage or TextureBrush, per passel's example)
then has mouse events tracking to detect:
1.) Whether one of the rectangles has a mouse cursor inside it,
(like a mouseover detect using mousemove event with a boolean state)
2.) Detect whether the rectangle contain a sprite?
(without using any kind of GetPixel test - the rectangles may have
complex background images that make this difficult).
3.) On mousedown event,
strictly and solely inside a rectangle that contains a sprite,
(point x,y test for rectangle.contains and Sprite.contains)
start a drag (blnDrag = True), then in the mousemove event associated
with blnDrag = True, use a region shaped control as a drag image
(clearing the sprite image from inside the rectangle
once dragging starts).
4.) In mouse up event (at the end of such a sprite dragging)
detect whether it is over another potential sprite-drop-enabled rectangle,
then detect whether that receiving rectangle has a sprite and, if so,
does one of a number of options (case..select):
a.) returning the dragged sprite back to its originating rectangle if it does
b.) or possibly "swap drops" (switches) any sprite that is already in the rectangle with the dragged sprite.
c.) or possibly (if the rectangle is already occupied with a sprite),
that it "shuffles" the dropped sprite into the nearest adjacent free rectangle space.

Just explaining the expected behaviors is a bit involved
so I imagine all the data structures and code needed to support
such behaviors won't be trivial.

I also looked for tutorials that tried to get thru 1-4 above,
and didn't find much detailed learning (but scalable) examples either.

So..any ideas appreciated..
Attached Images
File Type: jpg screenshot_spritesheet_frames_test.JPG (12.7 KB, 10 views)
Attached Files
File Type: zip spritesheet_frames_test.zip (23.2 KB, 7 views)

Last edited by surfR2911; 08-16-2012 at 07:58 PM.
Reply With Quote
  #2  
Old 08-17-2012, 07:15 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default drawing matrix of rectangles with maximum flexibility (a lot of optional parameters)

The code below works, but..

There should be some way to modify this sub to optionally allow any number of rectangles
with optionally specifying number of rectangles vertically
and optionally specifying number of rectangles horizontally
..maybe using a mod operator?
Code:
Public Class Form1
  Public Sub DrawMatrixofRectangles(e As PaintEventArgs, _
             Optional ByVal XOffset As Integer = 0, _
             Optional ByVal YOffset As Integer = 0, _
             Optional ByVal rectWidth As Integer = 64, _
             Optional ByVal rectheight As Integer = 64)
    ' Create pen.
    Dim blackPen As New Pen(Color.Black, 1)
    ' Create array of rectangles.
    Dim rects As Rectangle() = _
                {New Rectangle((0 + XOffset), (0 + YOffset), rectWidth, rectheight), _
                 New Rectangle((rectWidth + XOffset), (0 + YOffset), rectWidth, rectheight), _
                 New Rectangle(((2 * rectWidth) + XOffset), (0 + YOffset), rectWidth, rectheight), _
                 New Rectangle((0 + XOffset), (rectWidth + YOffset), rectWidth, rectheight), _
                 New Rectangle((rectWidth + XOffset), (rectWidth + YOffset), rectWidth, rectheight), _
                 New Rectangle((2 * rectWidth + XOffset), (rectWidth + YOffset), rectWidth, rectheight), _
                 New Rectangle((0 + XOffset), ((2 * rectWidth) + YOffset), rectWidth, rectheight), _
                 New Rectangle((rectWidth + XOffset), ((2 * rectWidth) + YOffset), rectWidth, rectheight), _
                 New Rectangle((2 * rectWidth + XOffset), ((2 * rectWidth) + YOffset), rectWidth, rectheight)}
    ' Draw rectangles to screen.
    e.Graphics.DrawRectangles(blackPen, rects)
  End Sub

  Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    'Draws 2 sets of nine rectangles in a 3x3 matrix layout
    DrawMatrixofRectangles(e, 2, 2, 20, 20)
    DrawMatrixofRectangles(e)
  End Sub
End Class
..but anyway now I can start to work on task #1 from the the first post of this thread.
Attached Images
File Type: jpg screenshot_matrix_of_rectangles_test.JPG (11.3 KB, 8 views)

Last edited by surfR2911; 08-17-2012 at 07:21 PM.
Reply With Quote
  #3  
Old 08-17-2012, 10:36 PM
Iceplug's Avatar
Iceplug Iceplug is offline
MetaCenturion

Retired Moderator
* Guru *
 
Join Date: Aug 2001
Location: California, USA
Posts: 16,583
Default

Let's discuss a few things:
A sprite is anything - typically its an object (person, chest, door) on a map, thus it has at least a position (Point). What else it has falls in context of what the game it is in. A simple tile map only requires a Point and a sprite identifier (a number that tells you what type of sprite it is... 0 is a box, 1 is a sign, etc.), and more complex situations will lead you with... Width/Height (Rectangle) for the sprite, information (what the sprite displays when you interact with it, ideally a number that refers to a list of strings that display), or, if you consider strategy games, the "sprite" becomes a sophisticated object with HP, attack power, range, etc.
Thus, there is no definitive answer for what to declare a sprite. However, I would narrow down a sprite as a structure or a class and sprites as a list or array, or some such structure.

Next, your rectangles seem to require some sort of function/subroutines that interface with them. If they are drawn in random locations, then you need to make the same things that you do for your sprites (that is, a structure or class to hold the position and size and maybe other info along with a list or array)
however if your 'rectangles' are in fact a 'grid', then you only need to retain information about the grid.

If you have a grid of pixel size X and Y that contains K rectangles going from left to right and L rectangles going top to bottom, and all rectangles are the same size, then you can easily determine:
how many rectangles you have is K*L
the size of the rectangles are all X/K width and Y/L height.

If you have offset the grid by C pixels from the left and D pixels from the top,
you can determine the location of any rectangle by:
C + X/K * ColumnNumber (x-coordinate) and D + Y/L * RowNumber (y-coordinate)

You can determine which rectangle contains the point (Ex, Ey) such as in the case of determining which rectangle has the mouse:
ColumnNumber = (Ex - C) \ (X/K)
RowNumber = (Ey - D) \ (Y/L)
where \ is integer division.

In response to #2, if your sprite has a width and height, it may not be contained in a rectangle if it lies over two, in which case you need to either A) use a specific coordinate for the sprite
B) use all the corners for the sprite
C) accept that the sprite may not be contained in a rectangle.
For collision detection, I have an example of how to handle this in the VB6 section.

To draw more than nine rectangles, you need to not use DrawRectangles with a hardcoded array. It will be easier to just draw one rectangle at a time in two For loops
For LY = 0 to L - 1
For LX = 0 to K - 1

and then you specify the coordinates for the rectangle using your grid offset (C, D), your rectangle width and height, whatever they are, to adjust the left and top.
If you insist to use DrawRectangles, you need to put each row in fixed positions in the array: Rects(10 * LY + LX) will support rows containing 10 rectangle, but you won't need it if you're drawing rectangles individually within the For Loop.
__________________

Iceplug, USN
Quadrill 1 Quadrill 2 (full) Quadrill 3 JumpCross .NET Website is ALIVE! - DL Platform Tour for VB.NET! Posting Guidelines Hint: Specify your location in your user cp profile if you want compassion!
Reply With Quote
  #4  
Old 08-18-2012, 12:56 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Hey Iceplug joins the thread - and visions of amtar revisited

Wow, I never thought IcePlug would contribute to this thread
(because you mainly stick to contributing to games programming threads).

But I'm happy to have you aboard and have your input to clarify things.

Quote:
Originally Posted by IcePlug
..if you consider strategy games, the "sprite" becomes a sophisticated object with HP, attack power, range, etc.
Thus, there is no definitive answer for what to declare a sprite. However, I would narrow down a sprite as a structure or a class and sprites as a list or array, or some such structure.
This is an important point..and you are, of course, totally right.

Quote:
Originally Posted by IcePlug
Next, your rectangles seem to require some sort of function/subroutines that interface with them.
If they are drawn in random locations, then you need to make the same
things that you do for your sprites (that is, a structure or class to hold
the position and size and maybe other info along with a list or array).
However if your 'rectangles' are in fact a 'grid', then you only need to retain information about the grid.
Your post has convinced me:
I don't want my solution to be "grid limited".
This will limit the flexibility and usability of any code I develop.

What if I used a 2 dimension array full of Points with
each Point representing the origins (x and y values for the upper left corners)
of each placed rectangle?

Such a 2 dimensional rect positioning locator array matrix (replam)
might be like populated like:
111
110
100

or

001
011
010

or even
111
101
111
..where the "1"s represent origin points for rectangles that are drawn
and the "0"s represent rectangles not drawn,
(maybe have the Point x,y values for rectangles not drawn
could be some negative off screen number like -16000,-16000).

Note: I also realize this introduces the possibility of pseudo-sparse arrays,
which are not quite "performance tuned" as fully populated arrays,
(you may have to loop thru vales that are non-sequiturs
to assign/retrieve all real/relevant values),
but flexibility if more important performance in this regard,
(see #2 below regarding possible paper doll placement).

I'm also thinking of reviving the old A.M.T.A.R concept.

The AmtarZone setup code would loop through the replam and
be able to assign a Count value inside AmtarZone Structure,
(probably necessary for For..Each iterating down the road).

This would save having to specify the number of rectangles
as a separate parameter inside a SetUpAmtarZone sub call
as well as avoid the situation where replam contains
more or less elements than the total specified number of rectangles.

Working on task #1, I quickly realized I am going to have be able to
loop through the array or rects to do a arrRect.Contains test.
So I need the array of rects to have an index.

I'm thinking of setting up a structure called AmtarZone

This structure would have (contain):
1.) the array of rects (each containing the usual: x, y, width, height)
This "arrRect" would probably be a one dimensional array.
2.) the replam (see acronym definition above)
3.) an boolean or byte array for "selected" (mouse click event toggled maybe)
4.) a boolean or byte array for "highlight on mouseover"

Both the type of highlighting (a rectangle fill or
change rectangle outline line color or alpha halo or something else)
and the selection indicator (which could be anything from set of
grab handles to an alternate sprite image to something else) would
be selectable from many options.

The replam would strictly be used for positioned rectangle drawing
and not necessarily have anything directly to do with any sprite placement

Indirectly, however, I want a particular arrSprite(index) to be associated
with an arrRect(index), and thus, based on the arrRect(Index),
you can get the appropriate amtarzone replam location point info
and use it for assigning positioning.

However it would allow the X and Y values inside each Point to be
individual adjusted.
Such individual rect placement adjusts would be valuable for:
1.) Custom spacing between rects (either vertically or horizontally)
2.) Custom placement of amtar rects at various location points
situated around a paper doll figure representing
the equipping (wearing locations) of an RPG character
3.) Laying out semi-staggered amtarzones representing
custom virtual control layouts.

So what about the Sprites?
They would have their own Structure called a SpriteZone.
The spritezone would have to contain indexed references to images of
individual sprites cut out of a spritesheet.
I thinking arrSprite to be a one dimension array the same as arrRect array
to facilitate syncing.
For instance an Image assigned to arrSprite(5) would be
drawn in arrRect(5).
The structure would also have to somehow sync with the amtarzone
rects.

So maybe the amtarzone and spritezone would be part of
(contained within) a larger structure called an AmtarSpriteZone.

I know this sounds overly complicated but the goal is to make everything
"dot notation friendly" (and intellisense friendly).

So there could be lines like:
Code:
Dim az as AmtarZone
Dim sz as SpriteZone
Dim asz as AmtarSpriteZone
Then there would be some code (like a sub) setting up the
the az and sz structures, then a call to:
Code:
asz = New AmtarSpriteZone(az, sz)
After which in a mouse down event
you could loop though az looking for rects that have an image assigned
and be able to able to "pop it out" of the rect
(stop having it drawn inside the rect) and make it a drag image.
Code:
If asz.az.arrRect(index).Contains(e.location) Then
  If asz.sz.arrSprite(index).Image <> Nothing Then
    pbDrag.Image = asz.sz.arrSprite(index).Image
    asz.sz.arrSprite(index).Image = Nothing
    'then run GetRegion shaping code for pbDrag  
  End If
End If
(..or would it be better to have a one dimensional boolean ContainsSprite array
inside the AmtarSpriteZone structure and do the
"if rect contains sprite" test that way?)

However I haven't really worked a lot with Structures so the question is:
Should SpriteZone and AmtarZone be nested inside of AmtarSpriteZone or
would this just complicate the syncing between the two zones?

Those are the latest thoughts ping ponging around my head.
Does it sound workable or am I just having (another) "wrong thinking" episode?

Any alternatives ideas that would be just as flexible
but easier to implement are welcome..

Last edited by surfR2911; 08-18-2012 at 01:53 PM.
Reply With Quote
  #5  
Old 08-18-2012, 06:36 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default progress...perhaps?

After about an hour of looking around I realized
no one has ever written such a code using VB.Net

Okay, then its time to move into trial and error,
"let's try to create some code from scratch" mode.

I've never tried to write any VB.Net code to utilize multi-dimensional arrays,
but it can't be any harder than looping through pixels, right?
Here's where I'm at so far:
Code:
Option Explicit On
Option Strict On

Public Class Form1
  ' Declare two-dimensional array of bytes
   Dim arrRectLayout(,) As Byte = New Byte(,) {{1, 1},
                                               {1, 0},
                                               {1, 1}}
  'arrRPO stands for an array of rectangle points for origins
  Dim m_arrRPO() As Point

  Private Sub GenerateRects(ByVal array As Array, _
            Optional ByVal XOffset As Integer = 0, _
             Optional ByVal YOffset As Integer = 0, _
             Optional ByVal rectWidth As Integer = 64, _
             Optional ByVal rectheight As Integer = 64)
    Dim intTotalRects As Int16 = Nothing
    Dim intTotalElementsDimenbsion0 As Int16 = Nothing
    Dim intTotalElementsDimenbsion1 As Int16 = Nothing
    Dim cntDimension0 As Int16 = Nothing
    Dim cntDimension1 As Int16 = Nothing
    Dim TotalNonZeroElements As Integer = Nothing
    Dim TotalNonZeroElements2 As Integer = Nothing
    Dim bound0 As Integer = arrRectLayout.GetUpperBound(0)
    Dim bound1 As Integer = arrRectLayout.GetUpperBound(1)
    intTotalRects = CShort(array.Length)
    lblTotalArrayElements.Text = "Total Array Elements =" & intTotalRects
    intTotalElementsDimenbsion0 = CShort(array.GetLength(0))
    lblArrayElements0.Text = "Total Array Elements Dimension(0) =" & intTotalElementsDimenbsion0
    intTotalElementsDimenbsion1 = CShort(array.GetLength(1))
    lblArrayElements1.Text = "Total Array Elements Dimension(1) =" & intTotalElementsDimenbsion1
    cntDimension0 = CShort(CountNonZeroElements(arrRectLayout, 0))
    lblcntDimension0.Text = "DimensionZeroNonZeroElementCount = " & _
                                            CStr(cntDimension0)
    cntDimension1 = CShort(CountNonZeroElements(arrRectLayout, 1))
    lblcntDimension1.Text = "DimensionOneNonZeroElementCount = " & _
                                            CStr(cntDimension1)
    TotalNonZeroElements2 = CountNonZeroElements2(arrRectLayout)
    lblTotalNonZeroElements2.Text = "TotalNonZeroElements2 = " & _
                                 CStr(TotalNonZeroElements2)
    ReDim m_arrRPO(intTotalRects)
    Dim index_count As Int16 = 0
    ' Loop over all elements.
    For i As Integer = 0 To bound0
        For j As Integer = 0 To bound1
        ' Get element.
          If arrRectLayout(i, j) <> 0 Then
            ' In the line below it should be something other than "0,O"
            ' It should be incrementing by rect width or rect height value 
            ' times a position offset --maybe?
            m_arrRPO(index_count) = New Point(0, 0)
            index_count = CShort(index_count + 1)
          End If
        Next
    Next
  End Sub

  Public Function CountNonZeroElements(ByVal data As Byte(,), ByVal index As Int16) As Integer
    Dim count As Int16 = 0
    For j = 0 To data.GetLength(1) - 1
      If data(index, j) <> 0 Then
         count = CShort(count + 1)
      End If
   Next
   Return count
  End Function

  Private Function CountNonZeroElements2(ByVal data As Byte(,)) As Int16
    Dim count As Int16 = 0
    ' Get bounds of the array.
    Dim bound0 As Integer = data.GetUpperBound(0)
    Dim bound1 As Integer = data.GetUpperBound(1)
    ' Loop over all elements.
    For i As Integer = 0 To bound0
        For j As Integer = 0 To bound1
      ' Get element.
        If data(i, j) <> 0 Then
            count = CShort(count + 1)
        End If
        Next
    Next
    Return count
  End Function

  Private Sub btnCreateRects_Click(sender As System.Object, _
                          e As System.EventArgs) Handles btnCreateRects.Click
    GenerateRects(arrRectLayout)
  End Sub
End Class
You can see from the comments that the issue is populating
arrRPO with created values as part of looping through the elements in arrRectLayout.

I should be able to re-purpose the code from post #2 of this thread somehow..but right now
my neuro-processor is in multidimensional overload.

Maybe someone will have some ideas..I'll take a timeout
and try to come back to work on it some more later.

Last edited by surfR2911; 08-18-2012 at 06:47 PM.
Reply With Quote
  #6  
Old 08-19-2012, 07:05 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default The first working Amatar demo using VB.Net code

From the title of this post one would be correct in assessing
that I've had some (limited) success.

However from this revised code snippet below,
(I won't paste the whole snippet from last post
just enough to give you an idea of what was updated),
you can see the obvious GenerateRects sub issue / limitation
(and that much more code structure development still has to be accomplished..).
Code:
Public Class Form1
  ' Declare two-dimensional array of bytes
  'Important Note: 
  ' The final code has to be able to handle ANY size array with ANY combinations of zeros and ones
   Dim arrRectLayout(,) As Byte = New Byte(,) {{1, 1},
                                           {1, 0},
                                           {1, 1}}
  'arrRPO stnads for an array of rectangle points for origins
  Dim m_arrRPO() As Point
  'array of rects used for .Contains testing
  Dim m_arrRects() As Rectangle
  'Individual boolean used for amtar testing for now
  ' will probably be a boolean array eventually..
  Dim m_blnToggleHighlightDrawingRect1 As Boolean
  Dim m_blnToggleHighlightDrawingRect2 As Boolean

  Private Sub GenerateRects(ByVal array As Array, _
            Optional ByVal XOffset As Integer = 0, _
             Optional ByVal YOffset As Integer = 0, _
             Optional ByVal rectWidth As Integer = 64, _
             Optional ByVal rectheight As Integer = 64)
    Dim intTotalRects As Int16 = Nothing
    Dim intTotalElementsDimenbsion0 As Int16 = Nothing
    Dim intTotalElementsDimenbsion1 As Int16 = Nothing
    Dim cntDimension0 As Int16 = Nothing
    Dim cntDimension1 As Int16 = Nothing
    Dim TotalNonZeroElements As Integer = Nothing
    Dim TotalNonZeroElements2 As Integer = Nothing
    Dim bound0 As Integer = arrRectLayout.GetUpperBound(0)
    Dim bound1 As Integer = arrRectLayout.GetUpperBound(1)
    intTotalRects = CShort(array.Length)
    lblTotalArrayElements.Text = "Total Array Elements =" & intTotalRects
    intTotalElementsDimenbsion0 = CShort(array.GetLength(0))
    lblArrayElements0.Text = "Total Array Elements Dimension(0) =" & intTotalElementsDimenbsion0
    intTotalElementsDimenbsion1 = CShort(array.GetLength(1))
    lblArrayElements1.Text = "Total Array Elements Dimension(1) =" & intTotalElementsDimenbsion1
    cntDimension0 = CShort(CountNonZeroElements(arrRectLayout, 0))
    lblcntDimension0.Text = "DimensionZeroNonZeroElementCount = " & _
                                            CStr(cntDimension0)
    cntDimension1 = CShort(CountNonZeroElements(arrRectLayout, 1))
    lblcntDimension1.Text = "DimensionOneNonZeroElementCount = " & _
                                            CStr(cntDimension1)
    TotalNonZeroElements2 = CountNonZeroElements2(arrRectLayout)
    lblTotalNonZeroElements2.Text = "TotalNonZeroElements2 = " & _
                                 CStr(TotalNonZeroElements2)
    ' Each set of point X, Y values is used to create a 
    ' rect in the m_arrRect array (see below)
    ReDim m_arrRPO(TotalNonZeroElements2)
    ReDim m_arrRects(TotalNonZeroElements2)
    Dim index_count As Int16 = 0
    ' Loop over all elements.
    For i As Integer = 0 To bound0
        For j As Integer = 0 To bound1
        ' Get element.
          If arrRectLayout(i, j) <> 0 Then
            'Here's where I need a way to structure the 
            'the creation of points in arrRPO so that 
            'not only are needed points created for all non-zero elements in arrRectLayout 
            'but the values generation code must handle: 
            '1.) a potentially unknown number of array elements
            '2.) a potentially unknown number of vertical dimension elements
            '3.) a potentially unknown number of horizontal dimension elements
            'In short, it has to handle ALL possible ways of array dimensioning..
            If i = 0 And j = 0 Then
              ' Technically it's: (0 + XOffset, 0 + YOffset)
              ' but mathematically the zero additions are not needed..
              m_arrRPO(index_count + 1) = New Point(XOffset, YOffset)
              m_arrRects(index_count + 1) = _
                New Rectangle((m_arrRPO(index_count + 1).X), _
                             m_arrRPO(index_count + 1).Y, _
                                 rectWidth, rectheight)
            ElseIf i = 0 And j = 1 Then
               m_arrRPO(index_count + 1) = New Point((rectWidth + XOffset), (0 + YOffset))
               m_arrRects(index_count + 1) = _
                 New Rectangle(m_arrRPO(index_count + 1).X, _
                             m_arrRPO(index_count + 1).Y, _
                              rectWidth, rectheight)
            End If
            index_count = CShort(index_count + 1)
          End If
        Next
    Next
  End Sub
End Class
I've including the working code as an attachment since
all the additional amtar code would make it an unwieldy code snippet.
Hopefully now that there is a working attachment forum members will be
less intimidated to jump in and offer suggestions..

Here's the next coding task
(beside correcting the GenerateRects code above):

How to hook this working amtar code into some kind of sprite structure
that will allow moving the sprite by "reassigning" it
in a way that associates it a different rect using arrRect(index)
..and that subsequently gets its new location updated in the next paint event call?

For sprite movement I'm going to concentrate
on moving the sprite by dragging, however,
for magnite7's thread (the thread with the post #7 post linked to in the
first post of this thread),
I would also like to have see the sprite be moved
by this alternative "two-click_double-select-to-move" method:
1.) Click inside the rect holding the sprite,
(and maybe having an array of selection "handles"
appear in or around the the rect holding the sprite)
2.) Selecting the new (empty) rect as it's "move to" target,
(also having an array of selection "handles" appear in or around that empty rect).
3.) Have the old rect drawn without the sprite
and the new rect drawn with the sprite.
Attached Images
File Type: jpg screenshot_replam-amtar_test.jpg (90.0 KB, 10 views)
Attached Files
File Type: zip _replam_amtar_test.zip (18.2 KB, 4 views)

Last edited by surfR2911; 08-19-2012 at 07:42 PM.
Reply With Quote
  #7  
Old 08-20-2012, 01:17 AM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Display sprites from spritesheet using 2D rect clipping from bitmap

We all know there are the two main ways to clip sprite frames
from a spritesheet:
1.) texturebrush
2.) DrawImage (see attachment to post #2 of this thread for sample / demo)

However there is another way to cut out images from a sheet using bitmap.clone with clip rectangle.

See attachment below.
Attached Images
File Type: jpg screenshot_bitmapClone_clipRect.JPG (49.1 KB, 18 views)
Attached Files
File Type: zip _bitmapClone_clipRect.zip (44.2 KB, 12 views)
Reply With Quote
  #8  
Old 09-04-2012, 06:37 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Slow progress continues..

While working on porting over the _replam_amtar code
(from post#6 of this thread),
to handle the magnite7 user interface requirements,
(allow drawing sprites inside the amtar rects as well as allowing click select transferring),
I noticed that a flaw in the way the booleans were set in the form's mousemove event,
was causing the AmtarDrawHightlighting sub to "favor" highlighting rect1 over rect2.

The revision attached below corrects this anomalous behavior.

Note: The issue of dynamically creating "origin" points,
basically assigning the correct x,y values
for the upper left corners of the rects in the array(s),
with a dynamically populated multi-dimensional array
still remains unresolved - any suggestions..perhaps
using a mod operator, would still be appreciated.
Attached Files
File Type: zip _replam_amtar_test_rev1.zip (19.1 KB, 5 views)

Last edited by surfR2911; 09-04-2012 at 06:45 PM.
Reply With Quote
  #9  
Old 09-05-2012, 04:58 PM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,722
Default

Quote:
Originally Posted by surfR2911 View Post
...Note: The issue of dynamically creating "origin" points,
basically assigning the correct x,y values
for the upper left corners of the rects in the array(s),
with a dynamically populated multi-dimensional array
still remains unresolved - any suggestions..perhaps
using a mod operator, would still be appreciated.
I'm not sure what the issue is.
If you just want to lay out the rectangles in a grid based on the width and height of the rectangle, you've done that any number of times in other threads.
You just multiply the column number by width to get X and the row number by height to get Y, and add offsets if you have them.
If you wanted a gap between rectangle you would add the gap values to the width and height before multiplying.

Iceplug gave a number of calculations than can be used to process rectangle grid location.

In your case, you're not fitting the rectangles to an area, but using the size of the rectangle to determine the area that will be utilized.

You would simply loop through your pattern array and where you've indicated a relative position of the rectangle, you would just calculate its position based on the width and height (and offsets) given.
Code:
'
    ReDim m_arrRects(TotalNonZeroElements2)
    ReDim m_blnToggleHighlight(TotalNonZeroElements2)

    Dim index_count As Int16 = 0
    ' Loop over all elements.
    For i As Integer = 0 To bound0  'for each row (relative Y = i * height)
      For j As Integer = 0 To bound1 'for each column (relative X = j * width)
        ' Get element.
        If arrRectLayout(i, j) <> 0 Then
          m_arrRects(index_count) = New Rectangle((j * rectWidth) + XOffset,
                                                  (i * rectheight) + YOffset,
                                                  rectWidth, rectheight)
          index_count += 1S
        End If
      Next
    Next
That is a 1"s" not 15. I guess the way you had it is less likely to be mis-interpreted. It is unfortunate that literals have a strong type, rather than a universal type.

Since the rectangle has a .Location property, as well as X and Y, having the point array for location seems redundant to me, so I took it out.

Just changed the HighLight boolean to an array as you said.
'Dim m_blnToggleHighlightDrawingRect1 As Boolean
'Dim m_blnToggleHighlightDrawingRect2 As Boolean
Dim m_blnToggleHighlight() As Boolean

Changed the MouseMove to loop through the array to hit test, but also only call Invalidate if it changed the state of a rectangle or rectangles.
Otherwise you could be triggering the redraw over 100 times per second as you drag the mouse across the form.
Code:
  Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
    'For amtar highlighting test - see AmtarDrawHightlighting call in form paint event
    'Note: A.M.T.A.R. is an acronym for active mouse tracking using an array of rects

    Dim changes As Boolean

    For r As Integer = 0 To UBound(m_arrRects)
      If m_arrRects(r).Contains(e.Location) Then
        If m_blnToggleHighlight(r) = False Then
          changes = True
          m_blnToggleHighlight(r) = True
        End If
      Else
        If m_blnToggleHighlight(r) = True Then
          changes = True
          m_blnToggleHighlight(r) = False
        End If
      End If
    Next
    If changes Then  'no use in Invalidating if nothing has changed
      Me.Invalidate()
    End If
  End Sub
You have a habit of not disposing of brushes and pens you create.
Also there is some overhead in creating pens and brushes, so if you're going to use a standard color, then you may as well use an already built system pen or brush so you don't have to create or dispose and garbage collect them.
Code:
  Private Sub AmtarDrawHightlighting(e As PaintEventArgs)
    For r As Integer = 0 To UBound(m_blnToggleHighlight)
      If m_blnToggleHighlight(r) Then
        e.Graphics.FillRectangle(Brushes.Magenta, m_arrRects(r))
      End If
    Next
  End Sub
To finish, fix all the hardcoded boolean highlight references to use the indexed hightlight array, example, change the following code from this:
Code:
  Private Sub btnDrawHighlightingTest_Click(sender As System.Object, e As System.EventArgs) Handles btnDrawHighlightingTest.Click
    If m_blnToggleHighlightDrawingRect1 = False Then
      m_blnToggleHighlightDrawingRect1 = True
      Me.Invalidate() 'Calls AmtarDrawHightlighting(e) in form paint event
    Else
      m_blnToggleHighlightDrawingRect1 = False
      Me.Invalidate() 'Calls AmtarDrawHightlighting(e) in form paint event
    End If
  End Sub
to this:
Code:
  Private Sub btnDrawHighlightingTest_Click(sender As System.Object, e As System.EventArgs) Handles btnDrawHighlightingTest.Click
    If m_blnToggleHighlight(0) = False Then
      m_blnToggleHighlight(0) = True
      Me.Invalidate() 'Calls AmtarDrawHightlighting(e) in form paint event
    Else
      m_blnToggleHighlight(0) = False
      Me.Invalidate() 'Calls AmtarDrawHightlighting(e) in form paint event
    End If
  End Sub
I went ahead and used the 0 index for the first rectangle, rather than leaving it unused.
If you still don't want to use the 0 index, then rather than indexing using (index_count + 1) in the loop and incrementing index_count at the bottom of the loop, I would increment it at the top of the loop and just use it.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Last edited by passel; 09-05-2012 at 05:20 PM.
Reply With Quote
  #10  
Old 09-06-2012, 08:21 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Handling multiple large AmtarZones

Quote:
Originally Posted by passel
I'm not sure what the issue is.
Thanks for taking a look at the code.

The issue is that this:
Code:
Dim arrRectLayout(,) As Byte = New Byte(,) {{1, 1},
                                           {1, 0},
                                           {1, 1}}
could be this:
Code:
Dim arrRectLayout(,) As Byte = New Byte(,) {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                                           {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}}
..in which case my GenerateRects will totally fail to generate all
the upper left hand corner points for all those rects properly.

So -what I need (essentially)
is to be generate the upper left hand corner values for
each rect that needs to be generated
(as specified by all the "1"s in the arrRectLayout)
irregardless of the offset of the upper left hand corner of the
amtar grid-of-spaced-rects "area" (what I call an "AmtarZone"),
or irregardless of the offsets due to spacing between rects inside the AmtarZone
and (of course) for whatever the total quantity of rects requested.

That is (to re-phase things one more time):
the GenerateRects sub code needs to be handle
generating the upper left hand corner points of
any amount of rects requested - it could even be
a thousand rows times a thousand columns
(with dozens of sections of possible "sparse array" gaps included)!

My GenerateRects routine at this point doesn't support that and
I don't know how to cleanly refactor it in order to support that.

It must even (eventually) have to handle multiple sets of rects (multiple AmtarZones).

So would I have multiple customized GenerateRects subs:
GenerateRects1, GenerateRects2, GenerateRects3
(one for each AmtarZone needed)?
That seems ridiculous.

I need to run GenerateRects in a loop feeding to multiple
AmtarZones (some kind of Structure?)
with each being separately identifiable in the form's
mousemove For..Each hit testing (even when the two or more AmtarZones
could be overlapped).

So it would be helpful to have code that:
1.) Finds the upper left hand corner of the rect at the first column
of second row
2.) Skips over having to create rects for 14 empty columns in the second row
3.) Then do some kind of "mod" operator function that jumps
the x,y, calculation to the rect in column 15 of row two
and finds the x,y values of the upper left corner of that far right rect,
..making allowances for the "empty space" (gap) left by the missing columns of rects
that weren't created or assigned upper left hand corner points.

I can try to explain further, but that's the best i can come up with for now..

Last edited by surfR2911; 09-06-2012 at 08:51 PM.
Reply With Quote
  #11  
Old 09-06-2012, 09:18 PM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,722
Default

Quote:
Originally Posted by surfR2911 View Post
...
..in which case my GenerateRects will totally fail to generate all
the upper left hand corner points for all those rects properly.
But the changes to your code I posted will handle that array.

{called with: GenerateRects(arrRectLayout, 10, 10, 8, 10) }

I didn't look at or change any of your status labels code, so the information displayed may not be correct.
Attached Images
File Type: png replam2.PNG (10.8 KB, 11 views)
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Last edited by passel; 09-06-2012 at 09:44 PM.
Reply With Quote
  #12  
Old 09-09-2012, 03:09 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default The final cleaned up version

A cut/paste of the snippets post # 9 only results in errors.
I'll work on it --see it I can patch things..

edit:
Okay had to change booleans in form load to use arrays
added some resource cleanup code, and commenting.
The attached screenshot uses this line in Form Load
Code:
GenerateRects(arrRectLayout, 10, 10, 16, 16)
and for the replam (rect positioning locator array matrix) uses this:
Code:
   Dim arrRectLayout(,) As Byte = New Byte(,) {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                                           {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}
Yes I know this is a little ridiculous but pushing things this far,
I'm convinced it can fill a maximized form of just about any screen dimensions/resolution.

Sample3b still doesn't handle multi-layer overlapping amtar placement,
but thanks to IcePlug and passel for all the kind help they've given in this thread up to his point.

Note: after the amtar rects are initially generated you can go back
and adjust the size and positioning of each one***
and it won't disrupt the amtar "effect".

***Alternate layouts might be:
1.) A large rectangle/square with a bunch of small ones
surrounding on three sides
2.) Two large rectangles with a series of small squares inside
3.) A non-grid configuration - such as rpg inventory item "slots"
surrounding a "paper-doll" type diagram of the character or
surround an avatar of the player character
whose image changes as armor, bracers, gloves, swords,
weapons, rings, etc. are equipped.

Of course in the last case you would probably want to add a "snapto"
drop routine to center the dropped sprite image withing the rect.
Quote:
A small bit of side commentary..

People reading through this thread might as ask:
Why not use a whole bunch of pictureboxes or
other controls like panels?

There are a number of reasons you probably don't want to go this route
when designing games.

Take a look at the attachment to post#9 to passel's Space Invaders thread.
It's far enough along you can see the outlines of a true game forming.

The code features a main game loop using a timer.

It also uses no controls but draws all its graphics on the form.
This helps out not only with performance but simplifies the coding
by having a single rendering container acting as an event handler.
This is what you want and this is why using a whole bunch of controls
just needlessly complicates things.

Of course designing an rpg is a couple steps up from a
2D retro shooter game.

I'm following the thread, hoping that passel eventually ends up at a point
where it is re-coded to show how to use a special class
that could handle all the rendering and event handling
in a more OOP manner (offloaded from the form
and abstracted to use either a form or a control as a container)...we'll see..

Because such a special class would be highly useful in handling
complex multi-layer float panels such as:
1.) avatar boxes for player character avatars and for his/her NPC retinue
(that shows equipped weapons/spells)
2.) Inventory/Spell book/knapsack panels
3.) Dialog panels (semi-transparent)
4.) Even non-rectangular ui elements, such as
irregular-shaped characteristics selection buttons, (used in character setup screens),
could be setup as "virtual controls" by such a class.
edit2 (later after midnight):
I'm still back to the original question of this thread:
What type of thing to store and manage the sprites in VB.Net?

This is the main MSDN reference I keep coming back to: Structure Design

Just to let anyone reading this thread know...I've also read:
Choosing Between Classes and Structures
and all the sections of the MSDN "Type Design Guidelines" page.

Doing a google search for:
vb.net structure "array of images"

I came across this "Lots of data to handle" xvbt thread.

In the second post of the thread is this:
Quote:
Originally Posted by AtmaWeapon
I'd use a Dictionary(Of String, Image to associate names with tiles and look up the tile that way.
I downloaded AW's "TilesetDemo.zip" attachment (post #6).
and it gives 4 warning errors (which prevent showing the MainForm
Designer),
the code across the project looks truly bizarre to me.

There's some "Inherits Control" classes but the main Tilemap class (in "TileMap.vb")
seems to specify the index using another class "TileSet"
Code:
Public Function GetTile(ByVal row As Integer, ByVal column As Integer) As Image
    'TODO: messy
    Return Tileset.Instance.GetTile(GetTileIndex(row, column))
End Function
..so in "TileSet.VB" is this sub:
Code:
Private Sub New()
    Dim tiles As New List(Of Image)()
    tiles.Add(GetTransparentTile())
    For Each color As Color In Colors
        tiles.Add(GetTile(color))
    Next
    _tiles = tiles.ToArray()
End Sub
However, I don't see the advantages to using this approach at all.
So I'm looking at starting with:
Code:
Option Explicit On
Option Strict On
Imports System
Public Class Form1
Private Structure AmtarZone
End Structure
End Class
..then how do I get my array of rects inside the Structure?
Code:
Dim m_arrRects() As Rectangle
In this "Understanding Structures in VB.NET" article it says:
Quote:
A VB.NET struct can also contain methods.
The methods can be either static or non-static.
But static methods can access only other static members
and they can't invoke by using an object of the structure.
They can invoke only by using the struct name.
So should I move my whole GenerateRects sub code inside
or just move:
Code:
GenerateRects(arrRectLayout, 10, 10, 16, 16)
..from Form Load in the attachment below to inside of
Code:
Private Structure AmtarZone
  GenerateRects(arrRectLayout, 10, 10, 16, 16)
End Structure
What the difference?

If I try this:
Code:
Private Structure AmtarZone
 Dim Sprites As Image (10)
End Structure
..it comes up with an error:
"Array bounds cannot appear in type specifiers"

Changing to this:
Code:
Private Structure AmtarZone
 Dim Sprites As Image = New Sprite(8) {}
End Structure
..gives a new error:
"Initializers on structure members are valid only for 'Shared' members and constants"

So based on this page I tried:
Code:
Private Structure AmtarZone
  Dim Sprites As Image
  Sub New(ByVal Spritesval As Image)
      Sprites = Spritesval(10)
   End Sub
End Structure
..which gives this error:
Class 'System.Drawing.Image' cannot be indexed because it has no default property

Whooey! Are we having fun yet? (You know I am..)
Attached Images
File Type: jpg screenshot_replam_amtar_test3b.jpg (107.4 KB, 6 views)
Attached Files
File Type: zip _replam_amtar_test_rev3b.zip (19.2 KB, 3 views)

Last edited by surfR2911; 09-10-2012 at 03:52 AM.
Reply With Quote
  #13  
Old 09-10-2012, 04:12 AM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Continuing from last post: coding for an image array inside a Structure - use ReDim?

I think I got it:
Code:
Option Explicit On
Option Strict On
Public Class Form1
 Private Structure AmtarZone
  Dim Sprites() As Image
  End Structure
  Dim az As AmtarZone
  Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    az.Sprites = New Image(10) {}
    az.Sprites(0) = My.Resources.spriteimage
    PictureBox1.Image = az.Sprites(0)
  End Sub
End Class
The curly brackets look weird but it works!
So I guess that 2 step approach is the way to pack
an array of image (or any other type of array..like rects) into a Structure

Credit goes to this DevX VBDotNet Team [MS] post for giving me a clue what to do..

I'm still left wondering how to recycle my GenerateRects sub into this approach however..

For instance, this code doesn't give any errors:
Code:
Public Class Form1
Private Structure AmtarZone
  Dim Sprites() As Image
  Dim arrRects() As Rectangle
End Structure
Dim az As AmtarZone
  Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    az.Sprites = New Image(10) {}
    az.arrRects = New Rectangle(10) {}
    az.Sprites(0) = My.Resources.spriteimage
    PictureBox1.Image = az.Sprites(0)
  End Sub
End Class
..but shouldn't I be using ReDim instead (somehow)?

If I try this:
Code:
Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
  az.Sprites = New Image(10) {}
  az.arrRects = ReDim arrRects(10) {}
  az.Sprites(0) = My.Resources.spriteimage
  PictureBox1.Image = az.Sprites(0)
End Sub
It gives me an error: "Expression expected", with the
blue squiggly line highlighting the word "ReDim".

What expression would make the VB.Net IDE happy?
Trying to slightly change the offending code line to:
Code:
az.arrRects = ReDim az.arrRects(10) {}
..gives the same error.

So I'm lost on how (or if I should) use ReDim with
defining/specifying array dimensioning inside of structures

One last unrelated thought:
Since "az" is module/form level might want to try and use "m_az" or "_az" instead.

Last edited by surfR2911; 09-10-2012 at 04:28 AM.
Reply With Quote
  #14  
Old 09-10-2012, 12:20 PM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,722
Default

I think you're staying up too late. I'm sure you've ReDim'd an array before.

ReDim az.arrRects(10)

Depending on what you're trying to do, you would probably move the whole GenerateRects sub into your class/structure so you would call it as part of the class/structure.

az.GenerateRects(arrRectLayout, 10, 10, 16, 16)

Remember this structure from the SpriteSheetAnimation example
Code:
'
  Public Structure Tile_Type
    Private TileRect As Rectangle         'Holds the size of the sprite, used in drawing
    Private Brush As TextureBrush         'Holds the TextureBrush used to paint the sprite

    Public Sub Init(ByVal bmp As Bitmap)  'Pass the bitmap to be used for the TextureBrush
      TileRect.Width = bmp.Width          'Save the width
      TileRect.Height = bmp.Height        'and Height in a Rectangle Structure
      Brush = New TextureBrush(bmp)       'Create the TextureBrush that will paint with the bitmap
    End Sub

    Public Sub Draw(ByRef g As Graphics, ByVal X As Double, ByVal Y As Double)
      TileRect.X = X                     'Update the Rectangle location to 
      TileRect.Y = Y                     'the location passed.
      Brush.TranslateTransform(X, Y)     'Transform the brush to align with this location
      g.FillRectangle(Brush, TileRect)   'Paint the sprite at the location using the brush
      Brush.ResetTransform()             'Reset the brush transform matrix back to the default identity matrix
    End Sub
  End Structure
That example set up a two dimensional (a 3x32) array of that structure,
Dim cars(2, 31) As Tile_Type 'Structures that encapsulate brush and draw sub

This held the 96 available "sprites" and when it needed to draw a particular image from the available sprites to a "grid" position, defined by X,Y coordinate, it called the Draw routine of that sprite and told it where to draw.

'Draw selected car image at position X,Y
cars(FrameSelectY, FrameSelectX).Draw(gameGraphic.Graphics, dstRect.X, dstRect.Y)

Of course, the X and Y of dstRect didn't have to be a grid corner, but in this case it was as it drew the cars in a user specified matrix of up to 20x20 cars.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #15  
Old 09-10-2012, 05:33 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Dimness regarding ReDim (and transforms) plus some rpg ui data structuring concerns..

Quote:
Originally Posted by passel
I think you're staying up too late. I'm sure you've ReDim'd an array before.
ReDim az.arrRects(10)
You're right.
In the light of day this seems obvious.
Quote:
Originally Posted by passel
Remember this structure from the SpriteSheetAnimation example..
I haven't mentioned this before but the particular code you cite
is the very part of your SpriteSheetAnimation example that I have the most
trouble with: Transforms.

I still haven't fully absorbed all that you patiently explained in the
Transforms in VB.Net: MatrixOrder.Append versus MatrixOrder.Perpend thread.

In mind mind I basically have no effective "visualization" I can associate
with doing a transform "translation".

I definitely can see the advantage of not storing the Images directly in
structure - just doing a "feed-thru".

Otherwise if there a lot of graphics to deal with,
having a huge array of images stored in memory
all the time is poor resource management.

Quote:
Originally Posted by passel
Depending on what you're trying to do,
you would probably move the whole GenerateRects sub into your class/structure
so you would call it as part of the class/structure.
az.GenerateRects(arrRectLayout, 10, 10, 16, 16)
This is what I was thinking about this morning.
Does tucking such a call inside the Structure really get me anywhere?

What I'm thinking is that I just want to use GenerateRects to generate
and just "pass thru" the needed origin (upper left corner) rect points
into the AmtarZone Structure

Can this be done with a "For..next" loop?
If I wanted to generate say, five AmtarZones,
and have each one assigned to its own "az".

Which way would be more advisable:
1.) Having an array of AmtarZones: az(0), az(1), az(2), etc.
--with az(1).arrRect(4) possibly mousemove hit testing as overlapping with az(4).arrRect(2)
or
2.) Using Dim-ing in such a way that I could have:
_az1.arrRects(1)
_az2.arrRects(1)
_az3.arrRects(1)
etc.

I can see where referencing the AmtarZones by index would be handy
for hit testing overlapping (multi-layer) amtarzones
but would the second way be less "unwieldy" in terms of a naming scheme.

Speaking of naming schemes..

With the "feed-thru" way you use is there a way to persistently store
a referencing tag descriptor associated with each frame (basically
giving each frame an text string "name").

Here's my thinking:
Did you ever encounter other people's code where, essentially,
the index numbers of arrays were basically "magic numbers"?

I want the to set things up in such a way that
a person just glancing at the code knows exactly what graphic
is stored at a particular array index location.
..perhaps even having a unique descriptor associated with each rect in the array of rects as well.

Why would a simple rect (basically acting as a container)
need a text string tag descriptor?

You keep mentioning "grid" in terms of the array of rects.

However, for me that is just happens to be the default starter initialization state
for the rect array (and easy way to create the rect array using looping).

At some later point as the program is running
(perhaps just at the tail end of the Form Load)
the rects may "migrate" to a non-grid oriented configuration.
What am I talking about?
Here's some screenshots (1, 2) of "paper doll" type layout for rpg character equipping.

Thinking in terms of drag and dropping..
If I drop an inventory item on the box for "head"
I not only need to know the "name" of the equipment item sprite being dropped
(like "Helm of Enlightenment"), but I have to be able to do a an assessment:
Is this equipment item sprite of the right type to be equipped at that position?
(i.e. if it's a pair of gloves or a ring it's preferred drop position is on the hand not the head).

I'm hoping to somehow "key" (like in a Dictionary key pairing sense)
each image to a equipping type.
The name of the item (like "Helm of Enlightenment"), must also be key-ed to a characteristics table.

Do you see how things can get very complicated very fast if they are not set up right?

Last edited by surfR2911; 09-10-2012 at 06:25 PM.
Reply With Quote
  #16  
Old 09-11-2012, 10:25 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Giving back to the spawning thread..

Although this thread is far from finished,
I'm far enough along with the amtar/replam coding
to generate a post#8 (with a working sample)
onto the end of magnite7's original thread.
Reply With Quote
  #17  
Old 09-11-2012, 10:59 PM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,722
Default

Quote:
Which way would be more advisable:
1.) Having an array of AmtarZones: az(0), az(1), az(2), etc.
--with az(1).arrRect(4) possibly mousemove hit testing as overlapping with az(4).arrRect(2)
or
2.) Using Dim-ing in such a way that I could have:
_az1.arrRects(1)
_az2.arrRects(1)
_az3.arrRects(1)
I wouldn't use numbered named variables, as that would indicate a hardcoded series.
Using arrays, or lists so you have flexibility in the quantity is generally a good thing.
If you're writting flight critical software, like avionics and flight control, then dynamic allocation of objects is not considered a good thing.
There they want fixed objects, know sizes, and where in memory everything is allocated.
So the only "dynamic" lists would be preallocated with a fixed size for the maximum number of things the list can hold, i.e. 80 flight plans of up to 200 legs each, and you would track how many "slots" were filled, but you could never have more flight plans or legs in a flight plan than allocated. And the 15th leg, of flightplan 34 would always be in a known, specific place in memory.
Anyway, I digress.

I'm kind of partial to organizing things by linking them.
For instance, I could have a variable that is the anchor for a linked list that is associated with a player, and call it "thingsNearMe". As all the moving objects are moved, they could check how close they were with the prime player, and if within a certain range, link themselves to the list. Then when the game had to draw the things around the player, or interact with things around the player, it could just process that list and not care about the multitude of other objects that are of no concern to the player.

Anyway, at the risk of adding to the confusion, I guess I have a program example from last year that grew from a request about rotating an image.
In this case, since I had the image of a car that was spun by using matrix transform (not a series of different bitmaps as was done in the SpriteAnimation example), I figured I may as well move it around an area.
And, for the heck of it, I would make it a fairly large area, and scatter a lot of other objects, sprites, tiles, whatever you want to call them around the area so you can see the motion of the car, and as an example of tracking the objects, deciding when they should be drawn, etc.

It doesn't do a whole lot, and since it was done last year, doesn't benefit from what I learned playing with the Space Invaders example.
It is not using the BufferedGraphics class, and uses drawimage for most of the drawing (with the exception of the underlying background texture, which uses FillRectangle with a texture brush), so I'm sure drawing speed could be improved.

There is a structure in this code as well, that holds some information, like the index of a bitmap, and size and location, so that it can draw it. It has a routine to add the bitmaps to a shared list within the structure (so one copy of the bitmaps is shared for all the objects created using the structure).

The "gaming area" is 262,144 by 262,144 pixels in size. An array is dimensioned so up to 1,000,001 (one million and one) objects could be defined and positioned around the area.
The example loads up 80 bushes and 32 trees as "sample" bitmaps, and scatters almost 610,000 of them across the gaming area.
To make deciding what objects need to be drawn around the player (the player is always in the middle), as the car moves around, an array of 256x256 integers is used as the base link of a linked list for an 1024x1024 pixel area of the game (262,144 / 256 = 1024)
When the objects are defined and positioned, the coordinates are divided by 1024 to get a number from 0 to 255, which dfines what 1024x1024 block (or cell) the object is in. The object is linked to that block.
When the car is moving around, and the area needs to be redrawn, all the objects in the block the car is in, and the 3 blocks adjacent to the nearest corner of that block are considered for drawing. So only the objects in 4 blocks have to be checked, out of 65536 blocks (256*256) that cover the gaming area.

You accelerate the car with the up arrow, decelerate with the down arrow (turn left or right with the left and right arrows). You can decelerate and come to a stop using the space key. Space key and down arrow together will stop you quick.
The max speed of the car is 1.5 pixels per millisecond, which I convert, based on the size of the car image, to representing 157.1 MPH max speed.

Nothing much to it at this point, just moving arround. No collision detection or any other interaction. It is designed to wrap around seamlessly from any direction, so you will never reach a wall. You just wrap around the world.
The "Heading" is displayed in the title bar, 0 degrees is down because of the orientation of the original bitmap, and I didn't bother flipping it.
The Left label shows speed in MPH. One of the labels shows what block the car is in. There is a line of code that can be uncommented which will draw a rectangle around the perimeter of the current block the car is in, so you can see where the current block border is.
The distance traveled is based on time elapsed between frames, so will travel the same distance regardless of your FPS. The up/down counter allows you to change the desired frame rate interval (the actual achieved FPS is displayed in a third label). The FPS acheived depends on the minimum amount (not counting 0) that your Thread.Sleep supports.
Some faster machines, I7 based, I've used actually have a much higher Thread.Sleep interval (slower tick interval), so the movement will be less steady if you go below 15 millisecond choice, whereas my business laptop is comfortable down to 8 ms for a 125 FPS update. Better drawing technics I'm sure could get that to better than 200hz.

The name of the project, I believe is the model of car (503), vb9 was to distinguish the original project (vb 2005) from the upgraded version (2008), and of course here, it is VB 2010.
The "trimmed" just refers to the fact that today I did go in and trim out all the commented out code, and some dead code, and unneeded code so there wouldn't be too many unrelated distractions. I also added a bunch of comments to help with trying to understanding most of it.

===Edit=============================================
P.S. I guess seeing that the attachment doesn't look like its been downloaded yet, rather than double posting, I'll update that attachment with changes done today.
I decided to turn Option Strict on so got to clean up a couple of dozen implicit conversions. Also took another pass through and added more comments.

The primary purpose for updating the example was to add code to allow selecting a given object from the 600+ thousand objects in the gaming area in an efficient manner, given the organization we have in place.

The selection process is pretty much a mirror of the drawing process.
The coordinate of interest (where we clicked, etc) is used to determine what 1024x1024 pixel block of the gaming area it falls in. It then is compared to all gameObjects located in that block to see if the point is contained in any of the gameObject rectangles. If it is, then we've found our object. All the objects in the block are checked (in drawn order), so if there is an overlap, the topmost drawn, is the last checked, so will be the one reported.
Pixel perfect checking is not done at this point, just the rectangular bounds.

If an object is not found in the block the point is in, then the three closest blocks (since portions of four blocks could be on screen at any time) are checked. Once an object is found in any block searched, the subsequent blocks are not searched.

So, to test the code, what was added is in the MouseDown event, the mouse coordinates are converted to Game Area coordinates, then the find object routine is called to see if the click was in the bounds of an object.
If so, a flag is set in the object structure that causes a rectangle to be drawn reflecting the bounds of the object.
If you click on another object, the selected object is deselected and the new object selected.
If you click on an object already selected, then it is deselected.

Also, to test to see if I could see a degradation in frame rate, I added code to do object selection based on the position of the car as it moves.
I didn't really notice any slow down.
As you run the car over the objects on the screen, the bounding selection box should show up on the object. The mouse can still select or deselect objects as well, but only one object is selected at a time, currently.

The two primary routines added are:
Sub SelectGameObjectByGameAreaCoordinate and
Function FindObjectInBlock

There were probably some other small changes or fixes as well.
=================================
P.P.S
-------------
What the heck, since the car was selecting the objects, went ahead and added some code to slow the car substantially when ever it hit one of these the objects.
Also, changed it so the car is drawn first so draws under the trees and bushes, just to see what that looked like.
And increase the random number offset range, when placing the objects, from 100 to 300, so there is no longer clear grid paths for the vehicle to traverse, and the gridness of the layout is really not that apparent any longer.
Attached Files
File Type: zip 503_vb9_3_trimmed.zip (568.7 KB, 5 views)
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Last edited by passel; 09-12-2012 at 05:15 PM.
Reply With Quote
  #18  
Old 09-12-2012, 06:58 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Organizing things and detection of specific graphic objects..

Quote:
I wouldn't use numbered named variables, as that would indicate a hard coded series.
Using arrays, or lists so you have flexibility in the quantity is generally a good thing.
This is the kind of real world advice that the MSDN is sadly lacking in and I appreciate your insight.
Quote:
Originally Posted by passel
I'm kind of partial to organizing things by linking them.
Yes I remember one of your VB6 examples for detecting
multi-layer bitblt-ed objects used linked lists to great advantage,
and there was also some linked list stuff in the flickscroll thread.
Quote:
Originally Posted by passel
I guess seeing that the attachment doesn't look like its been downloaded yet
Sorry about that..
I've been working on a much more developed RPG Inventory UI with dragging.
Unfortunately coding time (offline) sometimes takes away from attending to forum posts (online).
Quote:
Originally Posted by passel
What the heck, since the car was selecting the objects, went ahead and added some code to slow the car substantially when ever it hit one of these the objects.
Thanks for taking the time to dig this example out of your hard drive,
clean it up and add additional code.
I'm sure a lot of forum members will benefit from this, not only me.

Just from the description though, it sounds like there is a lot going on,
and knowing you the code will be very "boiled down" (i.e. a lot of "conceptual thinking"
will be distilled into some very tight code).

So I can't promise a high level of "transferability" into the code I'm working
worth, but I will try to gain what insight I can from studying the demo.

edit:
Thanks goodness its well commented.
It uses a separate thread for timing of the car movement through delegation.

The weird part is that when I select "NoParamDelegate" from the left drop down
on top of the code window, the right drop down shows "Empty".

What exactly does this mean?
That an empty delegate is still being used as a "passthru"
(that the invoke of the timing thread can still
"update the car's position and redraw the game area and display"
even though the delegate itself is "empty"?)
Quote:
Sometimes for an old VB6-er
wandering through a landscape of VB.Net code
is like taking a stroll through Wackyland,
(for those younger types out there here is a contextual reference).
Quote:
edit2:
As a side note:
Even though passel's example doesn't use it,
there is a .Net LinkedList(Of T) Class, but a thread safety note at the
bottom of that MSDN page says it is not "thread safe"
(which is why passel probably decided not to use it).

However there is also a .Net ConcurrentQueue(Of T) Class which says:
Represents a thread-safe first in-first out (FIFO) collection.
However a quick search of the forum shows no posts involving
"ConcurrentQueue".
Looking at "Public Sub UnlinkTile()" I'm thinking how would you find the object to be removed?
There is no text string name associated with a bmp, only a bmpID (which is a number).

By the way, here's the all important Structure
(that is very significant to the subject of this thread):
Code:
Private Structure TileObjectType
    Public id As Integer                          'This is the index in the object array where this object is stored. Our linked list uses this.
    Public PrevObj As Integer                     'The id of an object linked in "front" of this object
    Public NextObj As Integer                     'The id of an object linked "behind" this object
    Public TileRect As Rectangle                  'The position and size of this object (for drawing, and perhaps eventually hit test, etc).
    Public Shared spriteBmps As New List(Of Bitmap) 'The bitmaps that these objects share.  Only one copy of the bitmap itself.
    Public Shared bmpCnt As Integer               'Keep track of how many bitmaps we have stored in our list (without having to access the list)
    Public bmpId As Integer                       'The index into the spriteBmps list of the bitmap associated with this object
    Public DrawSelectionRectangle As Boolean      'Will draw a white rectangle around the object if this is set true
The tile scrolling is so smooth it reminds me of BillSoo's VB6 smoothscrolling example. I wonder how easy it would to convert it to 2.5D isometric?

The way that "Private Sub SelectGameObjectByGameAreaCoordinates"
is designed to "search at most four blocks (out of 65536 block) to find an object" is pure passel code cleverness!

I doubt anyone but him would ever have come up with code like that
(partly because it is intimately associated with passel's
particular way of working with linked lists).

Last edited by surfR2911; 09-12-2012 at 08:17 PM.
Reply With Quote
  #19  
Old 09-23-2012, 07:34 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default 503 Land Revisited

I've been spending a little more time with the 503 smoothscroller passel posted in #17 of this thread.

There's something that was confusing me.
If you select a place-able object with a mouse it puts a selection rectangle around it,
however if you collide the car with a place-able object it also uses the same selection rect.

So how do you tell if a previously selected object has been crashed into?
You can't.

So I revised things and in effort to visually separate the two events I added
a DrawCrashRectangle boolean to the TileObjectType structure.

Then in the MoveCar(0 sub it sets it to True if the crash happens, which
draws the rectangle in red (instead of the selection color, white)
if the object is being selected because it got crashed into versus if it got selected
with a mouse.

This allows a an object to be selected with a mouse (shows white selection rect),
then be crashed into by the car( rectangle turns red),
then back away from the crash and the rectangle turns back to white.

The bad part- if the object wasn't selected before it got crashed into,
it still shows a red rectangle at the time of impact, but ends up in white selection mode
when the car backs away (instead of not being selected at all and having all rectangles cleared).

The crash collision test probably needs to be tweaked to get rid of this,
but since it's tied in with the mousedown selection logic (via the SelectedObjID indexing),
it's beyond me how to restructure the way object selection works throughout the code (at least 4 different subs are involved).

The demo specifically spreads place-ables so there is no possible
of bumping into multiple place-ables at once.

But in a more developed example this possibility would have to be accounted for,
and a Case Select would have to be added to deal with different results (like triggering a trap)
that could occur based on the SelectedObjID index of the object collided with.

I decided to abstract the background drawing out of the DrawGamingArea sub
into a separate DrawBackground sub in case anyone want to expand the demo to load a tile map from a file.

The car also used a picturebox..don't know why..
(passel doesn't like to use extra controls if they're unnecessary).
So I get rid of of the picbox control and just loaded it as a My.Resources png image.

I also put in a little more text to clarify what the labels where outputting
and some buttons/booleans to toggle things on/off as well as a checkbox to
toggle visibility of the block areas with magenta.

Note: the blocks don't have a single index number, so the only way to reference them
(if you wanted to, for instance, load different area backgrounds into different blocks),
would be to test for each individual set of x,y values.

There also exists the possibility that the example objects scattering routine
(in the Form Load) could be adjusted so that when loading a particular area into a tile block that contains stone ruins
it would specifically scatter images from a a different sprite sheet,
--say, for example, various stoneware objects (statues, columns, etc).

I think (but I could be wrong) that the noparam delegating would make it awkward to integrate with the
Fred and Barney SemaphoreSlim class events abstraction class code in this post,
but maybe the MoveCar could be tucked into a Timer Class routine just running in the gui thread,
and offload everything else into a backgroundworker thread.

Anyway, I had fun playing around with it.
Attached Files
File Type: zip _503_Land_revisited.zip (598.0 KB, 2 views)

Last edited by surfR2911; 09-23-2012 at 07:45 PM.
Reply With Quote
  #20  
Old 09-25-2012, 12:09 PM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,722
Default

Quote:
Originally Posted by surfR2911 View Post
...There's something that was confusing me.
If you select a place-able object with a mouse it puts a selection rectangle around it,
however if you collide the car with a place-able object it also uses the same selection rect.
So how do you tell if a previously selected object has been crashed into?
You can't....
The original code (which was replaced since it hadn't been downloaded yet at the time), didn't have any selection code in it, it just spread the ~610 thousand items around the gaming area, and the car could be "driven" around the gaming area.
The point of that example, was just demonstrating how a large number of items could be organized so that when you had to draw the scrolling map, you didn't have to test all 610 thousand objects to see if they should be drawn.

The selection of an object using a mouse and displaying a rectangle around it was simply added because you were discussing being able to select objects. The point of that addition was just to show again, pretty much based on the same logic as drawing selection, you could hit test the mouse click against a limited number of objects, rather than the whole 600K+ of them to determine which object was clicked on, if any.

Once that was there, you also mentioned moving the objects, so a somewhat awkward example of repositioning the objects was added as just an example that show that "yes", you can move an object by selecting it, then clicking somewhere else to move it. But that was just to show it can be done easily, not really the method I would implement in a tool.
Since that was there, the next thing added was to show that you could also "find" an object by a "game area coordinate", not just a mouse click. Since the car is the only thing moving around the example that has a "game area coordinate", the code was originally changed to select objects on the fly as the car drove over them.

Once that was there, the car just flew over the objects, and white boxes would pop-up around any object "driven over".
But, I thought that was a little boring, so (and I think I indicated that this was just playing around code in my comments, not what would be implemented in a tool or game) I added simple "collision" logic that would slow the car's speed when it "hit" an object. The selection code was still there, and didn't really have anything to do with the hit.
In fact, I think in my version of the code, I took the selection part out, since there was no reason for the car to "Select" the object.

I haven't played around any further with this for a couple of weeks, but if I do, it would be to change the 503 code to follow the design of the QuickSpaceInvaders example, and move the main drawing to a non-GUI thread.
Quote:
...The crash collision test probably needs to be tweaked to get rid of this {automatic object selection},
but since it's tied in with the mouse down selection logic (via the SelectedObjID indexing),
it's beyond me how to restructure the way object selection works throughout the code (at least 4 different subs are involved).
I would have to look at it again to see the issue. It seems I just disabled the selection, but kept the crash, but don't remember off the top of my head.
Quote:
The demo specifically spreads place-ables so there is no possible
of bumping into multiple place-ables at once.
Yes, after posting, I commented out the line that places based on related "grid" coordinate, and just chose a random X,Y value from 0 to 262143 so the items are scattered by the random number generators distribution across the area. Some items do end up close or on top of each other in that case.
Quote:
But in a more developed example this possibility would have to be accounted for,
and a Case Select would have to be added to deal with different results (like triggering a trap)
that could occur based on the SelectedObjID index of the object collided with.
Currently, the selection criteria is if more than one item is collided with within the block (1024x1024) pixels, the topmost (last drawn) item is the one collided with.
It doesn't take into consideration objects that may be in different blocks, but at an edge, so that an object from an adjacent block may be drawn on top of an object from the block being checked. The code will select the highest object in a block, and if any collision is found in a block, the other blocks are not tested.

It wouldn't be hard to change it to go ahead and test all pertinent blocks, and create a list of objects collided with, in drawing order, so you can decide what action to take.

Quote:
The car also used a picturebox..don't know why..
(passel doesn't like to use extra controls if they're unnecessary).
So I get rid of the picbox control and just loaded it as a My.Resources png image.
This example grew out of the 503.zip project attached to the first post of this thread. It was in a picturebox, and I didn't change it at the time, or since.

Quote:
I also put in a little more text to clarify what the labels where outputting
and some buttons/booleans to toggle things on/off as well as a checkbox to
toggle visibility of the block areas with magenta.
Something that needed to be done, but I was being lazy.
Quote:
Note: the blocks don't have a single index number, so the only way to reference them
(if you wanted to, for instance, load different area backgrounds into different blocks),
would be to test for each individual set of x,y values.
Not sure of the point here. The "blocks" are just a way of dividing the total game area into smaller areas to logically gather the game objects into smaller groups so you can quickly ignore 99.994% of them (assuming an even distribution) when drawing or collision testing. Those operations go a lot faster if you only need to test .006% of your objects. It serves the same purpose as QuadTrees, but in a less sophisticated manner.

You could create a linear array of 65536 blocks, so you have a single index, but when you want to test the blocks "around" an items, you would have to have a little more calculation to determine the four adjacent blocks that need to be examined.

You can also convert the x,y index into a linear index by multiplying one by 256 and adding the other, but again, I'm not sure why that is desirable.
Most mapping systems use two dimensional coordinates to map two dimensional space.
Quote:
There also exists the possibility that the example objects scattering routine
(in the Form Load) could be adjusted so that when loading a particular area into a tile block that contains stone ruins
it would specifically scatter images from a different sprite sheet,
--say, for example, various stoneware objects (statues, columns, etc).
You can add any organizational properties and attributes you feel necessary to the objects you feel necessary. I wouldn't tie them to the "blocks" we are using to manage locality.
The location of all objects is based on the coordinate system of the gaming area, not what block they are in.
If you want to develop hierarchy of objects, and types, and environments, etc., those should be based on an organizational construct independent of the locality blocks. If the locality methodology changed to quadtrees, or different size blocks, or some other mechanism, it would ruin your object placement scheme. Whatever scheme you come up with, should have as its base reference, the coordinate system of the gaming area.

Quote:
I think (but I could be wrong) that the noparam delegating would make it awkward to integrate with the
Fred and Barney SemaphoreSlim class events abstraction class code in this post,
but maybe the MoveCar could be tucked into a Timer Class routine just running in the gui thread,
and offload everything else into a backgroundworker thread.

Anyway, I had fun playing around with it.
As previously stated, I would probably avoid having any game logic, timing or drawing in the GUI thread, other than stuff directly related to the user's input, or status displays, configuration, and other items that are independent of the game loop, and can update at arbitrary intervals.
I would completely get rid of the delegating back to the GUI thread to update the drawing. That just slows things down, and has a greater chance of incurring stutters in the drawing that you have no control over.
You may not have complete control over stuttering in the background thread either (this is not a real time OS), but I believe it would be less frequent and less noticeable.

{edit: Had to removed over 500 characters from the body of the text to get it under 10,000, hopefully no non sequiturs created}

p.s. Finally got around to downloading your changes. You didn't mention that the "grass" moves the same direction as the car is heading, so the car looks like it is traveling backwards and the trees and bushes look like they're moving across the ground as well.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Last edited by passel; 09-25-2012 at 03:01 PM.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
 
 
-->