Browse Source

implement acceleration based player movement

adapted from noerw/experimental-shooter-no3
master
noerw 1 year ago
parent
commit
f03838f0bb
6 changed files with 295 additions and 5 deletions
  1. 4
    0
      game.cpp
  2. 0
    1
      game.hpp
  3. 1
    1
      main.cpp
  4. 100
    0
      player.cpp
  5. 13
    3
      player.hpp
  6. 177
    0
      vec2util.hpp

+ 4
- 0
game.cpp View File

@@ -34,6 +34,9 @@ namespace Proto4 {
break;

case GameState::Running:
player.update(timestep, window.mapPixelToCoords(sf::Mouse::getPosition(window), mainView));
// mainView acts as camera. TODO: introduce lagging camera
mainView.setCenter(player.getPosition());
break;

default:
@@ -49,6 +52,7 @@ namespace Proto4 {
}

bool Game::reset() {
player = Player();
state = GameState::Uninitialized;
return true;
}

+ 0
- 1
game.hpp View File

@@ -30,6 +30,5 @@ namespace Proto4 {
GameState state = GameState::Uninitialized;
Player player{};
uint32_t score = 0;

};
}

+ 1
- 1
main.cpp View File

@@ -99,7 +99,7 @@ namespace Proto4 {
// move camera for background movement
gameView.setCenter(sf::Vector2f(
gameView.getCenter().x + timestep.asSeconds() * 100 * std::sin(currentTime.asSeconds()),
gameView.getCenter().y - timestep.asSeconds() * 100));
gameView.getCenter().y + timestep.asSeconds() * 100));
break;
case AppState::Game:
state = game.update(window, timestep);

+ 100
- 0
player.cpp View File

@@ -1,4 +1,7 @@
#include <cmath>

#include "player.hpp"
#include "vec2util.hpp"

