Commit b94a2497 authored by louiz’'s avatar louiz’

Use a Vec2 class which is used for both deplacement vectors and world position.

This class uses two mpreal for fixed point numbers, which should always be
identical, whatever the compiler, OS, architecture, etc.  Using vectors for
movements makes it easy to adapt the Opensteer algorithms to our code.
parent 671232a1
......@@ -59,3 +59,5 @@ Sources: https://github.com/ReneNyffenegger/development_misc/tree/master/base64
License: LGPL
Website: http://www.holoborodko.com/pavel/mpfr/
-----------------------------------------------
......@@ -111,14 +111,12 @@ void Camera::handle_middle_click(const sf::Event& event)
void Camera::handle_right_click(const sf::Event& event)
{
const sf::Vector2u pos = this->camera_to_world_position(event.mouseButton.x,
event.mouseButton.y);
int x;
int y;
this->world->get_cell_at_position(pos.x,
pos.y,
x, y);
this->world->handle_event(actions::Move, pos.x, pos.y);
const Position pos = this->camera_to_world_position(event.mouseButton.x,
event.mouseButton.y);
// int x;
// int y;
// this->world->get_cell_at_position(pos, x, y);
this->world->handle_event(actions::Move, pos.x.toLong(), pos.y.toLong());
}
void Camera::handle_left_click(const sf::Event& event)
......@@ -148,7 +146,7 @@ void Camera::set_mouse_selection_to_selection()
while ((entity = this->world->get_next_entity()) != 0)
{
if (this->mouse_selection.contains(mouse_pos,
this->world_to_camera_position(entity->x, entity->y),
this->world_to_camera_position(entity->pos),
entity->width + 4))
entity->selected = true;
else
......@@ -167,7 +165,7 @@ void Camera::add_mouse_selection_to_selection()
while ((entity = this->world->get_next_entity()) != 0)
{
if (this->mouse_selection.contains(mouse_pos,
this->world_to_camera_position(entity->x, entity->y),
this->world_to_camera_position(entity->pos),
entity->width + 4))
entity->selected = true;
}
......@@ -273,8 +271,8 @@ void Camera::draw()
this->world->reset_entity_iterator();
while ((entity = this->world->get_next_entity()) != 0)
{
this->world->get_cell_at_position(entity->x, entity->y, cellx, celly);
sf::Vector2u entpos = this->world_to_camera_position(entity->x, entity->y);
this->world->get_cell_at_position(entity->pos, cellx, celly);
sf::Vector2u entpos = this->world_to_camera_position(entity->pos);
if ((celly == y) && ((entpos.x > this->x) && (entpos.x < this->x + win_size.x) &&
(entpos.y > this->y) && (entpos.y < this->y + win_size.y)))
{
......@@ -328,38 +326,38 @@ void Camera::fixup_camera_position()
this->y = this->map->get_height_in_pixels() - win_size.y;
}
sf::Vector2u Camera::world_to_camera_position(const mpreal& x, const mpreal& y) const
sf::Vector2u Camera::world_to_camera_position(const Position& pos) const
{
sf::Vector2u res;
res.x = ((x * TILE_WIDTH) / CELL_SIZE).toLong();
res.y = ((y * TILE_HEIGHT) / CELL_SIZE).toLong();
mpreal height = this->world->get_position_height(x, y) * 32;
res.x = ((pos.x * TILE_WIDTH) / CELL_SIZE).toLong();
res.y = ((pos.y * TILE_HEIGHT) / CELL_SIZE).toLong();
mpreal height = this->world->get_position_height(pos) * 32;
res.y -= height.toLong();
return res;
}
sf::Vector2u Camera::camera_to_world_position(const int x,
const int y) const
Position Camera::camera_to_world_position(const int x,
const int y) const
{
sf::Vector2u res;
Position res;
const uint cell_size = static_cast<const uint>(CELL_SIZE);
res.x = (x + this->x) * (CELL_SIZE / static_cast<const float>(TILE_WIDTH));
res.y = (y + this->y) * (CELL_SIZE / static_cast<const float>(TILE_HEIGHT));
uint offset = (cell_size - (res.y % cell_size));
uint offset = (cell_size - (res.y.toLong() % cell_size));
uint i = 0;
mpreal height_of_bottom_cell = this->world->get_position_height(res.x, res.y + offset);
mpreal height_of_bottom_cell = this->world->get_position_height(Position(res.x, res.y + offset));
if (height_of_bottom_cell > ((offset) * (1.f/LAYER_HEIGHT)))
res.y += (height_of_bottom_cell * LAYER_HEIGHT).toLong();
else
{
offset += cell_size;
height_of_bottom_cell = this->world->get_position_height(res.x, res.y + offset);
height_of_bottom_cell = this->world->get_position_height(Position(res.x, res.y + offset));
if (height_of_bottom_cell > (offset * (1.f/LAYER_HEIGHT)))
res.y += (height_of_bottom_cell * LAYER_HEIGHT).toLong();
else
{
mpreal height_of_current_cell = this->world->get_position_height(res.x, res.y);
mpreal height_of_current_cell = this->world->get_position_height(Position(res.x, res.y));
res.y += (height_of_current_cell * LAYER_HEIGHT).toLong();
}
}
......
......@@ -22,6 +22,7 @@
#include <gui/camera/map.hpp>
#include <gui/camera/mouse_selection.hpp>
#include <mpreal/mpreal.h>
#include <world/position.hpp>
using namespace mpfr;
......@@ -61,8 +62,8 @@ public:
* input etc.
*/
void update(const Duration& dt);
sf::Vector2u world_to_camera_position(const mpreal&, const mpreal&) const;
sf::Vector2u camera_to_world_position(const int, const int) const;
sf::Vector2u world_to_camera_position(const Position&) const;
Position camera_to_world_position(const int, const int) const;
/**
* Start a mouse selection, i.e. drawing a rectangle to select entities
* inside it. The position is a world-static position, not a camera
......
......@@ -6,13 +6,12 @@ unsigned short Entity::current_id = 0;
unsigned short Entity::current_type_id = 0;
Entity::Entity():
x(0),
y(0),
pos(0, 0),
width(30),
height(0),
selected(false),
type_id(Entity::current_type_id++),
path(0),
// path(0),
health(0)
{
log_debug("Creating new unit model: id=" << this->type_id);
......@@ -20,11 +19,10 @@ Entity::Entity():
Entity::Entity(const Entity& model):
id(++Entity::current_id),
selected(false),
path(0)
selected(false)
// path(0)
{
this->y = model.y;
this->x = model.x;
this->pos = model.pos;
this->width = model.width;
this->height = model.height;
this->type_id = model.type_id;
......@@ -35,7 +33,7 @@ Entity::Entity(const Entity& model):
Entity::Entity(const Entity& model, const SerializableEntity& e):
id(++Entity::current_id),
selected(false),
path(0),
// path(0),
health(0)
{
this->width = model.width;
......@@ -43,9 +41,8 @@ Entity::Entity(const Entity& model, const SerializableEntity& e):
this->selected = model.selected;
this->type_id = model.type_id;
this->health = model.health;
this->path = 0;
this->x = e.x;
this->y = e.y;
// this->path = 0;
this->pos = Position(e.x, e.y);
log_debug("Creating new unit(" << this->type_id << ") of id: " << this->id);
}
......@@ -58,27 +55,27 @@ bool Entity::is_selected() const
return this->selected;
}
bool Entity::contains(const mpreal& x, const mpreal& y) const
bool Entity::contains(const Position& pos) const
{
if ((x >= this->x) && (y >= this->y) &&
(x <= this->x + this->width) && (y <= this->y + this->height))
if ((pos.x >= this->pos.x) && (pos.y >= this->pos.y) &&
(pos.x <= this->pos.x + this->width) && (pos.y <= this->pos.y + this->height))
return true;
return false;
}
void Entity::set_path(const Path& path)
{
if (this->path != 0)
delete this->path;
this->path = new Path(path);
}
// void Entity::set_path(const Path& path)
// {
// // if (this->path != 0)
// // delete this->path;
// // this->path = new Path(path);
// }
void Entity::cancel_path()
{
if (this->path != 0)
delete this->path;
this->path = 0;
}
// void Entity::cancel_path()
// {
// if (this->path != 0)
// delete this->path;
// this->path = 0;
// }
void Entity::tick()
{
......@@ -88,39 +85,22 @@ void Entity::tick()
void Entity::follow_path()
{
if (this->path == 0)
mpreal speed(5);
// return ;
if (this->path.size() == 0)
return ;
mpreal speed(3.0);
mpreal xdist;
if (this->x > this->path->x)
xdist = this->x - this->path->x;
else
xdist = this->path->x - this->x;
mpreal ydist;
if (this->y > this->path->y)
ydist = this->y - this->path->y;
else
ydist = this->path->y - this->y;
mpreal dist = xdist + ydist;
if (speed >= dist)
{
this->x = this->path->x;
this->y = this->path->y;
this->cancel_path();
return ;
}
mpreal xspeed;
mpreal yspeed;
xspeed = xdist/dist*speed;
yspeed = ydist/dist*speed;
if (this->x < this->path->x)
this->x += xspeed;
else
this->x -= xspeed;
if (this->y < this->path->y)
this->y += yspeed;
if (this->pos == this->path.front())
this->path.pop_front();
if (this->path.size() == 0)
return ;
Position goal = this->path.front();
// log_error("Current: " << this->pos << ". Goal: " << goal);
Vec2 movement(goal - this->pos);
if (Position::distance(goal, this->pos) < speed)
movement.set_length(Position::distance(goal, this->pos));
else
this->y -= yspeed;
movement.set_length(speed);
this->pos += movement;
}
void Entity::update_health()
......
......@@ -3,7 +3,7 @@
#include <logging/logging.hpp>
#include <world/path.hpp>
#include <mpreal/mpreal.h>
#include <world/position.hpp>
class Camera;
class World;
......@@ -27,7 +27,7 @@ public:
Entity(const Entity& model, const SerializableEntity& e);
virtual ~Entity();
bool is_selected() const;
bool contains(const mpreal&, const mpreal&) const;
bool contains(const Position&) const;
void update_health();
unsigned short get_id() const { return this->id; }
......@@ -42,14 +42,7 @@ public:
private:
Entity& operator=(const Entity&);
public:
/**
* The left position
*/
mpreal x;
/**
* The top position
*/
mpreal y;
Position pos;
/**
* The width
*/
......@@ -73,7 +66,7 @@ public:
/**
* The path to follow. If it is 0, the entity is not moving.
*/
Path* path;
Path path;
/**
* The entity health.
*/
......
......@@ -4,6 +4,8 @@
#include <utils/zlib.hpp>
#include <boost/utility.hpp>
#include <boost/foreach.hpp>
#include <map>
#include <climits>
Map::Map():
width(0),
......
#include <string>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <list>
#ifndef __MAP_HPP__
# define __MAP_HPP__
#include <logging/logging.hpp>
#include <world/layer.hpp>
#include <world/position.hpp>
#define LAYER_NUMBER 5
#define LEVEL_HEIGHT 32
......@@ -35,6 +37,8 @@ static const char tile_heights[6][4] =
{0, 0, 0, 0}
};
typedef std::list<std::size_t> cell_path_t;
class Camera;
class Map
......
#include <world/path.hpp>
Path::Path(const mpreal x, const mpreal y):
x(x),
y(y)
{
}
Path::Path(const Path& path)
{
this->x = path.x;
this->y = path.y;
}
Path& Path::operator=(const Path& path)
{
this->x = path.x;
this->y = path.y;
return *this;
}
Path::~Path()
{
}
......@@ -7,23 +7,10 @@
#ifndef __PATH_HPP__
# define __PATH_HPP__
#include <mpreal/mpreal.h>
#include <world/position.hpp>
#include <list>
using namespace mpfr;
class Path
{
public:
Path(const mpreal x, const mpreal y);
Path& operator=(const Path&);
Path(const Path&);
~Path();
/**
* Currently, a path is just a destination, but this will be changed.
*/
mpreal x;
mpreal y;
};
typedef std::list<Position> Path;
#endif // __PATH_HPP__
#ifndef __POSITION_HPP__
# define __POSITION_HPP__
#include <world/vec2.hpp>
typedef Vec2 Position;
#endif // __POSITION_HPP__
......@@ -2,9 +2,10 @@
SerializableEntity::SerializableEntity(const Entity& e)
{
this->x = e.x.toString();
this->y = e.y.toString();
this->x = e.pos.x.toString();
this->y = e.pos.y.toString();
this->type_id = e.type_id;
log_error("SerializableEntity: " << this->x << ":" << this->y);
}
SerializableEntity::~SerializableEntity()
......
#ifndef __VEC2_HPP__
# define __VEC2_HPP__
#include <mpreal/mpreal.h>
using namespace mpfr;
class Vec2
{
public:
mpreal x;
mpreal y;
~Vec2() {}
Vec2(const Vec2& v) {x=v.x; y=v.y;}
// constructors
Vec2 (): x( 0.0f ), y( 0.0f ) {}
Vec2 (mpreal X, mpreal Y) : x( X ), y( Y ) {}
// vector addition
Vec2 operator+ (const Vec2& v) const {return Vec2 (x+v.x, y+v.y);}
// vector subtraction
Vec2 operator- (const Vec2& v) const {return Vec2 (x-v.x, y-v.y);}
// unary minus
Vec2 operator- (void) const {return Vec2 (-x, -y);}
// vector times scalar product (scale length of vector times argument)
Vec2 operator* (const mpreal s) const {return Vec2 (x * s, y * s);}
// vector divided by a scalar (divide length of vector by argument)
Vec2 operator/ (const mpreal s) const {return Vec2 (x / s, y / s);}
// dot product
mpreal dot (const Vec2& v) const {return (x * v.x) + (y * v.y);}
// // length
// mpreal length (void) const {return sqrtXXX (lengthSquared ());}
// // length squared
// mpreal lengthSquared (void) const {return this->dot (*this);}
// normalize: returns normalized version (parallel to this, length = 1)
// Vec2 normalize (void) const
// {
// // skip divide if length is zero
// const mpreal len = length ();
// return (len>0) ? (*this)/len : (*this);
// }
// // cross product (modify "*this" to be A x B)
// // [XXX side effecting -- deprecate this function? XXX]
// void cross(const Vec2& a, const Vec2& b)
// {
// *this = Vec2 ((a.y * b.z) - (a.z * b.y),
// (a.z * b.x) - (a.x * b.z),
// (a.x * b.y) - (a.y * b.x));
// }
// assignment
Vec2& operator= (const Vec2& v) {x=v.x; y=v.y; return *this;}
// set XY coordinates to given two mpreals
Vec2& set (const mpreal _x, const mpreal _y)
{x = _x; y = _y; return *this;}
// +=
Vec2& operator+= (const Vec2& v) {return *this = (*this + v);}
// -=
Vec2& operator-= (const Vec2& v) {return *this = (*this - v);}
// *=
Vec2& operator*= (const mpreal& s) {return *this = (*this * s);}
// /=
Vec2& operator/=( mpreal d ) { return *this = (*this / d);}
// equality/inequality
bool operator== (const Vec2& v) const {return x==v.x && y==v.y;}
bool operator!= (const Vec2& v) const {return !(*this == v);}
// @todo Remove - use @c distance from the Vec2Utilitites header instead.
// XXX experimental (4-1-03 cwr): is this the right approach? defining
// XXX "Vec2 distance (vec3, Vec2)" collided with STL's distance template.
static mpreal distance(const Vec2& a, const Vec2& b)
{
return (a - b).length();
}
mpreal length() const
{
return sqrt(pow(x, 2) + pow(y, 2));
}
// Change the vector's length but keep the same direction.
void set_length(mpreal new_length)
{
mpreal mult = this->length() / new_length;
this->x /= mult;
this->y /= mult;
}
// Returns one of the two perpendicular vectors.
Vec2 perpendicular1() const
{
Vec2 res(this->y, -this->x);
return res;
}
Vec2 perpendicular2() const
{
Vec2 res(-this->y, this->x);
return res;
}
// --------------------------- utility member functions used in OpenSteer
// return component of vector parallel to a unit basis vector
// (IMPORTANT NOTE: assumes "basis" has unit magnitude (length==1))
// inline Vec2 parallelComponent (const Vec2& unitBasis) const
// {
// const mpreal projection = this->dot (unitBasis);
// return unitBasis * projection;
// }
// // return component of vector perpendicular to a unit basis vector
// // (IMPORTANT NOTE: assumes "basis" has unit magnitude (length==1))
// inline Vec2 perpendicularComponent (const Vec2& unitBasis) const
// {
// return (*this) - parallelComponent (unitBasis);
// }
// // clamps the length of a given vector to maxLength. If the vector is
// // shorter its value is returned unaltered, if the vector is longer
// // the value returned has length of maxLength and is paralle to the
// // original input.
// Vec2 truncateLength (const mpreal maxLength) const
// {
// const mpreal maxLengthSquared = maxLength * maxLength;
// const mpreal vecLengthSquared = this->lengthSquared ();
// if (vecLengthSquared <= maxLengthSquared)
// return *this;
// else
// return (*this) * (maxLength / sqrtXXX (vecLengthSquared));
// }
// // forces a 3d position onto the XZ (aka y=0) plane
// Vec2 setYtoZero (void) const {return Vec2 (this->x, 0, this->z);}
// // rotate this vector about the global Y (up) axis by the given angle
// Vec2 rotateAboutGlobalY (mpreal angle) const
// {
// const mpreal s = sinXXX (angle);
// const mpreal c = cosXXX (angle);
// return Vec2 ((this->x * c) + (this->z * s),
// (this->y),
// (this->z * c) - (this->x * s));
// }
// // version for caching sin/cos computation
// Vec2 rotateAboutGlobalY (mpreal angle, mpreal& sin, mpreal& cos) const
// {
// // is both are zero, they have not be initialized yet
// if (sin==0 && cos==0)
// {
// sin = sinXXX (angle);
// cos = cosXXX (angle);
// }
// return Vec2 ((this->x * cos) + (this->z * sin),
// (this->y),
// (this->z * cos) - (this->x * sin));
// }
// // if this position is outside sphere, push it back in by one diameter
// Vec2 sphericalWrapAround (const Vec2& center, mpreal radius)
// {
// const Vec2 offset = *this - center;
// const mpreal r = offset.length();
// if (r > radius)
// return *this + ((offset/r) * radius * -2);
// else
// return *this;
// }
// // names for frequently used vector constants
// static const Vec2 zero;
// static const Vec2 side;
// static const Vec2 up;
// static const Vec2 forward;
// };
// ----------------------------------------------------------------------------
// scalar times vector product ("mpreal * Vec2")
// return cross product a x b
// inline Vec2 crossProduct(const Vec2& a, const Vec2& b)
// {
// Vec2 result((a.y * b.z) - (a.z * b.y),
// (a.z * b.x) - (a.x * b.z),
// (a.x * b.y) - (a.y * b.x));
// return result;
// }
// ----------------------------------------------------------------------------