0
\$\begingroup\$
#pragma once
#include "SFML\Graphics.hpp"
#include "ResourceIdentifier.h"
#include "ResourceManager.h"

class Entity {

public:

    Entity() : m_angle(0) {
    }

    float getX() const noexcept { return m_sprite.getPosition().x; }

    float getY() const noexcept { return m_sprite.getPosition().y; }

    float left() const noexcept { return getX() - m_sprite.getGlobalBounds().width / 2.0f; }

    float right() const noexcept { return getX() + m_sprite.getGlobalBounds().width / 2.0f; }

    float top() const noexcept { return getY() - m_sprite.getGlobalBounds().height / 2.0f; }

    float bottom() const noexcept { return getY() + m_sprite.getGlobalBounds().height / 2.0f; }

    float spriteWidth() const noexcept { return m_sprite.getGlobalBounds().width; }

    float spriteHeight() const noexcept { return m_sprite.getGlobalBounds().height; }

    void draw(sf::RenderWindow& window) {
        window.draw(m_sprite);
    }

    bool checkCollision(const Entity& entity) const {
        return (m_sprite.getGlobalBounds().intersects(entity.m_sprite.getGlobalBounds()));
    }

    const sf::Sprite& getSprite() const {
        return m_sprite; 
    }

    virtual ~Entity() {
    }

protected:

    double m_angle;
    sf::Sprite m_sprite;
    int m_speed;//speed that you travel every second

};



#pragma once
#include "Globals.h"
#include "ResourceManager.h"
#include "ResourceIdentifier.h"
#include "Entity.h"
#include <iostream>
#include <cmath>

class Shooter : public Entity{

private:
    bool m_moving; 
    bool m_targetInDeadzone; 
    sf::Vector2f m_targetPos;
    const int m_deadzoneRadius = 5;
public:
    Shooter();
    void initialize(const TextureManager&);
    void moveShip(float dt);
    void angleShipToMouse(const sf::Vector2i&);
    void handleInput(const sf::Event&, const sf::Vector2i&);
    void update(const sf::Vector2i&, float);
    void adjustingTargetPosition();
    bool inDeadzone();
};

#include "SpaceShooter.h"

Shooter::Shooter() : m_moving(false)
{
}

void Shooter::initialize(const TextureManager& text)
{
    m_speed = 700;
    this->m_sprite.setTexture(text.get(TextureID::Shooter));
    this->m_sprite.setOrigin(m_sprite.getGlobalBounds().width / 2.0f, m_sprite.getGlobalBounds().height / 2.0f);
    this->m_sprite.setPosition(Globals::m_windowWidth / 2.0f, Globals::m_windowHeight / 2.0f); 
}

void Shooter
::moveShip(float dt) 
{
    if (m_moving) {

        if (m_targetInDeadzone) {
            adjustingTargetPosition(); //angle can change the width and height of sprite and this changes the size of the deadzone 
        }

        sf::Vector2f shipVelocity(cos(m_angle * Globals::deg2rad) * m_speed * dt, sin(m_angle * Globals::deg2rad) *  m_speed * dt);

        float targetDistance = sqrt(pow(m_targetPos.x - getX(), 2) + pow(m_targetPos.y - getY(), 2));
        float distanceToTravel = sqrt(pow(shipVelocity.x, 2) + pow(shipVelocity.y, 2));

        if (targetDistance > distanceToTravel) {
            this->m_sprite.move(shipVelocity.x, shipVelocity.y);
            std::cout << m_targetPos.y << std::endl;
        //  std::cout << targetDistance << " > " << distanceToTravel << std::endl;
        }
        else {
            this->m_sprite.setPosition(m_targetPos.x, m_targetPos.y);
            m_moving = false;
        }
    }
}

void Shooter::angleShipToMouse(const sf::Vector2i& mousePosition) {

    sf::Vector2f mouseRelativeShip(mousePosition.x - getX(), mousePosition.y - getY());

//5 pixel circular deadzone where mouse position cant change ship angle
    if (sqrt(pow(mouseRelativeShip.x, 2) + pow(mouseRelativeShip.y, 2)) <= m_deadzoneRadius) {
        return; 
    }

    float rotation = atan2(mouseRelativeShip.y, mouseRelativeShip.x)*Globals::rad2deg; //atan2 produces negative angles if vector is in QUADS 1&2, positive in QUADS 3&4

    this->m_sprite.setRotation(rotation);

    m_angle = this->m_sprite.getRotation();
}

void Shooter::handleInput(const sf::Event& event, const sf::Vector2i& mousePos) {
    if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) {   
        if (!m_moving) {
            m_moving = true;
            m_targetPos = static_cast<sf::Vector2f>(mousePos);
            m_targetInDeadzone = inDeadzone(); 
        }
    }
}

