I am creating an isometric RTS with SFML I have most of the unit AI and basic melee combat in place.
For a little demo see my devlog:
Now comes the hard part. It would be fun to add ranged units. In order to acomadate for this I've created a projectile class and started to work to try and render a paraboloic 3d trajectory in my 2d isometric space.
My projectiles move along x,y,z axis and I then translate their coördinates to my isometric projection:
screenX = x*2 //since a tile is 64 pixels wide and 32 tall
screenY = y+z //since any upward movement is only visable in the Y axis
around this concept I made the following class:
struct mouseWorldCord
{
int x;
int y;
};
class projectile
{
public:
projectile(int projectileStartX, int projectileStartY, int projectileTargetX, int projectileTargetY, int projectileType, int damageOnImpact, int splashDamageOnImpact);
void updatePosition();
void drawProjectile();
void doDamage();
void doSplashDamage();
private:
mouseWorldCord projectilePosition;
mouseWorldCord projectileTarget;
float timeFired;
int projectileType;
int damageOnImpact;
int splashDamageOnImpact;
float X;
float Y;
float Z;
float deltaX;
float deltaY;
float deltaZ;
bool reachedTarget;
};
std::vector<projectile> listOfProjectiles;
projectile::projectile(int projectileStartX, int projectileStartY, int projectileTargetX, int projectileTargetY, int projectileType, int damageOnImpact, int splashDamageOnImpact)
{
this->X = worldSpace(projectileStartX, projectileStartY, true)/2;
this->Y = worldSpace(projectileStartX, projectileStartY, false);
this->Z = 0;
this->projectileType = projectileType;
this->damageOnImpact = damageOnImpact;
this->projectileTarget = { projectileTargetX, projectileTargetY };
this->projectilePosition = {projectileStartX, projectileStartY};
this->splashDamageOnImpact = splashDamageOnImpact;
float travelTimeInSeconds = distEuclidean(projectileStartX * 32.f, projectileStartY * 32.f, projectileTargetX * 32.f, projectileTargetY * 32.f) / 32.f; //32 pixel/s
this->deltaX = ((projectileStartX * 32.f) - (projectileTargetX * 32.f)) / travelTimeInSeconds;
this->deltaY = ((projectileStartY * 32.f) - (projectileTargetY * 32.f)) / travelTimeInSeconds;
this->deltaZ = travelTimeInSeconds / 2;
this->timeFired = currentGame.getTime();
this->reachedTarget = false;
}
void projectile::updatePosition()
{
if (!reachedTarget) {
//speed is in pixels per second
if (this->timeFired + 0.016 < currentGame.getTime()) {
this->timeFired = currentGame.getTime();
this->X += this->deltaX/60.f;
this->Y += this->deltaY/60.f;
this->Z += this->deltaZ/60.f;
this->deltaZ -= 0.016f;
if (this->Z <= 0.0f) {
doDamage();
reachedTarget = true;
}
}
}
}
void projectile::drawProjectile()
{
int xScreenCord = this->X * int(2);
int yScreenCord = this->Y + this->Z;
currentGame.spriteArrow.setPosition(xScreenCord, yScreenCord);
window.draw(currentGame.spriteArrow);
}
void projectile::doDamage()
{
if (currentGame.occupiedByActorList[this->projectileTarget.x][this->projectileTarget.y] != -1) {
listOfActors[currentGame.occupiedByActorList[this->projectileTarget.x][this->projectileTarget.y]].takeDamage(this->damageOnImpact);
}
else if (currentGame.occupiedByBuildingList[this->projectileTarget.x][this->projectileTarget.y] != -1)
{
listOfBuildings[currentGame.occupiedByBuildingList[this->projectileTarget.x][this->projectileTarget.y]].takeDamage(this->damageOnImpact);
}
}
What I want to achieve is have a fixed horizontal velocity. I broke this down in an x-vector and y-vector. I vary the z velocity. My aim is to have the velocity decrease over time and be at 0 in the middle of the path and then have a negative velocity the second half which increases each frame. Just like gravity is pulling on the projectile. In this way I get a nice parabolic trajectory for my arrow without complicated math. Or so I thought.
I must have made a mistake somewhere because my arrow is not moving as intended. It just follows a straight line of the screen. There is probably something amiss in my initial deltaZ velocity.
Maybe a fresh set of eyes looking at the code will help.