Results 1 to 12 of 12

Thread: Short list of examples (exclusively 2D) as an introduction to XNA

  1. #1

    Thread Starter
    Fanatic Member ThomasJohnsen's Avatar
    Join Date
    Jul 2010
    Location
    Denmark
    Posts
    528

    Short list of examples (exclusively 2D) as an introduction to XNA

    Short list of examples on how XNA can be utilized to create a range of interesting effects (with almost complete focus on 2D).

    Disclaimer: This is not a guide for XNA. Nor it is an in-depth discussion about 2D-graphics and implementation thereof in XNA. It is simply meant as a taste of some of the graphics abilities of XNA, written solely to get a reader sufficiently curious to delve deeper into XNA himself/herself.
    I expect any reader to be not only an experienced VB programmer but also well-versed in graphical terms such as anti-aliasing, alpha-blending etc.

    Prelude: To use XNA in VB is a relative new feature. I had trouble getting it to work with my VB.Net 2010 Express, but was pointed to a satisfactory solution involving downloading VS 2010 Express for Windows Phone, which includes a VB template for XNA games. This template will be the base for all the examples. The fact that XNA is relative new to VB also means that the vast majority of all examples online are written in C#. And since HLSL (High-Level Shader Language used in some of the examples to code a graphics card directly) is very similar to ANSI C, it is adviceable that any reader has a firm grasp on C and C#.
    All examples are provided with the entire code at the top of the post. Any template-generated comment is removed and comments are added to the core lines I have added in the example. This will allow a reader to quickly sift through the code and advance to the next example right away, in case the example is understood without further reading. This introduction to XNA is supposed to be an extremely quick study and take no more than 2-4 hours to read through - links are provide in some cases to elaborate on certain topics, should the reader be inclined to study further.

    ------------------------------------------------------------------------------

    Example 1: Displaying a Sprite (examination of the template-generated code and making the most basic of examples).

    vb.net Code:
    1. Public Class Game1
    2.     Inherits Microsoft.Xna.Framework.Game
    3.  
    4.     Private WithEvents graphics As GraphicsDeviceManager
    5.     Private WithEvents spriteBatch As SpriteBatch
    6.  
    7.     Private myfirsttexture As Texture2D 'Add a global texture.
    8.  
    9.     Public Sub New()
    10.         graphics = New GraphicsDeviceManager(Me)
    11.         Content.RootDirectory = "Content"
    12.     End Sub
    13.  
    14.     Protected Overrides Sub Initialize()
    15.         IsMouseVisible = True           'Make the mousepointer visible.
    16.         Window.AllowUserResizing = True 'Allow user to resize window.
    17.         Window.Title = "Example 1"      'Change the title of the window.
    18.         MyBase.Initialize()
    19.     End Sub
    20.  
    21.     Protected Overrides Sub LoadContent()
    22.         spriteBatch = New SpriteBatch(GraphicsDevice)
    23.         myfirsttexture = Content.Load(Of Texture2D)("Koala") 'Loading the texture from the Content project.
    24.         MyBase.LoadContent()
    25.     End Sub
    26.  
    27.     Protected Overrides Sub UnloadContent()
    28.         MyBase.UnloadContent()
    29.     End Sub
    30.  
    31.     Protected Overrides Sub Update(ByVal gameTime As GameTime)
    32.         If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit() '** Modified to exit on Escape keypress
    33.  
    34.         MyBase.Update(gameTime)
    35.     End Sub
    36.  
    37.     Protected Overrides Sub Draw(ByVal gameTime As GameTime)
    38.         GraphicsDevice.Clear(Color.Black) '** Modified to be black background instead of CornflowerBlue
    39.  
    40.         spriteBatch.Begin()                                         'Begin a batch of sprites.
    41.         spriteBatch.Draw(myfirsttexture, Vector2.Zero, Color.White) 'Draw our texture to the batch.
    42.         spriteBatch.End()                                           'End the current batch of sprites.
    43.         MyBase.Draw(gameTime)
    44.     End Sub
    45. End Class

    Start by creating a new Windows Game (4.0) project and call it Example1. Most notably the solution will include 2 projects - one being your actual project and one being a container for all project content. The content project is similar in many ways to using Resources in VB.Net. Data loaded from the content-project need never be disposed - the contentmanager will make sure all allocated resources are freed before the program terminates.
    The main project includes a class called Game1 inheriting a Game-class. This is the class we will be editing and expanding in all of the examples.
    Besides the constructor, a Game class has 5 core methods:
    * Initialize.
    * LoadContent.
    * UnloadContent.
    * Update.
    * Draw.
    The 3 first are typically only called once while the last two are called in succession over and over while program is running. Typical program flow is:
    Initialize -> LoadContent -> Update -> Draw -> Update -> Draw -> ... -> Update -> Draw -> Update -> UnloadContent.
    Commonly Initialize is used for any pre-loading initializations, LoadContent is used to load content from the Content project, Update is used to get input from the user, Draw is used to refresh the display and UnloadContent is used to unload any non-content allocated resources. This is not written in stone though - you can easily load content in the Initialize method or scan for user-input in the Draw method, but as a general rule sticking as much to the common practises makes for readable code.
    You have probably noticed already, that XNA is not event-driven. There is a natural flow of Updates and Draws taking place while program is running, allowing you to process user-input etc. without using events. This seperates the Draw method from the traditional VB.Net Paint event and the Update method from any of the Mouse, Keyboard and similar events. Input from the user is handled very differently, which we will get back to in another example.
    You might also have noticed, that the Game1 class has two global variables declared for your convenience. You are free to remove or rename them as you see fit, but through the course of these examples, keeping them is a good idea. The first variable is a GraphicsDeviceManager object, used mainly to draw information about the current display-device and events attached to it. It will not be used much in the examples. The second variable is a SpriteBatch. SpriteBatches will be used in almost all examples as it is the only way to draw 2D textures to the display. Sprite is a very old name for a small and moveable bitmap, but it has in XNA terminology been extended to included any size 2D graphical object that can be drawn to the screen.
    At this point you should copy the code supplied at the top into the Game1 class (replacing all that was there already).
    I have added another global variable of type Texture2D. This variable is used to hold an image, and will be initialized in LoadContent. I added the picture 'Koala.jpg' to the content project (right-click and choose 'Add->Existing Item...') and loaded it into <myfirsttexture> using the method Content.Load(Of Texture2D)("Koala"). You will notice that no extension is supplied. Extensions are never used when loading from content!!!
    Besides these comments, I consider Initialize, the rest of LoadContent and Update to be self-explanatory (remember keyboard input will be handled in later examples, so the Update method can be overlooked for now). Thus we turn our attention to the Draw method:
    SpriteBatches are initialized with a call to the Begin method specifying which order, blending etc. things drawn to it should use. In our example, no parameters are supplied meaning that default values are used (most notably FIFO sorting and Alpha blending). After the Begin method, there can be any number of Draw methods invoked on the spritebatch, and finally an End method, that effectively terminates the drawing sequence. In this example, only a single call to Draw is made causing the Koala picture to be drawn at Vector2.Zero (which is (0,0)) with Color.White as tint.
    At this point feel free to load other images and add variables to hold them. Try drawing several images at the time, preferable some with varying degrees of transparency, on top of each other. Also try drawing at other locations (New Vector2(x, y)) and using other tints.

    Before this example is ended, I will take a line or two explaining how vectors and matrices work in XNA. Many of the known operators, such as +, -, *, / and unary -, work on both vectors and matrices. It is perfectly legal to use <VectorX-variable> + <VectorX-variable> and the result will be the expected one. Also <any scalar> * <VectorX> or <VectorX> / <any scalar> will produce the expected results. Matrices however are allways 4x4 (whereas vectors can be Vector2, Vector3 and Vector4), but any matrix can be applied to a vector using the shared VectorX.Transform() using only the apropriate entries. Both vectors and matrices are structures.
    In truth, a mature man who uses hair-oil, unless medicinally , that man has probably got a quoggy spot in him somewhere. As a general rule, he can't amount to much in his totality. (Melville: Moby Dick)

  2. #2

    Thread Starter
    Fanatic Member ThomasJohnsen's Avatar
    Join Date
    Jul 2010
    Location
    Denmark
    Posts
    528

    Re: Short list of examples (exclusively 2D) as an introduction to XNA

    Example 2: Fournier, Fussell, Carpenter algorithm modified to generate seamless clouds (using non-content data).

    vb.net Code:
    1. Public Class Game1
    2.     Inherits Microsoft.Xna.Framework.Game
    3.  
    4.     Private WithEvents graphics As GraphicsDeviceManager
    5.     Private WithEvents spriteBatch As SpriteBatch
    6.  
    7.     Private mytexture As Texture2D 'Modified texturename.
    8.  
    9.     Public Sub New()
    10.         graphics = New GraphicsDeviceManager(Me)
    11.         Content.RootDirectory = "Content"
    12.     End Sub
    13.  
    14.     Protected Overrides Sub Initialize()
    15.         MyBase.Initialize()
    16.         IsMouseVisible = True
    17.         Window.AllowUserResizing = True
    18.         Window.Title = "Example 2 (Fournier, Fussell, Carpenter modified to generate seamless clouds)" 'New title
    19.  
    20.         Dim depth As Integer = 10             'The depth to which the FFC-algorithm will go (2 ^ 10 = 1024)
    21.         Dim dimension As Integer = 1 << depth 'The dimension of the resulting bitmap (1024 x 1024).
    22.  
    23.         mytexture = New Texture2D(GraphicsDevice, dimension, dimension) 'Declare a new texture and initialize it.
    24.         mytexture.SetData(FournierFussellCarpenterNoise.Generate(depth, 1.0F, Color.Blue, Color.White, Color.DarkGray))
    25.     End Sub
    26.  
    27.     Protected Overrides Sub LoadContent()
    28.         MyBase.LoadContent()
    29.         spriteBatch = New SpriteBatch(GraphicsDevice)
    30.     End Sub
    31.  
    32.     Protected Overrides Sub UnloadContent()
    33.         MyBase.UnloadContent()
    34.         mytexture.Dispose() 'Dispose of the texture.
    35.     End Sub
    36.  
    37.     Protected Overrides Sub Update(ByVal gameTime As GameTime)
    38.         If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit()
    39.  
    40.         MyBase.Update(gameTime)
    41.     End Sub
    42.  
    43.     Protected Overrides Sub Draw(ByVal gameTime As GameTime)
    44.         GraphicsDevice.Clear(Color.Black)
    45.  
    46.         spriteBatch.Begin()
    47.         spriteBatch.Draw(mytexture, Vector2.Zero, Color.White) 'Draw the texture.
    48.         spriteBatch.End()
    49.         MyBase.Draw(gameTime)
    50.     End Sub
    51. End Class

    A new class called FournierFussellCarpenterNoise (create this class in the main project and copy/paste the code):
    vb.net Code:
    1. Public Class FournierFussellCarpenterNoise
    2.  
    3.     Private Shared rnd As New Random()
    4.  
    5.     Public Shared Function Generate(depth As Integer, roughness As Single, c1 As Color, c2 As Color, c3 As Color) As Color()
    6.  
    7.         Dim wh As Integer = 1 << depth 'Actual supposed dimension of the heightmap
    8.         Dim heightmap(wh - 1, wh - 1) As Single
    9.         Dim rval(wh * wh - 1) As Color
    10.         Dim k As Integer = 0
    11.  
    12.         Dim linecount As Integer = 1
    13.         Dim stepsize As Integer = 1 << (depth - 1)
    14.         Dim x, y As Integer
    15.         Dim xa, xb, xc, ya, yb, yc As Integer
    16.  
    17.         'Actually sets the 4 corner-values to roughness * [0.8; 0.9[, since the texture is seamlessly implemented.
    18.         heightmap(0, 0) = roughness * (Convert.ToSingle(rnd.NextDouble()) / 10.0F + 0.8F)
    19.  
    20.         While stepsize > 0
    21.  
    22.             'The square step------------------------------------------------------
    23.             y = stepsize
    24.  
    25.             For i As Integer = 1 To linecount
    26.  
    27.                 x = stepsize
    28.  
    29.                 ya = y + stepsize
    30.                 yb = y - stepsize
    31.                 yc = y
    32.  
    33.                 If ya < 0 Then ya += wh
    34.                 If ya >= wh Then ya -= wh
    35.                 If yb < 0 Then yb += wh
    36.                 If yb >= wh Then yb -= wh
    37.                 If yc >= wh Then yc -= wh
    38.  
    39.                 For j As Integer = 1 To linecount
    40.  
    41.                     xa = x + stepsize
    42.                     xb = x - stepsize
    43.                     xc = x
    44.  
    45.                     If xa < 0 Then xa += wh
    46.                     If xa >= wh Then xa -= wh
    47.                     If xb < 0 Then xb += wh
    48.                     If xb >= wh Then xb -= wh
    49.                     If xc >= wh Then xc -= wh
    50.  
    51.                     heightmap(xc, yc) = (heightmap(xa, ya) + heightmap(xa, yb) + _
    52.                                          heightmap(xb, ya) + heightmap(xb, yb)) / 4.0F + _
    53.                         roughness * Convert.ToSingle(rnd.NextDouble() - 0.5)
    54.  
    55.                     x += 2 * stepsize
    56.  
    57.                 Next
    58.  
    59.                 y += 2 * stepsize
    60.  
    61.             Next
    62.  
    63.             'The diamond step-------------------------------------------------------
    64.             For i As Integer = 1 To linecount
    65.  
    66.                 x = 0
    67.                 y = stepsize * (2 * i - 1)
    68.  
    69.                 While y <= wh
    70.  
    71.                     xa = x + stepsize
    72.                     xb = x - stepsize
    73.                     xc = x
    74.                     ya = y + stepsize
    75.                     yb = y - stepsize
    76.                     yc = y
    77.  
    78.                     If xa < 0 Then xa += wh
    79.                     If xa >= wh Then xa -= wh
    80.                     If xb < 0 Then xb += wh
    81.                     If xb >= wh Then xb -= wh
    82.                     If xc >= wh Then xc -= wh
    83.                     If ya < 0 Then ya += wh
    84.                     If ya >= wh Then ya -= wh
    85.                     If yb < 0 Then yb += wh
    86.                     If yb >= wh Then yb -= wh
    87.                     If yc >= wh Then yc -= wh
    88.  
    89.                     heightmap(xc, yc) = (heightmap(xc, ya) + heightmap(xc, yb) + _
    90.                                          heightmap(xa, yc) + heightmap(xb, yc)) / 4.0F + _
    91.                         roughness * Convert.ToSingle(rnd.NextDouble() - 0.5)
    92.  
    93.                     heightmap(yc, xc) = (heightmap(yc, xa) + heightmap(yc, xb) + _
    94.                                          heightmap(ya, xc) + heightmap(yb, xc)) / 4.0F + _
    95.                         roughness * Convert.ToSingle(rnd.NextDouble() - 0.5)
    96.  
    97.                     x += stepsize
    98.                     y += stepsize
    99.  
    100.                 End While
    101.  
    102.             Next
    103.  
    104.             linecount *= 2
    105.             stepsize \= 2
    106.             roughness /= 2
    107.  
    108.         End While
    109.  
    110.         'Conversion to bitmap
    111.         For i As Integer = 0 To wh - 1
    112.             For j As Integer = 0 To wh - 1
    113.  
    114.                 Dim v As Single = heightmap(i, j)
    115.  
    116.                 If v < 0.0F Then v = 0.0F
    117.                 If v > 1.0F Then 'Anything above 1.0 will interpolate colors c2 and c3
    118.                     rval(k) = Color.Lerp(c2, c3, v - 1.0F)
    119.                 ElseIf v > 0.6F Then 'Anything between 0.6 and 1.0 will interpolate c1 and c2
    120.                     rval(k) = Color.Lerp(c1, c2, (v - 0.6F) * 2.5F)
    121.                 Else 'Anything below 0.6 will be c1 (color of sky
    122.                     rval(k) = c1
    123.                 End If
    124.  
    125.                 k += 1
    126.             Next
    127.         Next
    128.  
    129.         Return rval
    130.  
    131.     End Function
    132.  
    133. End Class

    You need not focus on the class FournierFussellCarpenterNoise and how it works. If interested, the algorithm is discribed in detail here: link, but for the purpose of this example it is not neccessary to understand it. Suffice to say, I modified it somewhat to generate seamless textures (by using Mod operations on indices). It is used here to display how to initialize textures using SetData and properly dispose unmanaged data. If you look at the Game1 class, you will notice, that the texture holding the generated image is initialized through its constructor and 'drawn' by suppplying an array of colors fitting the dimensions of the texture (ie. length of array is width * height of texture). At program termination, the texture is disposed in the UnloadContent method.
    Feel free at this point to experiment with the generation (ie. supply various colors and/or roughness) or skip ahead to example 2b, if you don't really care about the algorithm.
    In truth, a mature man who uses hair-oil, unless medicinally , that man has probably got a quoggy spot in him somewhere. As a general rule, he can't amount to much in his totality. (Melville: Moby Dick)

  3. #3

    Thread Starter
    Fanatic Member ThomasJohnsen's Avatar
    Join Date
    Jul 2010
    Location
    Denmark
    Posts
    528

    Re: Short list of examples (exclusively 2D) as an introduction to XNA

    Example 2b: Expanding a bit on example 2 to illustrate mouse-input and wrapping of textures.

    vb.net Code:
    1. Public Class Game1
    2.     Inherits Microsoft.Xna.Framework.Game
    3.  
    4.     Private WithEvents graphics As GraphicsDeviceManager
    5.     Private WithEvents spriteBatch As SpriteBatch
    6.  
    7.     Private mytexture As Texture2D
    8.     Private location As Vector2 'Location added.
    9.  
    10.     Public Sub New()
    11.         graphics = New GraphicsDeviceManager(Me)
    12.         Content.RootDirectory = "Content"
    13.     End Sub
    14.  
    15.     Protected Overrides Sub Initialize()
    16.         MyBase.Initialize()
    17.         IsMouseVisible = True
    18.         Window.AllowUserResizing = True
    19.         Window.Title = "Example 2b (Using mouse input to display seamless clouds)" 'Modified title.
    20.  
    21.         Dim depth As Integer = 10
    22.         Dim dimension As Integer = 1 << depth
    23.  
    24.         mytexture = New Texture2D(GraphicsDevice, dimension, dimension)
    25.         mytexture.SetData(FournierFussellCarpenterNoise.Generate(depth, 1.0F, Color.Blue, Color.White, Color.DarkGray))
    26.     End Sub
    27.  
    28.     Protected Overrides Sub LoadContent()
    29.         MyBase.LoadContent()
    30.         spriteBatch = New SpriteBatch(GraphicsDevice)
    31.     End Sub
    32.  
    33.     Protected Overrides Sub UnloadContent()
    34.         MyBase.UnloadContent()
    35.         mytexture.Dispose()
    36.     End Sub
    37.  
    38.     Protected Overrides Sub Update(ByVal gameTime As GameTime)
    39.         If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit()
    40.  
    41.         location.X = Mouse.GetState.X 'Store the position of the mousepointer in location.
    42.         location.Y = Mouse.GetState.Y
    43.         MyBase.Update(gameTime)
    44.     End Sub
    45.  
    46.     Protected Overrides Sub Draw(ByVal gameTime As GameTime)
    47.         GraphicsDevice.Clear(Color.Black)
    48.  
    49.         'The source of the image being displayed as cut out from the mytexture.
    50.         Dim sourcerect As New Rectangle(-Convert.ToInt32(location.X), -Convert.ToInt32(location.Y), _
    51.                                         GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height)
    52.  
    53.         'The sprite-batch is drawn using linear wrap on textures.
    54.         spriteBatch.Begin(Nothing, Nothing, SamplerState.LinearWrap, Nothing, Nothing)
    55.         spriteBatch.Draw(mytexture, Vector2.Zero, sourcerect, Color.White) 'Draw to (0,0) location using the source rect.
    56.         spriteBatch.End()
    57.         MyBase.Draw(gameTime)
    58.     End Sub
    59. End Class

    In this example, the focus should be on the Update and Draw methods, since pretty much everything else is identical to example 2.
    Update method: User-input in XNA is retrieved in socalled states. For example keyboard input is stored in a KeyboardState and can be retrieved by using Keyboard.GetState. A state will tell you which keys/buttons were pressed and the location of wheels, joysticks etc. of the device you are examining. To get the location of the mouse-pointer for example, this example uses Mouse.GetState.X and Mouse.GetState.Y. I could also have declared a variable of class MouseState and used it to store Mouse.GetState. I could then later use this variable to get the location of the mouse-pointer, the position of the wheel and which buttons were pressed, at the instant the state was read. This differs from traditional VB.Net input-handling to some extent, since there is no immidiate way of telling when a button was pressed - only if it is pressed at this instant in time. Thus you will need to store 'old' states and compare them to new states looking for changes to respond to the equivalent of keydown, keyup, buttondown etc. events. It is important to note though, that states are cheap to retrieve and store (ie. fast to collect and low memory usage).
    Draw method: The draw method differs somewhat from the one in the previous example. Instead of just drawing our texture to a specified location, we cut out a piece of it and display it on screen. The piece cut out is determined by <sourcerect>, which is a rectangle the size of the screen with a location determined by the (inverse of the) mouse-pointer. This will lead to partially empty areas being cut out in most cases, but the spritebacth Begin method has been supplied with the argument SamplerState,LinearWrap which causes textures to be repeated indefinately in any direction. So basically we have an infinately huge cloud texture (consisting of repetitions of itself). Another way of having infinately large textures created from a base-texture that isn't seamless is to use mirror sampling. You can try it by adding a variable in the Draw method:
    Code:
    Dim s As New SamplerState With {.AddressU = TextureAddressMode.Mirror, .AddressV = TextureAddressMode.Mirror, .Filter = TextureFilter.Linear}
    and replacing SamplerState.LinearWrap with s in the spritebatch Begin method - NOTE: XNA only allows mirror sampling of images with width by height on the form 2^n x 2^m for n and m positive integers.
    Other sampling states aren't treated in these examples, but more information can be found here: link.
    In truth, a mature man who uses hair-oil, unless medicinally , that man has probably got a quoggy spot in him somewhere. As a general rule, he can't amount to much in his totality. (Melville: Moby Dick)

  4. #4

    Thread Starter
    Fanatic Member ThomasJohnsen's Avatar
    Join Date
    Jul 2010
    Location
    Denmark
    Posts
    528

    Re: Short list of examples (exclusively 2D) as an introduction to XNA

    Example 3: Using a DrawableGameComponent.

    vb.net Code:
    1. Public Class Game1
    2.     Inherits Microsoft.Xna.Framework.Game
    3.  
    4.     Private WithEvents graphics As GraphicsDeviceManager
    5.     Private WithEvents spriteBatch As SpriteBatch
    6.  
    7.     Private myball As New GradientBall(Me, 50, Color.Transparent, Color.Red, New Vector2(4, 7)) 'New gradient ball.
    8.  
    9.     Public Sub New()
    10.         graphics = New GraphicsDeviceManager(Me)
    11.         Content.RootDirectory = "Content"
    12.     End Sub
    13.  
    14.     Protected Overrides Sub Initialize()
    15.         IsMouseVisible = True
    16.         Window.AllowUserResizing = True
    17.         Window.Title = "Example 3 (Using DrawableGameComponent)" 'Modified title.
    18.  
    19.         Components.Add(myball)
    20.         MyBase.Initialize()
    21.     End Sub
    22.  
    23.     Protected Overrides Sub LoadContent()
    24.         MyBase.LoadContent()
    25.         spriteBatch = New SpriteBatch(GraphicsDevice)
    26.     End Sub
    27.  
    28.     Protected Overrides Sub UnloadContent()
    29.         MyBase.UnloadContent()
    30.     End Sub
    31.  
    32.     Protected Overrides Sub Update(ByVal gameTime As GameTime)
    33.         If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit()
    34.  
    35.         MyBase.Update(gameTime)
    36.     End Sub
    37.  
    38.     Protected Overrides Sub Draw(ByVal gameTime As GameTime)
    39.         GraphicsDevice.Clear(Color.Black)
    40.  
    41.         MyBase.Draw(gameTime)
    42.     End Sub
    43. End Class

    A new class called GradientBall (create this class in the main project and copy/paste the code):
    vb.net Code:
    1. Public Class GradientBall
    2.  
    3.     Inherits DrawableGameComponent
    4.  
    5.     Private sprites As SpriteBatch 'A SpriteBatch variable used to draw this component.
    6.  
    7.     Private mytexture As Texture2D             'A texture to hold the gradient ball.
    8.     Private location As Vector2 = Vector2.Zero 'The location of the gradient ball.
    9.  
    10.     Private _radius As Integer                 'Storing information about this gradient ball.
    11.     Private _c1 As Color
    12.     Private _c2 As Color
    13.     Private _direction As Vector2
    14.  
    15.     Public Sub New(myproject As Game, radius As Integer, c1 As Color, c2 As Color, direction As Vector2)
    16.         MyBase.New(myproject)
    17.  
    18.         _radius = radius
    19.         _c1 = c1
    20.         _c2 = c2
    21.         _direction = direction
    22.     End Sub
    23.  
    24.     Public Overrides Sub Initialize()
    25.         MyBase.Initialize()
    26.         Generate(_radius, _c1, _c2)
    27.     End Sub
    28.  
    29.     Protected Overrides Sub LoadContent()
    30.         MyBase.LoadContent()
    31.         sprites = New SpriteBatch(GraphicsDevice) 'Same declaration as in the game class.
    32.     End Sub
    33.  
    34.     Protected Overrides Sub UnloadContent()
    35.         MyBase.UnloadContent()
    36.         mytexture.Dispose() 'Dispose the texture.
    37.     End Sub
    38.  
    39.     Public Overrides Sub Update(ByVal gameTime As GameTime)
    40.         location += _direction
    41.  
    42.         If (location.X + _radius * 2 > GraphicsDevice.Viewport.Width) OrElse (location.X < 0) Then _direction.X = -_direction.X
    43.         If (location.Y + _radius * 2 > GraphicsDevice.Viewport.Height) OrElse (location.Y < 0) Then _direction.Y = -_direction.Y
    44.         MyBase.Update(gameTime)
    45.     End Sub
    46.  
    47.     Public Overrides Sub Draw(ByVal gameTime As GameTime)
    48.         sprites.Begin() 'Draw the texture.
    49.         sprites.Draw(mytexture, location, Color.White)
    50.         sprites.End()
    51.  
    52.         MyBase.Draw(gameTime)
    53.     End Sub
    54.  
    55.     '-------------------------------------------------------------------------------------
    56.  
    57.     Private Sub Generate(radius As Integer, c1 As Color, c2 As Color)
    58.  
    59.         Dim diameter As Integer = 2 * radius + 1
    60.         Dim rval(diameter * diameter - 1) As Color
    61.         Dim rsquared As Single = radius * radius
    62.         Dim k As Integer = 0
    63.         Dim l, d As Single
    64.  
    65.         For i As Integer = 0 To diameter - 1
    66.             d = (i - radius) * (i - radius)
    67.             For j As Integer = 0 To diameter - 1
    68.  
    69.                 l = (d + (j - radius) * (j - radius)) / rsquared
    70.                 rval(k) = Color.Lerp(c2, c1, l)
    71.                 k += 1
    72.             Next
    73.         Next
    74.  
    75.         mytexture = New Texture2D(GraphicsDevice, diameter, diameter)
    76.         mytexture.SetData(rval)
    77.     End Sub
    78.  
    79. End Class

    In the same way that a Form in VB.Net has a collection of Controls bound to it, a Game in XNA has a collection of Components. In this example, we add a new such component in the class GradientBall (in that it inherits DrawableGameComponent). The class GradientBall contains the same 5 core methods as the game class, so it should look somewhat familiar by now. A spritebacth is declared to draw the texture of the ball, and the texture itself and the location of it on screen are declared in the same old way. A bit of additional information about a ball is also stored (radius, edge-color, center-color and direction of movement). These additional variables are initialized in the constructor, and the texture of the ball is drawn in the Initialize method (it is drawn by using the previously used SetData method on a color array using linear interpolation, lerp, between colors based on the distance from the center). The location of the ball is constantly updated in the Update method, and if it goess off screen, the direction is changed.
    What remains is just to add it to the components in the game class, which is done in the Initialize method (before the call to MyBase.Initialize to ensure that the GradientBall.Initialize is actually called). The ball will bounce around in the window.
    In truth, a mature man who uses hair-oil, unless medicinally , that man has probably got a quoggy spot in him somewhere. As a general rule, he can't amount to much in his totality. (Melville: Moby Dick)

  5. #5

    Thread Starter
    Fanatic Member ThomasJohnsen's Avatar
    Join Date
    Jul 2010
    Location
    Denmark
    Posts
    528

    Re: Short list of examples (exclusively 2D) as an introduction to XNA

    Example 3b: Using multiple instances of DrawableGameComponent.

    Supplied below are the only two methods that have been changed from example 3:
    vb.net Code:
    1. Public Class Game1
    2.     Protected Overrides Sub Initialize()
    3.         IsMouseVisible = True
    4.         Window.AllowUserResizing = True
    5.         Window.Title = "Example 3b (Using DrawableGameComponent multiple instances)" 'Modified title.
    6.  
    7.         Dim rnd As New Random 'Declare a random variable and a set of colors both used to generate random balls.
    8.         Dim mycolorset() As Color = {Color.Red, Color.Blue, Color.Yellow, Color.Purple, Color.Violet, _
    9.                                      Color.Pink, Color.Orange, Color.Magenta, Color.Green, Color.Cyan, _
    10.                                      Color.White, Color.Gold, Color.Gray}
    11.  
    12.         For i As Integer = 1 To 100 'Generate 100 randomly colored balls of varying sizes moving in random directions.
    13.             Dim B As New GradientBall(Me, rnd.Next(30, 70), Color.Transparent, _
    14.                                       mycolorset(rnd.Next(0, mycolorset.GetUpperBound(0))), _
    15.                                       New Vector2(rnd.Next(2, 10), rnd.Next(2, 10)))
    16.             Components.Add(B)
    17.         Next
    18.  
    19.         MyBase.Initialize()
    20.     End Sub
    21.  
    22.     Protected Overrides Sub Update(ByVal gameTime As GameTime)
    23.         If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit()
    24.  
    25.         If Keyboard.GetState.IsKeyUp(Keys.P) Then MyBase.Update(gameTime) 'Will allow you to pause
    26.     End Sub
    27. End Class

    Example is for illustration purposes only and is considered self-explanatory.
    In truth, a mature man who uses hair-oil, unless medicinally , that man has probably got a quoggy spot in him somewhere. As a general rule, he can't amount to much in his totality. (Melville: Moby Dick)

  6. #6

    Thread Starter
    Fanatic Member ThomasJohnsen's Avatar
    Join Date
    Jul 2010
    Location
    Denmark
    Posts
    528

    Re: Short list of examples (exclusively 2D) as an introduction to XNA

    Example 3c: RenderTargets and Blending.

    NOTE: This example also uses the GradientBall class from example 3 and 3b. Also the picture Penguins.jpg has been added to Content.
    vb.net Code:
    1. Public Class Game1
    2.     Inherits Microsoft.Xna.Framework.Game
    3.  
    4.     Private WithEvents graphics As GraphicsDeviceManager
    5.     Private WithEvents spriteBatch As SpriteBatch
    6.  
    7.     Private background As Texture2D
    8.     Private rtarget As RenderTarget2D
    9.     Private blendsub As BlendState
    10.     Private blendrevsub As BlendState
    11.  
    12.     Public Sub New()
    13.         graphics = New GraphicsDeviceManager(Me)
    14.         Content.RootDirectory = "Content"
    15.  
    16.         Dim rnd As New Random
    17.  
    18.         For i As Integer = 1 To 20 'Generate 20 gray balls of varying sizes moving in random directions.
    19.             Dim B As New GradientBall(Me, rnd.Next(30, 70), Color.Transparent, _
    20.                                       Color.Gray, New Vector2(rnd.Next(2, 10), rnd.Next(2, 10)))
    21.             Components.Add(B)
    22.         Next
    23.     End Sub
    24.  
    25.     Protected Overrides Sub Initialize()
    26.         MyBase.Initialize()
    27.  
    28.         IsMouseVisible = True
    29.         Window.AllowUserResizing = True
    30.         Window.Title = "Example 3c (Various blendstates)" 'Modified title.
    31.  
    32.         blendsub = New BlendState() With {.AlphaBlendFunction = BlendFunction.Subtract, _
    33.                                           .ColorBlendFunction = BlendFunction.Subtract, _
    34.                                           .AlphaSourceBlend = Blend.One, .AlphaDestinationBlend = Blend.One, _
    35.                                           .ColorSourceBlend = Blend.One, .ColorDestinationBlend = Blend.One}
    36.         blendrevsub = New BlendState() With {.AlphaBlendFunction = BlendFunction.ReverseSubtract, _
    37.                                              .ColorBlendFunction = BlendFunction.ReverseSubtract, _
    38.                                              .AlphaSourceBlend = Blend.One, .AlphaDestinationBlend = Blend.One, _
    39.                                              .ColorSourceBlend = Blend.One, .ColorDestinationBlend = Blend.One}
    40.     End Sub
    41.  
    42.     Protected Overrides Sub LoadContent()
    43.         MyBase.LoadContent()
    44.         spriteBatch = New SpriteBatch(GraphicsDevice)
    45.         background = Content.Load(Of Texture2D)("Penguins")
    46.         rtarget = New RenderTarget2D(GraphicsDevice, background.Width, background.Height)
    47.     End Sub
    48.  
    49.     Protected Overrides Sub UnloadContent()
    50.         MyBase.UnloadContent()
    51.         rtarget.Dispose()
    52.     End Sub
    53.  
    54.     Protected Overrides Sub Update(ByVal gameTime As GameTime)
    55.         If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit()
    56.         If Keyboard.GetState.IsKeyUp(Keys.P) Then MyBase.Update(gameTime) 'Will allow you to pause
    57.     End Sub
    58.  
    59.     Protected Overrides Sub Draw(ByVal gameTime As GameTime)
    60.         'Draw the balls to the rtarget RenderTarget2D
    61.         GraphicsDevice.SetRenderTarget(rtarget)
    62.         GraphicsDevice.Clear(Color.Transparent)
    63.         MyBase.Draw(gameTime)
    64.         GraphicsDevice.SetRenderTarget(Nothing)
    65.  
    66.         'Blend with the background.
    67.         If Mouse.GetState.LeftButton = ButtonState.Pressed Then
    68.             GraphicsDevice.Clear(Color.Black)
    69.             spriteBatch.Begin(Nothing, blendsub)
    70.             spriteBatch.Draw(background, Vector2.Zero, Color.White)
    71.             spriteBatch.Draw(rtarget, Vector2.Zero, Color.White)
    72.             spriteBatch.End()
    73.         ElseIf Mouse.GetState.RightButton = ButtonState.Pressed Then
    74.             GraphicsDevice.Clear(Color.White)
    75.             spriteBatch.Begin(Nothing, blendrevsub)
    76.             spriteBatch.Draw(background, Vector2.Zero, Color.White)
    77.             spriteBatch.Draw(rtarget, Vector2.Zero, Color.White)
    78.             spriteBatch.End()
    79.         Else
    80.             GraphicsDevice.Clear(Color.Black)
    81.             spriteBatch.Begin(Nothing, BlendState.Additive)
    82.             spriteBatch.Draw(background, Vector2.Zero, Color.White)
    83.             spriteBatch.Draw(rtarget, Vector2.Zero, Color.White)
    84.             spriteBatch.End()
    85.         End If
    86.     End Sub
    87. End Class

    In this example, we will begin in the Draw method. Instead of just drawing the 20 balls, that are initialized in the same way as the one in example 3 or the 100 in example 3b, we choose to draw the balls to a target other than the screen. A socalled RenderTarget, which I have added as a global variable named rtarget and initialized/disposed in LoadContent and UnloadContent respectively, is basically nothing more than a bitmap. The GraphicsDevice is instructed to draw into this bitmap with the SetRenderTarget method, and the call to MyBase.Draw will draw all the 20 gray balls into it. The current render-target is then set to Nothing indicating that we wish to draw directly to the screen again.
    Now we encounter one of those gray areas, where I did not use Update for user-input, but rather chose to use the Draw method directly, as it makes for shorter code in this example. Apologies in advance for teaching you bad coding-practise. The Draw method is seperated into 3 parts:
    Pressing the LMB: On a black background, the blendsub BlendState is used to draw first the gray balls and then the Penguin texture.
    Pressing the RMB: On a white background, the blendrevsub BlendState is used to draw first the gray balls and then the Penguin texture.
    No buttons pressed: On a black background, additive blending is used to draw first the gray balls and then the Penguin texture.
    Basically all blending is done using the following formula:
    ResultColor = SourceColor * SourceBlendColor <ColorBlendFunction> DestinationColor * DestinationBlendColor
    ResultAlpha = SourceAlpha * SourceBlendAlpha <AlphaBlendFunction> DestinationAlpha * DestinationBlendAlpha
    The blendsub BlendState uses Subtraction as function and One for both blends giving a simple subtraction of source-color and destination-color as result. The blendrevsub is identical except it uses reverse subtraction giving subtraction of destination-color and source-color as result. And finally BlendState.Additive has one for both blends and uses addition as function giving source-color plus destination-color as result.
    In these 3 examples, the additive blend is the most interesting giving a glow-like effect, but subtraction, min, max etc. have their uses and can be combined to give a wide range of interesting results.
    At this point, you could try reloading your example 3b (100 balls) and try drawing the GradientBalls with additive blending (as opposed to the default Alpha). It should give you some odd modern-art type images with a complete blur of bright colors.
    In truth, a mature man who uses hair-oil, unless medicinally , that man has probably got a quoggy spot in him somewhere. As a general rule, he can't amount to much in his totality. (Melville: Moby Dick)

  7. #7

    Thread Starter
    Fanatic Member ThomasJohnsen's Avatar
    Join Date
    Jul 2010
    Location
    Denmark
    Posts
    528

    Re: Short list of examples (exclusively 2D) as an introduction to XNA

    Example 4: Simple buttons and sprite-fonts.

    vb.net Code:
    1. Public Class Game1
    2.     Inherits Microsoft.Xna.Framework.Game
    3.  
    4.     Private WithEvents graphics As GraphicsDeviceManager
    5.     Private WithEvents spriteBatch As SpriteBatch
    6.  
    7.     Private _myfont As SpriteFont
    8.  
    9.     Private WithEvents b1 As SimpleButton
    10.     Private WithEvents b2 As SimpleButton
    11.     Private WithEvents b3 As SimpleButton
    12.  
    13.     Private displaymessage As String = String.Empty
    14.     Private displaymiliseconds As Integer = 0
    15.     Private displaylocation As Vector2
    16.  
    17.     Public Sub New()
    18.         graphics = New GraphicsDeviceManager(Me)
    19.         Content.RootDirectory = "Content"
    20.     End Sub
    21.  
    22.     Protected Overrides Sub Initialize()
    23.         IsMouseVisible = True
    24.         Window.AllowUserResizing = True
    25.         Window.Title = "Example 4 (The simplest of buttons)" 'Modified title.
    26.  
    27.         _myfont = Content.Load(Of SpriteFont)("MyFont") 'Load the font Tahoma, 24pt
    28.  
    29.         'Add 3 simple buttons to components
    30.         b1 = New SimpleButton(Me, "Button1", _myfont, 50, 50, 160, 60) With {.ForeColor = Color.Red, .BackColor = Color.BlanchedAlmond}
    31.         b2 = New SimpleButton(Me, "Button2", _myfont, 50, 120, 160, 60) With {.ForeColor = Color.Black, .BackColor = Color.Tan}
    32.         b3 = New SimpleButton(Me, "Button3", _myfont, 50, 190, 160, 60) With {.ForeColor = Color.DarkGoldenrod, .BackColor = Color.OldLace}
    33.         Components.Add(b1)
    34.         Components.Add(b2)
    35.         Components.Add(b3)
    36.  
    37.         MyBase.Initialize()
    38.     End Sub
    39.  
    40.     Protected Overrides Sub LoadContent()
    41.         MyBase.LoadContent()
    42.         spriteBatch = New SpriteBatch(GraphicsDevice)
    43.     End Sub
    44.  
    45.     Protected Overrides Sub UnloadContent()
    46.         MyBase.UnloadContent()
    47.     End Sub
    48.  
    49.     Protected Overrides Sub Update(ByVal gameTime As GameTime)
    50.         MyBase.Update(gameTime)
    51.  
    52.         If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit()
    53.     End Sub
    54.  
    55.     Protected Overrides Sub Draw(ByVal gameTime As GameTime)
    56.         GraphicsDevice.Clear(Color.Black)
    57.  
    58.         'Display a message at the specified location if the duration is set
    59.         If displaymiliseconds > 0 Then
    60.             spriteBatch.Begin()
    61.             spriteBatch.DrawString(_myfont, displaymessage, displaylocation, Color.Blue)
    62.             spriteBatch.End()
    63.  
    64.             displaymiliseconds -= gameTime.ElapsedGameTime.Milliseconds
    65.         End If
    66.  
    67.         MyBase.Draw(gameTime)
    68.     End Sub
    69.  
    70.     Private Sub b1_Click(sender As Object, e As System.EventArgs) Handles b1.Click
    71.         displaymessage = "Button 1 was pressed."
    72.         displaylocation = New Vector2(220, 60)
    73.         displaymiliseconds = 2000
    74.     End Sub
    75.  
    76.     Private Sub b2_Click(sender As Object, e As System.EventArgs) Handles b2.Click
    77.         displaymessage = "Button 2 was pressed."
    78.         displaylocation = New Vector2(220, 130)
    79.         displaymiliseconds = 2000
    80.     End Sub
    81.  
    82.     Private Sub b3_Click(sender As Object, e As System.EventArgs) Handles b3.Click
    83.         displaymessage = "Button 3 was pressed."
    84.         displaylocation = New Vector2(220, 200)
    85.         displaymiliseconds = 2000
    86.     End Sub
    87.  
    88. End Class

    A new class called SimpleButton (create this class in the main project and copy/paste the code):
    vb.net Code:
    1. Public Class SimpleButton
    2.  
    3.     Inherits DrawableGameComponent
    4.  
    5.     Private btn_normal As RenderTarget2D  '3 bitmaps to render the button - one for each state.
    6.     Private btn_hover As RenderTarget2D
    7.     Private btn_pressed As RenderTarget2D
    8.     Private points() As VertexPositionTexture 'Vertices of the button (4 total giving 2 textured triangles).
    9.     Private indices() As Short = {0, 1, 2, 3} 'Indices to the vertices above - 4 indices for 2 textured triangles in a strip.
    10.     Private _effect As BasicEffect
    11.  
    12.     Private _text As String                   'Basic information about a button.
    13.     Private _font As SpriteFont
    14.     Private _rect As Rectangle
    15.     Private _forecolor As Color = Color.Black
    16.     Private _backcolor As Color = Color.Gray
    17.     Private _isdown As Boolean = False
    18.  
    19.     Public Event Click(sender As Object, e As EventArgs) 'Event to be raised upon clicking the button.
    20.  
    21.     Public Sub New(myproject As Game, text As String, font As SpriteFont, x As Integer, y As Integer, Width As Integer, Height As Integer)
    22.         MyBase.New(myproject)
    23.         _text = text
    24.         _font = font
    25.         _rect = New Rectangle(x, y, Width, Height)
    26.     End Sub
    27.  
    28.     Public Property ForeColor As Color
    29.         Get
    30.             Return _forecolor
    31.         End Get
    32.         Set(value As Color)
    33.             _forecolor = value
    34.         End Set
    35.     End Property
    36.  
    37.     Public Property BackColor As Color
    38.         Get
    39.             Return _backcolor
    40.         End Get
    41.         Set(value As Color)
    42.             _backcolor = value
    43.         End Set
    44.     End Property
    45.  
    46.     Public Overrides Sub Initialize()
    47.         MyBase.Initialize()
    48.     End Sub
    49.  
    50.     Protected Overrides Sub LoadContent()
    51.         MyBase.LoadContent()
    52.  
    53.         generateedges()    'Generate edges and textures for the button.
    54.         generatetextures()
    55.  
    56.         _effect = New BasicEffect(GraphicsDevice) 'Create a texture effect without lighting
    57.  
    58.         _effect.TextureEnabled = True
    59.         _effect.VertexColorEnabled = False
    60.         _effect.LightingEnabled = False
    61.         _effect.Texture = btn_normal
    62.  
    63.         updateprojection() 'Update the projection to the current viewport
    64.  
    65.         'Add a handler to handle changes in viewport resolution.
    66.         AddHandler Game.Window.ClientSizeChanged, AddressOf sizechange
    67.     End Sub
    68.  
    69.     Protected Overrides Sub UnloadContent()
    70.         MyBase.UnloadContent()
    71.         disposetextures()
    72.     End Sub
    73.  
    74.     Public Overrides Sub Update(ByVal gameTime As GameTime)
    75.         If _rect.Contains(Mouse.GetState.X, Mouse.GetState.Y) Then
    76.             If Mouse.GetState.LeftButton = ButtonState.Pressed Then
    77.                 If Not _isdown Then
    78.                     _isdown = True
    79.                     _effect.Texture = btn_pressed 'Texture has changed to pressed state.
    80.                     RaiseEvent Click(Me, Nothing)
    81.                 End If
    82.             Else
    83.                 _isdown = False
    84.                 _effect.Texture = btn_hover 'Testure has changed to hover state.
    85.             End If
    86.         Else
    87.             _isdown = False
    88.             _effect.Texture = btn_normal
    89.         End If
    90.  
    91.         MyBase.Update(gameTime)
    92.     End Sub
    93.  
    94.     Public Overrides Sub Draw(ByVal gameTime As GameTime)
    95.  
    96.         'Draw the 2 textured triangles-
    97.         For Each p As EffectPass In _effect.CurrentTechnique.Passes
    98.             p.Apply()
    99.             GraphicsDevice.DrawUserIndexedPrimitives(Of VertexPositionTexture)( _
    100.                 PrimitiveType.TriangleStrip, points, 0, 4, indices, 0, 2)
    101.         Next
    102.  
    103.         MyBase.Draw(gameTime)
    104.     End Sub
    105.  
    106.     Private Sub sizechange(sender As Object, e As EventArgs)
    107.         updateprojection() 'Respond to changes in viewport
    108.         disposetextures()  'RenderTargets must be redrawn.
    109.         generatetextures()
    110.     End Sub
    111.  
    112.     Private Sub updateprojection()
    113.         Dim w As Integer = GraphicsDevice.Viewport.Width
    114.         Dim h As Integer = GraphicsDevice.Viewport.Height
    115.  
    116.         'Use a non-perspective projection corresponding to the viewport looking at (0, 0).
    117.         _effect.Projection = Matrix.CreateOrthographicOffCenter(0.0F, w, h, 0.0F, 1.0F, 1000.0F)
    118.         _effect.View = Matrix.CreateLookAt(Vector3.UnitZ, Vector3.Zero, Vector3.Up)
    119.     End Sub
    120.  
    121.     Private Sub generateedges()
    122.         With _rect
    123.             points = New VertexPositionTexture() { _
    124.                 New VertexPositionTexture(New Vector3(.X, .Y, 0.0F), Vector2.Zero), _
    125.                 New VertexPositionTexture(New Vector3(.X + .Width, .Y, 0.0F), Vector2.UnitX), _
    126.                 New VertexPositionTexture(New Vector3(.X, .Y + .Height, 0.0F), Vector2.UnitY), _
    127.                 New VertexPositionTexture(New Vector3(.X + .Width, .Y + .Height, 0.0F), Vector2.One)}
    128.         End With
    129.     End Sub
    130.  
    131.     Private Sub generatetextures()
    132.         Dim sb As New SpriteBatch(GraphicsDevice)
    133.  
    134.         With _rect
    135.             Dim loc As Vector2 = (New Vector2(.Width, .Height) - _font.MeasureString(_text)) * 0.5F
    136.  
    137.             'Render to normal state texture using backcolor and forecolor.
    138.             btn_normal = New RenderTarget2D(GraphicsDevice, .Width, .Height)
    139.             GraphicsDevice.SetRenderTarget(btn_normal)
    140.             GraphicsDevice.Clear(_backcolor)
    141.             sb.Begin()
    142.             sb.DrawString(_font, _text, loc, _forecolor)
    143.             sb.End()
    144.  
    145.             'Render to hover state texture using lighter backcolor and forecolor.
    146.             btn_hover = New RenderTarget2D(GraphicsDevice, .Width, .Height)
    147.             GraphicsDevice.SetRenderTarget(btn_hover)
    148.             GraphicsDevice.Clear(_backcolor * 1.2F)
    149.             sb.Begin()
    150.             sb.DrawString(_font, _text, loc, _forecolor * 1.2F)
    151.             sb.End()
    152.  
    153.             'Render to pressed state texture using lighter backcolor and forecolor and slightly moved text.
    154.             btn_pressed = New RenderTarget2D(GraphicsDevice, .Width, .Height)
    155.             GraphicsDevice.SetRenderTarget(btn_pressed)
    156.             GraphicsDevice.Clear(_backcolor * 1.3F)
    157.             sb.Begin()
    158.             sb.DrawString(_font, _text, loc + New Vector2(2.0F, 1.0F), _forecolor * 1.3F)
    159.             sb.End()
    160.  
    161.             GraphicsDevice.SetRenderTarget(Nothing)
    162.         End With
    163.     End Sub
    164.  
    165.     Private Sub disposetextures()
    166.         btn_normal.Dispose()
    167.         btn_hover.Dispose()
    168.         btn_pressed.Dispose()
    169.     End Sub
    170.  
    171. End Class

    This may seem like a large example, but in fact it uses pretty much only things we have already gone through. A DrawableGameComponent is inherited to create a simple button, and three rendertargets are used to create textures for the button in normal, hover and pressed states. In order to try it out, you need to add a new sprite-font to the content project ('Add->New Item...'), choose sprite font and call it MyFont (will get extension .spritefont). Edit the XML of the font so the fontname is Tahoma and the size is 24. You can now try running the example.
    In the Game class, three variables are used to control a message being displayed on the screen, and three simple buttons are being declared as withevents. The spritefont is used through another global variable called _myfont. Besides that the Game class is pretty simple and should be a quick study. The only new thing is the method DrawString on spritebatches, but that should hardly present any problems at all.
    In the button class nothing much is new either. Since this is a 2D only study, I will refrain from explaining the 3D-stuff used to draw the buttons. Suffice to say - an orthographic projection is used to avoid perspective and the coordinate system is setup to have the same coordinates as the screen. Vertices of position and texture are used to describe the button, and a triangle-strip consisting of two triangles ({0,1,2,3} is interpreted as {0,1,2} and {1,2,3}) is used to draw it. No lighting has been used. The only thing noteworthy, is that the button class listens for events if the client-window changes size. This is done to ensure that the textures and coordinates are always viable. Thus changing the size of the client-window will recalculate the coordinate-system and dispose/redraw the textures.
    In truth, a mature man who uses hair-oil, unless medicinally , that man has probably got a quoggy spot in him somewhere. As a general rule, he can't amount to much in his totality. (Melville: Moby Dick)

  8. #8

    Thread Starter
    Fanatic Member ThomasJohnsen's Avatar
    Join Date
    Jul 2010
    Location
    Denmark
    Posts
    528

    Re: Short list of examples (exclusively 2D) as an introduction to XNA

    Example 5: Using Perlin simplex-noise to generate an infinite tiled map.

    vb.net Code:
    1. Public Class Game1
    2.     Inherits Microsoft.Xna.Framework.Game
    3.  
    4.     Private WithEvents graphics As GraphicsDeviceManager
    5.     Private WithEvents spriteBatch As SpriteBatch
    6.  
    7.     Private mymap As TiledMap
    8.  
    9.     Public Sub New()
    10.         graphics = New GraphicsDeviceManager(Me)
    11.         Content.RootDirectory = "Content"
    12.     End Sub
    13.  
    14.     Protected Overrides Sub Initialize()
    15.         mymap = New TiledMap(Me, 0.04F)
    16.         Components.Add(mymap)
    17.         IsMouseVisible = True
    18.         Window.AllowUserResizing = True
    19.         Window.Title = "Example 5 (A tiled map using Perlin simplex-noise)" 'Modified title.
    20.         MyBase.Initialize()
    21.     End Sub
    22.  
    23.     Protected Overrides Sub LoadContent()
    24.         spriteBatch = New SpriteBatch(GraphicsDevice)
    25.         MyBase.LoadContent()
    26.     End Sub
    27.  
    28.     Protected Overrides Sub UnloadContent()
    29.         MyBase.UnloadContent()
    30.     End Sub
    31.  
    32.     Protected Overrides Sub Update(ByVal gameTime As GameTime)
    33.         If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit()
    34.  
    35.         MyBase.Update(gameTime)
    36.     End Sub
    37.  
    38.     Protected Overrides Sub Draw(ByVal gameTime As GameTime)
    39.         GraphicsDevice.Clear(Color.Black)
    40.  
    41.         MyBase.Draw(gameTime)
    42.     End Sub
    43.  
    44. End Class

    A new class called TiledMap (create this class in the main project and copy/paste the code):
    vb.net Code:
    1. Public Class TiledMap
    2.  
    3.     Inherits DrawableGameComponent
    4.  
    5.     Private sprites As SpriteBatch
    6.     Private tile_texture As Texture2D
    7.     Private mappos_x, mappos_y, pixel_x, pixel_y As Integer
    8.     Private _rect As Rectangle = New Rectangle(0, 0, 64, 64)
    9.     Private _scale As Single
    10.     Private _oldmstate As MouseState
    11.  
    12.     Public Sub New(myproject As Game, scale As Single)
    13.         MyBase.New(myproject)
    14.         _scale = scale
    15.     End Sub
    16.  
    17.     Public Overrides Sub Initialize()
    18.         MyBase.Initialize()
    19.     End Sub
    20.  
    21.     Protected Overrides Sub LoadContent()
    22.         MyBase.LoadContent()
    23.         sprites = New SpriteBatch(GraphicsDevice)
    24.         tile_texture = Game.Content.Load(Of Texture2D)("SmallTextures")
    25.     End Sub
    26.  
    27.     Protected Overrides Sub UnloadContent()
    28.         MyBase.UnloadContent()
    29.     End Sub
    30.  
    31.     Public Overrides Sub Update(ByVal gameTime As GameTime)
    32.         Dim mstate As MouseState = Mouse.GetState
    33.  
    34.         If mstate.LeftButton = ButtonState.Pressed AndAlso Game.IsActive Then
    35.             If _oldmstate.LeftButton = ButtonState.Pressed Then
    36.  
    37.                 Dim deltax As Integer = _oldmstate.X - mstate.X
    38.                 Dim deltay As Integer = _oldmstate.Y - mstate.Y
    39.  
    40.                 mappos_x += deltax \ 64
    41.                 mappos_y += deltay \ 64
    42.                 pixel_x -= deltax Mod 64
    43.                 pixel_y -= deltay Mod 64
    44.  
    45.                 While pixel_x < 0
    46.                     pixel_x += 64
    47.                     mappos_x += 1
    48.                 End While
    49.  
    50.                 While pixel_x >= 64
    51.                     pixel_x -= 64
    52.                     mappos_x -= 1
    53.                 End While
    54.  
    55.                 While pixel_y < 0
    56.                     pixel_y += 64
    57.                     mappos_y += 1
    58.                 End While
    59.  
    60.                 While pixel_y >= 64
    61.                     pixel_y -= 64
    62.                     mappos_y -= 1
    63.                 End While
    64.  
    65.             End If
    66.         End If
    67.         _oldmstate = mstate
    68.  
    69.         MyBase.Update(gameTime)
    70.     End Sub
    71.  
    72.     Public Overrides Sub Draw(ByVal gameTime As GameTime)
    73.         Dim w As Integer = GraphicsDevice.Viewport.Width
    74.         Dim h As Integer = GraphicsDevice.Viewport.Height
    75.         Dim wtile As Integer = w \ 64 + 1
    76.         Dim htile As Integer = h \ 64 + 1
    77.         Dim loc, mappos As Vector2
    78.         Dim perlin As Single
    79.  
    80.         sprites.Begin()
    81.         For i As Integer = 0 To wtile
    82.             loc.X = pixel_x + 64.0F * (i - 1)
    83.             mappos.X = (mappos_x + i) * _scale
    84.             For j As Integer = 0 To htile
    85.                 loc.Y = pixel_y + 64.0F * (j - 1)
    86.                 mappos.Y = (mappos_y + j) * _scale
    87.  
    88.                 perlin = PerlinNoise.PerlinSimplex2D(mappos)
    89.  
    90.                 If perlin < 0.0F Then 'water
    91.                     _rect.X = 0
    92.                 ElseIf perlin < 0.6F Then 'grass
    93.                     _rect.X = 64
    94.                 ElseIf perlin < 0.8F Then 'forest
    95.                     _rect.X = 128
    96.                 ElseIf perlin < 0.9F Then 'desert
    97.                     _rect.X = 192
    98.                 Else 'mountain
    99.                     _rect.X = 256
    100.                 End If
    101.  
    102.                 sprites.Draw(tile_texture, loc, _rect, Color.White)
    103.             Next
    104.         Next
    105.         sprites.End()
    106.  
    107.         MyBase.Draw(gameTime)
    108.     End Sub
    109.  
    110. End Class

    A new class called PerlinNoise (create this class in the main project and copy/paste the code):
    vb.net Code:
    1. Public Class PerlinNoise
    2.  
    3.     'Created on the basis on this excellent article explaining simplex noise:
    4.     'Stefan Gustavson, Linköping University, Sweden (stegu@itn.liu.se), 2005-03-22
    5.  
    6.     Private Shared gradients() As Vector2 = _
    7.             {New Vector2(1.0F, 1.0F), New Vector2(-1.0F, 1.0F), New Vector2(1.0F, -1.0F), New Vector2(-1.0F, -1.0F), _
    8.              New Vector2(1.0F, 0.0F), New Vector2(-1.0F, 0.0F), New Vector2(1.0F, 0.0F), New Vector2(-1.0F, 0.0F), _
    9.              New Vector2(0.0F, 1.0F), New Vector2(0.0F, 1.0F), New Vector2(0.0F, -1.0F), New Vector2(0.0F, -1.0F)}
    10.  
    11.     Private Shared bytehash() As Byte = _
    12.         {&H97, &HA0, &H89, &H5B, &H5A, &HF, &H83, &HD, &HC9, &H5F, &H60, &H35, &HC2, &HE9, &H7, &HE1, _
    13.          &H8C, &H24, &H67, &H1E, &H45, &H8E, &H8, &H63, &H25, &HF0, &H15, &HA, &H17, &HBE, &H6, &H94, _
    14.          &HF7, &H78, &HEA, &H4B, &H0, &H1A, &HC5, &H3E, &H5E, &HFC, &HDB, &HCB, &H75, &H23, &HB, &H20, _
    15.          &H39, &HB1, &H21, &H58, &HED, &H95, &H38, &H57, &HAE, &H14, &H7D, &H88, &HAB, &HA8, &H44, &HAF, _
    16.          &H4A, &HA5, &H47, &H86, &H8B, &H30, &H1B, &HA6, &H4D, &H92, &H9E, &HE7, &H53, &H6F, &HE5, &H7A, _
    17.          &H3C, &HD3, &H85, &HE6, &HDC, &H69, &H5C, &H29, &H37, &H2E, &HF5, &H28, &HF4, &H66, &H8F, &H36, _
    18.          &H41, &H19, &H3F, &HA1, &H1, &HD8, &H50, &H49, &HD1, &H4C, &H84, &HBB, &HD0, &H59, &H12, &HA9, _
    19.          &HC8, &HC4, &H87, &H82, &H74, &HBC, &H9F, &H56, &HA4, &H64, &H6D, &HC6, &HAD, &HBA, &H3, &H40, _
    20.          &H34, &HD9, &HE2, &HFA, &H7C, &H7B, &H5, &HCA, &H26, &H93, &H76, &H7E, &HFF, &H52, &H55, &HD4, _
    21.          &HCF, &HCE, &H3B, &HE3, &H2F, &H10, &H3A, &H11, &HB6, &HBD, &H1C, &H2A, &HDF, &HB7, &HAA, &HD5, _
    22.          &H77, &HF8, &H98, &H2, &H2C, &H9A, &HA3, &H46, &HDD, &H99, &H65, &H9B, &HA7, &H2B, &HAC, &H9, _
    23.          &H81, &H16, &H27, &HFD, &H13, &H62, &H6C, &H6E, &H4F, &H71, &HE0, &HE8, &HB2, &HB9, &H70, &H68, _
    24.          &HDA, &HF6, &H61, &HE4, &HFB, &H22, &HF2, &HC1, &HEE, &HD2, &H90, &HC, &HBF, &HB3, &HA2, &HF1, _
    25.          &H51, &H33, &H91, &HEB, &HF9, &HE, &HEF, &H6B, &H31, &HC0, &HD6, &H1F, &HB5, &HC7, &H6A, &H9D, _
    26.          &HB8, &H54, &HCC, &HB0, &H73, &H79, &H32, &H2D, &H7F, &H4, &H96, &HFE, &H8A, &HEC, &HCD, &H5D, _
    27.          &HDE, &H72, &H43, &H1D, &H18, &H48, &HF3, &H8D, &H80, &HC3, &H4E, &H42, &HD7, &H3D, &H9C, &HB4, _
    28.          &H97, &HA0, &H89, &H5B, &H5A, &HF, &H83, &HD, &HC9, &H5F, &H60, &H35, &HC2, &HE9, &H7, &HE1, _
    29.          &H8C, &H24, &H67, &H1E, &H45, &H8E, &H8, &H63, &H25, &HF0, &H15, &HA, &H17, &HBE, &H6, &H94, _
    30.          &HF7, &H78, &HEA, &H4B, &H0, &H1A, &HC5, &H3E, &H5E, &HFC, &HDB, &HCB, &H75, &H23, &HB, &H20, _
    31.          &H39, &HB1, &H21, &H58, &HED, &H95, &H38, &H57, &HAE, &H14, &H7D, &H88, &HAB, &HA8, &H44, &HAF, _
    32.          &H4A, &HA5, &H47, &H86, &H8B, &H30, &H1B, &HA6, &H4D, &H92, &H9E, &HE7, &H53, &H6F, &HE5, &H7A, _
    33.          &H3C, &HD3, &H85, &HE6, &HDC, &H69, &H5C, &H29, &H37, &H2E, &HF5, &H28, &HF4, &H66, &H8F, &H36, _
    34.          &H41, &H19, &H3F, &HA1, &H1, &HD8, &H50, &H49, &HD1, &H4C, &H84, &HBB, &HD0, &H59, &H12, &HA9, _
    35.          &HC8, &HC4, &H87, &H82, &H74, &HBC, &H9F, &H56, &HA4, &H64, &H6D, &HC6, &HAD, &HBA, &H3, &H40, _
    36.          &H34, &HD9, &HE2, &HFA, &H7C, &H7B, &H5, &HCA, &H26, &H93, &H76, &H7E, &HFF, &H52, &H55, &HD4, _
    37.          &HCF, &HCE, &H3B, &HE3, &H2F, &H10, &H3A, &H11, &HB6, &HBD, &H1C, &H2A, &HDF, &HB7, &HAA, &HD5, _
    38.          &H77, &HF8, &H98, &H2, &H2C, &H9A, &HA3, &H46, &HDD, &H99, &H65, &H9B, &HA7, &H2B, &HAC, &H9, _
    39.          &H81, &H16, &H27, &HFD, &H13, &H62, &H6C, &H6E, &H4F, &H71, &HE0, &HE8, &HB2, &HB9, &H70, &H68, _
    40.          &HDA, &HF6, &H61, &HE4, &HFB, &H22, &HF2, &HC1, &HEE, &HD2, &H90, &HC, &HBF, &HB3, &HA2, &HF1, _
    41.          &H51, &H33, &H91, &HEB, &HF9, &HE, &HEF, &H6B, &H31, &HC0, &HD6, &H1F, &HB5, &HC7, &H6A, &H9D, _
    42.          &HB8, &H54, &HCC, &HB0, &H73, &H79, &H32, &H2D, &H7F, &H4, &H96, &HFE, &H8A, &HEC, &HCD, &H5D, _
    43.          &HDE, &H72, &H43, &H1D, &H18, &H48, &HF3, &H8D, &H80, &HC3, &H4E, &H42, &HD7, &H3D, &H9C, &HB4}
    44.  
    45.     Public Shared Function PerlinSimplex2D(loc As Vector2) As Single
    46.  
    47.         Static F As Single = Convert.ToSingle(Math.Sqrt(0.75)) - 0.5F
    48.         Static G As Single = 0.5F - Convert.ToSingle(Math.Sqrt(1.0 / 12.0))
    49.  
    50.         Dim s As Single = (loc.X + loc.Y) * F
    51.         Dim i As Integer = fastfloor(loc.X + s)
    52.         Dim j As Integer = fastfloor(loc.Y + s)
    53.         Dim t As Single = (i + j) * G
    54.         Dim v0 As New Vector2(loc.X - i + t, loc.Y - j + t)
    55.         Dim v1 As New Vector2(v0.X + G, v0.Y + G)
    56.         Dim v2 As New Vector2(v1.X + G - 1.0F, v1.Y + G - 1.0F)
    57.         Dim ii As Integer = i And &HFF
    58.         Dim jj As Integer = j And &HFF
    59.         Dim gi0 As Integer = bytehash(ii + bytehash(jj)) Mod 12
    60.         Dim gi1 As Integer
    61.         Dim gi2 As Integer = bytehash(ii + 1 + bytehash(jj + 1)) Mod 12
    62.  
    63.         If v0.X > v0.Y Then
    64.             v1.X -= 1.0F
    65.             gi1 = bytehash(ii + 1 + bytehash(jj)) Mod 12
    66.         Else
    67.             v1.Y -= 1.0F
    68.             gi1 = bytehash(ii + bytehash(jj + 1)) Mod 12
    69.         End If
    70.  
    71.         Dim t0 As Single = 0.5F - v0.LengthSquared
    72.         Dim t1 As Single = 0.5F - v1.LengthSquared
    73.         Dim t2 As Single = 0.5F - v2.LengthSquared
    74.         Dim d0, d1, d2 As Single
    75.  
    76.         If t0 < 0.0F Then
    77.             d0 = 0.0F
    78.         Else
    79.             t0 *= t0
    80.             d0 = t0 * t0 * Vector2.Dot(gradients(gi0), v0)
    81.         End If
    82.  
    83.         If t1 < 0.0F Then
    84.             d1 = 0.0F
    85.         Else
    86.             t1 *= t1
    87.             d1 = t1 * t1 * Vector2.Dot(gradients(gi1), v1)
    88.         End If
    89.  
    90.         If t2 < 0.0F Then
    91.             d2 = 0.0F
    92.         Else
    93.             t2 *= t2
    94.             d2 = t2 * t2 * Vector2.Dot(gradients(gi2), v2)
    95.         End If
    96.  
    97.         Return 70.0F * (d0 + d1 + d2)
    98.  
    99.     End Function
    100.  
    101.     Public Shared Function Generate(dimension As Integer, scale As Single, offset As Vector2, c1 As Color, c2 As Color) As Color()
    102.  
    103.         Dim v As New Vector2
    104.         Dim k As Integer = 0
    105.         Dim rval(dimension * dimension - 1) As Color
    106.  
    107.         For i As Integer = 0 To dimension - 1
    108.             v.X = i * scale + offset.X
    109.             v.Y = offset.Y
    110.             For j As Integer = 0 To dimension - 1
    111.                 rval(k) = Color.Lerp(c1, c2, (PerlinSimplex2D(v) + 1.0F) / 2.0F)
    112.                 v.Y += scale
    113.                 k += 1
    114.             Next
    115.         Next
    116.  
    117.         Return rval
    118.  
    119.     End Function
    120.  
    121.     Private Shared Function fastfloor(val As Single) As Integer
    122.  
    123.         Return Convert.ToInt32(If(val > 0, Int(val), Int(val) - 1))
    124.  
    125.     End Function
    126.  
    127. End Class

    I will not explain how Perlin noise is implemented or how it works. There are plenty of pages on that already - for interested readers, the article referred at the top of the PerlinNoise class is an excellent place to start. For others simply accept that for any given 2d-vector Perlin noise will give a floating point number, so that the function is continuous everywhere yet produces semi-random values. And Perlin spent a long time working on his version(s) trying to get it as fast as possible; using the additional shared generate method to construct entire textures of Perlin-noise is indeed doable. Even with multiple calls per pixel (as is costumary to generate the most spectacular of effects). In our little example however, we will just call the plain simplex function since this example is not about generating beautiful and accurate landscapes but rather illustrating a method. To run the example, you will need to supply a tiled texture of size 320 x 64 pixels consisting of 5 tiles of water, grass, forest, desert and mountains respectively. The one I used is linked here Name:  SmallTextures.png
