WizardBlast seems to be a legit 3D space game when you look at it, but when you start thinking about the in-game logic it turns out to be 2D limited.
In fact WizardBlast is a 3D rendered 2D game, because everything happens on 2D platform (maze). It is the representation of the maze that gets to full 3D.
In such mixed environment some of the variables regarding position of an in-game entity need to be 2D (x,y), some need to be 3D (x,y,z), and some need both. Also the 3D y component doesn't necessarily need to be equal to the 2D y component.
When I started coding WizardBlast I used Vector3 and Vector2 to store coordinates, and then worked on one of them when needed. It all made the code quite messy and difficult to read/modify/refactor.
That is why I created a new class to store complex position vectors that work in an unificated way. At any time I am able to get both 2D and 3D components and any modification made to one them affects the other.
I think it's a piece of code worth sharing. Not because it's difficult to write, but because it's not always obvious that you need such code :-)
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
Microsoft.Xna.Framework;
namespace
WizardBlast.Entities
{
public
class
Position
{
public
static
float
ZeroFieldXLocation = -2.5f;
public
static
float
ZeroFieldZLocation = -2.5f;
public
static
float
Rift = .55f;
public
static
float
InvRift = 1 / Rift;
private
float
z;
private
float
x;
private
int
ix;
private
int
iz;
public
float
Z { get
{ return
z; } set
{ z = value;
iz = FieldZIndex(value);
} }
public
float
Y { get;
set;
}
public
float
X { get
{ return
x; } set
{ x = value;
ix = FieldXIndex(value);
} }
public
int
IX { get
{ return
ix; } set
{ ix = value;
x = FieldXPosition(value);
} }
public
int
IZ { get
{ return
iz; } set
{ iz = value;
z = FieldZPosition(value);
} }
public
Position(Vector3
position)
{
Z
= position.Z;
Y
= position.Y;
X
= position.X;
}
public
Position(Position
position)
{
IZ
= position.IZ;
Y
= position.Y;
IX
= position.IX;
}
public
Position(int
x, int
z)
{
IZ
= z;
IX
= x;
Y
= 0f;
}
public
Position(float
x, float
z)
{
X
= x;
Z
= z;
Y
= 0f;
}
public
static
Position
operator
+(Position
p1, Position
p2)
{
var
result = new
Position(p1);
result.X
= p1.X + p2.X;
result.Y
= p1.Y + p2.Y;
result.Z
= p1.Z + p2.Z;
return
result;
}
public
static
bool
operator
==(Position
p1, Position
p2)
{
return
p1.ix == p2.ix && p1.iz == p2.iz;
}
public
static
bool
operator
!=(Position
p1, Position
p2)
{
return
p1.ix != p2.ix || p1.iz != p2.iz;
}
//Always
override GetHashCode(),Equals when overloading ==
public
override
bool
Equals(object
o)
{
return
this
== (Position)o;
}
public
override
int
GetHashCode()
{
return
ix ^ iz;
}
public
static
Position
operator
+(Position
p1, Vector3
p2)
{
var
result = new
Position(p1);
result.X
= p1.X + p2.X;
result.Y
= p1.Y + p2.Y;
result.Z
= p1.Z + p2.Z;
return
result;
}
public
static
Position
operator
+(Position
p1, Vector2
p2)
{
var
result = new
Position(p1);
result.X
= p1.X + p2.X;
result.Z
= p1.Z + p2.Y;
return
result;
}
public
static
Position
operator
-(Position
p1, Position
p2)
{
var
result = new
Position(p1);
result.X
= p1.X - p2.X;
result.Y
= p1.Y - p2.Y;
result.Z
= p1.Z - p2.Z;
return
result;
}
public
static
Position
operator
*(Position
p1, float
m)
{
var
result = new
Position(p1);
result.X
= p1.X * m;
result.Y
= p1.Y * m;
result.Z
= p1.Z * m;
return
result;
}
public
static
implicit
operator
Vector3(Position
pos)
{
return
new
Vector3(pos.X,
pos.Y, pos.Z);
}
public
static
implicit
operator
Vector2(Position
pos)
{
return
new
Vector2(pos.X,
pos.Z);
}
public
static
explicit
operator
Position(Vector3
vec)
{
return
new
Position(vec);
}
public
static
explicit
operator
Position(Vector2
vec)
{
return
new
Position((int)vec.X,
(int)vec.Y);
}
private
float
FieldXPosition(int
index)
{
return
ZeroFieldXLocation + index * Rift;
}
private
float
FieldZPosition(int
index)
{
return
ZeroFieldZLocation + index * Rift;
}
private
int
FieldXIndex(float
position)
{
return
Convert.ToInt32((position
- ZeroFieldXLocation) * InvRift);
}
private
int
FieldZIndex(float
position)
{
return
Convert.ToInt32((position
- ZeroFieldZLocation) * InvRift);
}
}
}
You might want to make it a struct rather than a class to avoid potentially loads of heap allocations.
ReplyDeleteGood point :-)
ReplyDelete