I am using C++ and SFML to make a top-down Zombie shooter. For now I have a player I can move around who can shoot but I am trying to have a basic AI for a Zombie who chases the player based on player position.
For some reason the zombie is moving in a straight direction rather than chasing player. I believe that the problem has to do with incorrect player position being used to calculate the direction of the zombie. But I can't seem to figure out how to fix the problem. Any help will be appreciated. Thanks!
Here is my code so far:
Player.cpp
//GetPosition() is getting player position
//I even tried getting output of player's x and y position in this class and
//its correctly showing player's position
sf::Vector2f Player::GetPosition()
{
xPos = playerSprite.getPosition().x;
yPos = playerSprite.getPosition().y;
sf::Vector2f position = sf::Vector2f(xPos, yPos);
//Correctly outputs position
std::cout << "X: " << position.x << " Y: " << position.y << std::endl;
return position;
}
void Player::movePlayer(sf::RenderWindow& window)
{
playerPosition = GetPosition();
//std::cout << "X: " << GetPosition().x << " Y: " << GetPosition().y <<
std::endl;
mousePosWindow = sf::Vector2f(sf::Mouse::getPosition(window));
if (mousePosWindow.x < 0.f || mousePosWindow.x > window.getSize().x ||
mousePosWindow.y < 0.f || mousePosWindow.y > window.getSize().y)
{
"";
}
aimDirection = mousePosWindow - playerPosition;
aimDirNorm = aimDirection / sqrt(pow(aimDirection.x, 2) +
pow(aimDirection.y, 2));
//Player
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) ||
sf::Keyboard::isKeyPressed(sf::Keyboard::A))
{
playerSprite.move(-5.f, 0.f);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right) ||
sf::Keyboard::isKeyPressed(sf::Keyboard::D))
{
playerSprite.move(5.f, 0.f);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) ||
sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
playerSprite.move(0.f, -5.f);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) ||
sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
playerSprite.move(0.f, 5.f);
}
//Rotate player relative to mouse position
const float PI = 3.14159265;
float dx = playerPosition.x - mousePosWindow.x;
float dy = playerPosition.y - mousePosWindow.y;
rotation = (atan2(dy, dx)) * 180 / PI;
playerSprite.setRotation(rotation + 180);
}
Zombie.h
#pragma once
#include <SFML/Graphics.hpp>
#include "Player.h"
class Zombie
{
public:
Zombie();
Player player;
sf::Texture zombieTexture;
sf::Sprite zombieSprite;
sf::Vector2f zombiePosition;
sf::Vector2f playerPosition;
sf::Vector2f direction;
sf::Vector2f normalizedDir;
int xPos;
int yPos;
float speed;
void Move();
};
Zombie.cpp
void Zombie::Move()
{
// Make movement
xPos = zombieSprite.getPosition().x;
yPos = zombieSprite.getPosition().y;
zombiePosition = sf::Vector2f(xPos, yPos);
playerPosition = player.GetPosition();
//Incorrectly outputs player position
//This outputs 0 constantly. But why?
std::cout << "X: " << player.playerPosition.x << " Y: " <<
player.playerPosition.y << std::endl;
direction = playerPosition - zombiePosition;
normalizedDir = direction / sqrt(pow(direction.x, 2) + pow(direction.y, 2));
speed = 2;
//Rotate the Zombie relative to player position
const float PI = 3.14159265;
float dx = zombiePosition.x - playerPosition.x;
float dy = zombiePosition.y - playerPosition.y;
float rotation = (atan2(dy, dx)) * 180 / PI;
zombieSprite.setRotation(rotation + 45);
sf::Vector2f currentSpeed = normalizedDir * speed;
zombieSprite.move(currentSpeed);
}
main.cpp
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include "Player.h"
#include "Bullet.h"
#include "Zombie.h"
#include <vector>
#include <iostream>
int main()
{
sf::RenderWindow window(sf::VideoMode(1280, 720), "Arcade Zombies :
Multiplayer");
window.setFramerateLimit(60);
window.setMouseCursorVisible(false); // Hide cursor
sf::View fixed = window.getView(); // Create a fixed view
//Background
sf::Texture backgroundTexture;
if (!backgroundTexture.loadFromFile("resources/background.png"))
{
std::cout << "Load failed" << std::endl;
system("pause");
}
sf::Sprite backgroundSprite;
backgroundSprite.setTexture(backgroundTexture);
backgroundSprite.setOrigin(sf::Vector2f(backgroundSprite.getTexture()-
>getSize().x, backgroundSprite.getTexture()->getSize().y));
backgroundSprite.setPosition(window.getSize().x, window.getSize().y);
backgroundSprite.scale(sf::Vector2f(1.1f, 0.7f)); // absolute scale factor
//Cursor
sf::Texture cursorTexture;
if (!cursorTexture.loadFromFile("resources/gun-pointer.png"))
{
std::cout << "Load failed" << std::endl;
system("pause");
}
sf::Sprite cursorSprite(cursorTexture);
cursorSprite.setOrigin(sf::Vector2f(cursorSprite.getTexture()->getSize().x *
0.5, cursorSprite.getTexture()->getSize().y * 0.5));
//Player
Player player;
player.playerSprite.setPosition(window.getSize().x / 2.f, window.getSize().y
- 50);
//Zombie
Zombie zombie;
zombie.zombieSprite.setPosition(window.getSize().x / 2.f, window.getSize().y
/ 2.f);
zombie.zombieSprite.scale(sf::Vector2f(0.3f, 0.3f));
//Bullet
Bullet bullet1;
std::vector<Bullet> bullets;
int shootTimer = 0;
//Sound
sf::SoundBuffer gunBuffer, footstepBuffer;
if (!gunBuffer.loadFromFile("resources/gun_shot_sound.wav"))
{
std::cout << "Load failed" << std::endl;
}
sf::Sound gunSound;
gunSound.setBuffer(gunBuffer);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
//Update
player.movePlayer(window);
//Zombie
zombie.Move();
//Shoot
if (shootTimer < 20)
shootTimer++;
if (sf::Mouse::isButtonPressed(sf::Mouse::Left) && shootTimer >= 20)
{
gunSound.play();
bullet1.bulletSprite.setOrigin(
sf::Vector2f(bullet1.bulletSprite.getTexture()->getSize().x * 0.5,
bullet1.bulletSprite.getTexture()->getSize().y * 0.5));
bullet1.bulletSprite.setPosition(player.playerPosition);
bullet1.currentVelocity = player.aimDirNorm * bullet1.maxSpeed;
bullet1.bulletSprite.setRotation(player.rotation + 90);
bullets.push_back(Bullet(bullet1));
shootTimer = 0;
}
for (size_t i = 0; i < bullets.size(); i++)
{
bullets[i].bulletSprite.move(bullets[i].currentVelocity);
if (bullets[i].bulletSprite.getPosition().x < 0 ||
bullets[i].bulletSprite.getPosition().x > window.getSize().x ||
bullets[i].bulletSprite.getPosition().y < 0 ||
bullets[i].bulletSprite.getPosition().y > window.getSize().y)
{
bullets.erase(bullets.begin() + i);
}
}
// Set mouse position
cursorSprite.setPosition(static_cast<sf::Vector2f>
(sf::Mouse::getPosition(window)));
//Draw
window.clear();
window.setView(fixed);
window.draw(backgroundSprite);
window.draw(player.playerSprite);
window.draw(zombie.zombieSprite);
window.draw(cursorSprite);
for (size_t i = 0; i < bullets.size(); i++)
{
window.draw(bullets[i].bulletSprite);
}
window.display();
}
return 0;
}