mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-10-09 07:59:40 +00:00
Spawn units in rally point direction
Differential Revision: https://code.wildfiregames.com/D1041 Reviewed by: bb Comments by: elexis, wraitii Fixes: #4735 This was SVN commit r21144.
This commit is contained in:
@@ -17,6 +17,16 @@ RallyPoint.prototype.AddPosition = function(x, z)
|
||||
});
|
||||
};
|
||||
|
||||
RallyPoint.prototype.HasPositions = function()
|
||||
{
|
||||
return this.pos.length > 0;
|
||||
};
|
||||
|
||||
RallyPoint.prototype.GetFirstPosition = function()
|
||||
{
|
||||
return this.pos.length ? Vector2D.from3D(this.pos[0]) : new Vector2D(-1, -1);
|
||||
};
|
||||
|
||||
RallyPoint.prototype.GetPositions = function()
|
||||
{
|
||||
// Update positions for moving target entities
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Engine.RegisterInterface("RallyPoint");
|
||||
@@ -3,7 +3,6 @@ Engine.LoadComponentScript("interfaces/Builder.js");
|
||||
Engine.LoadComponentScript("interfaces/Cost.js");
|
||||
Engine.LoadComponentScript("interfaces/Foundation.js");
|
||||
Engine.LoadComponentScript("interfaces/Health.js");
|
||||
Engine.LoadComponentScript("interfaces/RallyPoint.js");
|
||||
Engine.LoadComponentScript("interfaces/StatisticsTracker.js");
|
||||
Engine.LoadComponentScript("interfaces/TerritoryDecay.js");
|
||||
Engine.LoadComponentScript("interfaces/Trigger.js");
|
||||
|
||||
@@ -10,7 +10,6 @@ Engine.LoadComponentScript("interfaces/ProductionQueue.js");
|
||||
Engine.LoadComponentScript("interfaces/TechnologyManager.js");
|
||||
Engine.LoadComponentScript("interfaces/Timer.js");
|
||||
Engine.LoadComponentScript("interfaces/UnitAI.js");
|
||||
Engine.LoadComponentScript("interfaces/RallyPoint.js");
|
||||
|
||||
const garrisonedEntitiesList = [25, 26, 27, 28, 29, 30, 31, 32, 33];
|
||||
const garrisonHolderId = 15;
|
||||
|
||||
@@ -22,7 +22,6 @@ Engine.LoadComponentScript("interfaces/Market.js");
|
||||
Engine.LoadComponentScript("interfaces/Pack.js");
|
||||
Engine.LoadComponentScript("interfaces/ProductionQueue.js");
|
||||
Engine.LoadComponentScript("interfaces/Promotion.js");
|
||||
Engine.LoadComponentScript("interfaces/RallyPoint.js");
|
||||
Engine.LoadComponentScript("interfaces/Repairable.js");
|
||||
Engine.LoadComponentScript("interfaces/ResourceDropsite.js");
|
||||
Engine.LoadComponentScript("interfaces/ResourceGatherer.js");
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
Engine.LoadHelperScript("Player.js");
|
||||
Engine.LoadComponentScript("interfaces/Formation.js");
|
||||
Engine.LoadComponentScript("interfaces/Health.js");
|
||||
Engine.LoadComponentScript("interfaces/RallyPoint.js");
|
||||
Engine.LoadComponentScript("RallyPoint.js");
|
||||
|
||||
function initialRallyPointTest(test_function)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2017 Wildfire Games.
|
||||
/* Copyright (C) 2018 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -144,6 +144,9 @@ COMPONENT(Position) // must be before VisualActor
|
||||
INTERFACE(ProjectileManager)
|
||||
COMPONENT(ProjectileManager)
|
||||
|
||||
INTERFACE(RallyPoint)
|
||||
COMPONENT(RallyPointScripted)
|
||||
|
||||
INTERFACE(RallyPointRenderer)
|
||||
COMPONENT(RallyPointRenderer)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2017 Wildfire Games.
|
||||
/* Copyright (C) 2018 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -25,9 +25,10 @@
|
||||
#include "simulation2/components/ICmpObstructionManager.h"
|
||||
#include "simulation2/components/ICmpPathfinder.h"
|
||||
#include "simulation2/components/ICmpPosition.h"
|
||||
#include "simulation2/components/ICmpRallyPoint.h"
|
||||
#include "simulation2/components/ICmpUnitMotion.h"
|
||||
#include "simulation2/helpers/Geometry.h"
|
||||
#include "simulation2/MessageTypes.h"
|
||||
#include "graphics/Terrain.h" // For TERRAIN_TILE_SIZE
|
||||
#include "maths/FixedVector2D.h"
|
||||
|
||||
class CCmpFootprint : public ICmpFootprint
|
||||
@@ -43,6 +44,7 @@ public:
|
||||
entity_pos_t m_Size0; // width/radius
|
||||
entity_pos_t m_Size1; // height/radius
|
||||
entity_pos_t m_Height;
|
||||
entity_pos_t m_MaxSpawnDistance;
|
||||
|
||||
static std::string GetSchema()
|
||||
{
|
||||
@@ -52,10 +54,12 @@ public:
|
||||
"<a:example>"
|
||||
"<Square width='3.0' height='3.0'/>"
|
||||
"<Height>0.0</Height>"
|
||||
"<MaxSpawnDistance>8</MaxSpawnDistance>"
|
||||
"</a:example>"
|
||||
"<a:example>"
|
||||
"<Circle radius='0.5'/>"
|
||||
"<Height>0.0</Height>"
|
||||
"<MaxSpawnDistance>8</MaxSpawnDistance>"
|
||||
"</a:example>"
|
||||
"<choice>"
|
||||
"<element name='Square' a:help='Set the footprint to a square of the given size'>"
|
||||
@@ -80,7 +84,12 @@ public:
|
||||
"</choice>"
|
||||
"<element name='Height' a:help='Vertical extent of the footprint (in metres)'>"
|
||||
"<ref name='nonNegativeDecimal'/>"
|
||||
"</element>";
|
||||
"</element>"
|
||||
"<optional>"
|
||||
"<element name='MaxSpawnDistance' a:help='Farthest distance units can spawn away from the edge of this entity'>"
|
||||
"<ref name='nonNegativeDecimal'/>"
|
||||
"</element>"
|
||||
"</optional>";
|
||||
}
|
||||
|
||||
virtual void Init(const CParamNode& paramNode)
|
||||
@@ -104,6 +113,12 @@ public:
|
||||
}
|
||||
|
||||
m_Height = paramNode.GetChild("Height").ToFixed();
|
||||
|
||||
if (paramNode.GetChild("MaxSpawnDistance").IsOk())
|
||||
m_MaxSpawnDistance = paramNode.GetChild("MaxSpawnDistance").ToFixed();
|
||||
else
|
||||
// Pick some default
|
||||
m_MaxSpawnDistance = entity_pos_t::FromInt(8);
|
||||
}
|
||||
|
||||
virtual void Deinit()
|
||||
@@ -147,7 +162,8 @@ public:
|
||||
if (!cmpObstructionManager)
|
||||
return error;
|
||||
|
||||
entity_pos_t spawnedRadius;
|
||||
// If no spawned obstruction, use a positive radius to avoid division by zero errors.
|
||||
entity_pos_t spawnedRadius = fixed::FromInt(1);
|
||||
ICmpObstructionManager::tag_t spawnedTag;
|
||||
|
||||
CmpPtr<ICmpObstruction> cmpSpawnedObstruction(GetSimContext(), spawned);
|
||||
@@ -156,9 +172,8 @@ public:
|
||||
spawnedRadius = cmpSpawnedObstruction->GetUnitRadius();
|
||||
spawnedTag = cmpSpawnedObstruction->GetObstruction();
|
||||
}
|
||||
// else use zero radius
|
||||
|
||||
// Get passability class from UnitMotion
|
||||
// Get passability class from UnitMotion.
|
||||
CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), spawned);
|
||||
if (!cmpUnitMotion)
|
||||
return error;
|
||||
@@ -168,94 +183,85 @@ public:
|
||||
if (!cmpPathfinder)
|
||||
return error;
|
||||
|
||||
// Ignore collisions with the spawned entity.
|
||||
SkipTagObstructionFilter filter(spawnedTag);
|
||||
|
||||
CFixedVector2D initialPos = cmpPosition->GetPosition2D();
|
||||
entity_angle_t initialAngle = cmpPosition->GetRotation().Y;
|
||||
|
||||
// Max spawning distance in tiles
|
||||
const i32 maxSpawningDistance = 4;
|
||||
CFixedVector2D u = CFixedVector2D(fixed::Zero(), fixed::FromInt(1)).Rotate(initialAngle);
|
||||
CFixedVector2D v = u.Perpendicular();
|
||||
|
||||
if (m_Shape == CIRCLE)
|
||||
// Obstructions are squares, so multiply its radius by 2*sqrt(2) ~= 3 to determine the distance between units.
|
||||
entity_pos_t gap = spawnedRadius * 3;
|
||||
int rows = std::max(1, (m_MaxSpawnDistance / gap).ToInt_RoundToNegInfinity());
|
||||
|
||||
// The first row of units will be half a gap away from the footprint.
|
||||
CFixedVector2D halfSize = m_Shape == CIRCLE ?
|
||||
CFixedVector2D(m_Size1 + gap / 2, m_Size0 + gap / 2) :
|
||||
CFixedVector2D((m_Size1 + gap) / 2, (m_Size0 + gap) / 2);
|
||||
|
||||
// Figure out how many units can fit on each halfside of the rectangle.
|
||||
// Since 2*pi/6 ~= 1, this is also how many units can fit on a sixth of the circle.
|
||||
int a = std::max(1, (halfSize.X / gap).ToInt_RoundToNegInfinity());
|
||||
int b = std::max(1, (halfSize.Y / gap).ToInt_RoundToNegInfinity());
|
||||
|
||||
// Try more spawning points for large units in case some of them are partially blocked.
|
||||
if (rows == 1)
|
||||
{
|
||||
// Expand outwards from foundation
|
||||
for (i32 dist = 0; dist <= maxSpawningDistance; ++dist)
|
||||
a *= 2;
|
||||
b *= 2;
|
||||
}
|
||||
|
||||
// Store the position of the spawning point within each row that's closest to the spawning angle.
|
||||
std::vector<int> offsetPoints(rows, 0);
|
||||
|
||||
CmpPtr<ICmpRallyPoint> cmpRallyPoint(GetEntityHandle());
|
||||
if (cmpRallyPoint && cmpRallyPoint->HasPositions())
|
||||
{
|
||||
CFixedVector2D rallyPointPos = cmpRallyPoint->GetFirstPosition();
|
||||
if (m_Shape == CIRCLE)
|
||||
{
|
||||
// The spawn point should be far enough from this footprint to fit the unit, plus a little gap
|
||||
entity_pos_t clearance = spawnedRadius + entity_pos_t::FromInt(2 + (int)TERRAIN_TILE_SIZE*dist);
|
||||
entity_pos_t radius = m_Size0 + clearance;
|
||||
entity_angle_t offsetAngle = atan2_approx(rallyPointPos.X - initialPos.X, rallyPointPos.Y - initialPos.Y) - initialAngle;
|
||||
|
||||
// Try equally-spaced points around the circle in alternating directions, starting from the front
|
||||
const i32 numPoints = 31 + 2*dist;
|
||||
for (i32 i = 0; i < (numPoints+1)/2; i = (i > 0 ? -i : 1-i)) // [0, +1, -1, +2, -2, ... (np-1)/2, -(np-1)/2]
|
||||
{
|
||||
entity_angle_t angle = initialAngle + (entity_angle_t::Pi()*2).Multiply(entity_angle_t::FromInt(i)/(int)numPoints);
|
||||
// There are 6*(a+r) points in row r, so multiply that by angle/2pi to find the offset within the row.
|
||||
for (int r = 0; r < rows; ++r)
|
||||
offsetPoints[r] = (offsetAngle * 3 * (a + r) / fixed::Pi()).ToInt_RoundToNearest();
|
||||
}
|
||||
else
|
||||
{
|
||||
CFixedVector2D offsetPos = Geometry::NearestPointOnSquare(rallyPointPos - initialPos, u, v, halfSize);
|
||||
|
||||
fixed s, c;
|
||||
sincos_approx(angle, s, c);
|
||||
|
||||
CFixedVector3D pos (initialPos.X + s.Multiply(radius), fixed::Zero(), initialPos.Y + c.Multiply(radius));
|
||||
|
||||
SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity
|
||||
if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Z, spawnedRadius, spawnedPass) == ICmpObstruction::FOUNDATION_CHECK_SUCCESS)
|
||||
return pos; // this position is okay, so return it
|
||||
}
|
||||
// Scale and convert the perimeter coordinates of the point to its offset within the row.
|
||||
int x = (offsetPos.Dot(u) * b / halfSize.X).ToInt_RoundToNearest();
|
||||
int y = (offsetPos.Dot(v) * a / halfSize.Y).ToInt_RoundToNearest();
|
||||
for (int r = 0; r < rows; ++r)
|
||||
offsetPoints[r] = Geometry::GetPerimeterDistance(
|
||||
b + r,
|
||||
a + r,
|
||||
x >= b ? b + r : x <= -b ? -b - r : x,
|
||||
y >= a ? a + r : y <= -a ? -a - r : y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed s, c;
|
||||
sincos_approx(initialAngle, s, c);
|
||||
|
||||
// Expand outwards from foundation
|
||||
for (i32 dist = 0; dist <= maxSpawningDistance; ++dist)
|
||||
for (int k = 0; k < 2 * (a + b + 2 * rows); k = k > 0 ? -k : 1 - k)
|
||||
for (int r = 0; r < rows; ++r)
|
||||
{
|
||||
// The spawn point should be far enough from this footprint to fit the unit, plus a little gap
|
||||
entity_pos_t clearance = spawnedRadius + entity_pos_t::FromInt(2 + (int)TERRAIN_TILE_SIZE*dist);
|
||||
|
||||
for (i32 edge = 0; edge < 4; ++edge)
|
||||
CFixedVector2D pos = initialPos;
|
||||
if (m_Shape == CIRCLE)
|
||||
// Multiply the point by 2pi / 6*(a+r) to get the angle.
|
||||
pos += u.Rotate(fixed::Pi() * (offsetPoints[r] + k) / (3 * (a + r))).Multiply(halfSize.X + gap * r );
|
||||
else
|
||||
{
|
||||
// Try equally-spaced points along the edge in alternating directions, starting from the middle
|
||||
const i32 numPoints = 9 + 2*dist;
|
||||
|
||||
// Compute the direction and length of the current edge
|
||||
CFixedVector2D dir;
|
||||
fixed sx, sy;
|
||||
switch (edge)
|
||||
{
|
||||
case 0:
|
||||
dir = CFixedVector2D(c, -s);
|
||||
sx = m_Size0;
|
||||
sy = m_Size1;
|
||||
break;
|
||||
case 1:
|
||||
dir = CFixedVector2D(-s, -c);
|
||||
sx = m_Size1;
|
||||
sy = m_Size0;
|
||||
break;
|
||||
case 2:
|
||||
dir = CFixedVector2D(s, c);
|
||||
sx = m_Size1;
|
||||
sy = m_Size0;
|
||||
break;
|
||||
case 3:
|
||||
dir = CFixedVector2D(-c, s);
|
||||
sx = m_Size0;
|
||||
sy = m_Size1;
|
||||
break;
|
||||
}
|
||||
CFixedVector2D center = initialPos - dir.Perpendicular().Multiply(sy/2 + clearance);
|
||||
dir = dir.Multiply((sx + clearance*2) / (int)(numPoints-1));
|
||||
|
||||
for (i32 i = 0; i < (numPoints+1)/2; i = (i > 0 ? -i : 1-i)) // [0, +1, -1, +2, -2, ... (np-1)/2, -(np-1)/2]
|
||||
{
|
||||
CFixedVector2D pos (center + dir*i);
|
||||
|
||||
SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity
|
||||
if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, spawnedRadius, spawnedPass) == ICmpObstruction::FOUNDATION_CHECK_SUCCESS)
|
||||
return CFixedVector3D(pos.X, fixed::Zero(), pos.Y); // this position is okay, so return it
|
||||
}
|
||||
// Convert the point to coordinates and scale.
|
||||
std::pair<int, int> p = Geometry::GetPerimeterCoordinates(b + r, a + r, offsetPoints[r] + k);
|
||||
pos += u.Multiply((halfSize.X + gap * r) * p.first / (b + r)) +
|
||||
v.Multiply((halfSize.Y + gap * r) * p.second / (a + r));
|
||||
}
|
||||
|
||||
if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, spawnedRadius, spawnedPass) == ICmpObstruction::FOUNDATION_CHECK_SUCCESS)
|
||||
return CFixedVector3D(pos.X, fixed::Zero(), pos.Y);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/* Copyright (C) 2018 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ICmpRallyPoint.h"
|
||||
|
||||
#include "maths/FixedVector2D.h"
|
||||
#include "simulation2/system/InterfaceScripted.h"
|
||||
#include "simulation2/scripting/ScriptComponent.h"
|
||||
|
||||
BEGIN_INTERFACE_WRAPPER(RallyPoint)
|
||||
END_INTERFACE_WRAPPER(RallyPoint)
|
||||
|
||||
class CCmpRallyPointScripted : public ICmpRallyPoint
|
||||
{
|
||||
public:
|
||||
DEFAULT_SCRIPT_WRAPPER(RallyPointScripted)
|
||||
|
||||
virtual bool HasPositions()
|
||||
{
|
||||
return m_Script.Call<bool>("HasPositions");
|
||||
}
|
||||
|
||||
virtual CFixedVector2D GetFirstPosition()
|
||||
{
|
||||
return m_Script.Call<CFixedVector2D>("GetFirstPosition");
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_COMPONENT_SCRIPT_WRAPPER(RallyPointScripted)
|
||||
@@ -0,0 +1,38 @@
|
||||
/* Copyright (C) 2018 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_ICMPRALLYPOINT
|
||||
#define INCLUDED_ICMPRALLYPOINT
|
||||
|
||||
#include "simulation2/system/Interface.h"
|
||||
|
||||
class CFixedVector2D;
|
||||
|
||||
/**
|
||||
* Rally point.
|
||||
*/
|
||||
class ICmpRallyPoint : public IComponent
|
||||
{
|
||||
public:
|
||||
virtual bool HasPositions() = 0;
|
||||
|
||||
virtual CFixedVector2D GetFirstPosition() = 0;
|
||||
|
||||
DECLARE_INTERFACE_TYPE(RallyPoint)
|
||||
};
|
||||
|
||||
#endif // INCLUDED_ICMPRALLYPOINT
|
||||
@@ -15,8 +15,8 @@
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_ICMPRALLYPOINT
|
||||
#define INCLUDED_ICMPRALLYPOINT
|
||||
#ifndef INCLUDED_ICMPRALLYPOINTRENDERER
|
||||
#define INCLUDED_ICMPRALLYPOINTRENDERER
|
||||
|
||||
#include "maths/FixedVector2D.h"
|
||||
#include "simulation2/helpers/Position.h"
|
||||
@@ -56,4 +56,4 @@ public:
|
||||
DECLARE_INTERFACE_TYPE(RallyPointRenderer)
|
||||
};
|
||||
|
||||
#endif // INCLUDED_ICMPRALLYPOINT
|
||||
#endif // INCLUDED_ICMPRALLYPOINTRENDERER
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2017 Wildfire Games.
|
||||
/* Copyright (C) 2018 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -317,3 +317,43 @@ bool Geometry::TestSquareSquare(
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Geometry::GetPerimeterDistance(int x_max, int y_max, int x, int y)
|
||||
{
|
||||
if (x_max <= 0 || y_max <= 0)
|
||||
return 0;
|
||||
|
||||
int quarter = x_max + y_max;
|
||||
if (x == x_max && y >= 0)
|
||||
return y;
|
||||
if (y == y_max)
|
||||
return quarter - x;
|
||||
if (x == -x_max)
|
||||
return 2 * quarter - y;
|
||||
if (y == -y_max)
|
||||
return 3 * quarter + x;
|
||||
if (x == x_max)
|
||||
return 4 * quarter + y;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::pair<int, int> Geometry::GetPerimeterCoordinates(int x_max, int y_max, int k)
|
||||
{
|
||||
if (x_max <= 0 || y_max <= 0)
|
||||
return std::pair<int, int>(0, 0);
|
||||
|
||||
int quarter = x_max + y_max;
|
||||
k %= 4 * quarter;
|
||||
if (k < 0)
|
||||
k += 4 * quarter;
|
||||
|
||||
if (k < y_max)
|
||||
return std::pair<int, int>(x_max, k);
|
||||
if (k < quarter + x_max)
|
||||
return std::pair<int, int>(quarter - k, y_max);
|
||||
if (k < 2 * quarter + y_max)
|
||||
return std::pair<int, int>(-x_max, 2 * quarter - k);
|
||||
if (k < 3 * quarter + x_max)
|
||||
return std::pair<int, int>(k - 3 * quarter, -y_max);
|
||||
return std::pair<int, int>(x_max, k - 4 * quarter);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2017 Wildfire Games.
|
||||
/* Copyright (C) 2018 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -99,6 +99,22 @@ bool TestSquareSquare(
|
||||
const CFixedVector2D& c0, const CFixedVector2D& u0, const CFixedVector2D& v0, const CFixedVector2D& halfSize0,
|
||||
const CFixedVector2D& c1, const CFixedVector2D& u1, const CFixedVector2D& v1, const CFixedVector2D& halfSize1);
|
||||
|
||||
/**
|
||||
* Used in Footprint when spawning units:
|
||||
* Given a grid point (x, y) on the rectangle [-x_max, x_max] x [-y_max, y_max],
|
||||
* this returns the distance travelled in moving from (x_max, 0) to the the point while
|
||||
* walking counter-clockwise along the perimeter of the rectangle.
|
||||
*/
|
||||
int GetPerimeterDistance(int x_max, int y_max, int x, int y);
|
||||
|
||||
/**
|
||||
* Used in Footprint when spawning units:
|
||||
* This returns the grid point on the rectangle [-x_max, x_max] x [-y_max, y_max]
|
||||
* reached after starting at (x_max, 0) and walking a distance k
|
||||
* counter-clockwise along the perimeter of the rectangle.
|
||||
*/
|
||||
std::pair<int, int> GetPerimeterCoordinates(int x_max, int y_max, int k);
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // INCLUDED_HELPER_GEOMETRY
|
||||
|
||||
Reference in New Issue
Block a user