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.
Related
So I'm doing this little game for university and I've encountered a problem with the resizing of the sprites. My game's like a graphic adventure (monkey island, grim fandango and stuff) and it has an inventory where items can be saved. The problem is, although the world object sprites are good and have different sizes, I want their sprites to be resized when and save them in the inventory so they can fit.
I thought this were done using the Bounds class, but I have some issues with it. Also: the tutorial I was following did something that in it's time might work, but now it gives me a compile error. Showing below my function to save an item (and resize its sprite in the process):
void SaveInventoryItem()
{
string name = transform.parent.gameObject.name;
GameObject temporaryObject = Instantiate(inventoryItemPrefab);
temporaryObject.name = name;
temporaryObject.gameObject.GetComponent<SpriteRenderer>().sprite = transform.parent.GetComponent<SpriteRenderer>().sprite;
temporaryObject.transform.parent = inventoryCanvas.transform;
temporaryObject.transform.position = Vector3.forward * -1;
temporaryObject.gameObject.GetComponentInChildren<InteractZone>().interactText = "Usar " + name;
Bounds bounds = temporaryObject.gameObject.GetComponent<SpriteRenderer>().sprite.bounds.size ;
float factor = General.inventoryItemSize / bounds.size.y;
}
The error says cannot convert from UnityEngine.Vector3 to UnityEngine.Bounds
If someone knows a way to solve this error or another way to resize sprites in a default size, please let me know.
Look at #Erik Overflows comment. Use a canvas class in your inventory system, which will contain a bunch of images with properly set sizes. Then you can just assign the sprite to the image, and it should size automatically.
As Erik said in his comment, you can just set the image for the UI canvas element in the inventory to the sprite, it will automatically fit the sprite to the ui element. Then all you need to do is use the system figbar suggested to assign sprites to your images as inventory items are added or removed.
If you know the size of the sprite, under the Inspector, change the Pixels Per Unit to that size.
You could play around with the numbers until it fills, or you can change your Sprite Mode to multiple, click the Sprite Editor button, and go to slice. Select grid by cell size type and it may populate the pixel size, but you can play with it and figure it out if it doesn't.
Me and my team are working on a game in xna right now. However we've run into a problem. It is an open space sim where players will be able to build their own ships (top down view) room by room. Each room has a texture2d, however since the game is top-down, we will need to be able to "turn the ship".
We're running into a problem rotating the collection of texture2ds that make up the ship. In our old code, we tried to rotate all the rooms around a central origin as the location of the bridge. As we had problems with this, we looked online and decided to try our hand at RenderTargets (draw the whole ship onto an RT, then we could just rotate the RT image when it's drawn).
Our problem is that the RT draws a big purple background and, since our ships aren't always perfectly filled in rectangles, there's always a purple background somewhere poking out.
The question is: What is the best way to rotate a collection of texture2ds around a single origin in xna as if they were a single image?
Your problem is almost word-for-word the exact same problem I had until recently.
I had a collection of compartments (for each of my spaceships) rotating around an origin, but this resulted in:
Large overhead for calculating and reposition each and every compartment
Small gaps between compartments, probably due to the inaccuracies of the float
I recommend you go back to the RenderTarget approach. To get rid of the purple background, use:
GraphicsDevice.SetRenderTarget(render);
GraphicsDevice.Clear(Color.Transparent);
Much less overhead and a lot prettier without the gaps between compartments.
All the best to you and your team, may the best spaceship game win ;]
Create a camera that rotates instead of rotating all textures / make a rendertarget.
It basically views the sprites, instead of tweaking everything else.
There are plenty of tutorials on the internet, but I'll show you something:
class Camera
{
public Matrix transform; // The transformed matrix
public void Update(float rotation)
{
// you can add the positions here, x y z. Play around with it.
// x should be half of the screen width,
// y the half of the screen height, creating a "orgin" where it's rotating.
transform = Matrix.CreateTranslation(0, 0, 0) * Matrix.CreateRotationZ(rotation);
}
}
Put this in your Draw method, it uses the camera's viewport:
sb.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, camera.transform);
Also: I don't really know much about camera's. But this is a basic one.
You will have to find "center of mass" aka barycenter. it's averageing of all x and y coordinates. and you will have origin that you need.
this is code i found some times ago, but never tested... i guess it's also from stackoverflow.
Point bary = Point.Zero;
foreach (Point p in list)
{
bary.X += p.X;
bary.Y += p.Y;
}
bary.X = (bary.X + list.Count / 2) / list.Count;
bary.Y = (bary.Y + list.Count / 2) / list.Count;
return bary;
try this way
I am making a small game as sort of a test project, nothing major. I just started and am working on the graphics piece, but I'm not sure the best way to draw the graphics to the screen.
It is going to be sort of like the old Zelda, so pretty simple using bitmaps and such. I started thinking that I could just paint to a Picture Box control using Drawing.Graphics with the Handle from the control, but this seems cumbersome. I'm also not sure if I can use double buffering with this method either.
I looked at XNA, but for now I wanted to use a simple method to display everything.
So, my question. Using the current C# windows controls and framework, what is the best approach to displaying game graphics (i.e. Picture Box, build a custom control, etc.)
EDIT:
I will add how I am currently drawing to the picture box. I have a Tile object that just contains the pixels for the tile ( List< List< Color>> texture; ), nothing more for simplicity. I then draw that to the pic box by iterating through the pixels and using the FillRectangle method using a brush with the current pixel color and the size specified by a scale variable:
int scale = 5;
for (int i = 0; i < texture.Width;)
{
for (int j = 0; j < texture.Height; ++j)
{
int x = i * scale;
int y = j * scale;
picBox.FillRectangle(new SolidBrush(currentPixelColor), new Rectangle(x, y, scale, scale));
}
}
Yah, pretty cumbersome. Any suggestions or comments are appreciated.
I would recommend, that you take another look at XNA and try a few samples. It is really simple to make simple games with XNA as long as you stick with 2D. The framework does an excellent job at wrapping all the details in a easy to understand flow, where you basically fill in the blanks so to speak.
I did a complete (but very simple) Xbox game for my son in just 8 hours without little previous experience.
If you move to 3D things become more complex, as you have to understand various view models, shaders and so forth, but for 2D it is really simple to get started.
Another advantage of 2D is that the required tools are easier to get. I did all the graphics using Photoshop, the sounds were MP3s and voices I recorded using the Windows recorder. For 3D you need complex tools for building and exporting models and so forth.
I honestly believe XNA is by far one of the simplest game design frameworks I've used. Aside from that you could utilize WPF to draw objects on screen.
First I strongly recommend using XNA or DirectX for game development...
However, if you do not want XNA nor DirectX help.... then you will be forced to use .Net GDI+ painting tools.....
By this way, you can draw points, lines, circles, rectangles, arcs, bitmaps, texts and many more by GDI+ (that all is -of course- available in C# and .Net...)
You may make a new simple control (or use an existing one such as image box or the form itself !), then you will have to override its OnPaint(PaintEventArgs e) function... Then you will use e.Graphics to draw whatever you want...
Example:
Simple Tetris Game Tutorial in C#
EDIT:
Using a GDI+ to draw pixel by pixel picture is quite a performance drop!!
Better is to draw shapes yourself (circles,.. etc)
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 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