I would like to iterate through an array that covers every pixel on my screen. i.e:
for (int y = 598; y > 0; y--)
{
for (int x = 798; x > 0; x--)
{
if (grains[x][y])
{
spriteBatch.Draw(Grain, new Vector2(x,y), Color.White);
}
}
}
...my texture is a 1x1 pixel image that is drawn to the screen when the array value is true. It runs decent -- but there is definitely lag the more screen I cover. Is there a better way to accomplish what I am trying to achieve?
Instead of using X x Y individual sprites, create a single image, and set the pixels appropriately. Then just render the entire image as a texture on a single sprite.
The jagged array is most likely not the problem - rather the nearly half-million sprites.
The problem is that you're spending alot of CPU time within the drawing method each frame. The Draw method of your Game instance will always be called as often as possible, whether in Fixed Time or not. Given that, you always want to make sure you're spending as little time there as possible, which means you want to place most of the work on the GPU.
The nested for-loops as well as all the calls to spriteBatch.Draw are going to use the much slower CPU, especially when your loop gets bigger and bigger, which means delayed drawing.
If you want to do per-pixel calculations, per Draw, each frame, then the best way to go about it is to place the work on the GPU and use a pixel shader. You could accomplish your own problem by creating one texture the size you want and passing an array to the shader that holds your "on or off" information, among other ways to accomplish the same goal.
How To: Apply a Pixel Shader to Sprites
Related
I just started making my own mapgenerator. I finished the perlin noise yesterday. The problem now is that it gives me a texture with more wholes in it than a swiss cheese!... So i planned to make some code to cut out one of the wholes with some kind of automatic algorithm. Later i could blend them together on some background and make many different sized caves and ores and so on. Now i need an algorithm that can cut out one cave and put it on an alpha channel.
The way i would do it now is making my own method wich needs X and Y as parameter. This method would check if the pixel at the Coordinates is black. If it is it puts this pixel down on a 2d-Texture and it would call itself with the Coordinates of the pixels that are located next to the pixel it checked. if the pixel is not black it does nothing. I would also have to make sure the pixels will only get checked once.
Now do you think this is a clever way of generating my terrain, ores, caves, etc?
I'm working on a simple 2D Real time strategy game using XNA. Right now I have reached the point where I need to be able to click on the sprite for a unit or building and be able to reference the object associated with that sprite.
From the research I have done over the last three days I have found many references on how to do "Mouse picking" in 3D which does not seem to apply to my situation.
I understand that another way to do this is to simply have an array of all "selectable" objects in the world and when the player clicks on a sprite it checks the mouse location against the locations of all the objects in the array. the problem I have with this approach is that it would become rather slow if the number of units and buildings grows to larger numbers. (it also does not seem very elegant) so what are some other ways I could do this. (Please note that I have also worked over the ideas of using a Hash table to associate the object with the sprite location, and using a 2 dimensional array where each location in the array represents one pixel in the world. once again they seem like rather clunky ways of doing things.)
For up to hundreds of units, it should be fast enough to simply do a linear search O(n) over all the units in the world if the click regions are circles or rectangles. Especially seeing as it will be once per click, not once per frame.
If your units are not circular or rectangular, check against a bounding circle or rectangle first, and if that passes check against the more complicated bounding shape.
For a more detailed answer, here's my answer to a similar question about space partitioning. There I mention bucketed grids and quadtrees as potential structures for performance optimisation.
But you should never do performance optimisation until you have tested and actually do have a performance problem!
If you have a class that manages drawabel objects you could have a static int that you increase every time you make a new object, and save the old one as a local instance of Color in the drawabel object. You can then use the .Net type converter to make its to bye arrays and back, dont remember its name and im on my phoneon a train so can't check for you im afraid.
When you build the color from the byte array just remember to max the alpha channel, and if you happen to get too many objects you might overrun the indexes you can use.. not sure what to do then... probably have all your objects reaquire new colors from 0:0:0:255 again since hopefully some old ones are no longer in use :P
Not sure i made alot of sense but since im on a train thats all i can give you, sorry :)
You could use pixel perfect picking, which scales very well to massive numbers of objects (and has the advantage of being pixel perfect).
Essentially you render your scene using a unique colour for each object. Then you resolve the backbuffer into a texture and get the texture data back, finally you can simply check the pixel underneath the mouse and find out which object the mouse is on.
You can be clever about the information you get back, you can request just the single pixel the mouse is on top of.
Color[] pixel = new Color[1];
texture.GetData(pixel, mousePosition.Y * texture.Width + mousePosition.x, 1);
//pixel[0] == colour of the item the mouse is over. You can now look this up in a dictionary<Color, item>
You should be careful not to stall the pipeline by doing this (causing the CPU to wait for the GPU to render things). The best way to do this is to swap between 2 render targets, and always GetData from the render target you used last frame, this means the data is a frame out of date, but no human has fast enough reactions to notice.
Addendum in response to your comment.
To assign a unique colour to each object, simply increment a byte for each object. When that byte overflows, increment another, and when that one overflows increment another; Then you can use those three bytes as Red, Green and Blue. Remeber to keep alpha at max value, you don't want any see through objects!
To resolve the backbuffer is slightly changed in XNA4. Now you must render to a rendertarget and resolve that. To do this is pretty simple, and outlined by Shawn Hargreaves here
I am writing a map editing program for a 2D game using XNA. To create a Texture2D for all of the tiles that a map requires takes too long.
Are there any alternatives to using textures for drawing with XNA?
I attempted to create just one texture per tile set instead of a texture for every tile in a tile set, but there is a limit to the size of textures and I could not fit all the tiles of a tile set into one texture.
Currently the program contains all the would-be textures in memory as Bitmap objects. Is there a way to simply draw a Bitmap object to the screen in XNA? I have searched but I cannot find any information on this. This approach would avoid having to create textures altogether, however any tinting or effects I would have to do to the bitmap directly.
Is there any reason you haven't considered loading the image one time and then passing in x and y offset coordinates to the pixel shader?
You would basically set the C# up like this:
myGraphicsDevice.Textures[0] = whateverYourGiantMapTextureIs;
foreach(MapChunk chunk in mapChunks) {
myShader.Effect.Parameters["xOffset"] = chunk.XOffset;
myShader.Effect.Parameters["yOffset"] = chunk.YOffset;
myGraphicsDevice.DrawIndexedPrimitives( your chunk drawing code here );
}
And then the shader code like this:
float4x4 World;
float4x4 View;
float4x4 Projection;
float xOffset;
float yOffset;
sampler TextureSampler;
struct VS_INPUT {
float4 Position : POSITION0;
float4 Color : COLOR0;
};
VS_INPUT Transform(VS_INPUT Input) {
VS_INPUT Output;
float4 worldPosition = mul(Input.Position, World);
float4 viewPosition = mul(worldPosition, View);
Output.Position = mul(viewPosition, Projection);
Output.Color = Input.Color;
return Output;
}
float4 ColorTexture(VS_INPUT Input) : COLOR0{
return Input.Color.rgba * tex2D(TextureSampler, float2(xOffset, yOffset));
}
technique TransformColorTexture {
pass P0 {
VertexShader = compile vs_2_0 Transform();
PixelShader = compile ps_2_0 ColorTexture();
}
}
The shader code might need some fitting into your existing code but otherwise it should do the trick.
Using one texture per tile is not very efficient. Especially since it means you cannot do batching (in any real sense).
If you NEED to have them as separate textures in your content-project for some reason (easier to edit one tile, etc), you can quite easily compile them into tilemaps after loading.
How you do this is basicly:
1: Load a number of tiles (lets say 40 32*32 tiles for now)
2: Figure out a nice texture-size for the tilemap:
square root of 40 is 6.something, so we round up to 7. 7*32 is 224, which is nice, but 256 is nicer, so lets make the texture 256x256. (you can make code that figures out this on the fly)
3: Create a Rendertarget2D which is the desired size.
4: Activate rendertarget.
5: Render tiles on rendertarget:
int x, y = 0;
foreach (var tile in allTiles)
{
RenderTile(tile, x*32, y*32);
x++;
if (x >= 8)
{
x = 0;
y++;
}
}
To betch-render you have a vertex-buffer with 4 * 40 vertices. each set of 4 has a value indicating index of the quad it belongs to (0,1,2,etc...). In your shader you have an array of matrixes[40] for position of the tiles, as well as an array of tileIndex (int[40]) for knowing which tile to render from the tilemap.
I'm sorry, but I don't have time to write all the shader-code right now :s
An other trick I have used in our games is pre-rendering the level onto large tiles (640x360), which reduces the number of draw-calls by a great deal, especially when dealing with 5+ layers of tiles from different tilesets. Only thing is that it does not work with dynamic tiles (animated tiles, etc), but you can mark those and render them normally if you want...
Since you need to use a custom image format, if you want (for speed) you can attempt to write custom content pipeline importers and processors for XNA ( http://msdn.microsoft.com/en-us/library/bb447754.aspx ), but this may be overkill for what you need to do.
I see you want to design the GUI as easily as possible, even if these issues force you to use a language like C++ so you can use DirectX. In Visual C++ you should still be able to take advantage of visual Windows Forms layout if you are using Visual Studio.
Unfortunately, as far as I know, there is no way to directly draw a bitmap to the screen in XNA; it requires that everything is mapped to the Texture objects, which are by default buffered to the graphics card. It sounds like you're talking about a lot of tiles, though, if they won't all fit on the maximum allowed texture (I can't remember whether that was 1024 or 4096 square...) - have you tried having an unbuffered texture for speed purposes? Another alternative would be to lazy-load your tilesets into textures so the user didn't have to wait for them all to load - for an editor, using a bright pink fallback color is usually acceptable while it loads.
Also, is there anything inherently required to write your tool in XNA? Since it sounds like you're writing the tool separately from the game engine itself, you may find some very acceptable solutions in WPF, including drawing directly from BitmapSources and some utilities for your UI.
Assuming all the tiles that a map require existing images that are simply placing on a screen to lay out a tile map? Or are you making images in this map editor and want to save them out?
I read this, and your other post about textures - If they are all ready defined images that you want to use in your game couldnt you just include them in the content folder and reference them there? This allows XNA to compile the textures in the xnb format and you shouldn't have the problems you are explaining.
However if we are talking completely dynamic - or you are crafting one big image from the layout of the tiles (instead of doing something like a tile map) then I am not sure how to approach the issue.
If multiple tiles use the same texture, it will be enough to load it just once.
If the user includes textures in some file format, you could automatically convert it to a texture/image format which is faster for your needs.
Are you trying draw them all using a single thread of execution?
Try multi-threading your game. Threading in C# is quite easy and is supported by XNA.
Instead of looking at your screen as a whole, try splitting it into two (or more) portions. You may need to re-write the function you're using to Draw (I sure hope you didn't just dump everything directly in your Draw() method!!) to take in coordinates setting the boundaries of your draw regions.
I've been producing this 2d tile-based game engine to be used in several projects.
I have a class called "ScreenObject" which is mainly composed of a
Dictionary<Point, Tile>
The Point key is to show where to render the Tile on the screen, and the Tile contains one or more textures to be drawn at that point. This ScreenObject is where the tiles will be modified, deleted, added, etc..
My original method of drawing the tiles in the testing I've done was to iterate through the ScreenObject and draw each quad at each location separately. From what I've read, this is a massive waste of resources. It wasn't horribly slow in the testing, but after I've completed the animation classes and effect classes, I'm sure it would be extremely slow.
And one last thing, if you wouldn't mind..
As I said before, the Tile class can contain multiple textures to be drawn at the Point location on the screen.
I recognize possibly two options for me here. Either add a quad at that location for each texture to be drawn, or, somehow.. use a multiple texture for the same quad (if it's possible). Even if each tile contained one texture only, that would be 64 quads to be drawn on the screen. Most of the tiles will contain 2-5 textures, so the number of total quads would increase dramatically with this method. Would it be feasible to add a quad for each new texture, or am I ignoring a better way to do this?
I'd suspect using a Dictionary would be slower than just using a straight array. If your world consists of 512x512 tiles then you allocate an array 512x512 (262144) in length. YTou can get any given tile in that array by using "array[x + (y * 512)]".
You know how many tiles there are so store an array where each either points to the tile at that position or has an index to the tile in a list (you will likely save memory this way as you can probably keep all your tiles in an array less than 65536, or maybe even 256, in size and thus store the index as a 16-bit.
You then find the area of your array you want to render. To do this optimally you want to avoid switching textures as much as possible. So first thing I'd check to see how big your tiles are I'd then try and combine as many of the texture into 1 big texture. Then set your UVs to sample a sub portion of this large texture. This way you should be able to limit the number of textures in use with a few big textures. Of course you will probably find that a given tile set (lets say rocky ground, for example) will use the same groups of textures. There may also be some blending across to grass somewhere so it may well be worth holding the grass textures in BOTH big texture to avoid doing so many texture swaps. ie sacrifice video memory for speed.
You then iterate over the visible portion of the array and draw all the tiles using texture 1 and then all tiles using texture 2 and so on.
I would recommend to use single VAO object composed from triangles + indices. Calculate position on client side and just update it on each frame (streaming).
Use texture atlas to store everything in single texture (to avoid switching states). You can use texture packer tool.
Render in one shot (if you have depth buffer enabled). Otherwise render first objects that opaque and then render everything that should be blended.
I'm quite new to the world of 2D-Engines. I figured out how to load images and display those as sprites and stuff, but theres one question that bugs me.
For instance, when a "rocket" hits an object it will deal damage to it and leave a crater behind. I'd like to have the crater shown on that object. That would require "skipping" some of the pixels of that image when rendering, doesn't it?
My question is, how would you do such a thing? What data strcture would you use to save this? How to display a "broken" sprite?
Create a sprite sheet.
This will contain all the spirites your object, in this case the rocket. Some of these images would be of the rocket smashing into many pieces, fire etc...
Then when your object hits, you play the collision animation. Your method would technically work, but it's overkill. Using a sprite sheet is simple, rather than drawing a massive image, you just draw a portion of the sheet, and to play the animation increment in the X an Y axis of the sheet. This naturally requires the sheet to be layed out even, but it's not too much work.
For some situations, you can simply draw another sprite on top of the original sprite. Alternatively, you can switch between different sprites depending on the state of the object.
I see you have tagged this with XNA, so assume that is your API (though this answer could well be applied to any OpenGL/D3d approach with appropriate calls). If you want to do this in an elegant fashion, I suggest using a temporary RenderState. You would switch to the new RenderState and draw your original background texture, then draw crater sprites over the top (you can modify the AlphaSourceBlend and AlphaDestinationBlend properties of the RenderState to create the subtractive effect you are looking for).
Once you have finished drawing, you can retrieve the RenderState as a texture easily using the GetTexture() function.
Keep in mind that if you are changing the blend modes, your SpriteBatch should be performing in the "immediate" mode (I forget the XNA term, but the one where it doesn't do ordering of sprites for efficiency) else it will be reset unexpectedly.
View this: http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series2D/Adding_craters.php
Slow, but probably fast enough.
public static void Fill(this Texture2D t, Func<int, int, Color> perPixel)
{
var data = new Color[t.Height * t.Width];
for (int y = 0; y < t.Height; y++)
for (int x = 0; x < t.Width; x++)
{
data[x + (y * t.Width)] = perPixel(x, y);
}
t.SetData(data);
}
I was working on something like this on a mobile Java game, a worms/scorched earth clone (actually based on GunBound).
You don't "skip" the pixels in order to leave a crater. You change the pixels in your planet's bitmap, so the crater is now a permanent part of your planet. I assume you know all about bitmaps, blitting transparent, and hit testing.
To create a crater I used a circle-fill algorithm and filled the "explosion area" with the background or transparent color.
So when doing hit-testing you have to do it twice. A bounding-box hit test for speed, then a per-pixel hit test when then bounding boxes overlap.