Why Vector2 (from XNA's library) uses float not int?
Position on computer screen is given in pixels so that cursor position can be defined by two integers. There is no such a thing like half a pixel. Why we use floats then?
In SpriteBatch class I've found 7 overloaded methods called Draw. Two of them:
public void Draw(Texture2D texture, Rectangle destinationRectangle, Color color);
public void Draw(Texture2D texture, Vector2 position, Color color);
So we can see that Draw accepts both int and float coordinates.
I came across this problem when I've been implementing screen coordinates of my game's objects. I assumed that Rectangle is good choice to hold object's size and screen coordinates. But now I'm not sure...
Mathematically, a vector is a motion, not a position. While a position on the screen might not technically be able to be between integers, a motion definitely can. If a vector used ints then the slowest you could move would be (1, 1). With floats you can move (.1, .1), (.001, .001), and so on.
(Notice also that the XNA struct Point does actually use ints.)
You could use both Vector2 and Rectangle to represent your objects coordinates. I usually do it like this:
public class GameObject
{
Texture2D _texture;
public Vector2 Position { get; set; }
public int Width { get; private set; } //doesn't have to be private
public int Height { get; private set; } //but it's nicer when it doesn't change :)
public Rectangle PositionRectangle
{
get
{
return new Rectangle((int)Position.X, (int)Position.Y, Width, Height);
}
}
public GameObject(Texture2D texture)
{
this._texture = texture;
this.Width = texture.Width;
this.Height = texture.Height;
}
}
To move objects, just set their Position property to a new value.
_player.Position = new Vector2(_player.Position.X, 100);
You don't have to worry about the rectangle, as it's value depends directly on Position.
My game objects also usually contain methods to draw themselves, such as
public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
{
spriteBatch.Draw(this._texture, this.Position, Color.White);
}
Collision detection code in your Game.Update() could just use the PositionRectangle to test for collisions
//_player and _enemy are of type GameObject (or one that inherits it)
if(_player.PositionRectangle.Intersects(_enemy.PositionRectangle))
{
_player.Lives--;
_player.InvurnerabilityPeriod = 2000;
//or something along these lines;
}
You could also call the spriteBatch.Draw() with PositionRectangle, you shouldn't notice much difference.
There is such a thing as "half a pixel." Using float coordinates that aren't pixel-aligned will cause your sprites to be rendered at sub-pixel coordinates. This is often necessary to make objects appear to scroll smoothly, but it can also produce an unpleasant shimmering effect in some circumstances.
See here for a summary of the basic idea: Subpixel rendering
Related
I want to make a game where the player can place objects in an existing gamemap like a wall or different kind of turrets.
The gamemap consist 2 things:
So basicaly the main gamemap where the player can walk around in, that exist of trees, walls and water that is already there.
And the objects (with their specific heights and widths) that the player can place (when he gots wood, gold (when the player slays monsters etc) in that main gamemap.
How should I approach this? Any tips, class structures with methods would be nice to have.
The main gamemap could be a grid of tiles. Your turrets could then have width and height as multiples of the tile sizes and occupy a certain number of them.
For example, a 2x2 turret would occupy four tiles. Limiting turrets/walls to tiles rather than giving them arbitrary positions and lengths is limiting, but it allows you faster collision detection.
You could then have:
class Tile
{
public Building WhatIsConstructedHereIfAnything;
}
and
class Building
{
public List<Tile> TilesOccupiedByThisBuilding;
}
You could then update the building by going over the list of buildings and handle collisions only by looking at nearby tiles.
Add a Rectangle to your object class, and use its Width and Height properties.
class YourObject
{
public Rectangle Rectangle;
public YourObject(Vector2 position, int width, int height)
{
Rectangle = new Rectangle((int)position.X, (int)position.Y, width, height);
}
public void Draw()
{
spritebatch.Draw(Texture, Rectangle, Color);
}
}
Earlier, I had an issue with my Windows cursor being uncoordinated with the game and asked here how I could solve this. A member suggested me to hide the Windows cursor and create a custom game cursor, so I did this. However, a new problem occurred.
My game cursor is usually offset to the right of the Windows mouse, so when I want to move the game cursor to the left side of the window and click my left mouse button, it causes a disturbance to the game, such as bringing an application in the background to the top.
Here is a picture of what I mean: http://i.imgur.com/nChwToh.png
As you can see, the game cursor is offset to the right of the Windows cursor, and if I use game cursor to click on something on the left side of the window, the application in the background (Google Chrome in this case), will be brought up to the front, causing disturbance to the game.
Is there anything I can do to use my game cursor without any disturbances?
I have just tried to move everything out of their classes, all into the main Game class.
This fixed the problem, but does not give me an answer to WHY this happens.
The code is exactly the same, it's just organized to separate classes.
So, does anyone know why this is?
Why is using object-oriented programming instead of putting everything in the game class going mess up my mouse coordination and stuff?
Normally, you would have a texture for you in-game cursor where, for instance, the pixel at [16,16] is where you are "aiming" (the center of a crosshair, for instance). What you owuld to to draw this centered on the mouse is to use Mouse.GetState() to get the position, and then offset the drawing of your mouse-texture by the negative of the "center" of the "aim"-point.
so let's say we make a custom Mouse-Class:
public class GameMouse
{
public Vector2 Position = Vector2.Zero;
private Texture2D Texture { get; set; }
private Vector2 CenterPoint = Vector2.Zero;
public MouseState State { get; set; }
public MouseState PreviousState { get; set; }
//Returns true if left button is pressed (true as long as you hold button)
public Boolean LeftDown
{
get { return State.LeftButton == ButtonState.Pressed; }
}
//Returns true if left button has been pressed since last update (only once per click)
public Boolean LeftPressed
{
get { return (State.LeftButton == ButtonState.Pressed) &&
(PreviousState.LeftButton == ButtonState.Released); }
}
//Initialize texture and states.
public GameMouse(Texture2D texture, Vector2 centerPoint)
{
Texture = texture;
CenterPoint = centerPoint;
State = Mouse.GetState();
//Calling Update will set previousstate and update Position.
Update();
}
public void Update()
{
PreviousState = State;
State = Mouse.GetState();
Position.X = State.X;
Position.Y = State.Y;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Begin();
spriteBatch.Draw(Texture, Position - CenterPoint, Color.White);
spriteBatch.End();
}
}
Here is the code for a project im working on, where an enemy moves back and forth at the bottom of the screen.
class enemy1
{
Texture2D texture;
public Vector2 position;
bool isAlive = false;
Random rand;
int whichSide;
public enemy1(Texture2D texture, Vector2 position)
{
this.texture = texture;
this.position = position;
}
public void Update()
{
if (isAlive)
{
if (whichSide == 1)
{
position.X += 4;
if (position.X > 1000 + texture.Width)
isAlive = false;
}
if (whichSide == 2)
{
position.X -= 4;
if (position.X < 0)
isAlive = false;
}
}
else
{
rand = new Random();
whichSide = rand.Next(1, 3);
SetInStartPosition();
}
}
private void SetInStartPosition()
{
isAlive = true;
if (whichSide == 1)
position = new Vector2(0 - texture.Width, 563 - texture.Height);
if (whichSide == 2)
position = new Vector2(1000 + texture.Width, 563 - texture.Height);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
Now i want there to be a few enemys going back and forth but they start at differant positions so it looks like there is a few enemys going back and forth at the bottom of the screen. I have managed to draw a few other enemies on the screen, except they do not behave like the first enemy. They just are pictures on a screen not moving anywhere. So now all i have is the hero moving around and one enemy at the bottom of the screen, along with 5 other enemys sitting at the top of the screen doing nothing. How do i easily add a new sprite from a class that has the same behavior, at any time, while not making a billion variables to store them in?
Generally it's a good idea to have similar logic contained within the proper class, so if all Sprites where to do the same thing, then all you would need to do is put your movement code inside a public method and then call that method inside Update().
So, if your Sprite class looks something like this:
public class Sprite
{
private Vector2 Position;
public Sprite(Texture2D texture, Vector2 position)
{
Position = position;
}
//then just add this
public void MoveSprite(int amount)
{
position.X += amount;
}
}
Now, the object name "Sprite" is pretty generic, you will more than likely have many "Sprites" in your game.
So you're going to want to follow good OOP practices and maybe name this specific sprite something different and then have it derive from this class we're looking at right now. (But i'm not going to make design decisions for you)
This was a vague question, but that's my best shot at an answer for you.
Currently, my game using some pixel detections.
For exemple, for sprites, i retrieve the pixel of its position.
When i move it, the position values have some decimals like :
thePixel = new vector(position.X, position.Y);
//thePixel = (52.2451, 635.2642)
so i have to Round These values
thePixel = new vector((float)Math.Round(position.X, 0), (float)Math.Round(position.Y, 0));
//thePixel = (52, 635)
I would like to know if there are some other ways to get perfect position (means, without decimal) without Rounding them.
Is it maybe a moving method problem ?
Thx for reading, hope you can help.
You can't really get around the need to round your values, but you can make it a lot nicer to code by using an extension method:
public static class Vector2Extensions
{
public static Vector2 Floor(this Vector2 vector)
{
return new Vector2((float)Math.Floor(vector.X), (float)Math.Floor(vector.Y));
}
}
(As you can see, personally I prefer Floor to Round. I also have one for Ceiling.)
Then you can just use it like this:
HandleCollision(position.Floor());
Of course, if you're doing per-pixel collision detection - your collision maths should probably be integer-based (not stored as float in a Vector2). You could use Point. Turns out I have an extension method for that too:
public static class Vector2Extensions
{
public static Point AsXnaPoint(this Vector2 v)
{
return new Point((int)v.X, (int)v.Y);
}
}
Then:
HandleCollision(position.AsXNAPoint());
Or possibly:
HandleCollision(position.Floor().AsXNAPoint());
In DirectX it is possible to set the D3DXSPRITE parameters to be a combination of both:
D3DXSPRITE_SORT_DEPTH_BACKTOFRONT
and
D3DXSPRITE_SORT_TEXTURE
Meaning that sprites are sorted first by their layer depth and then secondly by the texture that they are on. I'm trying to do the same in XNA and i'm having some problems. I've tried:
SpriteBtch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.BackToFront & SpriteSortMode.Texture, SaveStateMode.None);
But it doesn't work and just seems to do them in Texture ordering, ignoring the textures layer depth. Am I doing something wrong!? Or is it not even possible?
SpriteSortMode is an enum and should be combined using the | operator:
SpriteSortMode.BackToFront | SpriteSortMode.Texture
Update: as this article mentions, your scenario is not possible in XNA:
sorting by depth and sorting by
texture are mutually exclusive
A possible solution :
Define a new object representing a sprite to draw
class Sprite
{
public float Priority { get; set; } // [0..1]
public String TextureName { get; set; }
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(TextureName, ..., Priority); // here Priority is useless because of the sort mode.
}
}
Then add a "sprites to draw" list that you:
Sort by drawing priority, reverse order so Priority == 1 is first
Sort by texture when a.Priority == b.Priority (this is the tricky part but not THAT hard)
So in your Main class for example, you'll have :
private List<Sprite> spritesToDrawThisTick = new List<Sprite>();
And every tick, you :
Add sprites to draw
Do the sorting logic
Call your SpriteBatch.Begin using SpriteSortMode.Immediate
Do a foreach on your list to call every Sprite's Draw method
important: empty your spritesToDrawThisTick list