namespace Proto4 {
Player::Player() {
@@ -14,4 +17,101 @@ namespace Proto4 {
void Player::setPosition(sf::Vector2f pos) {
triangle.setPosition(pos);
}

sf::Vector2f Player::getPosition() {
return triangle.getPosition();
}

void Player::update(sf::Time timeStep, sf::Vector2f mousePos) {
setRotation(timeStep.asSeconds(), mousePos);
move(timeStep.asSeconds(), keyboard2Acceleration());
}

sf::Vector2f Player::keyboard2Acceleration() {
sf::Vector2f acceleration = sf::Vector2f(0, 0);

if (
sf::Keyboard::isKeyPressed(sf::Keyboard::Left) ||
sf::Keyboard::isKeyPressed(sf::Keyboard::A)
) {
acceleration.x -= 100.f;
}
if (
sf::Keyboard::isKeyPressed(sf::Keyboard::Right) ||
sf::Keyboard::isKeyPressed(sf::Keyboard::D)
) {
acceleration.x += 100.f;
}
if (
sf::Keyboard::isKeyPressed(sf::Keyboard::Up) ||
sf::Keyboard::isKeyPressed(sf::Keyboard::W)
) {
acceleration.y -= 100.f;
}
if (
sf::Keyboard::isKeyPressed(sf::Keyboard::Down) ||
sf::Keyboard::isKeyPressed(sf::Keyboard::S)
) {
acceleration.y += 100.f;
}

return normalized(acceleration);
}

void Player::move(float timeStep, sf::Vector2f accel) {
accel *= acceleration * timeStep;
float decel = 1 - deceleration * timeStep;

// x / y accelerate & decelerate separately
// to allow for exponential deceleration
if (accel.y == 0.f) {
speed.y *= decel;
} else {
speed.y += accel.y;
}

if (accel.x == 0.f) {
speed.x *= decel;
} else {
speed.x += accel.x;
}

// normalize with speed limit * timeStep
float currentSpeed = magnitude(speed);
if (currentSpeed > maxSpeed) {
speed *= maxSpeed / currentSpeed;
}

triangle.move(speed * timeStep);
}

void Player::setRotation(float timeStep, sf::Vector2f mousePos) {
sf::Vector2f playerPos = triangle.getPosition();
if (playerPos == mousePos) return;

//calc mouse<>player angle
float targetRotation = -180 - atan2(mousePos.x - playerPos.x, mousePos.y - playerPos.y) * 180 / PI;
float rot = triangle.getRotation();
float rotationDiff = std::remainder(targetRotation - rot + 180, 360);
//limit rotationspeed
if (rotationDiff > maxRotationSpeed * timeStep) {
rot -= maxRotationSpeed * timeStep;
}
else if (rotationDiff < -maxRotationSpeed * timeStep) {
rot += maxRotationSpeed * timeStep;
}
else {
rot = targetRotation;
}

//bring the value back down into the interval [0, 360]
if (rot < 0) {
rot += 360;
}
else if (rot > 360) {
rot -= 360;
}

triangle.setRotation(rot);
}
}

+ 13
- 3
player.hpp View File

@@ -4,16 +4,26 @@
#include <SFML/System.hpp>
#include <SFML/Window.hpp>


namespace Proto4 {
class Player : public sf::Drawable, public sf::Transformable {
sf::CircleShape triangle;
sf::Vector2f speed {0.f, 0.f};

const float acceleration = 2500;
const float deceleration = 3;
const float maxSpeed = 650;
const float maxRotationSpeed = 800;

public:
sf::Vector2f keyboard2Acceleration();
void move(float timeStep, sf::Vector2f acceleration);
void setRotation(float timeStep, sf::Vector2f mousePos);

public:
Player();
virtual void draw(sf::RenderTarget &window,
sf::RenderStates states) const;

void update(sf::Time timeStep, sf::Vector2f mousePosition);
virtual void setPosition(sf::Vector2f pos);
virtual sf::Vector2f getPosition();
};
}

+ 177
- 0
vec2util.hpp View File

@@ -0,0 +1,177 @@
// Simple utility header for the sf::Vector2f class.
// copied from https://en.sfml-dev.org/forums/index.php?topic=21356.0

#pragma once

#include <math.h>
#include <SFML/System/Vector2.hpp>

#define PI 3.14159265359
#define RAD2DEG 57.2957795056
#define DEG2RAD 0.01745329252

typedef sf::Vector2f Vec2;

/**
* @brief dot
* @param a vector
* @param b vector
* @return a . b
*/
static inline float dot (const Vec2& a, const Vec2& b)
{
return a.x*b.x + a.y*b.y;
}

/**
* @brief magnitudeSq
* @param v vector
* @return |v|^2
*/
static inline float magnitudeSq (const Vec2& v)
{
return v.x*v.x + v.y*v.y;
}

/**
* @brief magnitude
* @param v vector
* @return |v|
*/
static inline float magnitude (const Vec2& v)
{
return sqrt (v.x*v.x + v.y*v.y);
}


/**
* @brief normalize
* @param v vector
* v' = v / |v|
*/
static inline void normalize (Vec2& v)
{
float len = sqrt (v.x*v.x + v.y*v.y);
if (len != 0) {
v.x = v.x / len;
v.y = v.y / len;
}
}

/**
* @brief normalized (faster)
* @param res vector
* @param v vector
* res = v / |v|
*/
static inline void normalized (Vec2& res, const Vec2& v)
{
float len = sqrt (v.x*v.x + v.y*v.y);
if (len != 0) {
res.x = v.x / len;
res.y = v.y / len;
}
}

/**
* @brief normalized
* @param v vector
* @return res = v / |v|
*/
static inline Vec2 normalized (const Vec2& v)
{
Vec2 res;
normalized(res, v);
return res;
}

/**
* @brief truncate (faster)
* @param res vector
* @param v vector
* @param max magnitude
* res = max * v / |v|
*/
static inline void truncate (Vec2& res, const Vec2& v, float max)
{
float len = sqrt (v.x*v.x + v.y*v.y);
if (len > max)
{
res = normalized(v);
res *= max;
} else {
res = v;
}
}

/**
* @brief truncate
* @param v vector
* @param max magnitude
* @return res = max * v / |v|
*/
static inline Vec2 truncate (const Vec2& v, float max)
{
Vec2 res;
truncate(res, v, max);
return res;
}

/**
* @brief lerp (faster)
* @param res vector
* @param a vector
* @param b vector
* @param t alpha value
* res = (1-t)*a + t*b
*/
static inline void lerp (Vec2& res, const Vec2& a, const Vec2& b, float t)
{
res.x = (1-t)*a.x + t*b.x;
res.y = (1-t)*a.y + t*b.y;
}

/**
* @brief lerp
* @param a vector
* @param b vector
* @param t alpha value
* @return res = (1-t)*a + t*b
*/
static inline Vec2 lerp (const Vec2& a, const Vec2& b, float t)
{
Vec2 res;
lerp(res, a, b, t);
return res;
}

/**
* @brief rotate
* @param res vector
* @param v vector
* @param angle
* R = |cos -sin|
* |sin cos|
* res = v * R
*/
static inline void rotate (Vec2& res, const Vec2& v, float angle)
{
const float rad = DEG2RAD * angle;
const float sin0 = sin(rad);
const float cos0 = cos(rad);
res.x = v.x * cos0 + v.y * -sin0;
res.y = v.x * sin0 + v.y * cos0;
}

/**
* @brief rotate
* @param v vector
* @param angle
* @return res = v * R
*/
static inline Vec2 rotate (Vec2& v, float angle)
{
Vec2 res;
rotate(res, v, angle);
return res;
}

Loading…
Cancel
Save