mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Randomized center positions of zones.
This commit is contained in:
parent
3a6f748fb5
commit
27dcf70b1a
@ -321,6 +321,7 @@
|
||||
<ClInclude Include="rmg\CRmgTemplateZone.h" />
|
||||
<ClInclude Include="rmg\CZoneGraphGenerator.h" />
|
||||
<ClInclude Include="rmg\CZonePlacer.h" />
|
||||
<ClInclude Include="rmg\float3.h" />
|
||||
<ClInclude Include="StartInfo.h" />
|
||||
<ClInclude Include="StdInc.h" />
|
||||
<ClInclude Include="UnlockGuard.h" />
|
||||
|
@ -396,5 +396,8 @@
|
||||
<ClInclude Include="registerTypes\RegisterTypes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rmg\float3.h">
|
||||
<Filter>rmg</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
@ -12,6 +12,7 @@
|
||||
#include "../filesystem/Filesystem.h"
|
||||
#include "CRmgTemplate.h"
|
||||
#include "CRmgTemplateZone.h"
|
||||
#include "CZonePlacer.h"
|
||||
|
||||
CMapGenerator::CMapGenerator(shared_ptr<CMapGenOptions> mapGenOptions, int randomSeed /*= std::time(nullptr)*/) :
|
||||
mapGenOptions(mapGenOptions), randomSeed(randomSeed)
|
||||
@ -26,10 +27,10 @@ CMapGenerator::~CMapGenerator()
|
||||
|
||||
std::unique_ptr<CMap> CMapGenerator::generate()
|
||||
{
|
||||
mapGenOptions->finalize(rand);
|
||||
mapGenOptions->finalize(rand);
|
||||
|
||||
map = make_unique<CMap>();
|
||||
editManager = map->getEditManager();
|
||||
map = make_unique<CMap>();
|
||||
editManager = map->getEditManager();
|
||||
try
|
||||
{
|
||||
editManager->getUndoManager().setUndoRedoLimit(0);
|
||||
@ -144,13 +145,16 @@ void CMapGenerator::genZones()
|
||||
|
||||
|
||||
auto tmpl = mapGenOptions->getMapTemplate();
|
||||
auto zones = tmpl->getZones();
|
||||
zones = tmpl->getZones(); //copy from template (refactor?)
|
||||
|
||||
int player_per_side = zones.size() > 4 ? 3 : 2;
|
||||
int zones_cnt = zones.size() > 4 ? 9 : 4;
|
||||
|
||||
logGlobal->infoStream() << boost::format("Map size %d %d, players per side %d") % w % h % player_per_side;
|
||||
|
||||
CZonePlacer placer(this);
|
||||
placer.placeZones(mapGenOptions, &rand);
|
||||
|
||||
int i = 0;
|
||||
int part_w = w/player_per_side;
|
||||
int part_h = h/player_per_side;
|
||||
@ -192,4 +196,9 @@ void CMapGenerator::addHeaderInfo()
|
||||
map->description = getMapDescription();
|
||||
map->difficulty = 1;
|
||||
addPlayerInfo();
|
||||
}
|
||||
|
||||
std::map<TRmgTemplateZoneId, CRmgTemplateZone*> CMapGenerator::getZones() const
|
||||
{
|
||||
return zones;
|
||||
}
|
@ -62,6 +62,8 @@ public:
|
||||
int randomSeed;
|
||||
CMapEditManager * editManager;
|
||||
|
||||
std::map<TRmgTemplateZoneId, CRmgTemplateZone*> getZones() const;
|
||||
|
||||
private:
|
||||
std::map<TRmgTemplateZoneId, CRmgTemplateZone*> zones;
|
||||
|
||||
|
@ -81,6 +81,16 @@ void CJsonRmgTemplateLoader::loadTemplates()
|
||||
connections.push_back(conn);
|
||||
}
|
||||
tpl->setConnections(connections);
|
||||
{
|
||||
auto zones = tpl->getZones();
|
||||
for (auto con : tpl->getConnections())
|
||||
{
|
||||
auto idA = con.getZoneA()->getId();
|
||||
auto idB = con.getZoneB()->getId();
|
||||
zones[idA]->addConnection(idB);
|
||||
zones[idB]->addConnection(idA);
|
||||
}
|
||||
}
|
||||
tpl->validate();
|
||||
templates[tpl->getName()] = tpl;
|
||||
}
|
||||
|
@ -272,6 +272,26 @@ void CRmgTemplateZone::setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> v
|
||||
townTypeLikeZone = value;
|
||||
}
|
||||
|
||||
void CRmgTemplateZone::addConnection(TRmgTemplateZoneId otherZone)
|
||||
{
|
||||
connections.push_back (otherZone);
|
||||
}
|
||||
|
||||
std::vector<TRmgTemplateZoneId> CRmgTemplateZone::getConnections() const
|
||||
{
|
||||
return connections;
|
||||
}
|
||||
float3 CRmgTemplateZone::getCenter() const
|
||||
{
|
||||
return center;
|
||||
}
|
||||
void CRmgTemplateZone::setCenter(float3 f)
|
||||
{
|
||||
//limit boundaries to (0,1) square
|
||||
center = float3 (std::min(std::max(f.x, 0.f), 1.f), std::min(std::max(f.y, 0.f), 1.f), f.z);
|
||||
}
|
||||
|
||||
|
||||
bool CRmgTemplateZone::pointIsIn(int x, int y)
|
||||
{
|
||||
int i, j;
|
||||
@ -316,21 +336,26 @@ void CRmgTemplateZone::setShape(std::vector<int3> shape)
|
||||
}
|
||||
}
|
||||
|
||||
int3 CRmgTemplateZone::getCenter()
|
||||
int3 CRmgTemplateZone::getPos()
|
||||
{
|
||||
si32 cx = 0;
|
||||
si32 cy = 0;
|
||||
si32 area = 0;
|
||||
si32 sz = shape.size();
|
||||
//include last->first too
|
||||
for(si32 i = 0, j = sz-1; i < sz; j = i++) {
|
||||
si32 sf = (shape[i].x * shape[j].y - shape[j].x * shape[i].y);
|
||||
cx += (shape[i].x + shape[j].x) * sf;
|
||||
cy += (shape[i].y + shape[j].y) * sf;
|
||||
area += sf;
|
||||
}
|
||||
area /= 2;
|
||||
return int3(std::abs(cx/area/6), std::abs(cy/area/6), shape[0].z);
|
||||
//si32 cx = 0;
|
||||
//si32 cy = 0;
|
||||
//si32 area = 0;
|
||||
//si32 sz = shape.size();
|
||||
////include last->first too
|
||||
//for(si32 i = 0, j = sz-1; i < sz; j = i++) {
|
||||
// si32 sf = (shape[i].x * shape[j].y - shape[j].x * shape[i].y);
|
||||
// cx += (shape[i].x + shape[j].x) * sf;
|
||||
// cy += (shape[i].y + shape[j].y) * sf;
|
||||
// area += sf;
|
||||
//}
|
||||
//area /= 2;
|
||||
//return int3(std::abs(cx/area/6), std::abs(cy/area/6), shape[0].z);
|
||||
return pos;
|
||||
}
|
||||
void CRmgTemplateZone::setPos(int3 Pos)
|
||||
{
|
||||
pos = Pos;
|
||||
}
|
||||
|
||||
bool CRmgTemplateZone::fill(CMapGenerator* gen)
|
||||
@ -356,7 +381,7 @@ bool CRmgTemplateZone::fill(CMapGenerator* gen)
|
||||
town->builtBuildings.insert(BuildingID::FORT);
|
||||
town->builtBuildings.insert(BuildingID::DEFAULT);
|
||||
|
||||
placeObject(gen, town, getCenter());
|
||||
placeObject(gen, town, getPos());
|
||||
logGlobal->infoStream() << "Placed object";
|
||||
|
||||
logGlobal->infoStream() << "Fill player info " << player_id;
|
||||
@ -512,7 +537,7 @@ void CRmgTemplateZone::checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance*
|
||||
|
||||
void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos)
|
||||
{
|
||||
logGlobal->infoStream() << boost::format("Inserting object at %d %d") % pos.x % pos.y;
|
||||
logGlobal->traceStream() << boost::format("Inserting object at %d %d") % pos.x % pos.y;
|
||||
|
||||
checkAndPlaceObject (gen, object, pos);
|
||||
|
||||
@ -537,7 +562,7 @@ void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object,
|
||||
bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str)
|
||||
{
|
||||
|
||||
logGlobal->infoStream() << boost::format("Guard object at %d %d") % object->pos.x % object->pos.y;
|
||||
logGlobal->traceStream() << boost::format("Guard object at %d %d") % object->pos.x % object->pos.y;
|
||||
int3 visitable = object->visitablePos();
|
||||
std::vector<int3> tiles;
|
||||
for(int i = -1; i < 2; ++i)
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "../GameConstants.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "float3.h"
|
||||
|
||||
class CMapgenerator;
|
||||
|
||||
@ -98,10 +99,20 @@ public:
|
||||
void setTerrainTypeLikeZone(boost::optional<TRmgTemplateZoneId> value);
|
||||
boost::optional<TRmgTemplateZoneId> getTownTypeLikeZone() const;
|
||||
void setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> value);
|
||||
|
||||
float3 getCenter() const;
|
||||
void setCenter(float3 f);
|
||||
int3 getPos();
|
||||
void setPos(int3 pos);
|
||||
|
||||
void setShape(std::vector<int3> shape);
|
||||
bool fill(CMapGenerator* gen);
|
||||
|
||||
void addConnection(TRmgTemplateZoneId otherZone);
|
||||
std::vector<TRmgTemplateZoneId> getConnections() const;
|
||||
|
||||
private:
|
||||
//template info
|
||||
TRmgTemplateZoneId id;
|
||||
ETemplateZoneType::ETemplateZoneType type;
|
||||
int size;
|
||||
@ -113,11 +124,17 @@ private:
|
||||
std::set<ETerrainType> terrainTypes;
|
||||
boost::optional<TRmgTemplateZoneId> terrainTypeLikeZone, townTypeLikeZone;
|
||||
|
||||
std::vector<int3> shape;
|
||||
std::map<int3, CTileInfo> tileinfo;
|
||||
//content info
|
||||
std::vector<int3> shape; //TODO: remove
|
||||
std::vector<CGObjectInstance*> objects;
|
||||
|
||||
int3 getCenter();
|
||||
//placement info
|
||||
int3 pos;
|
||||
float3 center;
|
||||
std::map<int3, CTileInfo> tileinfo; //irregular area assined to zone
|
||||
std::vector<TRmgTemplateZoneId> connections; //list of adjacent zones
|
||||
std::map<TRmgTemplateZoneId, bool> alreadyConnected; //TODO: allow multiple connections between two zones?
|
||||
|
||||
bool pointIsIn(int x, int y);
|
||||
bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos);
|
||||
void checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos);
|
||||
|
@ -10,16 +10,20 @@
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "../CRandomGenerator.h"
|
||||
#include "CZonePlacer.h"
|
||||
#include "CRmgTemplateZone.h"
|
||||
|
||||
#include "CZoneGraphGenerator.h"
|
||||
|
||||
CPlacedZone::CPlacedZone(const CRmgTemplateZone * zone)// : zone(zone)
|
||||
class CRandomGenerator;
|
||||
|
||||
CPlacedZone::CPlacedZone(const CRmgTemplateZone * zone) : zone(zone)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CZonePlacer::CZonePlacer()// : map(nullptr), gen(nullptr)
|
||||
CZonePlacer::CZonePlacer(CMapGenerator * Gen) : gen(Gen)
|
||||
{
|
||||
|
||||
}
|
||||
@ -29,7 +33,85 @@ CZonePlacer::~CZonePlacer()
|
||||
|
||||
}
|
||||
|
||||
void CZonePlacer::placeZones(CMap * map, unique_ptr<CZoneGraph> graph, CRandomGenerator * gen)
|
||||
int3 CZonePlacer::cords (float3 f) const
|
||||
{
|
||||
|
||||
return int3(f.x * gen->map->width, f.y * gen->map->height, f.z);
|
||||
}
|
||||
|
||||
void CZonePlacer::placeZones(shared_ptr<CMapGenOptions> mapGenOptions, CRandomGenerator * rand)
|
||||
{
|
||||
//some relaxation-simmulated annealing algorithm
|
||||
|
||||
const int iterations = 5;
|
||||
float temperature = 1;
|
||||
const float temperatureModifier = 0.9;
|
||||
|
||||
logGlobal->infoStream() << "Starting zone placement";
|
||||
|
||||
int width = mapGenOptions->getWidth();
|
||||
int height = mapGenOptions->getHeight();
|
||||
|
||||
auto zones = gen->getZones();
|
||||
|
||||
//TODO: consider underground zones
|
||||
|
||||
float totalSize = 0;
|
||||
for (auto zone : zones)
|
||||
{
|
||||
totalSize += zone.second->getSize();
|
||||
zone.second->setCenter (float3(rand->nextDouble(0,1), rand->nextDouble(0,1), 0));
|
||||
}
|
||||
//prescale zones
|
||||
float prescaler = sqrt (width * height / totalSize) / 3.14f; //let's assume we try to fit N circular zones with radius = size on a map
|
||||
float mapSize = sqrt (width * height);
|
||||
for (auto zone : zones)
|
||||
{
|
||||
zone.second->setSize (zone.second->getSize() * prescaler);
|
||||
}
|
||||
|
||||
for (int i = 0; i < iterations; ++i)
|
||||
{
|
||||
for (auto zone : zones)
|
||||
{
|
||||
//attract connected zones
|
||||
for (auto con : zone.second->getConnections())
|
||||
{
|
||||
auto otherZone = zones[con];
|
||||
float distance = zone.second->getCenter().dist2d (otherZone->getCenter());
|
||||
float minDistance = (zone.second->getSize() + otherZone->getSize())/mapSize; //scale down to (0,1) coordinates
|
||||
if (distance > minDistance)
|
||||
{
|
||||
//attract our zone
|
||||
float scaler = (distance - minDistance)/distance * temperature; //positive
|
||||
auto positionVector = (otherZone->getCenter() - zone.second->getCenter()); //positive value
|
||||
zone.second->setCenter (zone.second->getCenter() + positionVector * scaler); //positive movement
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto zone : zones)
|
||||
{
|
||||
//separate overlaping zones
|
||||
for (auto otherZone : zones)
|
||||
{
|
||||
if (zone == otherZone)
|
||||
continue;
|
||||
|
||||
float distance = zone.second->getCenter().dist2d (otherZone.second->getCenter());
|
||||
float minDistance = (zone.second->getSize() + otherZone.second->getSize())/mapSize;
|
||||
if (distance < minDistance)
|
||||
{
|
||||
//move our zone away
|
||||
float scaler = (distance ? (distance - minDistance)/distance : 1) * temperature; //negative
|
||||
auto positionVector = (otherZone.second->getCenter() - zone.second->getCenter()); //positive value
|
||||
zone.second->setCenter (zone.second->getCenter() + positionVector * scaler); //negative movement
|
||||
}
|
||||
}
|
||||
}
|
||||
temperature *= temperatureModifier;
|
||||
}
|
||||
for (auto zone : zones) //finalize zone positions
|
||||
{
|
||||
zone.second->setPos(cords(zone.second->getCenter()));
|
||||
logGlobal->infoStream() << boost::format ("Placed zone %d at relative position %s and coordinates %s") % zone.first % zone.second->getCenter() % zone.second->getPos();
|
||||
}
|
||||
}
|
||||
|
@ -11,35 +11,41 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CMapGenerator.h"
|
||||
#include "../mapping/CMap.h"
|
||||
|
||||
#include "float3.h"
|
||||
#include "../int3.h"
|
||||
|
||||
class CZoneGraph;
|
||||
class CMap;
|
||||
class CRandomGenerator;
|
||||
class CRmgTemplateZone;
|
||||
class CMapGenerator;
|
||||
|
||||
class CPlacedZone
|
||||
{
|
||||
public:
|
||||
explicit CPlacedZone(const CRmgTemplateZone * zone);
|
||||
explicit CPlacedZone(const CRmgTemplateZone * Zone);
|
||||
|
||||
private:
|
||||
//const CRmgTemplateZone * zone;
|
||||
const CRmgTemplateZone * zone;
|
||||
|
||||
//TODO exact outline data of zone
|
||||
//TODO perhaps further zone data, guards, obstacles, etc...
|
||||
};
|
||||
|
||||
//TODO add voronoi helper classes(?), etc...
|
||||
|
||||
class CZonePlacer
|
||||
{
|
||||
public:
|
||||
CZonePlacer();
|
||||
explicit CZonePlacer(CMapGenerator * gen);
|
||||
int3 cords (float3 f) const;
|
||||
~CZonePlacer();
|
||||
|
||||
void placeZones(CMap * map, unique_ptr<CZoneGraph> graph, CRandomGenerator * gen);
|
||||
void placeZones(shared_ptr<CMapGenOptions> mapGenOptions, CRandomGenerator * rand);
|
||||
|
||||
private:
|
||||
//CMap * map;
|
||||
unique_ptr<CZoneGraph> graph;
|
||||
//CRandomGenerator * gen;
|
||||
//unique_ptr<CZoneGraph> graph;
|
||||
CMapGenerator * gen;
|
||||
};
|
||||
|
132
lib/rmg/float3.h
Normal file
132
lib/rmg/float3.h
Normal file
@ -0,0 +1,132 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* float3.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
/// Class which consists of three float values. Represents position virtual RMG (0;1) area.
|
||||
class float3
|
||||
{
|
||||
public:
|
||||
float x, y;
|
||||
si32 z;
|
||||
inline float3():x(0),y(0),z(0){}; //c-tor, x/y/z initialized to 0
|
||||
inline float3(const float X, const float Y, const si32 Z):x(X),y(Y),z(Z){}; //c-tor
|
||||
inline float3(const float3 & val) : x(val.x), y(val.y), z(val.z){} //copy c-tor
|
||||
inline float3 & operator=(const float3 & val) {x = val.x; y = val.y; z = val.z; return *this;} //assignemt operator
|
||||
~float3() {} // d-tor - does nothing
|
||||
inline float3 operator+(const float3 & i) const //returns float3 with coordinates increased by corresponding coordinate of given float3
|
||||
{return float3(x+i.x,y+i.y,z+i.z);}
|
||||
inline float3 operator+(const float i) const //returns float3 with coordinates increased by given numer
|
||||
{return float3(x+i,y+i,z+i);}
|
||||
inline float3 operator-(const float3 & i) const //returns float3 with coordinates decreased by corresponding coordinate of given float3
|
||||
{return float3(x-i.x,y-i.y,z-i.z);}
|
||||
inline float3 operator-(const float i) const //returns float3 with coordinates decreased by given numer
|
||||
{return float3(x-i,y-i,z-i);}
|
||||
inline float3 operator*(const float i) const //returns float3 with plane coordinates decreased by given numer
|
||||
{return float3(x*i, y*i, z);}
|
||||
inline float3 operator/(const float i) const //returns float3 with plane coordinates decreased by given numer
|
||||
{return float3(x/i, y/i, z);}
|
||||
inline float3 operator-() const //returns opposite position
|
||||
{return float3(-x,-y,-z);}
|
||||
inline double dist2d(const float3 &other) const //distance (z coord is not used)
|
||||
{return std::sqrt((double)(x-other.x)*(x-other.x) + (y-other.y)*(y-other.y));}
|
||||
inline bool areNeighbours(const float3 &other) const
|
||||
{return dist2d(other) < 2. && z == other.z;}
|
||||
inline void operator+=(const float3 & i)
|
||||
{
|
||||
x+=i.x;
|
||||
y+=i.y;
|
||||
z+=i.z;
|
||||
}
|
||||
inline void operator+=(const float & i)
|
||||
{
|
||||
x+=i;
|
||||
y+=i;
|
||||
z+=i;
|
||||
}
|
||||
inline void operator-=(const float3 & i)
|
||||
{
|
||||
x-=i.x;
|
||||
y-=i.y;
|
||||
z-=i.z;
|
||||
}
|
||||
inline void operator-=(const float & i)
|
||||
{
|
||||
x+=i;
|
||||
y+=i;
|
||||
z+=i;
|
||||
}
|
||||
inline void operator*=(const float & i) //scale on plane
|
||||
{
|
||||
x*=i;
|
||||
y*=i;
|
||||
}
|
||||
inline void operator/=(const float & i) //scale on plane
|
||||
{
|
||||
x/=i;
|
||||
y/=i;
|
||||
}
|
||||
|
||||
inline bool operator==(const float3 & i) const
|
||||
{return (x==i.x) && (y==i.y) && (z==i.z);}
|
||||
inline bool operator!=(const float3 & i) const
|
||||
{return !(*this==i);}
|
||||
inline bool operator<(const float3 & i) const
|
||||
{
|
||||
if (z<i.z)
|
||||
return true;
|
||||
if (z>i.z)
|
||||
return false;
|
||||
if (y<i.y)
|
||||
return true;
|
||||
if (y>i.y)
|
||||
return false;
|
||||
if (x<i.x)
|
||||
return true;
|
||||
if (x>i.x)
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
inline std::string operator ()() const
|
||||
{
|
||||
return "(" + boost::lexical_cast<std::string>(x) +
|
||||
" " + boost::lexical_cast<std::string>(y) +
|
||||
" " + boost::lexical_cast<std::string>(z) + ")";
|
||||
}
|
||||
inline bool valid() const
|
||||
{
|
||||
return z >= 0; //minimal condition that needs to be fulfilled for tiles in the map
|
||||
}
|
||||
template <typename Handler> void serialize(Handler &h, const float version)
|
||||
{
|
||||
h & x & y & z;
|
||||
}
|
||||
|
||||
};
|
||||
inline std::istream & operator>>(std::istream & str, float3 & dest)
|
||||
{
|
||||
str>>dest.x>>dest.y>>dest.z;
|
||||
return str;
|
||||
}
|
||||
inline std::ostream & operator<<(std::ostream & str, const float3 & sth)
|
||||
{
|
||||
return str<<sth.x<<' '<<sth.y<<' '<<sth.z;
|
||||
}
|
||||
|
||||
struct Shashfloat3
|
||||
{
|
||||
size_t operator()(float3 const& pos) const
|
||||
{
|
||||
size_t ret = std::hash<float>()(pos.x);
|
||||
vstd::hash_combine(ret, pos.y);
|
||||
vstd::hash_combine(ret, pos.z);
|
||||
return ret;
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user