void Shooter::update(const sf::Vector2i& mousePosition, float dt) {
    angleShipToMouse(mousePosition);
    moveShip(dt);
}

void Shooter::adjustingTargetPosition()
{
    if (m_targetPos.x < spriteWidth() / 2.0f) {
        m_targetPos.x = spriteWidth() / 2.0f;
    }
    else if (m_targetPos.x > Globals::m_windowWidth - spriteWidth() / 2.0f) {
        m_targetPos.x = Globals::m_windowWidth - spriteWidth() / 2.0f; 
    }
    else if(m_targetPos.y < spriteHeight() / 2.0f){
        m_targetPos.y = spriteHeight() / 2.0f;
    }
    else if (m_targetPos.y > Globals::m_windowHeight - spriteHeight() / 2.0f) {
        m_targetPos.y = Globals::m_windowHeight - spriteHeight() / 2.0f;
    }
}

bool Shooter::inDeadzone()
{
    if (m_targetPos.x < spriteWidth() / 2.0f || m_targetPos.x > Globals::m_windowWidth - spriteWidth() / 2.0f || 
        m_targetPos.y < spriteHeight() / 2.0f || m_targetPos.y > Globals::m_windowHeight - spriteHeight() / 2.0f) {
        return true; 
    } return false; 
}

The problem is that clicking on a new target position or dragging the mouse while the spaceship is in motion will cause the ship to follow the cursor, but I am trying to do 1 click, spaceship flies there and cannot redirect before it reaches the target. I tried to achieve this by not letting it change the target position with the flag (!m_moving) while flying and I tested this by debugging it and it seems the target is not changing which is great which is why im confused as to why it lets me do this. I've disabled repeated key presses for the windows.

The second problem is the boundaries, sometimes it works correctly but often it won't, the spaceship will fly through at times. I've printed out targetposition vs the distancetotravel, and it showed it working for a while and then eventually (the targetposition starts increasing when it should be gradually decreasing before it satisfies the condition that targetposition

This shows the targetdistance > distancetotravel when it goes towards the boundary, as you can see it bugs out at one point, and I can't think why because it works fine if its not against the boundary.

enter image description here

\$\endgroup\$
  • \$\begingroup\$ First question: do you have access to C++11 features? \$\endgroup\$ – Pharap Apr 25 '17 at 7:28
  • \$\begingroup\$ It's not pertinent to the problem, but a bit of advice: sqrt(pow(mouseRelativeShip.x, 2) + pow(mouseRelativeShip.y, 2)) <= m_deadzoneRadius can be made cheaper by changing it to pow(mouseRelativeShip.x, 2) + pow(mouseRelativeShip.y, 2) <= m_deadzoneRadius * m_deadzoneRadius because sqrt is typically more expensive than * and the logic is still the same because instead of reducing the exponent of the left hand side you increase the exponent of the right hand side and the ratio remains the same. \$\endgroup\$ – Pharap Apr 25 '17 at 7:39
1
\$\begingroup\$

I think your problem lies here:

void Shooter::adjustingTargetPosition()
{
    if (m_targetPos.x < spriteWidth() / 2.0f) {
        m_targetPos.x = spriteWidth() / 2.0f;
    }
    else if (m_targetPos.x > Globals::m_windowWidth - spriteWidth() / 2.0f) {
        m_targetPos.x = Globals::m_windowWidth - spriteWidth() / 2.0f; 
    }
    else if(m_targetPos.y < spriteHeight() / 2.0f){
        m_targetPos.y = spriteHeight() / 2.0f;
    }
    else if (m_targetPos.y > Globals::m_windowHeight - spriteHeight() / 2.0f) {
        m_targetPos.y = Globals::m_windowHeight - spriteHeight() / 2.0f;
    }
}

See that this is all one else-if chain, but you are attempting to clamp both x and y, thus y is never clamped if x is clamped beforehand.

Try the following:

void Shooter::adjustingTargetPosition()
{
    const float xMin = spriteWidth() / 2.0f;
    const float xMax = Globals::m_windowWidth - spriteWidth() / 2.0f
    const float yMin = spriteHeight() / 2.0f;
    const float yMax = Globals::m_windowHeight - spriteHeight() / 2.0f

    m_targetPos.x = (m_targetPos.x < xMin) ? xMin : (m_targetPos.x > xMax) ? xMax : m_targetPos.x;
    m_targetPos.y = (m_targetPos.y < yMin) ? yMin : (m_targetPos.y > yMay) ? yMay : m_targetPos.y;
}
\$\endgroup\$
0
\$\begingroup\$

I am not a pro in C++ so I might be totally wrong:

First problem: your vector m_target get the adress of your mousePointer. If you click elsewhere, even if the condition are not met to update the value of the target, your the value of your mousePointer is changing so does your m_target, am i wrong?

Second problem: Do you update your m_angle when you are near the deadzone?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.