Defining two SpriteSortModes? - xna

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

Related

How to compare values within two List<List<CustomClass>> in Dart?

I have a 2048-type game where the gameboard grid is made up of a list of 4 other lists (each of which contain 4 Tiles).
Each time a move is made, the newGameboardGrid is saved in yet another list (so that removeLast can be called when a player wants to undo a move).
When a player swipes, I need to compare the newGameboardGrid grid with the previous one to see if any actual movement took place or if the tile values are still the same (as would happen if a player swiped in a direction where no movement was possible).
I tried this code:
if (newGameboardGrid == listOfGameboardGrids.last) {
// do something
}
It almost works in that it is comparing the <List<List< Tile>> from the new move with the <List<List< Tile>> of the last move, but the problem is that it never results in the two <List<List< Tile>> as being equal, even when all the tile values are identical. I believe it's because it is comparing hashcodes and/or other things.
The Tile class has lots of stuff in it, but the thing I would like to compare is that int named "value". Is it possible to compare only the "value" variable for these two <List<List< Tile>>?
Thanks in advance for any help! (And apologies if any of my terms are imprecise.)
Dart list implementations do not override the operator== of Object, so they are only ever equal to themselves. The elements are not checked.
IF you want to compare the elements (and here, the elements of the list elements), you can use the Equality classes from package:collection:
const boardEquality = ListEquality(ListEquality(DefaultEquality()));
This creates a ListEquality object which compares two lists of lists of elements by checking that they contain the same number of lists, which again contains the same number of equal elements. (I assume that Tile implements operator==).
You can the use it as: if (boardEquality.equals(newGameboardGrid, listOfGameboardGrids.last)) { ... }.
You could do an extension method on your particular list type and make an isEqual method for that compares each Tile:
extension TileListComp on List<List<Tile>> {
bool isEqual(List<List<Tile>> other) {
if(this.length != other.length || this[0]?.length != other[0]?.length) {
return false;
}
for(int x = 0; x < this.length; x++) {
for(int y = 0; y < this[0].length; y++) {
if(this[x][y] != other[x][y]) {
return false;
}
}
}
return true;
}
}
If you have not implemented any kind of comparison for your Tile class, you will need to do so. I can advise if necessary.

XNA How to place objects with variable width and height in a map

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);
}
}

How to move a sprite without decimals in its position

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());

Why Vector2 (from XNA's library) uses float not int?

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

How can I fill an actionscript 3 polygon with a solid color?

I'm building a map editor for a project and need to draw a hexagon and fill it with a solid color. I have the shape correct but for the life of me can't figure out how to fill it. I suspect it may be due to whether the thing is a Shape, Sprite or UIComponent. Here is what I have for the polygon itself:
import com.Polygon;
import mx.core.UIComponent;
public class greenFillOne extends UIComponent {
public var hexWidth:Number = 64;
public var hexLength:Number = 73;
public function greenFillOne() {
var hexPoly:Polygon = new Polygon;
hexPoly.drawPolygon(40,6,27+(hexWidth*.25),37,0x499b0e,1,30);
addChild(hexPoly);
}
}
The Polygon class isn't a standard Adobe library, so I don't know the specifics. However, assuming that it uses the standard flash API, it should be no problem to add some code to extend the function. You just need to make sure you're doing a graphics.beginFill before the graphics.lineTo / graphics.moveTo functions. And then finish with graphics.endFill.
e.g.,
var g:Graphics = someShape.graphics;
g.beginFill(0xFF0000,.4); // red, .4 opacity
g.moveTo(x1,y1);
g.lineTo(x2,y2);
g.lineTo(x3,y3);
g.lineTo(x1,y1);
g.endFill();
This will draw a triangle filled with .4 red.
I'll put this here because answering it as a comment to Glenn goes past the character limit. My actionscript file extends UIComponent. When I created a variable hexPoly:Polygon = new Polygon; it would render the outline of the hex, but would not fill it no matter what I did. I examined polygon.as and duplicated the methods, but as a sprite and it worked. So, I need to figure out how to wrap the polygon as a sprite, or just leave it as is.
var hexPoly:Sprite = new Sprite;
hexPoly.graphics.beginFill(0x4ea50f,1);
hexPoly.graphics.moveTo(xCenter+(hexWidth*.25)+Math.sin(radians(330))*radius,offset+(radius-Math.cos(radians(330))*radius));
hexPoly.graphics.lineTo(xCenter+(hexWidth*.25)+Math.sin(radians(30))*radius,offset+(radius-Math.cos(radians(30))*radius));
hexPoly.graphics.lineTo(xCenter+(hexWidth*.25)+Math.sin(radians(90))*radius,offset+(radius-Math.cos(radians(90))*radius));
hexPoly.graphics.lineTo(xCenter+(hexWidth*.25)+Math.sin(radians(150))*radius,offset+(radius-Math.cos(radians(150))*radius));
hexPoly.graphics.lineTo(xCenter+(hexWidth*.25)+Math.sin(radians(210))*radius,offset+(radius-Math.cos(radians(210))*radius));
hexPoly.graphics.lineTo(xCenter+(hexWidth*.25)+Math.sin(radians(270))*radius,offset+(radius-Math.cos(radians(270))*radius));
hexPoly.graphics.endFill();
addChild(hexPoly);

Resources