-
Nov 18th, 2012, 12:34 PM
#1
Thread Starter
Fanatic Member
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:
Public Class Game1
Inherits Microsoft.Xna.Framework.Game
Private WithEvents graphics As GraphicsDeviceManager
Private WithEvents spriteBatch As SpriteBatch
Private myfirsttexture As Texture2D 'Add a global texture.
Public Sub New()
graphics = New GraphicsDeviceManager(Me)
Content.RootDirectory = "Content"
End Sub
Protected Overrides Sub Initialize()
IsMouseVisible = True 'Make the mousepointer visible.
Window.AllowUserResizing = True 'Allow user to resize window.
Window.Title = "Example 1" 'Change the title of the window.
MyBase.Initialize()
End Sub
Protected Overrides Sub LoadContent()
spriteBatch = New SpriteBatch(GraphicsDevice)
myfirsttexture = Content.Load(Of Texture2D)("Koala") 'Loading the texture from the Content project.
MyBase.LoadContent()
End Sub
Protected Overrides Sub UnloadContent()
MyBase.UnloadContent()
End Sub
Protected Overrides Sub Update(ByVal gameTime As GameTime)
If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit() '** Modified to exit on Escape keypress
MyBase.Update(gameTime)
End Sub
Protected Overrides Sub Draw(ByVal gameTime As GameTime)
GraphicsDevice.Clear(Color.Black) '** Modified to be black background instead of CornflowerBlue
spriteBatch.Begin() 'Begin a batch of sprites.
spriteBatch.Draw(myfirsttexture, Vector2.Zero, Color.White) 'Draw our texture to the batch.
spriteBatch.End() 'End the current batch of sprites.
MyBase.Draw(gameTime)
End Sub
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)
-
Nov 18th, 2012, 12:38 PM
#2
Thread Starter
Fanatic Member
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:
Public Class Game1 Inherits Microsoft.Xna.Framework.Game Private WithEvents graphics As GraphicsDeviceManager Private WithEvents spriteBatch As SpriteBatch Private mytexture As Texture2D 'Modified texturename. Public Sub New() graphics = New GraphicsDeviceManager(Me) Content.RootDirectory = "Content" End Sub Protected Overrides Sub Initialize() MyBase.Initialize() IsMouseVisible = True Window.AllowUserResizing = True Window.Title = "Example 2 (Fournier, Fussell, Carpenter modified to generate seamless clouds)" 'New title Dim depth As Integer = 10 'The depth to which the FFC-algorithm will go (2 ^ 10 = 1024) Dim dimension As Integer = 1 << depth 'The dimension of the resulting bitmap (1024 x 1024). mytexture = New Texture2D(GraphicsDevice, dimension, dimension) 'Declare a new texture and initialize it. mytexture.SetData(FournierFussellCarpenterNoise.Generate(depth, 1.0F, Color.Blue, Color.White, Color.DarkGray)) End Sub Protected Overrides Sub LoadContent() MyBase.LoadContent() spriteBatch = New SpriteBatch(GraphicsDevice) End Sub Protected Overrides Sub UnloadContent() MyBase.UnloadContent() mytexture.Dispose() 'Dispose of the texture. End Sub Protected Overrides Sub Update(ByVal gameTime As GameTime) If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit() MyBase.Update(gameTime) End Sub Protected Overrides Sub Draw(ByVal gameTime As GameTime) GraphicsDevice.Clear(Color.Black) spriteBatch.Begin() spriteBatch.Draw(mytexture, Vector2.Zero, Color.White) 'Draw the texture. spriteBatch.End() MyBase.Draw(gameTime) End Sub End Class
A new class called FournierFussellCarpenterNoise (create this class in the main project and copy/paste the code):
vb.net Code:
Public Class FournierFussellCarpenterNoise Private Shared rnd As New Random() Public Shared Function Generate(depth As Integer, roughness As Single, c1 As Color, c2 As Color, c3 As Color) As Color() Dim wh As Integer = 1 << depth 'Actual supposed dimension of the heightmap Dim heightmap(wh - 1, wh - 1) As Single Dim rval(wh * wh - 1) As Color Dim k As Integer = 0 Dim linecount As Integer = 1 Dim stepsize As Integer = 1 << (depth - 1) Dim x, y As Integer Dim xa, xb, xc, ya, yb, yc As Integer 'Actually sets the 4 corner-values to roughness * [0.8; 0.9[, since the texture is seamlessly implemented. heightmap(0, 0) = roughness * (Convert.ToSingle(rnd.NextDouble()) / 10.0F + 0.8F) While stepsize > 0 'The square step------------------------------------------------------ y = stepsize For i As Integer = 1 To linecount x = stepsize ya = y + stepsize yb = y - stepsize yc = y If ya < 0 Then ya += wh If ya >= wh Then ya -= wh If yb < 0 Then yb += wh If yb >= wh Then yb -= wh If yc >= wh Then yc -= wh For j As Integer = 1 To linecount xa = x + stepsize xb = x - stepsize xc = x If xa < 0 Then xa += wh If xa >= wh Then xa -= wh If xb < 0 Then xb += wh If xb >= wh Then xb -= wh If xc >= wh Then xc -= wh heightmap(xc, yc) = (heightmap(xa, ya) + heightmap(xa, yb) + _ heightmap(xb, ya) + heightmap(xb, yb)) / 4.0F + _ roughness * Convert.ToSingle(rnd.NextDouble() - 0.5) x += 2 * stepsize Next y += 2 * stepsize Next 'The diamond step------------------------------------------------------- For i As Integer = 1 To linecount x = 0 y = stepsize * (2 * i - 1) While y <= wh xa = x + stepsize xb = x - stepsize xc = x ya = y + stepsize yb = y - stepsize yc = y If xa < 0 Then xa += wh If xa >= wh Then xa -= wh If xb < 0 Then xb += wh If xb >= wh Then xb -= wh If xc >= wh Then xc -= wh If ya < 0 Then ya += wh If ya >= wh Then ya -= wh If yb < 0 Then yb += wh If yb >= wh Then yb -= wh If yc >= wh Then yc -= wh heightmap(xc, yc) = (heightmap(xc, ya) + heightmap(xc, yb) + _ heightmap(xa, yc) + heightmap(xb, yc)) / 4.0F + _ roughness * Convert.ToSingle(rnd.NextDouble() - 0.5) heightmap(yc, xc) = (heightmap(yc, xa) + heightmap(yc, xb) + _ heightmap(ya, xc) + heightmap(yb, xc)) / 4.0F + _ roughness * Convert.ToSingle(rnd.NextDouble() - 0.5) x += stepsize y += stepsize End While Next linecount *= 2 stepsize \= 2 roughness /= 2 End While 'Conversion to bitmap For i As Integer = 0 To wh - 1 For j As Integer = 0 To wh - 1 Dim v As Single = heightmap(i, j) If v < 0.0F Then v = 0.0F If v > 1.0F Then 'Anything above 1.0 will interpolate colors c2 and c3 rval(k) = Color.Lerp(c2, c3, v - 1.0F) ElseIf v > 0.6F Then 'Anything between 0.6 and 1.0 will interpolate c1 and c2 rval(k) = Color.Lerp(c1, c2, (v - 0.6F) * 2.5F) Else 'Anything below 0.6 will be c1 (color of sky rval(k) = c1 End If k += 1 Next Next Return rval End Function 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)
-
Nov 18th, 2012, 12:42 PM
#3
Thread Starter
Fanatic Member
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:
Public Class Game1 Inherits Microsoft.Xna.Framework.Game Private WithEvents graphics As GraphicsDeviceManager Private WithEvents spriteBatch As SpriteBatch Private mytexture As Texture2D Private location As Vector2 'Location added. Public Sub New() graphics = New GraphicsDeviceManager(Me) Content.RootDirectory = "Content" End Sub Protected Overrides Sub Initialize() MyBase.Initialize() IsMouseVisible = True Window.AllowUserResizing = True Window.Title = "Example 2b (Using mouse input to display seamless clouds)" 'Modified title. Dim depth As Integer = 10 Dim dimension As Integer = 1 << depth mytexture = New Texture2D(GraphicsDevice, dimension, dimension) mytexture.SetData(FournierFussellCarpenterNoise.Generate(depth, 1.0F, Color.Blue, Color.White, Color.DarkGray)) End Sub Protected Overrides Sub LoadContent() MyBase.LoadContent() spriteBatch = New SpriteBatch(GraphicsDevice) End Sub Protected Overrides Sub UnloadContent() MyBase.UnloadContent() mytexture.Dispose() End Sub Protected Overrides Sub Update(ByVal gameTime As GameTime) If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit() location.X = Mouse.GetState.X 'Store the position of the mousepointer in location. location.Y = Mouse.GetState.Y MyBase.Update(gameTime) End Sub Protected Overrides Sub Draw(ByVal gameTime As GameTime) GraphicsDevice.Clear(Color.Black) 'The source of the image being displayed as cut out from the mytexture. Dim sourcerect As New Rectangle(-Convert.ToInt32(location.X), -Convert.ToInt32(location.Y), _ GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height) 'The sprite-batch is drawn using linear wrap on textures. spriteBatch.Begin(Nothing, Nothing, SamplerState.LinearWrap, Nothing, Nothing) spriteBatch.Draw(mytexture, Vector2.Zero, sourcerect, Color.White) 'Draw to (0,0) location using the source rect. spriteBatch.End() MyBase.Draw(gameTime) End Sub 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)
-
Nov 18th, 2012, 12:44 PM
#4
Thread Starter
Fanatic Member
Re: Short list of examples (exclusively 2D) as an introduction to XNA
Example 3: Using a DrawableGameComponent.
vb.net Code:
Public Class Game1 Inherits Microsoft.Xna.Framework.Game Private WithEvents graphics As GraphicsDeviceManager Private WithEvents spriteBatch As SpriteBatch Private myball As New GradientBall(Me, 50, Color.Transparent, Color.Red, New Vector2(4, 7)) 'New gradient ball. Public Sub New() graphics = New GraphicsDeviceManager(Me) Content.RootDirectory = "Content" End Sub Protected Overrides Sub Initialize() IsMouseVisible = True Window.AllowUserResizing = True Window.Title = "Example 3 (Using DrawableGameComponent)" 'Modified title. Components.Add(myball) MyBase.Initialize() End Sub Protected Overrides Sub LoadContent() MyBase.LoadContent() spriteBatch = New SpriteBatch(GraphicsDevice) End Sub Protected Overrides Sub UnloadContent() MyBase.UnloadContent() End Sub Protected Overrides Sub Update(ByVal gameTime As GameTime) If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit() MyBase.Update(gameTime) End Sub Protected Overrides Sub Draw(ByVal gameTime As GameTime) GraphicsDevice.Clear(Color.Black) MyBase.Draw(gameTime) End Sub End Class
A new class called GradientBall (create this class in the main project and copy/paste the code):
vb.net Code:
Public Class GradientBall Inherits DrawableGameComponent Private sprites As SpriteBatch 'A SpriteBatch variable used to draw this component. Private mytexture As Texture2D 'A texture to hold the gradient ball. Private location As Vector2 = Vector2.Zero 'The location of the gradient ball. Private _radius As Integer 'Storing information about this gradient ball. Private _c1 As Color Private _c2 As Color Private _direction As Vector2 Public Sub New(myproject As Game, radius As Integer, c1 As Color, c2 As Color, direction As Vector2) MyBase.New(myproject) _radius = radius _c1 = c1 _c2 = c2 _direction = direction End Sub Public Overrides Sub Initialize() MyBase.Initialize() Generate(_radius, _c1, _c2) End Sub Protected Overrides Sub LoadContent() MyBase.LoadContent() sprites = New SpriteBatch(GraphicsDevice) 'Same declaration as in the game class. End Sub Protected Overrides Sub UnloadContent() MyBase.UnloadContent() mytexture.Dispose() 'Dispose the texture. End Sub Public Overrides Sub Update(ByVal gameTime As GameTime) location += _direction If (location.X + _radius * 2 > GraphicsDevice.Viewport.Width) OrElse (location.X < 0) Then _direction.X = -_direction.X If (location.Y + _radius * 2 > GraphicsDevice.Viewport.Height) OrElse (location.Y < 0) Then _direction.Y = -_direction.Y MyBase.Update(gameTime) End Sub Public Overrides Sub Draw(ByVal gameTime As GameTime) sprites.Begin() 'Draw the texture. sprites.Draw(mytexture, location, Color.White) sprites.End() MyBase.Draw(gameTime) End Sub '------------------------------------------------------------------------------------- Private Sub Generate(radius As Integer, c1 As Color, c2 As Color) Dim diameter As Integer = 2 * radius + 1 Dim rval(diameter * diameter - 1) As Color Dim rsquared As Single = radius * radius Dim k As Integer = 0 Dim l, d As Single For i As Integer = 0 To diameter - 1 d = (i - radius) * (i - radius) For j As Integer = 0 To diameter - 1 l = (d + (j - radius) * (j - radius)) / rsquared rval(k) = Color.Lerp(c2, c1, l) k += 1 Next Next mytexture = New Texture2D(GraphicsDevice, diameter, diameter) mytexture.SetData(rval) End Sub 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)
-
Nov 18th, 2012, 12:45 PM
#5
Thread Starter
Fanatic Member
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:
Public Class Game1 Protected Overrides Sub Initialize() IsMouseVisible = True Window.AllowUserResizing = True Window.Title = "Example 3b (Using DrawableGameComponent multiple instances)" 'Modified title. Dim rnd As New Random 'Declare a random variable and a set of colors both used to generate random balls. Dim mycolorset() As Color = {Color.Red, Color.Blue, Color.Yellow, Color.Purple, Color.Violet, _ Color.Pink, Color.Orange, Color.Magenta, Color.Green, Color.Cyan, _ Color.White, Color.Gold, Color.Gray} For i As Integer = 1 To 100 'Generate 100 randomly colored balls of varying sizes moving in random directions. Dim B As New GradientBall(Me, rnd.Next(30, 70), Color.Transparent, _ mycolorset(rnd.Next(0, mycolorset.GetUpperBound(0))), _ New Vector2(rnd.Next(2, 10), rnd.Next(2, 10))) Components.Add(B) Next MyBase.Initialize() End Sub Protected Overrides Sub Update(ByVal gameTime As GameTime) If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit() If Keyboard.GetState.IsKeyUp(Keys.P) Then MyBase.Update(gameTime) 'Will allow you to pause End Sub 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)
-
Nov 18th, 2012, 12:49 PM
#6
Thread Starter
Fanatic Member
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:
Public Class Game1 Inherits Microsoft.Xna.Framework.Game Private WithEvents graphics As GraphicsDeviceManager Private WithEvents spriteBatch As SpriteBatch Private background As Texture2D Private rtarget As RenderTarget2D Private blendsub As BlendState Private blendrevsub As BlendState Public Sub New() graphics = New GraphicsDeviceManager(Me) Content.RootDirectory = "Content" Dim rnd As New Random For i As Integer = 1 To 20 'Generate 20 gray balls of varying sizes moving in random directions. Dim B As New GradientBall(Me, rnd.Next(30, 70), Color.Transparent, _ Color.Gray, New Vector2(rnd.Next(2, 10), rnd.Next(2, 10))) Components.Add(B) Next End Sub Protected Overrides Sub Initialize() MyBase.Initialize() IsMouseVisible = True Window.AllowUserResizing = True Window.Title = "Example 3c (Various blendstates)" 'Modified title. blendsub = New BlendState() With {.AlphaBlendFunction = BlendFunction.Subtract, _ .ColorBlendFunction = BlendFunction.Subtract, _ .AlphaSourceBlend = Blend.One, .AlphaDestinationBlend = Blend.One, _ .ColorSourceBlend = Blend.One, .ColorDestinationBlend = Blend.One} blendrevsub = New BlendState() With {.AlphaBlendFunction = BlendFunction.ReverseSubtract, _ .ColorBlendFunction = BlendFunction.ReverseSubtract, _ .AlphaSourceBlend = Blend.One, .AlphaDestinationBlend = Blend.One, _ .ColorSourceBlend = Blend.One, .ColorDestinationBlend = Blend.One} End Sub Protected Overrides Sub LoadContent() MyBase.LoadContent() spriteBatch = New SpriteBatch(GraphicsDevice) background = Content.Load(Of Texture2D)("Penguins") rtarget = New RenderTarget2D(GraphicsDevice, background.Width, background.Height) End Sub Protected Overrides Sub UnloadContent() MyBase.UnloadContent() rtarget.Dispose() End Sub Protected Overrides Sub Update(ByVal gameTime As GameTime) If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit() If Keyboard.GetState.IsKeyUp(Keys.P) Then MyBase.Update(gameTime) 'Will allow you to pause End Sub Protected Overrides Sub Draw(ByVal gameTime As GameTime) 'Draw the balls to the rtarget RenderTarget2D GraphicsDevice.SetRenderTarget(rtarget) GraphicsDevice.Clear(Color.Transparent) MyBase.Draw(gameTime) GraphicsDevice.SetRenderTarget(Nothing) 'Blend with the background. If Mouse.GetState.LeftButton = ButtonState.Pressed Then GraphicsDevice.Clear(Color.Black) spriteBatch.Begin(Nothing, blendsub) spriteBatch.Draw(background, Vector2.Zero, Color.White) spriteBatch.Draw(rtarget, Vector2.Zero, Color.White) spriteBatch.End() ElseIf Mouse.GetState.RightButton = ButtonState.Pressed Then GraphicsDevice.Clear(Color.White) spriteBatch.Begin(Nothing, blendrevsub) spriteBatch.Draw(background, Vector2.Zero, Color.White) spriteBatch.Draw(rtarget, Vector2.Zero, Color.White) spriteBatch.End() Else GraphicsDevice.Clear(Color.Black) spriteBatch.Begin(Nothing, BlendState.Additive) spriteBatch.Draw(background, Vector2.Zero, Color.White) spriteBatch.Draw(rtarget, Vector2.Zero, Color.White) spriteBatch.End() End If End Sub 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)
-
Nov 18th, 2012, 12:52 PM
#7
Thread Starter
Fanatic Member
Re: Short list of examples (exclusively 2D) as an introduction to XNA
Example 4: Simple buttons and sprite-fonts.
vb.net Code:
Public Class Game1 Inherits Microsoft.Xna.Framework.Game Private WithEvents graphics As GraphicsDeviceManager Private WithEvents spriteBatch As SpriteBatch Private _myfont As SpriteFont Private WithEvents b1 As SimpleButton Private WithEvents b2 As SimpleButton Private WithEvents b3 As SimpleButton Private displaymessage As String = String.Empty Private displaymiliseconds As Integer = 0 Private displaylocation As Vector2 Public Sub New() graphics = New GraphicsDeviceManager(Me) Content.RootDirectory = "Content" End Sub Protected Overrides Sub Initialize() IsMouseVisible = True Window.AllowUserResizing = True Window.Title = "Example 4 (The simplest of buttons)" 'Modified title. _myfont = Content.Load(Of SpriteFont)("MyFont") 'Load the font Tahoma, 24pt 'Add 3 simple buttons to components b1 = New SimpleButton(Me, "Button1", _myfont, 50, 50, 160, 60) With {.ForeColor = Color.Red, .BackColor = Color.BlanchedAlmond} b2 = New SimpleButton(Me, "Button2", _myfont, 50, 120, 160, 60) With {.ForeColor = Color.Black, .BackColor = Color.Tan} b3 = New SimpleButton(Me, "Button3", _myfont, 50, 190, 160, 60) With {.ForeColor = Color.DarkGoldenrod, .BackColor = Color.OldLace} Components.Add(b1) Components.Add(b2) Components.Add(b3) MyBase.Initialize() End Sub Protected Overrides Sub LoadContent() MyBase.LoadContent() spriteBatch = New SpriteBatch(GraphicsDevice) End Sub Protected Overrides Sub UnloadContent() MyBase.UnloadContent() End Sub Protected Overrides Sub Update(ByVal gameTime As GameTime) MyBase.Update(gameTime) If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit() End Sub Protected Overrides Sub Draw(ByVal gameTime As GameTime) GraphicsDevice.Clear(Color.Black) 'Display a message at the specified location if the duration is set If displaymiliseconds > 0 Then spriteBatch.Begin() spriteBatch.DrawString(_myfont, displaymessage, displaylocation, Color.Blue) spriteBatch.End() displaymiliseconds -= gameTime.ElapsedGameTime.Milliseconds End If MyBase.Draw(gameTime) End Sub Private Sub b1_Click(sender As Object, e As System.EventArgs) Handles b1.Click displaymessage = "Button 1 was pressed." displaylocation = New Vector2(220, 60) displaymiliseconds = 2000 End Sub Private Sub b2_Click(sender As Object, e As System.EventArgs) Handles b2.Click displaymessage = "Button 2 was pressed." displaylocation = New Vector2(220, 130) displaymiliseconds = 2000 End Sub Private Sub b3_Click(sender As Object, e As System.EventArgs) Handles b3.Click displaymessage = "Button 3 was pressed." displaylocation = New Vector2(220, 200) displaymiliseconds = 2000 End Sub End Class
A new class called SimpleButton (create this class in the main project and copy/paste the code):
vb.net Code:
Public Class SimpleButton Inherits DrawableGameComponent Private btn_normal As RenderTarget2D '3 bitmaps to render the button - one for each state. Private btn_hover As RenderTarget2D Private btn_pressed As RenderTarget2D Private points() As VertexPositionTexture 'Vertices of the button (4 total giving 2 textured triangles). Private indices() As Short = {0, 1, 2, 3} 'Indices to the vertices above - 4 indices for 2 textured triangles in a strip. Private _effect As BasicEffect Private _text As String 'Basic information about a button. Private _font As SpriteFont Private _rect As Rectangle Private _forecolor As Color = Color.Black Private _backcolor As Color = Color.Gray Private _isdown As Boolean = False Public Event Click(sender As Object, e As EventArgs) 'Event to be raised upon clicking the button. Public Sub New(myproject As Game, text As String, font As SpriteFont, x As Integer, y As Integer, Width As Integer, Height As Integer) MyBase.New(myproject) _text = text _font = font _rect = New Rectangle(x, y, Width, Height) End Sub Public Property ForeColor As Color Get Return _forecolor End Get Set(value As Color) _forecolor = value End Set End Property Public Property BackColor As Color Get Return _backcolor End Get Set(value As Color) _backcolor = value End Set End Property Public Overrides Sub Initialize() MyBase.Initialize() End Sub Protected Overrides Sub LoadContent() MyBase.LoadContent() generateedges() 'Generate edges and textures for the button. generatetextures() _effect = New BasicEffect(GraphicsDevice) 'Create a texture effect without lighting _effect.TextureEnabled = True _effect.VertexColorEnabled = False _effect.LightingEnabled = False _effect.Texture = btn_normal updateprojection() 'Update the projection to the current viewport 'Add a handler to handle changes in viewport resolution. AddHandler Game.Window.ClientSizeChanged, AddressOf sizechange End Sub Protected Overrides Sub UnloadContent() MyBase.UnloadContent() disposetextures() End Sub Public Overrides Sub Update(ByVal gameTime As GameTime) If _rect.Contains(Mouse.GetState.X, Mouse.GetState.Y) Then If Mouse.GetState.LeftButton = ButtonState.Pressed Then If Not _isdown Then _isdown = True _effect.Texture = btn_pressed 'Texture has changed to pressed state. RaiseEvent Click(Me, Nothing) End If Else _isdown = False _effect.Texture = btn_hover 'Testure has changed to hover state. End If Else _isdown = False _effect.Texture = btn_normal End If MyBase.Update(gameTime) End Sub Public Overrides Sub Draw(ByVal gameTime As GameTime) 'Draw the 2 textured triangles- For Each p As EffectPass In _effect.CurrentTechnique.Passes p.Apply() GraphicsDevice.DrawUserIndexedPrimitives(Of VertexPositionTexture)( _ PrimitiveType.TriangleStrip, points, 0, 4, indices, 0, 2) Next MyBase.Draw(gameTime) End Sub Private Sub sizechange(sender As Object, e As EventArgs) updateprojection() 'Respond to changes in viewport disposetextures() 'RenderTargets must be redrawn. generatetextures() End Sub Private Sub updateprojection() Dim w As Integer = GraphicsDevice.Viewport.Width Dim h As Integer = GraphicsDevice.Viewport.Height 'Use a non-perspective projection corresponding to the viewport looking at (0, 0). _effect.Projection = Matrix.CreateOrthographicOffCenter(0.0F, w, h, 0.0F, 1.0F, 1000.0F) _effect.View = Matrix.CreateLookAt(Vector3.UnitZ, Vector3.Zero, Vector3.Up) End Sub Private Sub generateedges() With _rect points = New VertexPositionTexture() { _ New VertexPositionTexture(New Vector3(.X, .Y, 0.0F), Vector2.Zero), _ New VertexPositionTexture(New Vector3(.X + .Width, .Y, 0.0F), Vector2.UnitX), _ New VertexPositionTexture(New Vector3(.X, .Y + .Height, 0.0F), Vector2.UnitY), _ New VertexPositionTexture(New Vector3(.X + .Width, .Y + .Height, 0.0F), Vector2.One)} End With End Sub Private Sub generatetextures() Dim sb As New SpriteBatch(GraphicsDevice) With _rect Dim loc As Vector2 = (New Vector2(.Width, .Height) - _font.MeasureString(_text)) * 0.5F 'Render to normal state texture using backcolor and forecolor. btn_normal = New RenderTarget2D(GraphicsDevice, .Width, .Height) GraphicsDevice.SetRenderTarget(btn_normal) GraphicsDevice.Clear(_backcolor) sb.Begin() sb.DrawString(_font, _text, loc, _forecolor) sb.End() 'Render to hover state texture using lighter backcolor and forecolor. btn_hover = New RenderTarget2D(GraphicsDevice, .Width, .Height) GraphicsDevice.SetRenderTarget(btn_hover) GraphicsDevice.Clear(_backcolor * 1.2F) sb.Begin() sb.DrawString(_font, _text, loc, _forecolor * 1.2F) sb.End() 'Render to pressed state texture using lighter backcolor and forecolor and slightly moved text. btn_pressed = New RenderTarget2D(GraphicsDevice, .Width, .Height) GraphicsDevice.SetRenderTarget(btn_pressed) GraphicsDevice.Clear(_backcolor * 1.3F) sb.Begin() sb.DrawString(_font, _text, loc + New Vector2(2.0F, 1.0F), _forecolor * 1.3F) sb.End() GraphicsDevice.SetRenderTarget(Nothing) End With End Sub Private Sub disposetextures() btn_normal.Dispose() btn_hover.Dispose() btn_pressed.Dispose() End Sub 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)
-
Nov 18th, 2012, 12:55 PM
#8
Thread Starter
Fanatic Member
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:
Public Class Game1 Inherits Microsoft.Xna.Framework.Game Private WithEvents graphics As GraphicsDeviceManager Private WithEvents spriteBatch As SpriteBatch Private mymap As TiledMap Public Sub New() graphics = New GraphicsDeviceManager(Me) Content.RootDirectory = "Content" End Sub Protected Overrides Sub Initialize() mymap = New TiledMap(Me, 0.04F) Components.Add(mymap) IsMouseVisible = True Window.AllowUserResizing = True Window.Title = "Example 5 (A tiled map using Perlin simplex-noise)" 'Modified title. MyBase.Initialize() End Sub Protected Overrides Sub LoadContent() spriteBatch = New SpriteBatch(GraphicsDevice) MyBase.LoadContent() End Sub Protected Overrides Sub UnloadContent() MyBase.UnloadContent() End Sub Protected Overrides Sub Update(ByVal gameTime As GameTime) If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit() MyBase.Update(gameTime) End Sub Protected Overrides Sub Draw(ByVal gameTime As GameTime) GraphicsDevice.Clear(Color.Black) MyBase.Draw(gameTime) End Sub End Class
A new class called TiledMap (create this class in the main project and copy/paste the code):
vb.net Code:
Public Class TiledMap Inherits DrawableGameComponent Private sprites As SpriteBatch Private tile_texture As Texture2D Private mappos_x, mappos_y, pixel_x, pixel_y As Integer Private _rect As Rectangle = New Rectangle(0, 0, 64, 64) Private _scale As Single Private _oldmstate As MouseState Public Sub New(myproject As Game, scale As Single) MyBase.New(myproject) _scale = scale End Sub Public Overrides Sub Initialize() MyBase.Initialize() End Sub Protected Overrides Sub LoadContent() MyBase.LoadContent() sprites = New SpriteBatch(GraphicsDevice) tile_texture = Game.Content.Load(Of Texture2D)("SmallTextures") End Sub Protected Overrides Sub UnloadContent() MyBase.UnloadContent() End Sub Public Overrides Sub Update(ByVal gameTime As GameTime) Dim mstate As MouseState = Mouse.GetState If mstate.LeftButton = ButtonState.Pressed AndAlso Game.IsActive Then If _oldmstate.LeftButton = ButtonState.Pressed Then Dim deltax As Integer = _oldmstate.X - mstate.X Dim deltay As Integer = _oldmstate.Y - mstate.Y mappos_x += deltax \ 64 mappos_y += deltay \ 64 pixel_x -= deltax Mod 64 pixel_y -= deltay Mod 64 While pixel_x < 0 pixel_x += 64 mappos_x += 1 End While While pixel_x >= 64 pixel_x -= 64 mappos_x -= 1 End While While pixel_y < 0 pixel_y += 64 mappos_y += 1 End While While pixel_y >= 64 pixel_y -= 64 mappos_y -= 1 End While End If End If _oldmstate = mstate MyBase.Update(gameTime) End Sub Public Overrides Sub Draw(ByVal gameTime As GameTime) Dim w As Integer = GraphicsDevice.Viewport.Width Dim h As Integer = GraphicsDevice.Viewport.Height Dim wtile As Integer = w \ 64 + 1 Dim htile As Integer = h \ 64 + 1 Dim loc, mappos As Vector2 Dim perlin As Single sprites.Begin() For i As Integer = 0 To wtile loc.X = pixel_x + 64.0F * (i - 1) mappos.X = (mappos_x + i) * _scale For j As Integer = 0 To htile loc.Y = pixel_y + 64.0F * (j - 1) mappos.Y = (mappos_y + j) * _scale perlin = PerlinNoise.PerlinSimplex2D(mappos) If perlin < 0.0F Then 'water _rect.X = 0 ElseIf perlin < 0.6F Then 'grass _rect.X = 64 ElseIf perlin < 0.8F Then 'forest _rect.X = 128 ElseIf perlin < 0.9F Then 'desert _rect.X = 192 Else 'mountain _rect.X = 256 End If sprites.Draw(tile_texture, loc, _rect, Color.White) Next Next sprites.End() MyBase.Draw(gameTime) End Sub End Class
A new class called PerlinNoise (create this class in the main project and copy/paste the code):
vb.net Code:
Public Class PerlinNoise 'Created on the basis on this excellent article explaining simplex noise: 'Stefan Gustavson, Linköping University, Sweden (stegu@itn.liu.se), 2005-03-22 Private Shared gradients() As Vector2 = _ {New Vector2(1.0F, 1.0F), New Vector2(-1.0F, 1.0F), New Vector2(1.0F, -1.0F), New Vector2(-1.0F, -1.0F), _ New Vector2(1.0F, 0.0F), New Vector2(-1.0F, 0.0F), New Vector2(1.0F, 0.0F), New Vector2(-1.0F, 0.0F), _ New Vector2(0.0F, 1.0F), New Vector2(0.0F, 1.0F), New Vector2(0.0F, -1.0F), New Vector2(0.0F, -1.0F)} Private Shared bytehash() As Byte = _ {&H97, &HA0, &H89, &H5B, &H5A, &HF, &H83, &HD, &HC9, &H5F, &H60, &H35, &HC2, &HE9, &H7, &HE1, _ &H8C, &H24, &H67, &H1E, &H45, &H8E, &H8, &H63, &H25, &HF0, &H15, &HA, &H17, &HBE, &H6, &H94, _ &HF7, &H78, &HEA, &H4B, &H0, &H1A, &HC5, &H3E, &H5E, &HFC, &HDB, &HCB, &H75, &H23, &HB, &H20, _ &H39, &HB1, &H21, &H58, &HED, &H95, &H38, &H57, &HAE, &H14, &H7D, &H88, &HAB, &HA8, &H44, &HAF, _ &H4A, &HA5, &H47, &H86, &H8B, &H30, &H1B, &HA6, &H4D, &H92, &H9E, &HE7, &H53, &H6F, &HE5, &H7A, _ &H3C, &HD3, &H85, &HE6, &HDC, &H69, &H5C, &H29, &H37, &H2E, &HF5, &H28, &HF4, &H66, &H8F, &H36, _ &H41, &H19, &H3F, &HA1, &H1, &HD8, &H50, &H49, &HD1, &H4C, &H84, &HBB, &HD0, &H59, &H12, &HA9, _ &HC8, &HC4, &H87, &H82, &H74, &HBC, &H9F, &H56, &HA4, &H64, &H6D, &HC6, &HAD, &HBA, &H3, &H40, _ &H34, &HD9, &HE2, &HFA, &H7C, &H7B, &H5, &HCA, &H26, &H93, &H76, &H7E, &HFF, &H52, &H55, &HD4, _ &HCF, &HCE, &H3B, &HE3, &H2F, &H10, &H3A, &H11, &HB6, &HBD, &H1C, &H2A, &HDF, &HB7, &HAA, &HD5, _ &H77, &HF8, &H98, &H2, &H2C, &H9A, &HA3, &H46, &HDD, &H99, &H65, &H9B, &HA7, &H2B, &HAC, &H9, _ &H81, &H16, &H27, &HFD, &H13, &H62, &H6C, &H6E, &H4F, &H71, &HE0, &HE8, &HB2, &HB9, &H70, &H68, _ &HDA, &HF6, &H61, &HE4, &HFB, &H22, &HF2, &HC1, &HEE, &HD2, &H90, &HC, &HBF, &HB3, &HA2, &HF1, _ &H51, &H33, &H91, &HEB, &HF9, &HE, &HEF, &H6B, &H31, &HC0, &HD6, &H1F, &HB5, &HC7, &H6A, &H9D, _ &HB8, &H54, &HCC, &HB0, &H73, &H79, &H32, &H2D, &H7F, &H4, &H96, &HFE, &H8A, &HEC, &HCD, &H5D, _ &HDE, &H72, &H43, &H1D, &H18, &H48, &HF3, &H8D, &H80, &HC3, &H4E, &H42, &HD7, &H3D, &H9C, &HB4, _ &H97, &HA0, &H89, &H5B, &H5A, &HF, &H83, &HD, &HC9, &H5F, &H60, &H35, &HC2, &HE9, &H7, &HE1, _ &H8C, &H24, &H67, &H1E, &H45, &H8E, &H8, &H63, &H25, &HF0, &H15, &HA, &H17, &HBE, &H6, &H94, _ &HF7, &H78, &HEA, &H4B, &H0, &H1A, &HC5, &H3E, &H5E, &HFC, &HDB, &HCB, &H75, &H23, &HB, &H20, _ &H39, &HB1, &H21, &H58, &HED, &H95, &H38, &H57, &HAE, &H14, &H7D, &H88, &HAB, &HA8, &H44, &HAF, _ &H4A, &HA5, &H47, &H86, &H8B, &H30, &H1B, &HA6, &H4D, &H92, &H9E, &HE7, &H53, &H6F, &HE5, &H7A, _ &H3C, &HD3, &H85, &HE6, &HDC, &H69, &H5C, &H29, &H37, &H2E, &HF5, &H28, &HF4, &H66, &H8F, &H36, _ &H41, &H19, &H3F, &HA1, &H1, &HD8, &H50, &H49, &HD1, &H4C, &H84, &HBB, &HD0, &H59, &H12, &HA9, _ &HC8, &HC4, &H87, &H82, &H74, &HBC, &H9F, &H56, &HA4, &H64, &H6D, &HC6, &HAD, &HBA, &H3, &H40, _ &H34, &HD9, &HE2, &HFA, &H7C, &H7B, &H5, &HCA, &H26, &H93, &H76, &H7E, &HFF, &H52, &H55, &HD4, _ &HCF, &HCE, &H3B, &HE3, &H2F, &H10, &H3A, &H11, &HB6, &HBD, &H1C, &H2A, &HDF, &HB7, &HAA, &HD5, _ &H77, &HF8, &H98, &H2, &H2C, &H9A, &HA3, &H46, &HDD, &H99, &H65, &H9B, &HA7, &H2B, &HAC, &H9, _ &H81, &H16, &H27, &HFD, &H13, &H62, &H6C, &H6E, &H4F, &H71, &HE0, &HE8, &HB2, &HB9, &H70, &H68, _ &HDA, &HF6, &H61, &HE4, &HFB, &H22, &HF2, &HC1, &HEE, &HD2, &H90, &HC, &HBF, &HB3, &HA2, &HF1, _ &H51, &H33, &H91, &HEB, &HF9, &HE, &HEF, &H6B, &H31, &HC0, &HD6, &H1F, &HB5, &HC7, &H6A, &H9D, _ &HB8, &H54, &HCC, &HB0, &H73, &H79, &H32, &H2D, &H7F, &H4, &H96, &HFE, &H8A, &HEC, &HCD, &H5D, _ &HDE, &H72, &H43, &H1D, &H18, &H48, &HF3, &H8D, &H80, &HC3, &H4E, &H42, &HD7, &H3D, &H9C, &HB4} Public Shared Function PerlinSimplex2D(loc As Vector2) As Single Static F As Single = Convert.ToSingle(Math.Sqrt(0.75)) - 0.5F Static G As Single = 0.5F - Convert.ToSingle(Math.Sqrt(1.0 / 12.0)) Dim s As Single = (loc.X + loc.Y) * F Dim i As Integer = fastfloor(loc.X + s) Dim j As Integer = fastfloor(loc.Y + s) Dim t As Single = (i + j) * G Dim v0 As New Vector2(loc.X - i + t, loc.Y - j + t) Dim v1 As New Vector2(v0.X + G, v0.Y + G) Dim v2 As New Vector2(v1.X + G - 1.0F, v1.Y + G - 1.0F) Dim ii As Integer = i And &HFF Dim jj As Integer = j And &HFF Dim gi0 As Integer = bytehash(ii + bytehash(jj)) Mod 12 Dim gi1 As Integer Dim gi2 As Integer = bytehash(ii + 1 + bytehash(jj + 1)) Mod 12 If v0.X > v0.Y Then v1.X -= 1.0F gi1 = bytehash(ii + 1 + bytehash(jj)) Mod 12 Else v1.Y -= 1.0F gi1 = bytehash(ii + bytehash(jj + 1)) Mod 12 End If Dim t0 As Single = 0.5F - v0.LengthSquared Dim t1 As Single = 0.5F - v1.LengthSquared Dim t2 As Single = 0.5F - v2.LengthSquared Dim d0, d1, d2 As Single If t0 < 0.0F Then d0 = 0.0F Else t0 *= t0 d0 = t0 * t0 * Vector2.Dot(gradients(gi0), v0) End If If t1 < 0.0F Then d1 = 0.0F Else t1 *= t1 d1 = t1 * t1 * Vector2.Dot(gradients(gi1), v1) End If If t2 < 0.0F Then d2 = 0.0F Else t2 *= t2 d2 = t2 * t2 * Vector2.Dot(gradients(gi2), v2) End If Return 70.0F * (d0 + d1 + d2) End Function Public Shared Function Generate(dimension As Integer, scale As Single, offset As Vector2, c1 As Color, c2 As Color) As Color() Dim v As New Vector2 Dim k As Integer = 0 Dim rval(dimension * dimension - 1) As Color For i As Integer = 0 To dimension - 1 v.X = i * scale + offset.X v.Y = offset.Y For j As Integer = 0 To dimension - 1 rval(k) = Color.Lerp(c1, c2, (PerlinSimplex2D(v) + 1.0F) / 2.0F) v.Y += scale k += 1 Next Next Return rval End Function Private Shared Function fastfloor(val As Single) As Integer Return Convert.ToInt32(If(val > 0, Int(val), Int(val) - 1)) End Function 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 , 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)
-
Nov 18th, 2012, 01:01 PM
#9
Thread Starter
Fanatic Member
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:
Public Class Game1
Inherits Microsoft.Xna.Framework.Game
Private WithEvents graphics As GraphicsDeviceManager
Private WithEvents spriteBatch As SpriteBatch
Private myeffects() As Effect
Private mytexture As Texture2D
Private activeeffect As Effect = Nothing
Public Sub New()
graphics = New GraphicsDeviceManager(Me)
Content.RootDirectory = "Content"
End Sub
Protected Overrides Sub Initialize()
IsMouseVisible = True
Window.AllowUserResizing = True
Window.Title = "Example 6 (Using simple HLSL pixelshaders to generate various effects 1-7)" 'Modified title.
MyBase.Initialize()
End Sub
Protected Overrides Sub LoadContent()
spriteBatch = New SpriteBatch(GraphicsDevice)
mytexture = Content.Load(Of Texture2D)("Penguins")
'These are the simple filters used in this example. No efficiency considerations have been made to either filter
'except that Gauss blur is implemented in 2 passes (horizontal + vertical) lowering the number of computations.
'For more advanced bilateral and median filters, using HLSL will be difficult, since there is a limit on the number
'of computations allowed at each pixel (ie. rendering real-time is nigh impossible).
myeffects = New Effect() {Content.Load(Of Effect)("Grayscale"), _
Content.Load(Of Effect)("LuminanceITU_R"), _
Content.Load(Of Effect)("LuminanceCCIR601"), _
Content.Load(Of Effect)("Sepia"), _
Content.Load(Of Effect)("Saturate"), _
Content.Load(Of Effect)("Sobel"), _
Content.Load(Of Effect)("GaussBlur")}
With myeffects(4) 'Saturate
.Parameters("SatValue").SetValue(1.4F) 'Set saturation to 1.4f
End With
With myeffects(5) 'Sobel
.Parameters("Width").SetValue(mytexture.Width) 'Supply dimensions of background
.Parameters("Height").SetValue(mytexture.Height)
.Parameters("ForeColor").SetValue(New Vector4(0.0F, 0.0F, 0.0F, 0.0F)) 'Supply colors (black and white in this case)
.Parameters("ForeColor").SetValue(New Vector4(1.0F, 1.0F, 1.0F, 0.0F))
End With
With myeffects(6) 'Gauss
.Parameters("Width").SetValue(mytexture.Width) 'Supply dimensions of background
.Parameters("Height").SetValue(mytexture.Height)
End With
MyBase.LoadContent()
End Sub
Protected Overrides Sub UnloadContent()
MyBase.UnloadContent()
End Sub
Protected Overrides Sub Update(ByVal gameTime As GameTime)
If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit()
If Keyboard.GetState.IsKeyDown(Keys.D1) Then
activeeffect = myeffects(0)
ElseIf Keyboard.GetState.IsKeyDown(Keys.D2) Then
activeeffect = myeffects(1)
ElseIf Keyboard.GetState.IsKeyDown(Keys.D3) Then
activeeffect = myeffects(2)
ElseIf Keyboard.GetState.IsKeyDown(Keys.D4) Then
activeeffect = myeffects(3)
ElseIf Keyboard.GetState.IsKeyDown(Keys.D5) Then
activeeffect = myeffects(4)
ElseIf Keyboard.GetState.IsKeyDown(Keys.D6) Then
activeeffect = myeffects(5)
ElseIf Keyboard.GetState.IsKeyDown(Keys.D7) Then
activeeffect = myeffects(6)
Else
activeeffect = Nothing
End If
MyBase.Update(gameTime)
End Sub
Protected Overrides Sub Draw(ByVal gameTime As GameTime)
GraphicsDevice.Clear(Color.Black)
spriteBatch.Begin(Nothing, Nothing, Nothing, Nothing, Nothing, activeeffect)
spriteBatch.Draw(mytexture, Vector2.Zero, Color.White)
spriteBatch.End()
MyBase.Draw(gameTime)
End Sub
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)
-
Nov 18th, 2012, 01:08 PM
#10
Thread Starter
Fanatic Member
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 {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:
Public Class Game1 Inherits Microsoft.Xna.Framework.Game Private WithEvents graphics As GraphicsDeviceManager Private WithEvents spriteBatch As SpriteBatch Private background As Texture2D Private ghost As Texture2D Private ghost_location As Vector2 Private gradientball As Texture2D Private display As RenderTarget2D = Nothing Private screamsound As SoundEffect Private rnd As New Random Private blend_min As BlendState = New BlendState With _ {.AlphaBlendFunction = BlendFunction.Min, .AlphaSourceBlend = Blend.One, .AlphaDestinationBlend = Blend.One, _ .ColorBlendFunction = BlendFunction.Min, .ColorSourceBlend = Blend.One, .ColorDestinationBlend = Blend.One} Public Sub New() graphics = New GraphicsDeviceManager(Me) Content.RootDirectory = "Content" End Sub Protected Overrides Sub Initialize() IsMouseVisible = True Window.AllowUserResizing = True AddHandler Window.ClientSizeChanged, AddressOf picknewlocation MyBase.Initialize() End Sub Protected Overrides Sub LoadContent() spriteBatch = New SpriteBatch(GraphicsDevice) background = Content.Load(Of Texture2D)("Penguins") ghost = Content.Load(Of Texture2D)("LittleGhost") screamsound = Content.Load(Of SoundEffect)("Scream") generate_gradientball(100, Color.Black, Color.White) picknewlocation() MyBase.LoadContent() End Sub Protected Overrides Sub UnloadContent() display.Dispose() gradientball.Dispose() MyBase.UnloadContent() End Sub Protected Overrides Sub Update(ByVal gameTime As GameTime) If Keyboard.GetState.IsKeyDown(Keys.Escape) Then Me.Exit() Dim u As Vector2 = New Vector2(Mouse.GetState.X, Mouse.GetState.Y) Dim v As Vector2 = New Vector2(ghost_location.X + ghost.Width \ 2, ghost_location.Y + ghost.Height \ 2) If Vector2.Distance(u, v) < 8 Then screamsound.Play() picknewlocation() End If MyBase.Update(gameTime) End Sub Protected Overrides Sub Draw(ByVal gameTime As GameTime) GraphicsDevice.Clear(Color.Black) spriteBatch.Begin() spriteBatch.Draw(gradientball, New Vector2(Mouse.GetState.X - gradientball.Width \ 2, _ Mouse.GetState.Y - gradientball.Height \ 2), Color.White) spriteBatch.End() spriteBatch.Begin(Nothing, blend_min) spriteBatch.Draw(display, Vector2.Zero, Color.White) spriteBatch.End() MyBase.Draw(gameTime) End Sub Private Sub picknewlocation() If display IsNot Nothing Then display.Dispose() display = New RenderTarget2D(GraphicsDevice, background.Width, background.Height) ghost_location = New Vector2(rnd.Next(0, background.Width - ghost.Width), rnd.Next(0, background.Height - ghost.Height)) GraphicsDevice.SetRenderTarget(display) spriteBatch.Begin() spriteBatch.Draw(background, Vector2.Zero, Color.White) spriteBatch.Draw(ghost, ghost_location, Color.White) spriteBatch.End() GraphicsDevice.SetRenderTarget(Nothing) End Sub Private Sub generate_gradientball(radius As Integer, c1 As Color, c2 As Color) Dim diameter As Integer = 2 * radius + 1 Dim rval(diameter * diameter - 1) As Color Dim rsquared As Single = radius * radius Dim k As Integer = 0 Dim l, d As Single For i As Integer = 0 To diameter - 1 d = (i - radius) * (i - radius) For j As Integer = 0 To diameter - 1 l = (d + (j - radius) * (j - radius)) / rsquared rval(k) = Color.Lerp(c2, c1, l) k += 1 Next Next gradientball = New Texture2D(GraphicsDevice, diameter, diameter) gradientball.SetData(rval) End Sub 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)
-
Nov 19th, 2012, 12:52 AM
#11
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
-
Nov 19th, 2012, 07:58 AM
#12
Thread Starter
Fanatic Member
Re: Short list of examples (exclusively 2D) as an introduction to XNA
Originally Posted by Nightwalker83
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|