Views: 965
Size:  1.5 KB, which is merely colored squares representing the areas (I'm not much of an artist).
    Aside from the fact that Perlin-noise is used, nothing much is new in this example. The tiled texture is loaded and 64 by 64 bits of it is displayed at every location on the screen based on the Perlin-simplex of the location (or rather a scaled down version of the location). The update method in the TiledMap class illustrates how an 'old' state of the mouse is saved to determine if the left button has just been pressed. Then the location of the mousepointer is used to generate a small offset of pixels and an offset into the map. Feel free to adjust the levels in TiledMap.Draw to accomodate more forest or whatever - Perlin-noise gives values in the range -1 to 1, and it should be easy to allow for more area-types or various other features.
    In truth, a mature man who uses hair-oil, unless medicinally , that man has probably got a quoggy spot in him somewhere. As a general rule, he can't amount to much in his totality. (Melville: Moby Dick)

  9. #9

    Thread Starter
    Fanatic Member ThomasJohnsen's Avatar
    Join Date
    Jul 2010
    Location
    Denmark
    Posts
    528

    Re: Short list of examples (exclusively 2D) as an introduction to XNA

    Example 6: Using HLSL (High Level Shader Language) to generate interesting picture effects.

    vb.net Code:
    1. Public Class Game1
    2.     Inherits Microsoft.Xna.Framework.Game
    3.  
    4.     Private WithEvents graphics As GraphicsDeviceManager
    5.     Private WithEvents spriteBatch As SpriteBatch
    6.  
    7.     Private myeffects() As Effect
    8.     Private mytexture As Texture2D
    9.     Private activeeffect As Effect = Nothing
    10.  
    11.     Public Sub New()
    12.         graphics = New GraphicsDeviceManager(Me)
    13.         Content.RootDirectory = "Content"
    14.     End Sub
    15.  
    16.     Protected Overrides Sub Initialize()
    17.         IsMouseVisible = True
    18.         Window.AllowUserResizing = True
    19.         Window.Title = "Example 6 (Using simple HLSL pixelshaders to generate various effects 1-7)" 'Modified title.
    20.         MyBase.Initialize()
    21.     End Sub
    22.  
    23.     Protected Overrides Sub LoadContent()
    24.         spriteBatch = New SpriteBatch(GraphicsDevice)
    25.         mytexture = Content.Load(Of Texture2D)("Penguins")
    26.  
    27.         'These are the simple filters used in this example. No efficiency considerations have been made to either filter
    28.         'except that Gauss blur is implemented in 2 passes (horizontal + vertical) lowering the number of computations.
    29.         'For more advanced bilateral and median filters, using HLSL will be difficult, since there is a limit on the number
    30.         'of computations allowed at each pixel (ie. rendering real-time is nigh impossible).
    31.         myeffects = New Effect() {Content.Load(Of Effect)("Grayscale"), _
    32.                                   Content.Load(Of Effect)("LuminanceITU_R"), _
    33.                                   Content.Load(Of Effect)("LuminanceCCIR601"), _
    34.                                   Content.Load(Of Effect)("Sepia"), _
    35.                                   Content.Load(Of Effect)("Saturate"), _
    36.                                   Content.Load(Of Effect)("Sobel"), _
    37.                                   Content.Load(Of Effect)("GaussBlur")}
    38.  
    39.         With myeffects(4) 'Saturate
    40.             .Parameters("SatValue").SetValue(1.4F) 'Set saturation to 1.4f
    41.         End With
    42.  
    43.         With myeffects(5) 'Sobel
    44.             .Parameters("Width").SetValue(mytexture.Width)   'Supply dimensions of background
    45.             .Parameters("Height").SetValue(mytexture.Height)
    46.             .Parameters("ForeColor").SetValue(New Vector4(0.0F, 0.0F, 0.0F, 0.0F)) 'Supply colors (black and white in this case)
    47.             .Parameters("ForeColor").SetValue(New Vector4(1.0F, 1.0F, 1.0F, 0.0F))
    48.         End With
    49.  
    50.         With myeffects(6) 'Gauss
    51.             .Parameters("Width").SetValue(mytexture.Width)   'Supply dimensions of background
    52.             .Parameters("Height").SetValue(mytexture.Height)
    53.         End With
    54.  
    55.         MyBase.LoadContent()
    56.     End Sub
    57.  
    58.     Protected Overrides Sub UnloadContent()
    59.         MyBase.UnloadContent()
    60.     End Sub
    61.  
    62.     Protected Overrides Sub Update(ByVal gameTime As GameTime)
    63.         If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit()
    64.  
    65.         If Keyboard.GetState.IsKeyDown(Keys.D1) Then
    66.             activeeffect = myeffects(0)
    67.         ElseIf Keyboard.GetState.IsKeyDown(Keys.D2) Then
    68.             activeeffect = myeffects(1)
    69.         ElseIf Keyboard.GetState.IsKeyDown(Keys.D3) Then
    70.             activeeffect = myeffects(2)
    71.         ElseIf Keyboard.GetState.IsKeyDown(Keys.D4) Then
    72.             activeeffect = myeffects(3)
    73.         ElseIf Keyboard.GetState.IsKeyDown(Keys.D5) Then
    74.             activeeffect = myeffects(4)
    75.         ElseIf Keyboard.GetState.IsKeyDown(Keys.D6) Then
    76.             activeeffect = myeffects(5)
    77.         ElseIf Keyboard.GetState.IsKeyDown(Keys.D7) Then
    78.             activeeffect = myeffects(6)
    79.         Else
    80.             activeeffect = Nothing
    81.         End If
    82.         MyBase.Update(gameTime)
    83.     End Sub
    84.  
    85.     Protected Overrides Sub Draw(ByVal gameTime As GameTime)
    86.         GraphicsDevice.Clear(Color.Black)
    87.  
    88.         spriteBatch.Begin(Nothing, Nothing, Nothing, Nothing, Nothing, activeeffect)
    89.         spriteBatch.Draw(mytexture, Vector2.Zero, Color.White)
    90.         spriteBatch.End()
    91.         MyBase.Draw(gameTime)
    92.     End Sub
    93.  
    94. End Class

    A new effect called Grayscale (create this effect in the content project and copy/paste the code):
    Code:
    sampler2D s_2D;
    
    const float4 v_grayscale = { 0.3086f, 0.6094f, 0.0820f, 0.0f };
    
    float4 Grayscale(float2 uv : TEXCOORD) : COLOR
    {
    	float gray = dot(v_grayscale, tex2D(s_2D, uv));
    
        return float4(gray, gray, gray, 0.0f);
    }
    
    technique Technique1
    {
        pass Pass1
        {
            PixelShader = compile ps_2_0 Grayscale();
        }
    }
    A new effect called LuminanceITU_R (create this effect in the content project and copy/paste the code):
    Code:
    sampler2D s_2D;
    
    const float4 v_luminance_ITU_R = { 0.2126f, 0.7152f, 0.0722f, 0.0f };
    
    float4 ITU_R(float2 uv : TEXCOORD) : COLOR
    {
    	float gray = dot(v_luminance_ITU_R, tex2D(s_2D, uv));
    
        return float4(gray, gray, gray, 0.0f);
    }
    
    technique Technique1
    {
        pass Pass1
        {
            PixelShader = compile ps_2_0 ITU_R();
        }
    }
    A new effect called LuminanceCCIR601 (create this effect in the content project and copy/paste the code):
    Code:
    sampler2D s_2D;
    
    const float4 v_luminance_CCIR601 = { 0.299f,  0.587f,  0.114f,  0.0f };
    
    float4 CCIR601(float2 uv : TEXCOORD) : COLOR
    {
    	float gray = dot(v_luminance_CCIR601, tex2D(s_2D, uv));
    
        return float4(gray, gray, gray, 0.0f);
    }
    
    technique Technique1
    {
        pass Pass1
        {
            PixelShader = compile ps_2_0 CCIR601();
        }
    }
    A new effect called Sepia (create this effect in the content project and copy/paste the code):
    Code:
    sampler2D s_2D;
    
    const float4x4 sepia_matrix = { 0.3588f, 0.7044f, 0.1368f, 0.0f,
                                    0.2990f, 0.5870f, 0.1140f, 0.0f,
                                    0.2392f, 0.4696f, 0.0912f, 0.0f,
                                    0.0f,    0.0f,    0.0f,    1.0f };
    
    float4 Sepia(float2 uv : TEXCOORD) : COLOR
    {
    	return mul(sepia_matrix, tex2D(s_2D, uv));
    }
    
    technique Technique1
    {
        pass Pass1
        {
            PixelShader = compile ps_2_0 Sepia();
        }
    }
    A new effect called Saturate (create this effect in the content project and copy/paste the code):
    Code:
    sampler2D s_2D;
    
    float SatValue;
    
    float4 SaturateInput(float sat, float4 input)
    {
        float rw = (1.0f - sat) * 0.3086f;
    	float gw = (1.0f - sat) * 0.6094f;
    	float bw = (1.0f - sat) * 0.0820f;
    
    	float4 rval = { (rw + sat) * input.r + gw * input.g + bw * input.b,
    	                rw * input.r + (gw + sat) * input.g + bw * input.b,
    	                rw * input.r + gw * input.g + (bw + sat) * input.b,
    			        input.a };
    
        return rval;
    }
    
    float4 Saturate(float2 uv : TEXCOORD) : COLOR
    {
    	return SaturateInput(SatValue, tex2D(s_2D, uv));
    }
    
    technique Technique1
    {
        pass Pass1
        {
            PixelShader = compile ps_2_0 Saturate();
        }
    }
    A new effect called Sobel (create this effect in the content project and copy/paste the code):
    Code:
    sampler2D s_2D;
    
    int Width;
    int Height;
    
    float4 BackColor;
    float4 ForeColor;
    
    const float4 grayscale         = { 0.3086f, 0.6094f, 0.0820f, 0.0f };
    const float4 luminance_ITU_R   = { 0.2126f, 0.7152f, 0.0722f, 0.0f };
    const float4 luminance_CCIR601 = { 0.299f,  0.587f,  0.114f,  0.0f };
    
    const float threshold = 0.4f;
    
    float4 Sobel(float2 uv : TEXCOORD) : COLOR
    {
    	float2 psize = { 1.0f / Width, 1.0f / Height };
    
        float g1 = dot(luminance_ITU_R, tex2D(s_2D, uv + float2(-psize.x, -psize.y)));
    	float g2 = dot(luminance_ITU_R, tex2D(s_2D, uv + float2( 0.0f,    -psize.y)));
        float g3 = dot(luminance_ITU_R, tex2D(s_2D, uv + float2( psize.x, -psize.y)));
        float g4 = dot(luminance_ITU_R, tex2D(s_2D, uv + float2(-psize.x,  0.0f)));
        float g5 = dot(luminance_ITU_R, tex2D(s_2D, uv + float2( 0.0f,     0.0f)));
        float g6 = dot(luminance_ITU_R, tex2D(s_2D, uv + float2( psize.x,  0.0f)));
        float g7 = dot(luminance_ITU_R, tex2D(s_2D, uv + float2(-psize.x,  psize.y)));
        float g8 = dot(luminance_ITU_R, tex2D(s_2D, uv + float2( 0.0f,     psize.y)));
        float g9 = dot(luminance_ITU_R, tex2D(s_2D, uv + float2( psize.x,  psize.y)));
    
    	float hx = g3 - g1 + 2 * (g6 - g4) + g9 - g7;
    	float hy = g7 - g1 + 2 * (g8 - g2) + g9 - g3;
    
        return (hx * hx + hy * hy < threshold) ? ForeColor : BackColor;
    }
    
    technique Technique1
    {
        pass Pass1
        {
            PixelShader = compile ps_2_0 Sobel();
        }
    }
    A new effect called GaussBlur (create this effect in the content project and copy/paste the code):
    Code:
    sampler2D s_2D;
    
    int Width;
    int Height;
    
    float4 GaussBlurHorz(float2 uv : TEXCOORD) : COLOR
    {
    	float2 poffset = { 1.0f / Width, 0.0 };
    
        float4 blur = 0.0162162162f * tex2D(s_2D, uv - 4.0f * poffset);
        blur +=       0.0540540541f * tex2D(s_2D, uv - 3.0f * poffset);
        blur +=       0.1216216216f * tex2D(s_2D, uv - 2.0f * poffset);
        blur +=       0.1945945946f * tex2D(s_2D, uv - 1.0f * poffset);
        blur +=       0.2270270270f * tex2D(s_2D, uv);
        blur +=       0.1945945946f * tex2D(s_2D, uv + 1.0f * poffset);
        blur +=       0.1216216216f * tex2D(s_2D, uv + 2.0f * poffset);
        blur +=       0.0540540541f * tex2D(s_2D, uv + 3.0f * poffset);
        blur +=       0.0162162162f * tex2D(s_2D, uv + 4.0f * poffset);
    
        return blur;
    }
    
    float4 GaussBlurVert(float2 uv : TEXCOORD) : COLOR
    {
    	float2 poffset = { 0.0, 1.0f / Height };
    
        float4 blur = 0.0162162162f * tex2D(s_2D, uv - 4.0f * poffset);
        blur +=       0.0540540541f * tex2D(s_2D, uv - 3.0f * poffset);
        blur +=       0.1216216216f * tex2D(s_2D, uv - 2.0f * poffset);
        blur +=       0.1945945946f * tex2D(s_2D, uv - 1.0f * poffset);
        blur +=       0.2270270270f * tex2D(s_2D, uv);
        blur +=       0.1945945946f * tex2D(s_2D, uv + 1.0f * poffset);
        blur +=       0.1216216216f * tex2D(s_2D, uv + 2.0f * poffset);
        blur +=       0.0540540541f * tex2D(s_2D, uv + 3.0f * poffset);
        blur +=       0.0162162162f * tex2D(s_2D, uv + 4.0f * poffset);
    
        return blur;
    }
    
    technique Technique1
    {
        pass Pass1
        {
            PixelShader = compile ps_2_0 GaussBlurHorz();
        }
        pass Pass2
        {
            PixelShader = compile ps_2_0 GaussBlurVert();
        }
    }
    Also you will need to add that same old texture Penguins.jpg (or Koala or similar as long as you remember to change the name) to the content project.

    Phew that was alot of work creating and copying all those effects. And if you're no fan of C, they might look a tad difficult to read.
    The first line in either effect simply declares a global variable of type sampler2D. Nothing is ever supplied to it, so the sampler used is the default in all cases (linear wrap). float in HLSL is equivalent to Single in VB - similarly Vector2 is equivalent to float2, Vector3 to float3 and Vector4 to float4. Matrix is equivalent to float4x4, but HLSL also supports float3x3 etc. int is equivalent to Integer or Int32. HLSL like C is case-sensitive!
    The same rules as in VB apply to vectors in HLSL, in that you can add and subtract them using +/- and scale them using * and /. To take the dot-product of two vectors use dot(u, v) and to transform a vector with a matrix use mul(m, u). The function tex2D(<sampler>, <float2>) will use the supplied sampler to sample the texture-color at the location supplied in the float2 (which are coordinates in the range 0 to 1). TEXCOORD and COLOR are semantics used to tell the compiler that we're dealing with texture-coordinates and a color-vector respectively. Any PixelShader should take as argument a uv coordinate set (but possibly more parameters in a struct) and return a color. Thus all our effects (which are pixel-shaders) use the TEXCOORD/COLOR semantics.
    An effect consists of a range of techniques each containing a range of passes. This is what the bottom lines in each effect signify. All examples except the last uses one technique and one pass. The last example contains a single technique consisting of two passes (initial texture goes through first pass and the result is used as source for second pass - result of second pass is final result).

    The three first examples are simple. We just extract the color at the specified uv-coordinate and multiply it by a constant vector (dot product) to get a grayscale value that is returned as a non-transparent gray color (colors in HLSL are 0 to 1 values of RGBA in a float4). The variation between the three is very subtle to the human eye, but supposedly they each have characteristics useful in various areas.
    In the fourth example, we instead use a matrix to multiply the color from the texture to get a sepia-color effect.
    The fifth example introduces a parameter to the effect in the form of a float called SatValue (declared as a global variable). The value of this variable can be set from outside HLSL, so we may control the level of saturation used. The function SaturateInput uses a well-described method for saturating a pixel in RGB color-space (you may note that if v is a variable of type floatX, you can use v.x or v.r to get the first element, v.y or v.g to get the second and so on. HLSL also supports using v.xy/v.rg to extract a float2 from a floatX or using v.rgb/v.xyz to extract a float3 from a float4).
    The sixth example has four parameters for width by height of the source texture and the two colors used as return values. It is a Sobel operator taking nine samples from the source texture, converting them all to gray and using a simple formula between them to determine if a given point is on an edge between two colors. If the pixel is found to be on an edge, the ForeColor is returned - otherwise the backcolor is returned. I used the Luminance_ITU_R in the example, but feel free to try out the other two listed.
    The seventh example is a two-pass version of Gaussian blur with a four pixel radius. The first pass blurs the current pixel with every pixel in a horizontal span of four pixels to each side. The second pass blurs the current pixel with every pixel in a vertical span of four pixels to the top and bottom. The values used have been found in various articles on Gaussian blur.
    In truth, a mature man who uses hair-oil, unless medicinally , that man has probably got a quoggy spot in him somewhere. As a general rule, he can't amount to much in his totality. (Melville: Moby Dick)

  10. #10

    Thread Starter
    Fanatic Member ThomasJohnsen's Avatar
    Join Date
    Jul 2010
    Location
    Denmark
    Posts
    528

    Re: Short list of examples (exclusively 2D) as an introduction to XNA

    Example 7: A complete game using just 100 lines of code and relying on nothing but what you've learned.

    I thought that I would end this series of examples with a little funny game with rich potential for development. The game basically consists of an invisible background (make the window full-screen). Your mouse-pointer is a torch, that you can use to light up the image - find the ghost and make him scream! Once you have found him, he will move to a new location. There are plenty of oppotunities to add score to this game - and difficulty making the torch smaller or the ghost more invisible. Or adding bonus ghosts. This is a cash-cow handed to you .
    To use it simply add my little ghost and my scream to the Content project - both are linked here Name:  LittleGhost.png
Views: 958
Size:  1.9 KB {OK so there's no method of uploading sound - but find and download a very short scream (3-5 secs tops) and add it as Scream(.wav)}. As background the trusty old Penguins.jpg is used. Enjoy and thanks for reading.

    vb.net Code:
    1. Public Class Game1
    2.     Inherits Microsoft.Xna.Framework.Game
    3.  
    4.     Private WithEvents graphics As GraphicsDeviceManager
    5.     Private WithEvents spriteBatch As SpriteBatch
    6.  
    7.     Private background As Texture2D
    8.     Private ghost As Texture2D
    9.     Private ghost_location As Vector2
    10.     Private gradientball As Texture2D
    11.     Private display As RenderTarget2D = Nothing
    12.     Private screamsound As SoundEffect
    13.     Private rnd As New Random
    14.     Private blend_min As BlendState = New BlendState With _
    15.         {.AlphaBlendFunction = BlendFunction.Min, .AlphaSourceBlend = Blend.One, .AlphaDestinationBlend = Blend.One, _
    16.          .ColorBlendFunction = BlendFunction.Min, .ColorSourceBlend = Blend.One, .ColorDestinationBlend = Blend.One}
    17.  
    18.     Public Sub New()
    19.         graphics = New GraphicsDeviceManager(Me)
    20.         Content.RootDirectory = "Content"
    21.     End Sub
    22.  
    23.     Protected Overrides Sub Initialize()
    24.         IsMouseVisible = True
    25.         Window.AllowUserResizing = True
    26.         AddHandler Window.ClientSizeChanged, AddressOf picknewlocation
    27.         MyBase.Initialize()
    28.     End Sub
    29.  
    30.     Protected Overrides Sub LoadContent()
    31.         spriteBatch = New SpriteBatch(GraphicsDevice)
    32.         background = Content.Load(Of Texture2D)("Penguins")
    33.         ghost = Content.Load(Of Texture2D)("LittleGhost")
    34.         screamsound = Content.Load(Of SoundEffect)("Scream")
    35.         generate_gradientball(100, Color.Black, Color.White)
    36.         picknewlocation()
    37.         MyBase.LoadContent()
    38.     End Sub
    39.  
    40.     Protected Overrides Sub UnloadContent()
    41.         display.Dispose()
    42.         gradientball.Dispose()
    43.         MyBase.UnloadContent()
    44.     End Sub
    45.  
    46.     Protected Overrides Sub Update(ByVal gameTime As GameTime)
    47.         If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit()
    48.         Dim u As Vector2 = New Vector2(Mouse.GetState.X, Mouse.GetState.Y)
    49.         Dim v As Vector2 = New Vector2(ghost_location.X + ghost.Width \ 2, ghost_location.Y + ghost.Height \ 2)
    50.         If Vector2.Distance(u, v) < 8 Then
    51.             screamsound.Play()
    52.             picknewlocation()
    53.         End If
    54.         MyBase.Update(gameTime)
    55.     End Sub
    56.  
    57.     Protected Overrides Sub Draw(ByVal gameTime As GameTime)
    58.         GraphicsDevice.Clear(Color.Black)
    59.         spriteBatch.Begin()
    60.         spriteBatch.Draw(gradientball, New Vector2(Mouse.GetState.X - gradientball.Width \ 2, _
    61.                                                    Mouse.GetState.Y - gradientball.Height \ 2), Color.White)
    62.         spriteBatch.End()
    63.         spriteBatch.Begin(Nothing, blend_min)
    64.         spriteBatch.Draw(display, Vector2.Zero, Color.White)
    65.         spriteBatch.End()
    66.         MyBase.Draw(gameTime)
    67.     End Sub
    68.  
    69.     Private Sub picknewlocation()
    70.         If display IsNot Nothing Then display.Dispose()
    71.  
    72.         display = New RenderTarget2D(GraphicsDevice, background.Width, background.Height)
    73.         ghost_location = New Vector2(rnd.Next(0, background.Width - ghost.Width), rnd.Next(0, background.Height - ghost.Height))
    74.         GraphicsDevice.SetRenderTarget(display)
    75.         spriteBatch.Begin()
    76.         spriteBatch.Draw(background, Vector2.Zero, Color.White)
    77.         spriteBatch.Draw(ghost, ghost_location, Color.White)
    78.         spriteBatch.End()
    79.         GraphicsDevice.SetRenderTarget(Nothing)
    80.     End Sub
    81.  
    82.     Private Sub generate_gradientball(radius As Integer, c1 As Color, c2 As Color)
    83.         Dim diameter As Integer = 2 * radius + 1
    84.         Dim rval(diameter * diameter - 1) As Color
    85.         Dim rsquared As Single = radius * radius
    86.         Dim k As Integer = 0
    87.         Dim l, d As Single
    88.         For i As Integer = 0 To diameter - 1
    89.             d = (i - radius) * (i - radius)
    90.             For j As Integer = 0 To diameter - 1
    91.  
    92.                 l = (d + (j - radius) * (j - radius)) / rsquared
    93.                 rval(k) = Color.Lerp(c2, c1, l)
    94.                 k += 1
    95.             Next
    96.         Next
    97.         gradientball = New Texture2D(GraphicsDevice, diameter, diameter)
    98.         gradientball.SetData(rval)
    99.     End Sub
    100. End Class

    Ok so the 'nothing but what you have learned'-comment was a bit rash. We actually hadn't covered sound yet, but since it is as simple as scratching you own arse (pardon my italian), I thought I'd leave it to you to determine how that <SoundEffect>.Play works.

    Regards Tom
    Last edited by ThomasJohnsen; Nov 18th, 2012 at 01:36 PM.
    In truth, a mature man who uses hair-oil, unless medicinally , that man has probably got a quoggy spot in him somewhere. As a general rule, he can't amount to much in his totality. (Melville: Moby Dick)

  11. #11
    PowerPoster Nightwalker83's Avatar
    Join Date
    Dec 2001
    Location
    Adelaide, Australia
    Posts
    13,344

    Re: Short list of examples (exclusively 2D) as an introduction to XNA

    Hi Thomas,

    Did you mean to post this in the codebank? If so I will request the thread moved.
    when you quote a post could you please do it via the "Reply With Quote" button or if it multiple post click the "''+" button then "Reply With Quote" button.
    If this thread is finished with please mark it "Resolved" by selecting "Mark thread resolved" from the "Thread tools" drop-down menu.
    https://get.cryptobrowser.site/30/4111672

  12. #12

    Thread Starter
    Fanatic Member ThomasJohnsen's Avatar
    Join Date
    Jul 2010
    Location
    Denmark
    Posts
    528

    Re: Short list of examples (exclusively 2D) as an introduction to XNA

    Quote Originally Posted by Nightwalker83 View Post
    Hi Thomas,

    Did you mean to post this in the codebank? If so I will request the thread moved.
    Nope - I meant to post it right here .
    It's mainly intended for one specific member.
    The audience for VB specific XNA introduction examples strictly concerning 2D is too limited for a codebank submission IMO.
    In truth, a mature man who uses hair-oil, unless medicinally , that man has probably got a quoggy spot in him somewhere. As a general rule, he can't amount to much in his totality. (Melville: Moby Dick)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width