Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Enemy Sprites spawn but don't move and can't be killed  (Read 2963 times)

0 Members and 1 Guest are viewing this topic.

frank

  • Newbie
  • *
  • Posts: 1
    • View Profile
    • Email
Enemy Sprites spawn but don't move and can't be killed
« on: August 09, 2024, 01:09:57 am »
Hi;
I'm following the ZombieArena tutorial in Beginning C++ Game Programming. When I compile and run my code the zombies spawn so for the first level 5 are supposed to spawn, out of the 5 one or two might actually be running around chasing me, the others are immobile and can't be interacted with making it impossible to complete levels as you have to kill all zombies before going to next level.
I am on linux mint so I'm wondering if it's a windows to linux issue? As the book author is on windows?
Below are files that I believe the issue may be in..
I'm totally new to C++ and SFML so I would appreciate any guidance

This is my main.cpp if that helps?
#include <sstream>
#include <fstream>
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include "ZombieArena.h"
#include "Player.h"
#include "TextureHolder.h"
#include "Bullet.h"
#include "Pickup.h"
#include<iostream>
using namespace sf;

int main()
{
    // Here is the instance of TextureHolder
    TextureHolder holder;


    // The game will always be in one of four states
    enum class State {
        PAUSED, LEVELING_UP,
        GAME_OVER, PLAYING
    };

    // Start with the GAME_OVER state
    State state = State::GAME_OVER;
    // Get the screen resolution and
    // create an SFML window
    Vector2f resolution;
    resolution.x =
        VideoMode::getDesktopMode().width;
    resolution.y =
        VideoMode::getDesktopMode().height;
    RenderWindow window(
        VideoMode(resolution.x, resolution.y),
        "Zombie Arena", Style::Fullscreen);
    // Create a an SFML View for the main action
    View mainView(sf::FloatRect(0, 0,
        resolution.x, resolution.y));
    // Here is our clock for timing everything
    Clock clock;
    // How long has the PLAYING state been active
    Time gameTimeTotal;
    // Where is the mouse in
    // relation to world coordinates
    Vector2f mouseWorldPosition;
    // Where is the mouse in
    // relation to screen coordinates
    Vector2i mouseScreenPosition;
    // Create an instance of the Player class
    Player player;
    // The boundaries of the arena
    IntRect arena;
    // Create the background
    VertexArray background;
    // Load the texture for our background vertex array
    Texture textureBackground = TextureHolder::GetTexture(
        "graphics/background_sheet.png");


    // Prepare for a horde of zombies
    int numZombies;
    int numZombiesAlive;
    Zombie* zombies = NULL;

    // 100 bullets should do
    Bullet bullets[100];
    int currentBullet = 0;
    int bulletsSpare = 24;
    int bulletsInClip = 6;
    int clipSize = 6;
    float fireRate = 1;
    // When was the fire button last pressed?
    Time lastPressed;

    // Hide the mouse pointer and replace it with crosshair
    window.setMouseCursorVisible(true);
    Sprite spriteCrosshair;
    Texture textureCrosshair = TextureHolder::GetTexture("graphics/crosshair.png");
    spriteCrosshair.setTexture(textureCrosshair);
    spriteCrosshair.setOrigin(25, 25);

    // Create a couple of pickups
    Pickup healthPickup(1);
    Pickup ammoPickup(2);

    // About the game
    int score = 0;
    int hiScore = 0;

    // For the home/game over screen
    Sprite spriteGameOver;
    Texture textureGameOver = TextureHolder::GetTexture("graphics/background.png");
    spriteGameOver.setTexture(textureGameOver);
    spriteGameOver.setPosition(0, 0);
    // Create a view for the HUD
    View hudView(sf::FloatRect(0, 0, 1920,1080));
    // Create a sprite for the ammo icon
    Sprite spriteAmmoIcon;
    Texture textureAmmoIcon = TextureHolder::GetTexture(
        "graphics/ammo_icon.png");
    spriteAmmoIcon.setTexture(textureAmmoIcon);
    spriteAmmoIcon.setPosition(20, 980);
    // Load the font
    Font font;
    font.loadFromFile("fonts/zombiecontrol.ttf");
    // Paused
    Text pausedText;
    pausedText.setFont(font);
    pausedText.setCharacterSize(155);
    pausedText.setFillColor(Color::White);
    pausedText.setPosition(400, 400);
    pausedText.setString("Press Enter \nto continue");
    // Game Over
    Text gameOverText;
    gameOverText.setFont(font);
    gameOverText.setCharacterSize(125);
    gameOverText.setFillColor(Color::White);
    gameOverText.setPosition(250, 850);
    gameOverText.setString("Press Enter to play");
    // LEVELING up
    Text levelUpText;
    levelUpText.setFont(font);
    levelUpText.setCharacterSize(80);
    levelUpText.setFillColor(Color::White);
    levelUpText.setPosition(150, 250);
    std::stringstream levelUpStream;
    levelUpStream <<
        "1- Increased rate of fire" <<
        "\n2- Increased clip size(next reload)" <<
        "\n3- Increased max health" <<
        "\n4- Increased run speed" <<
        "\n5- More and better health pickups" <<
        "\n6- More and better ammo pickups";
    levelUpText.setString(levelUpStream.str());
    // Ammo
    Text ammoText;
    ammoText.setFont(font);
    ammoText.setCharacterSize(55);
    ammoText.setFillColor(Color::White);
    ammoText.setPosition(200, 980);
    // Score
    Text scoreText;
    scoreText.setFont(font);
    scoreText.setCharacterSize(55);
    scoreText.setFillColor(Color::White);
    scoreText.setPosition(20, 0);

    // Load the high score from a text file
    std::ifstream inputFile("gamedata/scores.txt");
    if (inputFile.is_open())
    {
        // >> Reads the data
        inputFile >> hiScore;
        inputFile.close();
    }


    // Hi Score
    Text hiScoreText;
    hiScoreText.setFont(font);
    hiScoreText.setCharacterSize(55);
    hiScoreText.setFillColor(Color::White);
    hiScoreText.setPosition(1400, 0);
    std::stringstream s;
    s << "Hi Score:" << hiScore;
    hiScoreText.setString(s.str());
    // Zombies remaining
    Text zombiesRemainingText;
    zombiesRemainingText.setFont(font);
    zombiesRemainingText.setCharacterSize(55);
    zombiesRemainingText.setFillColor(Color::White);
    zombiesRemainingText.setPosition(1500, 980);
    zombiesRemainingText.setString("Zombies: 100");
    // Wave number
    int wave = 0;
    Text waveNumberText;
    waveNumberText.setFont(font);
    waveNumberText.setCharacterSize(55);
    waveNumberText.setFillColor(Color::White);
    waveNumberText.setPosition(1250, 980);
    waveNumberText.setString("Wave: 0");
    // Health bar
    RectangleShape healthBar;
    healthBar.setFillColor(Color::Red);
    healthBar.setPosition(450, 980);

    // When did we last update the HUD?
    int framesSinceLastHUDUpdate = 0;
    // How often (in frames) should we update the HUD
    int fpsMeasurementFrameInterval = 1000;

    // Prepare the hit sound
    SoundBuffer hitBuffer;
    hitBuffer.loadFromFile("sound/hit.wav");
    Sound hit;
    hit.setBuffer(hitBuffer);
    // Prepare the splat sound
    SoundBuffer splatBuffer;
    splatBuffer.loadFromFile("sound/splat.wav");
    Sound splat;
    splat.setBuffer(splatBuffer);
    // Prepare the shoot sound
    SoundBuffer shootBuffer;
    shootBuffer.loadFromFile("sound/shoot.wav");
    Sound shoot;
    shoot.setBuffer(shootBuffer);
    // Prepare the reload sound
    SoundBuffer reloadBuffer;
    reloadBuffer.loadFromFile("sound/reload.wav");
    Sound reload;
    reload.setBuffer(reloadBuffer);
    // Prepare the failed sound
    SoundBuffer reloadFailedBuffer;
    reloadFailedBuffer.loadFromFile("sound/reload_failed.wav");
    Sound reloadFailed;
    reloadFailed.setBuffer(reloadFailedBuffer);
    // Prepare the powerup sound
    SoundBuffer powerupBuffer;
    powerupBuffer.loadFromFile("sound/powerup.wav");
    Sound powerup;
    powerup.setBuffer(powerupBuffer);
    // Prepare the pickup sound
    SoundBuffer pickupBuffer;
    pickupBuffer.loadFromFile("sound/pickup.wav");
    Sound pickup;
    pickup.setBuffer(pickupBuffer);


    // The main game loop
    while (window.isOpen())
    {
        /*
    ************
    Handle input
    ************
    */

    // Handle events by polling
        Event event;
        while (window.pollEvent(event))
        {
            if (event.type == Event::KeyPressed)
            {
                // Pause a game while playing
                if (event.key.code == Keyboard::Return &&
                    state == State::PLAYING)
                {
                    state = State::PAUSED;
                }
                // Restart while paused
                else if (event.key.code == Keyboard::Return &&
                    state == State::PAUSED)
                {
                    state = State::PLAYING;
                    // Reset the clock so there isn&#39;t a frame jump
                    clock.restart();
                }
                // Start a new game while in GAME_OVER state
                else if (event.key.code == Keyboard::Return &&
                    state == State::GAME_OVER)
                {
                    state = State::LEVELING_UP;
                    wave = 0;
                    score = 0;
                    // Prepare the gun and ammo for next game
                    currentBullet = 0;
                    bulletsSpare = 24;
                    bulletsInClip = 6;
                    clipSize = 6;
                    fireRate = 1;
                    // Reset the player&#39;s stats
                    player.resetPlayerStats();

                }
                if (state == State::PLAYING)
                {
                    // Reloading
                    if (event.key.code == Keyboard::R)
                    {
                        if (bulletsSpare >= clipSize)
                        {
                            // Plenty of bullets. Reload.
                            bulletsInClip = clipSize;
                            bulletsSpare -= clipSize;
                            reload.play();
                        }
                        else if (bulletsSpare > 0)
                        {
                            // Only few bullets left
                            bulletsInClip = bulletsSpare;
                            bulletsSpare = 0;
                            reload.play();
                        }
                        else
                        {
                            // More here soon?!
                            reloadFailed.play();
                        }
                    }

                }
            }
        }// End event polling

        // Handle the player quitting
        if (Keyboard::isKeyPressed(Keyboard::Escape))
        {
            window.close();
        }

        // Handle WASD while playing
        if (state == State::PLAYING)
        {
            // Handle the pressing and releasing of WASD keys
            if (Keyboard::isKeyPressed(Keyboard::W))
            {
                player.moveUp();
            }
            else
            {
                player.stopUp();
            }
            if (Keyboard::isKeyPressed(Keyboard::S))
            {
                player.moveDown();
            }
            else
            {
                player.stopDown();
            }
            if (Keyboard::isKeyPressed(Keyboard::A))
            {
                player.moveLeft();
            }
            else
            {
                player.stopLeft();
            }
            if (Keyboard::isKeyPressed(Keyboard::D))
            {
                player.moveRight();
            }
            else
            {
                player.stopRight();
            }

            // Fire a bullet
            if (Mouse::isButtonPressed(sf::Mouse::Left))
            {
                if (gameTimeTotal.asMilliseconds()
                    - lastPressed.asMilliseconds()
            > 1000 / fireRate && bulletsInClip > 0)
                {
                    // Pass the centre of the player
                    // and the centre of the cross-hair
                    // to the shoot function
                    bullets[currentBullet].shoot(
                        player.getCenter().x, player.getCenter().y,
                        mouseWorldPosition.x, mouseWorldPosition.y);
                    currentBullet++;
                    if (currentBullet > 99)
                    {
                        currentBullet = 0;
                    }
                    lastPressed = gameTimeTotal;
                    shoot.play();
                    bulletsInClip--;
                }
            }// End fire a bullet

        }// End WASD while playing

        // Handle the LEVELING up state
        if (state == State::LEVELING_UP)
        {
            // Handle the player LEVELING up
            // Handle the player LEVELING up
            if (event.key.code == Keyboard::Num1)
            {
                // Increase fire rate
                fireRate++;
                state = State::PLAYING;
            }
            if (event.key.code == Keyboard::Num2)
            {
                // Increase clip size
                clipSize += clipSize;
                state = State::PLAYING;
            }
            if (event.key.code == Keyboard::Num3)
            {
                // Increase health
                player.upgradeHealth();
                state = State::PLAYING;
            }
            if (event.key.code == Keyboard::Num4)
            {
                // Increase speed
                player.upgradeSpeed();
                state = State::PLAYING;
            }
            if (event.key.code == Keyboard::Num5)
            {
                // Upgrade pickup
                healthPickup.upgrade();
                state = State::PLAYING;
            }
            if (event.key.code == Keyboard::Num6)
            {
                // Upgrade pickup
                ammoPickup.upgrade();
                state = State::PLAYING;
            }


            if (state == State::PLAYING)
            {
                // Increase the wave number
                wave++;

                // Prepare the level
                // We will modify the next two lines later
                arena.width = 500 * wave;
                arena.height = 500 * wave;

                arena.left = 0;
                arena.top = 0;
                // Pass the vertex array by reference
                // to the createBackground function
                int tileSize = createBackground(background, arena);
                // We will modify this line of code later
                // int tileSize = 50;

                // Spawn the player in middle of the arena
                player.spawn(arena, resolution, tileSize);
                // Create a horde of zombies
                // Configure the pick-ups
                healthPickup.setArena(arena);
                ammoPickup.setArena(arena);

                numZombies = 5 * wave;
                // Delete the previously allocated memory (if it exists)
                delete[] zombies;
                zombies = createHorde(numZombies, arena);
                numZombiesAlive = numZombies;

                // Play the powerup sound
                powerup.play();


                // Reset clock so there isn&#39;t a frame jump
                clock.restart();
            }
        }// End LEVELING up

        /*
    ****************
    UPDATE THE FRAME
    ****************
    */

        if (state == State::PLAYING)
        {
            // Update the delta time
            Time dt = clock.restart();

            // Update the total game time
            gameTimeTotal += dt;

            // Make a fraction of 1 from the delta time
            float dtAsSeconds = dt.asSeconds();
            // Where is the mouse pointer
            mouseScreenPosition = Mouse::getPosition();

            // Convert mouse position to world
            // based coordinates of mainView
            mouseWorldPosition = window.mapPixelToCoords(
                Mouse::getPosition(), mainView);

            // Set the crosshair to the mouse world location
            spriteCrosshair.setPosition(mouseWorldPosition);

            // Update the player
            player.update(dtAsSeconds, Mouse::getPosition());
            // Make a note of the players new position
            Vector2f playerPosition(player.getCenter());

            // Make the view centre
            // the around player                
            mainView.setCenter(player.getCenter());
            // Loop through each Zombie and update them
            for (int i = 0; i < numZombies; i++)
            {
                if (zombies[i].isAlive())
                {
                    zombies[i].update(dt.asSeconds(), playerPosition);
                }
            }
            // Update any bullets that are in-flight
            for (int i = 0; i < 100; i++)
            {
                if (bullets[i].isInFlight())
                {
                    bullets[i].update(dtAsSeconds);
                }
            }

            // Update the pickups
            healthPickup.update(dtAsSeconds);
            ammoPickup.update(dtAsSeconds);

            // Collision detection
            // Have any zombies been shot?
            for (int i = 0; i < 100; i++)
            {
                for (int j = 0; j < numZombies; j++)
                {
                    if (bullets[i].isInFlight() &&
                        zombies[j].isAlive())
                    {
                        if (bullets[i].getPosition().intersects
                        (zombies[j].getPosition()))
                        {
                            // Stop the bullet
                            bullets[i].stop();
                            // Register the hit and see if it was a kill
                            if (zombies[j].hit())
                            {
                                // Not just a hit but a kill too
                                score += 10;
                                if (score >= hiScore)
                                {
                                    hiScore = score;
                                }
                                numZombiesAlive--;
                                // When all the zombies are dead (again)
                                if (numZombiesAlive == 0) {
                                    state = State::LEVELING_UP;
                                }

                                // Make a splat sound
                                splat.play();

                            }

                        }
                    }
                }
            }// End zombie being shot

            // Have any zombies touched the player            
            for (int i = 0; i < numZombies; i++)
            {
                if (player.getPosition().intersects
                (zombies[i].getPosition()) && zombies[i].isAlive())
                {
                    if (player.hit(gameTimeTotal))
                    {
                        // More here later
                       
                        hit.play();
                    }
                    if (player.getHealth() <= 0)
                    {
                        state = State::GAME_OVER;
                        std::ofstream outputFile("gamedata/scores.txt");
                        // << writes the data
                        outputFile << hiScore;
                        outputFile.close();

                    }
                }
            }// End player touched

            // Has the player touched health pickup
            if (player.getPosition().intersects(healthPickup.getPosition()) && healthPickup.isSpawned())
            {
                player.increaseHealthLevel(healthPickup.gotIt());
                // Play a sound
                pickup.play();



            }
            // Has the player touched ammo pickup
            if (player.getPosition().intersects(ammoPickup.getPosition()) && ammoPickup.isSpawned())
            {
                bulletsSpare += ammoPickup.gotIt();
                // Play a sound
                reload.play();


            }

            // size up the health bar
            healthBar.setSize(Vector2f(player.getHealth() * 3, 50));
            // Increment the number of frames since the previous update
            framesSinceLastHUDUpdate++;
            // re-calculate every fpsMeasurementFrameInterval frames
            if (framesSinceLastHUDUpdate > fpsMeasurementFrameInterval)
            {
                // Update game HUD text
                std::stringstream ssAmmo;
                std::stringstream ssScore;
                std::stringstream ssHiScore;
                std::stringstream ssWave;
                std::stringstream ssZombiesAlive;
                // Update the ammo text
                ssAmmo << bulletsInClip << "/" << bulletsSpare;
                ammoText.setString(ssAmmo.str());
                // Update the score text
                ssScore << "Score:" << score;
                scoreText.setString(ssScore.str());
                // Update the high score text
                ssHiScore << "Hi Score:" << hiScore;
                hiScoreText.setString(ssHiScore.str());
                // Update the wave
                ssWave << "Wave:" << wave;
                waveNumberText.setString(ssWave.str());
                // Update the high score text
                ssZombiesAlive << "Zombies:" << numZombiesAlive;
                zombiesRemainingText.setString(ssZombiesAlive.str());
                framesSinceLastHUDUpdate = 0;
            }// End HUD update


        }// End updating the scene

         

    /*
    **************
    Draw the scene
    **************
    */

        if (state == State::PLAYING)
        {
            window.clear();
            // set the mainView to be displayed in the window
            // And draw everything related to it
            window.setView(mainView);

            // Draw the background
            window.draw(background, &textureBackground);

            // Draw the zombies
            for (int i = 0; i < numZombies; i++)
            {
                window.draw(zombies[i].getSprite());
            }

            for (int i = 0; i < 100; i++)
            {
                if (bullets[i].isInFlight())
                {
                    window.draw(bullets[i].getShape());
                }
            }

            // Draw the pick-ups, if currently spawned
            if (ammoPickup.isSpawned())
            {
                window.draw(ammoPickup.getSprite());
            }

            if (healthPickup.isSpawned())
            {
                window.draw(healthPickup.getSprite());
            }

            //Draw the crosshair
            window.draw(spriteCrosshair);

            // Draw the player
            window.draw(player.getSprite());

            // Switch to the HUD view
            window.setView(hudView);
            // Draw all the HUD elements
            window.draw(spriteAmmoIcon);
            window.draw(ammoText);
            window.draw(scoreText);
            window.draw(hiScoreText);
            window.draw(healthBar);
            window.draw(waveNumberText);
            window.draw(zombiesRemainingText);


           
        }

        if (state == State::LEVELING_UP)
        {
            window.draw(spriteGameOver);
            window.draw(levelUpText);

        }

        if (state == State::PAUSED)
        {
            window.draw(pausedText);
        }

        if (state == State::GAME_OVER)
        {
            window.draw(spriteGameOver);
            window.draw(gameOverText);
            window.draw(scoreText);
            window.draw(hiScoreText);

        }

        window.display();

    }// End game loop


    // Delete the previously allocated memory (if it exists)
    delete[] zombies;

    return 0;

}
« Last Edit: August 09, 2024, 10:58:34 pm by frank »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11004
    • View Profile
    • development blog
    • Email
