I'm working on a 3D Spaceship game with XNA 3.1
I tried to separate my painting code from the game logic (altought XNA makes this almost).
I'm using a special static class that paints my models on screen... the main Game class uses this code at painting:
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.Black);
// Draws the stage (the skybox and objects like rocks)
stageManager.Draw(gameTime, GraphicsDevice, camera);
// Draws each player and each Enemy on stage given the camera
foreach (Player p in players)
p.Draw(camera);
foreach(Enemy e in enemies)
e.Draw(camera);
if(Configuration.Debug)
col.renderColBoundings(GraphicsDevice, camera);
GraphicHelper.drawOverlayText("50", "10"); // "Error" line...
base.Draw(gameTime);
}
But when I paint text, something weird occurs... Here's an image (original):
As you can see, everything looks overlapped (but in place)... Like the spaceship turbines.
The code inside GraphicHelper.drawOverlayText is this:
public static void drawOverlayText(String p1Hp, String currEnemies)
{
string text1 = "Player1: " + p1Hp;
string text2 = "Enemies: " + currEnemies + "/10";
string text3 = "Space Hogs Beta";
spriteBatch.Begin();
// Draw the string twice to create a drop shadow, first colored black
// and offset one pixel to the bottom right, then again in white at the
// intended position. This makes text easier to read over the background.
spriteBatch.DrawString(font, text1, new Vector2(651, 11), Color.Gray);
spriteBatch.DrawString(font, text1, new Vector2(650, 10), Color.White);
spriteBatch.DrawString(font, text2, new Vector2(851, 11), Color.Gray);
spriteBatch.DrawString(font, text2, new Vector2(850, 10), Color.White);
spriteBatch.DrawString(font, text3, new Vector2(741, 611), Color.Gray);
spriteBatch.DrawString(font, text3, new Vector2(740, 610), Color.White);
spriteBatch.End();
}
And this static class has this attributes:
static ContentManager content;
static GraphicsDevice graphics;
static Camera camera;
static Dictionary<String, Model> models = new Dictionary<string, Model>();
static SpriteBatch spriteBatch;
static SpriteFont font;
public static void initHelper(ContentManager c, GraphicsDevice g, Camera cam)
{
content = c;
graphics = g;
camera = cam;
spriteBatch = new SpriteBatch(g);
font = c.Load<SpriteFont>("Fonts/main");
}
Hope you can help me :)
The odd rendering you are seeing is because the depth buffer is turned off. It gets turned off when you use SpriteBatch. This is a known oddity of the XNA 3.1 API. XNA 4.0 at least makes it a bit more obvious that this is happening.
Here is an explanation of what render states are changed by SpriteBatch in XNA 3.1. And here is the same thing for XNA 4.0.
The solution is to basically set your render states back to what you want them to be, after using SpriteBatch. In this case, at least, set:
GraphicsDevice.RenderState.DepthBufferEnable = true;
(There may also be some other states in there you want to change back.)
Related
I'm having this problem with sprites in my Unity3D project. Basiclly I can't change sprite in SpriteRenderer component during runtime. During my research I've only seen solutions that require you to have the sprite pre-loaded, but I can't because it's generated based on the users input image.
So what happens is the user can change the background of the "game" by inputing his own photo from his computer. I get the photo in and everything and I generate a sprite from it, but when I change the base sprite with his sprite, nothing happens. The base sprite is still showing. If I put the background sprite on a panel's Image in canvas, then everything works great, but if I do the same with SpriteRenderer then nothing happens. Here is my code:
public class UploadImage : MonoBehaviour
{
public GameObject background;
public Sprite sp;
[DllImport("__Internal")]
private static extern void ImageUploaderCaptureClick();
public void setTexture(Texture2D texture)
{
sp = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(texture.width / 2, texture.height / 2));
background.GetComponent<SpriteRenderer>().sprite = sp;
}
IEnumerator LoadTexture(string url)
{
WWW image = new WWW(url);
yield return image;
Texture2D texture = new Texture2D(1, 1);
image.LoadImageIntoTexture(texture);
Debug.Log("Loaded image size: " + texture.width + "x" + texture.height);
setTexture(texture);
}
void FileSelected(string url)
{
StartCoroutine(LoadTexture(url));
}
public void OnButtonPointerDown()
{
#if UNITY_EDITOR
string path = UnityEditor.EditorUtility.OpenFilePanel("Open image", "", "jpg,png,bmp");
if (!System.String.IsNullOrEmpty(path))
FileSelected("file:///" + path);
#else
ImageUploaderCaptureClick ();
#endif
}
}
I can't have the background on an image in canvas because other game objects lose transparency and if I set the alpha on image too low, then when game objects move, it leaves everything blurry.
Thanks for your help
I think you are setting the sprites pivot wrong when generating the sprite. Your sprite should even be displayed at the moment but its far away from where you expect it to be.
Change your code to something like this:
sp = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
I am trying to make a very simple game for learning purposes, but i am struggling with SharpDX.
Basically what i'm trying to achieve is: Take several bitmap images and display them in a window on certain x y coordinates. After that, i will clear the window a display those images again, but on different x y coordinates (a very basic game loop basically, which means the images will be re-displayed many times per second).
I have this code:
using SharpDX;
using SharpDX.Toolkit;
internal sealed class MyGame : Game
{
private readonly GraphicsDeviceManager _graphicsDeviceManager;
public MyGame()
{
_graphicsDeviceManager = new GraphicsDeviceManager(this);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
}
}
-------
public partial class MainWindow : Window
{
public MainWindow()
{
using (var game = new MyGame())
game.Run();
}
}
When compiled, it simply opens a window with a blue background.
Then, I have two images:
var img = new BitmapImage(new Uri("C:/img/pic1.png"));
var img1 = new BitmapImage(new Uri("C:/img/pic2.png"));
And this is where the problem lies, i am unable to figure out, how to take these two images and actually display them in the window. img should be displayed at x10 y50 coordinates (or in other words, 10 pixels from the left side of the window, and 50 pixels from the top) and img1 at x200 y150 coordinates.
I'm sure the solution is something easy, but I just can't figure it out.
Inside MyGame.
Firstly, in LoadContent method load the texture:
private Texture2D myTexture;
protected override void LoadContent()
{
this.myTexture = this.Content.Load<Texture2D>("Path to img");
}
then in Draw;
protected override void Draw(GameTime gameTime)
{
var sprite = new SpriteBatch(this.GraphicsDevice);
sprite.Begin();
sprite.Draw(this.myTexture,
new Rectangle(10, 50, // position: x and y coordiantes in pixels
/* width and height below
- do not remeber order: */
25, 25),
Color.White);
sprite.End();
base.Draw(gameTime);
}
This is the basic way to draw anything with SharpDX.
I'm creating an XNA game that creates random islands from multiple sprites. It creates them in a separate thread, then compiles them to a single texture using RenderTarget2D.
To create my RenderTarget2D I need a graphics device. If I use the automatically created graphics device, things work okay for the most part, except that draw calls in the main game thread conflict with it. Using lock() on the graphics device causes flickering, and even then the texture is sometimes not created properly.
If I create my own Graphics device, there are no conflicts but the islands never render correctly, instead coming out pure black and white. I have no idea why this happens. Basically I need a way to create a second graphics device that lets me get the same results, instead of the black / white. Anyone got any ideas?
Here's the code I'm using to try and create my second graphics device for exclusive use by the TextureBuilder:
var presParams = game.GraphicsDevice.PresentationParameters.Clone();
// Configure parameters for secondary graphics device
GraphicsDevice2 = new GraphicsDevice(game.GraphicsDevice.Adapter, GraphicsProfile.HiDef, presParams);
Here's the code I'm using to render my islands to a single texture:
public IslandTextureBuilder(List<obj_Island> islands, List<obj_IslandDecor> decorations, SeaGame game, Vector2 TL, Vector2 BR, int width, int height)
{
gDevice = game.Game.GraphicsDevice; //default graphics
//gDevice = game.GraphicsDevice2 //created graphics
render = new RenderTarget2D(gDevice, width, height, false, SurfaceFormat.Color, DepthFormat.None);
this.islands = islands;
this.decorations = decorations;
this.game = game;
this.width = width;
this.height = height;
this.TL = TL; //top left coordinate
this.BR = BR; //bottom right coordinate
}
public Texture2D getTexture()
{
lock (gDevice)
{
//Set render target. Clear the screen.
gDevice.SetRenderTarget(render);
gDevice.Clear(Color.Transparent);
//Point camera at the island
Camera cam = new Camera(gDevice.Viewport);
cam.Position = TL;
cam.Update();
//Draw all of the textures to render
SpriteBatch batch = new SpriteBatch(gDevice);
batch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, cam.Transform);
{
foreach (obj_Island island in islands)
{
island.Draw(batch);
}
foreach (obj_IslandDecor decor in decorations)
{
decor.Draw(batch);
}
}
batch.End();
//Clear render target
gDevice.SetRenderTarget(null);
//Copy to texture2D for permanant storage
Texture2D texture = new Texture2D(gDevice, render.Width, render.Height);
Color[] color = new Color[render.Width * render.Height];
render.GetData<Color>(color);
texture.SetData<Color>(color);
Console.WriteLine("done");
return texture;
}
Here's what should happen, with a transparent background (and usually does if I use the default device)
http://i110.photobucket.com/albums/n81/taumonkey/GoodIsland.png
Here's happens when the default device conflicts and the main thread manages to call Clear() (even though it's locked too)
NotSoGoodIsland.png (need 10 reputation....)
Here's what happens when I use my own Graphics device
http://i110.photobucket.com/albums/n81/taumonkey/BadIsland.png
Thanks in advance for any help provided!
I may have solved this by moving the RenderToTarget code into the Draw() method and calling it from within the main thread the first time Draw() is called.
I am having some issues with my mouse coordinates in XNA - the 0x0 is arbitrarily near (but not in) the top left corner of my screen.
I am running the game in a windowed mode right now, but the coordinates are based off the screen, not the game window (even though the XNA documentation tells me it should be otherwise)
Thanks in advance!
Here's the code:
namespace TheGame
{
class Mousey
{
static public Vector2 pos;
static private Texture2D tex;
static public MouseState mouseState;
static public MouseState previousState;
//static public Mousey()
//{
//}
static public void Update()
{
previousState = mouseState;
mouseState = Mouse.GetState(); //Needed to find the most current mouse states.
pos.X = mouseState.X; //Change x pos to mouseX
pos.Y = mouseState.Y; //Change y pos to mouseY
}
//Drawing function to be called in the main Draw function.
static public void LoadContent(ContentManager thecontent)
{
tex = thecontent.Load<Texture2D>("mousey");
}
static public void Draw(SpriteBatch batch) //SpriteBatch to use.
{
batch.Draw(tex, pos, Color.White); //Draw it using the batch.
}
static public bool LBP()
{
if (mouseState.LeftButton == ButtonState.Pressed && previousState.LeftButton == ButtonState.Released)
{
return true;
}
else
{
return false;
}
}
}
}
In game.cs:
//sets the windows mouse handle to client bounds handle
Mouse.WindowHandle = Window.Handle;
private IntPtr intPtr;
public MouseControle(int w, int h, IntPtr intPtr)
{
screenwidth = w;
screenheight = h;
this.intPtr = intPtr;
Mouse.WindowHandle = intPtr;
}
This works for me ;)
To use this, I add this to my game-component using that class:
mouse = new MouseControle(((Game1)Game).setscreen.width,
((Game1)Game).setscreen.height,
((Game1)Game).Window.Handle);
Hope this helps sombody :D
Did you try something simpler like this?
protected override void Draw( GameTime gameTime )
{
graphics.GraphicsDevice.Clear( Color.CornflowerBlue );
base.Draw( gameTime );
MouseState current_mouse = Mouse.GetState();
Vector2 pos = new Vector2(current_mouse.X, current_mouse.Y);
batch.Draw(tex, pos, Color.White);
}
There may be some time between draw and update, due to the way timing works in XNA, maybe is this the cause of the perceived pixel offset?
And... are you sure you "configured" your sprite batch correctly? Coordinates are relative to game window, so the documentation say.
Another thing: Why are you using static fields? I really don't like this choice, an anti-pattern. Use class fields, not static fields.
Also... i guess you are drawing a mouse icon, right? consider that XNA start to draw the texture from the specified point, are you sure the texture is well shaped with the top-left point as your mouse arrow end?
I found a nice example here you may like: http://azerdark.wordpress.com/2009/07/08/displaying-cursor-xna/
Consider also that you can enable and disable the normal windows OS mouse cursor with IsMouseVisible = true;
Your draw call is not offsetting the texture at all. If the "pointer" part of your image isn't in the 0,0 position (top left) of your Texture, the positioning will seem off.
Add a Console.WriteLine(pos); to your update to see the position it is drawing to. Remember to remove this after your debugging because writeline will kill your performance.
Try one of the overloaded SpriteBatch.Draw() calls which factor in an "origin" which lets you decide which point of the texture should be drawn at the position. In the following code tweak the Vector 2 based upon how your texture is drawn.
batch.Draw(tex, pos, null, Color.White, 0.0f, new Vector2(10, 10), SpriteEffects.None, 0.0f);
I'm a c++ programmer trying out c#. I've done a lot with box2d in c++, but this is my first time with c#. So, I'm trying to make a simple game with farseer physics engine. When I try to compile my code (I'm using visual studio c# 2010 express and xna game studio 4.0), it stops in body.cs at IBroadPhase broadPhase = World.ContactManager.BroadPhase; With this error: nullreferenceexception was unhandled. I believe the problem is in my Player class, so here's the code for that:
public class Player : Entity
{
Vector2 position;
SpriteBatch spriteBatch;
Texture2D texture;
Rectangle rectangle;
Body body;
CircleShape shape;
Fixture fixture;
public Player()
{
// TODO: Construct any child components here
}
///
/// Allows the game component to perform any initialization it needs to before starting
/// to run. This is where it can query for any required services and load content.
///
public override void Initialize(World world, SpriteBatch spriteBatch, Texture2D texture)
{
// TODO: Add your initialization code here
this.spriteBatch = spriteBatch;
this.texture = texture;
rectangle = new Rectangle(0, 0, 11, 14);
body = BodyFactory.CreateBody(world);
body.BodyType = BodyType.Dynamic;
body.Position = new Vector2(0, 0);
shape = new CircleShape(1.0f, 1.0f);
fixture = body.CreateFixture(shape);
base.Initialize(world, spriteBatch, texture);
}
///
/// Allows the game component to update itself.
///
/// <param name="gameTime" />Provides a snapshot of timing values.
public override void Update(GameTime gameTime)
{
// TODO: Add your update code here
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
spriteBatch.Begin();
spriteBatch.Draw(texture, new Vector2(body.WorldCenter.X * 10, body.WorldCenter.Y * 10), rectangle, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
The farseer testbed runs fine, so I'm pretty sure my code is the problem, and not farseer. Let me know if you need to see more of my code. I've also posted this in the farseer forums, so If I get an answer there, I'll let you guys know. Thanks in advance.
Someone asked me to show the code of Game1.cs, and found the problem. The problem was that I had never constructed the world before initializing my player. It was fixed by adding world = new World(Vector2.Zero); before I initialized the player.