I'm making a 2D shooter, and the player object holds an array of bullets that represent how many shots the player can have on screen at once. At least, this is what I'm trying for. What's happening is that each time any of the objects in the array is called, it seems to update a single object in memory. So, if I fire and then fire again, the object "starts over" from where I shot from and moves twice as fast. I've spent weeks trying to fix this and I've managed nothing. Hopefully another pair of eyes will see something I've missed.
Player.cpp
#include "Player.h"
const int startLives = 3;
const int maxHealth = 2;
const float speed = 1;
const int maxVelocity = 500;
const int topBound = WINDOW_HEIGHT / 5 * 3;
const int slowRate = 500;
const int accRate = 1000;
const int maxBullets = 5;
const float spriteWidth = 99;
const float spriteHeight = 75;
const Vector2f startPosition =
{
(WINDOW_WIDTH / 2) - (spriteWidth / 2),
(WINDOW_HEIGHT / 4 * 3) - (spriteHeight / 2)
};
Bullet bullets[maxBullets];
Bullet * bulletPointers[maxBullets];
SDL_Texture * playerHealthy;
SDL_Texture * playerDamaged;
SDL_Texture * currentSprite;
SDL_Rect * rect;
Vector2f position;
Vector2f velocity;
int Health;
int Lives;
Player::Player()
{
rect = new SDL_Rect();
}
Player::~Player()
{
SDL_DestroyTexture(playerHealthy);
SDL_DestroyTexture(playerDamaged);
SDL_DestroyTexture(currentSprite);
rect = NULL;
}
void Player::Initialize(SDL_Renderer * renderer)
{
SDL_Surface * temp;
temp = IMG_Load(".\\Sprites\\player.png");
if (temp == NULL)
{
printf("Initialization Error: %s\n", IMG_GetError());
exit(PLAYER_INITIALIZATION_ERROR);
}
playerHealthy = SDL_CreateTextureFromSurface(renderer, temp);
temp = IMG_Load(".\\Sprites\\playerDamaged.png");
if (temp == NULL)
{
printf("Initialization Error: %s\n", IMG_GetError());
exit(PLAYER_INITIALIZATION_ERROR);
}
playerDamaged = SDL_CreateTextureFromSurface(renderer, temp);
temp = IMG_Load(".\\Sprites\\laserGreen.png");
if (temp == NULL)
{
printf("Initialization Error: %s\n", IMG_GetError());
exit(PLAYER_INITIALIZATION_ERROR);
}
SDL_Texture * bullet = SDL_CreateTextureFromSurface(renderer, temp);
temp = IMG_Load(".\\Sprites\\laserGreenShot.png");
if (temp == NULL)
{
printf("Initialization Error: %s\n", IMG_GetError());
exit(PLAYER_INITIALIZATION_ERROR);
}
SDL_Texture * explosion = SDL_CreateTextureFromSurface(renderer, temp);
for (int i = 0; i < maxBullets; i++)
{
bullets[i].Initialize(renderer, bullet, explosion);
bulletPointers[i] = NULL;
}
temp = NULL;
rect->h = spriteHeight;
rect->w = spriteWidth;
Reset();
}
void Player::Update(Input input, float deltaTime)
{
if (abs(velocity.x) < slowRate * deltaTime)
{
velocity.x = 0;
}
else if (velocity.x > 0)
{
velocity.x -= slowRate * deltaTime;
}
else if (velocity.x < 0)
{
velocity.x += slowRate * deltaTime;
}
if (abs(velocity.y) < slowRate * deltaTime)
{
velocity.y = 0;
}
if (velocity.y > 0)
{
velocity.y -= slowRate * deltaTime;
}
else if (velocity.y < 0)
{
velocity.y += slowRate * deltaTime;
}
if (Health <= 0)
{
--Lives;
Spawn();
}
velocity.x += UnitVector(input.InputNew.movement).x * accRate * deltaTime;
velocity.y += UnitVector(input.InputNew.movement).y * accRate * deltaTime;
if (Magnitude(velocity) > maxVelocity)
{
velocity.x = UnitVector(velocity).x * maxVelocity;
velocity.y = UnitVector(velocity).y * maxVelocity;
}
position.x += velocity.x * deltaTime * speed;
position.y += velocity.y * deltaTime * speed;
if (input.InputNew.JumpLeft && !input.InputOld.JumpLeft)
{
position.x -= spriteWidth;
}
if (input.InputNew.JumpRight && !input.InputOld.JumpRight)
{
position.x += spriteWidth;
}
Boundaries();
rect->x = position.x;
rect->y = position.y;
if (input.InputNew.Fire && !input.InputOld.Fire)
{
Fire();
}
for (int i = 0; i < maxBullets; ++i)
{
if (bulletPointers[i] != NULL)
{
bullets[i].Update(deltaTime);
if (bullets[i].getPosition().y < -33)
{
bulletPointers[i] = NULL;
}
}
}
}
void Player::Draw(SDL_Renderer * renderer)
{
for (int i = 0; i < maxBullets; ++i)
{
if (bulletPointers[i] != NULL)
{
bullets[i].Draw(renderer);
}
}
SDL_RenderCopy(renderer, currentSprite, NULL, rect);
}
void Player::Spawn()
{
position = startPosition;
Health = maxHealth;
currentSprite = playerHealthy;
rect->x = position.x;
rect->y = position.y;
}
void Player::Boundaries()
{
if (position.x < 0)
{
position.x = 0;
velocity.x *= -1;
}
else if (position.x > WINDOW_WIDTH - spriteWidth)
{
position.x = WINDOW_WIDTH - spriteWidth;
velocity.x *= -1;
}
if (position.y < topBound)
{
position.y = topBound;
velocity.y *= -1;
}
else if (position.y > WINDOW_HEIGHT - spriteHeight)
{
position.y = WINDOW_HEIGHT - spriteHeight;
velocity.y *= -1;
}
}
int Player::getLives()
{
return Lives;
}
void Player::Reset()
{
Lives = startLives;
Spawn();
}
void Player::Fire()
{
for (int i = 0; i < maxBullets; ++i)
{
if (bulletPointers[i] == NULL)
{
bulletPointers[i] = &bullets[i];
bullets[i].Fire(position,velocity.x/2);
break;
}
}
}
Bullet.cpp
#include "Bullet.h"
const int speed = 500;
Vector2f bulletVelocity;
float ExplosionMax = 0.5f;
float ExplosionTimer;
const Vector2f fireOffset = { 45.5f, 10.0f };
const Vector2f explosionOffset = { 23.5f, -27.0f };
const Vector2i bulletSize = { 9, 33 };
const Vector2i explosionSize = { 56, 54 };
Vector2f bulletPosition;
SDL_Texture * bulletSprite;
SDL_Texture * explosionSprite;
SDL_Texture * bulletCurrentSprite;
SDL_Rect * bulletRect;
Bullet::Bullet()
{
}
Bullet::~Bullet()
{
}
void Bullet::Initialize(SDL_Renderer * renderer, SDL_Texture * bullet, SDL_Texture * explosion)
{
bulletSprite = bullet;
explosionSprite = explosion;
bulletRect = new SDL_Rect();
}
void Bullet::Update(float deltaTime)
{
bulletPosition.y -= bulletVelocity.y * deltaTime;
bulletPosition.x += bulletVelocity.x * deltaTime;
bulletRect->x = static_cast<int>(bulletPosition.x);
bulletRect->y = static_cast<int>(bulletPosition.y);
}
void Bullet::Draw(SDL_Renderer * renderer)
{
SDL_RenderCopy(renderer, bulletCurrentSprite, NULL, bulletRect);
}
void Bullet::Fire(Vector2f pos, float xSpeed)
{
bulletPosition.x = pos.x + fireOffset.x;
bulletPosition.y = pos.y + fireOffset.y;
bulletVelocity.x = xSpeed;
bulletVelocity.y = speed;
bulletCurrentSprite = bulletSprite;
bulletRect->h = bulletSize.y;
bulletRect->w = bulletSize.x;
bulletRect->x = static_cast<int>(bulletPosition.x);
bulletRect->y = static_cast<int>(bulletPosition.y);
}
Vector2f Bullet::getPosition()
{
return bulletPosition;
}
void Bullet::Hit()
{
bulletCurrentSprite = explosionSprite;
bulletVelocity = { 0.0f, 0.0f };
ExplosionTimer = ExplosionMax;
bulletPosition.x += explosionOffset.x;
bulletPosition.y += explosionOffset.y;
bulletRect->w = explosionSize.x;
bulletRect->h = explosionSize.y;
}