Re: Enemy Sprites spawn but don't move and can't be killed
« Reply #1 on: August 12, 2024, 12:23:53 pm »
It's quite a bit of code. Best to use a debugger, step through your code and look at variables to understand what's going on.

My guess from a quick glance at it is, that you're not updating numZombies properly.
So when you switch to the playing state you calculate 5 * wave, where wave is set to 1 and thus you'll always just get 5 zombies being updated.
That's just from very quickly looking at it, without analyzing the code flow more in-depth.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

JZ

  • Newbie
  • *
  • Posts: 2
    • View Profile
Re: Enemy Sprites spawn but don't move and can't be killed
« Reply #2 on: September 21, 2024, 07:35:31 pm »
Hi Frank,

I have the exact same problem though I'm only in chapter 10 so I don't have as much of the code fleshed out as in your example. The code will compile correctly and the game will start but a seemingly random number of the enemy sprites will remain fixed to the arena walls and are unresponsive. To compare with my code I ran the sample code the publisher posted to github to check and see if I could identify any errors. When I ran the example the same problem appeared.

I'm not sure if the problem is in the code logic itself or if it's an artifact of something else. I'm using the g++ compiler in ubuntu using a makefile and writing my code in text files; I'm not using visual studio so I wonder if that could be the source of the problem.

