Newer
Older
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using UnityEditorInternal;
using UnityEngine.Rendering;
private Vector2 position, attractor, repulsor, prefDirection;
private int actionRadius;
private bool useCustomRadius = false;
private List<Vector2> borderPart;
private System.Func<Vector2, bool> borderFilter;
public int Tokens { get => tokens; }
public int ActionRadius { get => actionRadius; }
public CoastlineAgent(CoastlineGenerator generator, Vector2 position, int tokens, List<Vector2> borderPart, int actionRadius = -1)
this.tokens = tokens;
this.tokensRemaining = tokens;
this.position = position;
this.actionRadius = actionRadius;
this.borderPart = borderPart;
// calculate preferred direction
Vector2 tangent = (borderPart[borderPart.Count - 1] - borderPart[0]).normalized;
Vector2 bitangent = new Vector2(-tangent.y, tangent.x);
if(bitangent == Vector2.zero) // in case of the first agent, just create any random pref direction
{
prefDirection = Random.insideUnitCircle;
prefDirection.Normalize();
}
else
{
prefDirection = RotateVector(bitangent, Random.Range(-70.0f, 70.0f));
}
if (this.actionRadius > 0)
{
useCustomRadius = true;
borderFilter = p => (p - position).sqrMagnitude <= actionRadius * actionRadius;
}
else
{
borderFilter = p => (p - position).sqrMagnitude <= coastlineGenerator.SqrActionRadius;
}
// create random attractor / repulsor and make sure they point at different directions
Vector2 direction = Random.insideUnitCircle * coastlineGenerator.ActionRadius;
attractor = position + direction;
repulsor = position + RotateVector(-direction, Random.Range(-90f, 90));
}
public bool UpdateLand()
{
if (tokensRemaining <= 0) return false;
Vector2 pos = GetRandomPosition();
if(pos == new Vector2(0, 0))
{
tokensRemaining--;
return true;
}
Vector2 initPos = new Vector2(-1, -1);
Vector2 highestPos = initPos;
float highestScore = 0.0f;
// score
for (int x = -1; x <= 1; x++)
for (int y = -1; y <= 1; y++)
{
Vector2 currPos = new Vector2((int)pos.x + x, (int)pos.y + y);
if (currPos.x < 0 || currPos.x >= coastlineGenerator.TerrainSize) continue;
if (currPos.y < 0 || currPos.y >= coastlineGenerator.TerrainSize) continue;
int currIndex = (int)(currPos.x + currPos.y * coastlineGenerator.TerrainSize);
if (coastlineGenerator.landBitField[currIndex]) continue;
float score = Score(currPos);
if (score > highestScore || highestPos == initPos)
{
highestScore = score;
highestPos = currPos;
}
}
if (highestPos == initPos || pos == Vector2.zero)
{
// couldn't find a decent neighbor
tokensRemaining--;
return true;
}
if(highestPos.x < 0 || highestPos.x >= coastlineGenerator.TerrainSize)
{
Debug.Log("whoops");
}
else if (highestPos.y < 0 || highestPos.y >= coastlineGenerator.TerrainSize)
{
Debug.Log("whoops");
}
else
{
coastlineGenerator.coastText.SetPixel((int)highestPos.x, (int)highestPos.y, Color.grey);
int highestIndex = (int)highestPos.x + (int)highestPos.y * coastlineGenerator.TerrainSize;
coastlineGenerator.landBitField[highestIndex] = true;
coastlineGenerator.borderPoints.Add(highestPos);
if (!borderPart.Contains(highestPos)) borderPart.Add(highestPos);
coastlineGenerator.RemoveNonBoundaryPixels(highestPos);
}
int terrainSize = coastlineGenerator.TerrainSize;
float mapHorizDist = (pos.x < terrainSize * 0.5f ? pos.x : terrainSize - pos.x);
float mapVertDist = (pos.y < terrainSize * 0.5f ? pos.y : terrainSize - pos.y);
float mapDist = Mathf.Min(mapHorizDist, mapVertDist);
return ((repulsor - pos).sqrMagnitude * 1f - (attractor - pos).sqrMagnitude * 1f) + 3 * mapDist * mapDist;
}
public Vector2 GetRandomPosition()
{
if (borderPart.Count == 0)
{
//Debug.Log("borderpart count is zero!");
return Vector2.zero;
}
int randIndex = Random.Range(0, borderPart.Count);
Vector2 pos = borderPart[randIndex];
if(pos.x == 0 || pos.x == (coastlineGenerator.TerrainSize - 1))
{
return Vector2.zero;
}
if(pos.y == 0 || pos.y == (coastlineGenerator.TerrainSize - 1))
{
return Vector2.zero;
}
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
bool inland = true;
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
if (x == 0 && y == 0) continue;
if ((pos.x + x) < 0 || (pos.x + x) >= coastlineGenerator.TerrainSize) continue;
if ((pos.y + y) < 0 || (pos.y + y) >= coastlineGenerator.TerrainSize) continue;
int index = (int)((pos.x + x) + (pos.y + y) * coastlineGenerator.TerrainSize);
if (!coastlineGenerator.landBitField[index])
{
inland = false;
break;
}
}
if(!inland)
{
break;
}
}
if (inland)
{
// not a valid border point anymore, remove
borderPart.Remove(pos);
coastlineGenerator.borderPoints.Remove(pos);
Vector2 oldPos = pos;
// find new border point in preferred direction
pos = TraverseToCoastline(oldPos);
//pos = new Vector2(-1, -1);
if(pos == new Vector2(-1, -1))
{
return Vector2.zero;
}
else if (!borderPart.Contains(pos)) borderPart.Add(pos);
}
return pos;
}
public Vector2 TraverseToCoastline(Vector2 startPos)
{
Vector2 pos = new Vector2(-1, -1);
if (startPos.x == 0 || startPos.x == (coastlineGenerator.TerrainSize - 1)) return pos;
if (startPos.y == 0 || startPos.y == (coastlineGenerator.TerrainSize - 1)) return pos;
Vector2 prevPos = pos;
bool foundCoastPoint = false;
float oldX = startPos.x;
float oldY = startPos.y;
int maxCounter = 0;
int newX = (int)(oldX + prefDirection.x);
int newY = (int)(oldY + prefDirection.y);
if (newX < 0 || newX >= coastlineGenerator.TerrainSize) return pos;
if (newY < 0 || newY >= coastlineGenerator.TerrainSize) return pos;
Vector2 newPos = new Vector2(newX, newY);
int idx = coastlineGenerator.TerrainSize * newY + newX;
if(!coastlineGenerator.landBitField[idx])
{
foundCoastPoint = true;
pos = prevPos;
}
else
{
//Debug.Log("not a coastline!");
//Debug.Log("pref dir x: " + prefDirection.x);
//Debug.Log("pref dir y: " + prefDirection.y);
}
prevPos = newPos;
oldX = (oldX + prefDirection.x);
oldY = (oldY + prefDirection.y);
//foundCoastPoint = coastlineGenerator.borderPoints.Contains(possibleCoastPoint);
//if (foundCoastPoint) pos = possibleCoastPoint;
while (!foundCoastPoint && maxCounter < 100);
return pos;
}
private static Vector2 RotateVector(Vector2 v, float degrees)
{
float rad = degrees * Mathf.Deg2Rad;
float ca = Mathf.Cos(rad);
float sa = Mathf.Sin(rad);
return new Vector2(ca * v.x - sa * v.y, sa * v.x + ca * v.y);