If you have made any progress on this I'd be curious to hear about what you did.

Best,
JZ

JZ

  • Newbie
  • *
  • Posts: 2
    • View Profile
Re: Enemy Sprites spawn but don't move and can't be killed
« Reply #3 on: September 29, 2024, 12:38:28 pm »
I figured out the problem. There is a bug in the github code and I believe in the book itself. In the Zombie.cpp file the m_Alive boolean is never initialized. All I had to do was set m_Alive = true; in the void Zombie::spawn() type like so:
void Zombie::spawn(float startX, float startY, int type, int seed)
{
        m_Alive = true;
        switch(type)
        {
        case 0:
                // Bloater
                m_Sprite = Sprite(TextureHolder::GetTexture("graphics/bloater.png"));
                m_Speed = BLOATER_SPEED;
                m_Health = BLOATER_HEALTH;
                break;

        case 1:
                // Chaser
                m_Sprite = Sprite(TextureHolder::GetTexture("graphics/chaser.png"));
                m_Speed = CHASER_SPEED;
                m_Health = CHASER_HEALTH;
                break;
               
        case 2:
                // Crawler
                m_Sprite = Sprite(TextureHolder::GetTexture("graphics/crawler.png"));
                m_Speed = CRAWLER_SPEED;
                m_Health = CRAWLER_HEALTH;
                break; 
        }