Improved submarine movement (buoyancy & drag), engine and "navigation terminal", new map, optimized levels (less vertices and physics bodies)
This commit is contained in:
@@ -48,7 +48,7 @@ namespace Subsurface
|
||||
for (int i = 0; i<range*10; i++)
|
||||
{
|
||||
Game1.particleManager.CreateParticle("explosionfire", position,
|
||||
Vector2.Normalize(new Vector2(ToolBox.RandomFloatLocal(-1.0f, 1.0f), ToolBox.RandomFloatLocal(-1.0f, 1.0f))) * ToolBox.RandomFloatLocal(3.0f, 4.0f),
|
||||
Vector2.Normalize(new Vector2(MathUtils.RandomFloatLocal(-1.0f, 1.0f), MathUtils.RandomFloatLocal(-1.0f, 1.0f))) * MathUtils.RandomFloatLocal(3.0f, 4.0f),
|
||||
0.0f);
|
||||
}
|
||||
|
||||
|
||||
@@ -250,20 +250,20 @@ namespace Subsurface
|
||||
pos.Y = ConvertUnits.ToSimUnits(MathHelper.Clamp(lowerSurface, rect.Y-rect.Height, rect.Y));
|
||||
|
||||
Game1.particleManager.CreateParticle("watersplash",
|
||||
new Vector2(pos.X, pos.Y - ToolBox.RandomFloatLocal(0.0f, 0.1f)),
|
||||
new Vector2(flowForce.X * ToolBox.RandomFloatLocal(0.005f, 0.007f), flowForce.Y * ToolBox.RandomFloatLocal(0.005f, 0.007f)));
|
||||
new Vector2(pos.X, pos.Y - MathUtils.RandomFloatLocal(0.0f, 0.1f)),
|
||||
new Vector2(flowForce.X * MathUtils.RandomFloatLocal(0.005f, 0.007f), flowForce.Y * MathUtils.RandomFloatLocal(0.005f, 0.007f)));
|
||||
|
||||
pos.Y = ConvertUnits.ToSimUnits(ToolBox.RandomFloatLocal(lowerSurface, rect.Y - rect.Height));
|
||||
pos.Y = ConvertUnits.ToSimUnits(MathUtils.RandomFloatLocal(lowerSurface, rect.Y - rect.Height));
|
||||
Game1.particleManager.CreateParticle("bubbles", pos, flowForce / 200.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.Y += Math.Sign(flowForce.Y) * ConvertUnits.ToSimUnits(rect.Height / 2.0f);
|
||||
for (int i = 0; i < rect.Width; i += (int)ToolBox.RandomFloatLocal(80, 100))
|
||||
for (int i = 0; i < rect.Width; i += (int)MathUtils.RandomFloatLocal(80, 100))
|
||||
{
|
||||
pos.X = ConvertUnits.ToSimUnits(ToolBox.RandomFloatLocal(rect.X, rect.X+rect.Width));
|
||||
pos.X = ConvertUnits.ToSimUnits(MathUtils.RandomFloatLocal(rect.X, rect.X+rect.Width));
|
||||
Subsurface.Particles.Particle splash = Game1.particleManager.CreateParticle("watersplash", pos,
|
||||
new Vector2(flowForce.X * ToolBox.RandomFloatLocal(0.005f, 0.008f), flowForce.Y * ToolBox.RandomFloatLocal(0.005f, 0.008f)));
|
||||
new Vector2(flowForce.X * MathUtils.RandomFloatLocal(0.005f, 0.008f), flowForce.Y * MathUtils.RandomFloatLocal(0.005f, 0.008f)));
|
||||
|
||||
if (splash!=null) splash.Size = splash.Size * MathHelper.Clamp(rect.Width / 50.0f, 0.8f, 4.0f);
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ namespace Subsurface
|
||||
for (int i = 0; i < waveY.Length; i++)
|
||||
{
|
||||
float maxDelta = Math.Max(Math.Abs(rightDelta[i]), Math.Abs(leftDelta[i]));
|
||||
if (maxDelta > ToolBox.RandomFloatLocal(0.2f,10.0f))
|
||||
if (maxDelta > MathUtils.RandomFloatLocal(0.2f,10.0f))
|
||||
{
|
||||
Game1.particleManager.CreateParticle("mist",
|
||||
ConvertUnits.ToSimUnits(new Vector2(rect.X + WaveWidth * i,surface + waveY[i])),
|
||||
|
||||
+214
-95
@@ -24,7 +24,7 @@ namespace Subsurface
|
||||
|
||||
private int siteInterval;
|
||||
|
||||
const int gridCellWidth = 1000;
|
||||
const int gridCellWidth = 2000;
|
||||
List<VoronoiCell>[,] cellGrid;
|
||||
|
||||
//List<Body> bodies;
|
||||
@@ -66,7 +66,7 @@ namespace Subsurface
|
||||
|
||||
Game1.random = new Random(seed);
|
||||
|
||||
if (loaded != this && loaded != null)
|
||||
if (loaded != null)
|
||||
{
|
||||
loaded.Unload();
|
||||
}
|
||||
@@ -160,7 +160,7 @@ namespace Subsurface
|
||||
borders.Right - siteInterval * 2, borders.Y + borders.Height - siteInterval * 2);
|
||||
|
||||
Vector2 start = pathCells[Game1.random.Next(1,pathCells.Count-2)].Center;
|
||||
Vector2 end = new Vector2(ToolBox.RandomFloat(pathBorders.X, pathBorders.Right), ToolBox.RandomFloat(pathBorders.Y, pathBorders.Bottom));
|
||||
Vector2 end = new Vector2(MathUtils.RandomFloat(pathBorders.X, pathBorders.Right), MathUtils.RandomFloat(pathBorders.Y, pathBorders.Bottom));
|
||||
|
||||
pathCells.AddRange
|
||||
(
|
||||
@@ -174,12 +174,16 @@ namespace Subsurface
|
||||
startPosition = pathCells[0].Center;
|
||||
endPosition = pathCells[pathCells.Count - 1].Center;
|
||||
|
||||
cells = CleanCells(pathCells);
|
||||
|
||||
foreach (VoronoiCell cell in pathCells)
|
||||
{
|
||||
cells.Remove(cell);
|
||||
}
|
||||
|
||||
GenerateLevel(cells);
|
||||
//GenerateBodies(cells, pathCells);
|
||||
|
||||
GeneratePolygons(cells, pathCells);
|
||||
|
||||
Debug.WriteLine("Generatelevel: " + sw2.ElapsedMilliseconds + " ms");
|
||||
sw2.Restart();
|
||||
@@ -303,6 +307,25 @@ namespace Subsurface
|
||||
return tooCloseCells;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// remove all cells except those that are adjacent to the empty cells
|
||||
/// </summary>
|
||||
private List<VoronoiCell> CleanCells(List<VoronoiCell> emptyCells)
|
||||
{
|
||||
List<VoronoiCell> newCells = new List<VoronoiCell>();
|
||||
|
||||
foreach (VoronoiCell cell in emptyCells)
|
||||
{
|
||||
foreach (GraphEdge edge in cell.edges)
|
||||
{
|
||||
VoronoiCell adjacent = edge.AdjacentCell(cell);
|
||||
if (!newCells.Contains(adjacent)) newCells.Add(adjacent);
|
||||
}
|
||||
}
|
||||
|
||||
return newCells;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// check whether line from a to b is intersecting with line from c to b
|
||||
/// </summary>
|
||||
@@ -319,6 +342,18 @@ namespace Subsurface
|
||||
|
||||
return (r >= 0 && r <= 1) && (s >= 0 && s <= 1);
|
||||
}
|
||||
|
||||
//public Microsoft.Xna.Framework.Point GridCell(Vector2 position)
|
||||
//{
|
||||
// Microsoft.Xna.Framework.Point point = new Microsoft.Xna.Framework.Point(
|
||||
// (int)Math.Floor(position.X / gridCellWidth),
|
||||
// (int)Math.Floor(position.Y / gridCellWidth));
|
||||
|
||||
// point.X = MathHelper.Clamp(point.X, 0, cellGrid.GetLength(0) - 1);
|
||||
// point.Y = MathHelper.Clamp(point.X, 0, cellGrid.GetLength(1) - 1);
|
||||
|
||||
// return point;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// find the index of the cell which the point is inside
|
||||
@@ -354,25 +389,71 @@ namespace Subsurface
|
||||
return cells.IndexOf(closestCell);
|
||||
}
|
||||
|
||||
private void GenerateLevel(List<VoronoiCell> cells)
|
||||
private void GenerateBodies(List<VoronoiCell> cells, List<VoronoiCell> emptyCells)
|
||||
{
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
List<Vector2> points = new List<Vector2>();
|
||||
foreach (GraphEdge edge in cell.edges)
|
||||
{
|
||||
VoronoiCell adjacentCell = edge.AdjacentCell(cell);
|
||||
if (!emptyCells.Contains(adjacentCell)) continue;
|
||||
|
||||
if (!points.Contains(edge.point1)) points.Add(edge.point1);
|
||||
if (!points.Contains(edge.point2)) points.Add(edge.point2);
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (points.Count == 0) continue;
|
||||
|
||||
for (int i = 0 ; i<points.Count; i++)
|
||||
{
|
||||
points[i] = ConvertUnits.ToSimUnits(points[i]);
|
||||
}
|
||||
|
||||
Vertices vertices = new Vertices(points);
|
||||
|
||||
Debug.WriteLine("simple: "+vertices.IsSimple());
|
||||
Debug.WriteLine("convex: "+vertices.IsConvex());
|
||||
Debug.WriteLine("ccw: "+ vertices.IsCounterClockWise());
|
||||
|
||||
Body edgeBody = BodyFactory.CreateChainShape(
|
||||
Game1.world, vertices, cell);
|
||||
|
||||
edgeBody.BodyType = BodyType.Static;
|
||||
edgeBody.CollisionCategories = Physics.CollisionWall | Physics.CollisionLevel;
|
||||
|
||||
cell.body = edgeBody;
|
||||
}
|
||||
}
|
||||
|
||||
private void GeneratePolygons(List<VoronoiCell> cells, List<VoronoiCell> emptyCells)
|
||||
{
|
||||
List<VertexPositionColor> verticeList = new List<VertexPositionColor>();
|
||||
//bodies = new List<Body>();
|
||||
|
||||
|
||||
List<Vector2> tempVertices = new List<Vector2>();
|
||||
List<Vector2> bodyPoints = new List<Vector2>();
|
||||
|
||||
int n = 0;
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
n = (n + 30) % 255;
|
||||
|
||||
bodyPoints.Clear();
|
||||
tempVertices.Clear();
|
||||
foreach (GraphEdge ge in cell.edges)
|
||||
{
|
||||
if (ge.point1 == ge.point2) continue;
|
||||
if (!tempVertices.Contains(ge.point1)) tempVertices.Add(ge.point1);
|
||||
if (!tempVertices.Contains(ge.point2)) tempVertices.Add(ge.point2);
|
||||
|
||||
VoronoiCell adjacentCell = ge.AdjacentCell(cell);
|
||||
if (!emptyCells.Contains(adjacentCell)) continue;
|
||||
|
||||
if (!bodyPoints.Contains(ge.point1)) bodyPoints.Add(ge.point1);
|
||||
if (!bodyPoints.Contains(ge.point2)) bodyPoints.Add(ge.point2);
|
||||
}
|
||||
|
||||
if (tempVertices.Count < 3) continue;
|
||||
@@ -404,10 +485,28 @@ namespace Subsurface
|
||||
|
||||
if (isSame) continue;
|
||||
|
||||
CreateBody(cell, triangleVertices);
|
||||
//CreateBody(cell, triangleVertices);
|
||||
}
|
||||
|
||||
if (bodyPoints.Count < 2) continue;
|
||||
|
||||
bodyPoints.Sort(new CompareCCW(cell.Center));
|
||||
|
||||
for (int i = 0; i < bodyPoints.Count; i++)
|
||||
{
|
||||
bodyPoints[i] = ConvertUnits.ToSimUnits(bodyPoints[i]);
|
||||
}
|
||||
|
||||
Vertices bodyVertices = new Vertices(bodyPoints);
|
||||
|
||||
Body edgeBody = BodyFactory.CreateChainShape(
|
||||
Game1.world, bodyVertices, cell);
|
||||
edgeBody.UserData = cell;
|
||||
|
||||
edgeBody.BodyType = BodyType.Static;
|
||||
edgeBody.CollisionCategories = Physics.CollisionWall | Physics.CollisionLevel;
|
||||
|
||||
cell.body = edgeBody;
|
||||
}
|
||||
|
||||
vertices = verticeList.ToArray();
|
||||
@@ -415,77 +514,96 @@ namespace Subsurface
|
||||
//return bodies;
|
||||
}
|
||||
|
||||
private void CreateBody(VoronoiCell cell, List<Vector2> bodyVertices)
|
||||
//private void CreateBody(VoronoiCell cell, List<Vector2> bodyVertices)
|
||||
//{
|
||||
// for (int i = 0; i < bodyVertices.Count; i++)
|
||||
// {
|
||||
// bodyVertices[i] = ConvertUnits.ToSimUnits(bodyVertices[i]);
|
||||
// }
|
||||
// //get farseer 'vertices' from vectors
|
||||
// Vertices _shapevertices = new Vertices(bodyVertices);
|
||||
// //_shapevertices.Sort(new CompareCCW(cell.Center));
|
||||
|
||||
// //feed vertices array to BodyFactory.CreatePolygon to get a new farseer polygonal body
|
||||
// Body _newBody = BodyFactory.CreatePolygon(Game1.world, _shapevertices, 15);
|
||||
// _newBody.BodyType = BodyType.Static;
|
||||
// _newBody.CollisionCategories = Physics.CollisionWall | Physics.CollisionLevel;
|
||||
// _newBody.UserData = cell;
|
||||
|
||||
// cell.body = _newBody;
|
||||
//}
|
||||
|
||||
|
||||
public Vector2 position;
|
||||
|
||||
public void SetPosition(Vector2 pos)
|
||||
{
|
||||
for (int i = 0; i < bodyVertices.Count; i++)
|
||||
Vector2 amount = ConvertUnits.ToSimUnits(pos - position);
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
bodyVertices[i] = ConvertUnits.ToSimUnits(bodyVertices[i]);
|
||||
if (cell.body == null) continue;
|
||||
//foreach (Body b in cell.bodies)
|
||||
//{
|
||||
cell.body.SetTransform(cell.body.Position + amount, cell.body.Rotation);
|
||||
//}
|
||||
}
|
||||
//get farseer 'vertices' from vectors
|
||||
Vertices _shapevertices = new Vertices(bodyVertices);
|
||||
//_shapevertices.Sort(new CompareCCW(cell.Center));
|
||||
|
||||
//feed vertices array to BodyFactory.CreatePolygon to get a new farseer polygonal body
|
||||
Body _newBody = BodyFactory.CreatePolygon(Game1.world, _shapevertices, 15);
|
||||
_newBody.BodyType = BodyType.Static;
|
||||
_newBody.CollisionCategories = Physics.CollisionWall;
|
||||
|
||||
cell.bodies.Add(_newBody);
|
||||
position = pos;
|
||||
}
|
||||
|
||||
|
||||
Vector2 position;
|
||||
public void Move(Vector2 amount, float deltaTime)
|
||||
public void Move(Vector2 amount)
|
||||
{
|
||||
amount = amount * deltaTime;
|
||||
position += amount;
|
||||
|
||||
amount = ConvertUnits.ToSimUnits(amount);
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
foreach (Body b in cell.bodies)
|
||||
{
|
||||
b.SetTransform(b.Position+amount, b.Rotation);
|
||||
}
|
||||
if (cell.body == null) continue;
|
||||
//foreach (Body b in cell.bodies)
|
||||
//{
|
||||
// b.SetTransform(b.Position+amount, b.Rotation);
|
||||
//}
|
||||
cell.body.SetTransform(cell.body.Position + amount, cell.body.Rotation);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void SetObserverPosition(Vector2 position)
|
||||
{
|
||||
position = position - this.position;
|
||||
int gridPosX = (int)Math.Floor(position.X / gridCellWidth);
|
||||
int gridPosY = (int)Math.Floor(position.Y / gridCellWidth);
|
||||
int searchOffset = 1;
|
||||
|
||||
for (int x = 0; x < cellGrid.GetLength(0); x++)
|
||||
foreach (Character character in Character.characterList)
|
||||
{
|
||||
for (int y = 0; y <cellGrid.GetLength(1); y++)
|
||||
if (character.animController.CurrentHull==null)
|
||||
{
|
||||
for (int i = 0; i < cellGrid[x, y].Count; i++)
|
||||
foreach (Limb limb in character.animController.limbs)
|
||||
{
|
||||
foreach (Body b in cellGrid[x, y][i].bodies)
|
||||
{
|
||||
b.Enabled = false;
|
||||
}
|
||||
|
||||
|
||||
limb.body.SetTransform(limb.body.Position + amount, limb.body.Rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = Math.Max(gridPosX - searchOffset, 0); x <= Math.Min(gridPosX + searchOffset, cellGrid.GetLength(0) - 1); x++)
|
||||
|
||||
}
|
||||
Vector2 observerPosition;
|
||||
public void SetObserverPosition(Vector2 position)
|
||||
{
|
||||
observerPosition = position - this.position;
|
||||
int gridPosX = (int)Math.Floor(observerPosition.X / gridCellWidth);
|
||||
int gridPosY = (int)Math.Floor(observerPosition.Y / gridCellWidth);
|
||||
int searchOffset = 2;
|
||||
|
||||
int startX = Math.Max(gridPosX - searchOffset, 0);
|
||||
int endX = Math.Min(gridPosX + searchOffset, cellGrid.GetLength(0) - 1);
|
||||
|
||||
int startY = Math.Max(gridPosY - searchOffset, 0);
|
||||
int endY = Math.Min(gridPosY + searchOffset, cellGrid.GetLength(1) - 1);
|
||||
|
||||
for (int x = 0; x < cellGrid.GetLength(0); x++)
|
||||
{
|
||||
for (int y = Math.Max(gridPosY - searchOffset, 0); y <= Math.Min(gridPosY + searchOffset, cellGrid.GetLength(1) - 1); y++)
|
||||
for (int y = 0; y < cellGrid.GetLength(1); y++)
|
||||
{
|
||||
for (int i = 0; i < cellGrid[x, y].Count; i++)
|
||||
{
|
||||
foreach (Body b in cellGrid[x, y][i].bodies)
|
||||
{
|
||||
b.Enabled = true;
|
||||
}
|
||||
//foreach (Body b in cellGrid[x, y][i].bodies)
|
||||
//{
|
||||
if (cellGrid[x, y][i].body == null) continue;
|
||||
cellGrid[x, y][i].body.Enabled = (x >= startX && x <= endX && y >= startY && y <= endY);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -494,7 +612,37 @@ namespace Subsurface
|
||||
|
||||
public void RenderLines(SpriteBatch spriteBatch)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(borders.X, borders.Y-borders.Height, borders.Width, borders.Height), Color.Cyan);
|
||||
//GUI.DrawRectangle(spriteBatch, new Rectangle(borders.X, borders.Y-borders.Height, borders.Width, borders.Height), Color.Cyan);
|
||||
|
||||
//for (int x = 0; x < cellGrid.GetLength(0); x++)
|
||||
//{
|
||||
// for (int y = 0; y < cellGrid.GetLength(1); y++)
|
||||
// {
|
||||
// GUI.DrawRectangle(spriteBatch,
|
||||
// new Rectangle(x * gridCellWidth + (int)position.X, borders.Y - borders.Height + y * gridCellWidth - (int)position.Y, gridCellWidth, gridCellWidth),
|
||||
// Color.Cyan);
|
||||
// }
|
||||
//}
|
||||
|
||||
int gridPosX = (int)Math.Floor(-observerPosition.X / gridCellWidth);
|
||||
int gridPosY = (int)Math.Floor(-observerPosition.Y / gridCellWidth);
|
||||
int searchOffset = 2;
|
||||
|
||||
int startX = Math.Max(gridPosX - searchOffset, 0);
|
||||
int endX = Math.Min(gridPosX + searchOffset, cellGrid.GetLength(0) - 1);
|
||||
|
||||
int startY = Math.Max(gridPosY - searchOffset, 0);
|
||||
int endY = Math.Min(gridPosY + searchOffset, cellGrid.GetLength(1) - 1);
|
||||
|
||||
for (int x = startX; x < endX; x++)
|
||||
{
|
||||
for (int y = startY; y < endY; y++)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle(x * gridCellWidth + (int)position.X, borders.Y - borders.Height + y * gridCellWidth - (int)position.Y, gridCellWidth, gridCellWidth),
|
||||
Color.Cyan);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
@@ -505,8 +653,8 @@ namespace Subsurface
|
||||
|
||||
Vector2 end = cell.edges[i].point2+position;
|
||||
end.Y = -end.Y;
|
||||
|
||||
GUI.DrawLine(spriteBatch, start, end, Color.Red);
|
||||
|
||||
GUI.DrawLine(spriteBatch, start, end, (cell.body!=null && cell.body.Enabled) ? Color.Green : Color.Red);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -528,13 +676,15 @@ namespace Subsurface
|
||||
|
||||
private void Unload()
|
||||
{
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
foreach (Body b in cell.bodies)
|
||||
{
|
||||
Game1.world.RemoveBody(b);
|
||||
}
|
||||
}
|
||||
position = Vector2.Zero;
|
||||
|
||||
//foreach (VoronoiCell cell in cells)
|
||||
//{
|
||||
// //foreach (Body b in cell.bodies)
|
||||
// //{
|
||||
// Game1.world.RemoveBody(cell.body);
|
||||
// //}
|
||||
//}
|
||||
|
||||
|
||||
//bodies = null;
|
||||
@@ -547,36 +697,5 @@ namespace Subsurface
|
||||
vertexBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
class CompareCCW : IComparer<Vector2>
|
||||
{
|
||||
private Vector2 center;
|
||||
|
||||
public CompareCCW(Vector2 center)
|
||||
{
|
||||
this.center = center;
|
||||
}
|
||||
public int Compare(Vector2 a, Vector2 b)
|
||||
{
|
||||
if (a.X - center.X >= 0 && b.X - center.X < 0) return -1;
|
||||
if (a.X - center.X < 0 && b.X - center.X >= 0) return 1;
|
||||
if (a.X - center.X == 0 && b.X - center.X == 0)
|
||||
{
|
||||
if (a.Y - center.Y >= 0 || b.Y - center.Y >= 0) return Math.Sign(b.Y-a.Y);
|
||||
return Math.Sign(a.Y-b.Y);
|
||||
}
|
||||
|
||||
// compute the cross product of vectors (center -> a) x (center -> b)
|
||||
float det = (a.X - center.X) * (b.Y - center.Y) - (b.X - center.X) * (a.Y - center.Y);
|
||||
if (det < 0) return -1;
|
||||
if (det > 0) return 1;
|
||||
|
||||
// points a and b are on the same line from the center
|
||||
// check which point is closer to the center
|
||||
float d1 = (a.X - center.X) * (a.X - center.X) + (a.Y - center.Y) * (a.Y - center.Y);
|
||||
float d2 = (b.X - center.X) * (b.X - center.X) + (b.Y - center.Y) * (b.Y - center.Y);
|
||||
return Math.Sign(d2-d1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -418,7 +418,12 @@ namespace Subsurface
|
||||
{
|
||||
if (sections[sectionIndex].gap == null)
|
||||
{
|
||||
sections[sectionIndex].gap = new Gap(sections[sectionIndex].rect, !isHorizontal);
|
||||
Rectangle gapRect = sections[sectionIndex].rect;
|
||||
gapRect.X -= 10;
|
||||
gapRect.Y += 10;
|
||||
gapRect.Width += 20;
|
||||
gapRect.Height += 20;
|
||||
sections[sectionIndex].gap = new Gap(gapRect, !isHorizontal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+307
-78
@@ -1,6 +1,10 @@
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Collision;
|
||||
using FarseerPhysics.Common;
|
||||
using FarseerPhysics.Common.Decomposition;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Contacts;
|
||||
using FarseerPhysics.Factories;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -9,6 +13,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using Voronoi2;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
@@ -19,30 +24,29 @@ namespace Subsurface
|
||||
|
||||
class Submarine
|
||||
{
|
||||
static string SaveFolder;
|
||||
Md5Hash hash;
|
||||
|
||||
public static List<Submarine> SavedSubmarines = new List<Submarine>();
|
||||
|
||||
|
||||
private static Submarine loaded;
|
||||
|
||||
//public static Map Loaded
|
||||
//{
|
||||
// get { return loaded; }
|
||||
// set { loaded = value; }
|
||||
//}
|
||||
|
||||
|
||||
public static readonly Vector2 gridSize = new Vector2(16.0f, 16.0f);
|
||||
|
||||
private static Vector2 lastPickedPosition;
|
||||
private static float lastPickedFraction;
|
||||
|
||||
static string SaveFolder;
|
||||
Md5Hash hash;
|
||||
|
||||
Vector2 speed;
|
||||
|
||||
private Rectangle borders;
|
||||
|
||||
private Body hullBody;
|
||||
|
||||
private string filePath;
|
||||
private string name;
|
||||
|
||||
//properties ----------------------------------------------------
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return name; }
|
||||
@@ -94,6 +98,104 @@ namespace Subsurface
|
||||
get { return filePath; }
|
||||
}
|
||||
|
||||
//constructors & generation ----------------------------------------------------
|
||||
|
||||
public Submarine(string filePath, string hash = "")
|
||||
{
|
||||
this.filePath = filePath;
|
||||
try
|
||||
{
|
||||
name = System.IO.Path.GetFileNameWithoutExtension(filePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error loading map " + filePath + "!", e);
|
||||
}
|
||||
|
||||
if (hash != "")
|
||||
{
|
||||
this.hash = new Md5Hash(hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
//XDocument doc = OpenDoc(filePath);
|
||||
|
||||
//string md5Hash = ToolBox.GetAttributeString(doc.Root, "md5hash", "");
|
||||
//if (md5Hash == "" || md5Hash.Length < 16)
|
||||
//{
|
||||
// DebugConsole.ThrowError("Couldn't find a valid MD5 hash in the map file");
|
||||
//}
|
||||
|
||||
//this.mapHash = new MapHash(md5Hash);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private List<Vector2> GenerateConvexHull()
|
||||
{
|
||||
List<Vector2> points = new List<Vector2>();
|
||||
|
||||
Vector2 leftMost = Vector2.Zero;
|
||||
|
||||
foreach (Structure wall in Structure.wallList)
|
||||
{
|
||||
for (int x = -1; x <= 1; x += 2)
|
||||
{
|
||||
for (int y = -1; y <= 1; y += 2)
|
||||
{
|
||||
Vector2 corner = new Vector2(wall.Rect.X + wall.Rect.Width / 2.0f, wall.Rect.Y - wall.Rect.Height / 2.0f);
|
||||
corner.X += x * wall.Rect.Width / 2.0f;
|
||||
corner.Y += y * wall.Rect.Height / 2.0f;
|
||||
|
||||
if (points.Contains(corner)) continue;
|
||||
|
||||
points.Add(corner);
|
||||
if (leftMost == Vector2.Zero || corner.X < leftMost.X) leftMost = corner;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Vector2> hullPoints = new List<Vector2>();
|
||||
|
||||
Vector2 currPoint = leftMost;
|
||||
Vector2 endPoint;
|
||||
do
|
||||
{
|
||||
hullPoints.Add(currPoint);
|
||||
endPoint = points[0];
|
||||
|
||||
for (int i = 1; i < points.Count; i++)
|
||||
{
|
||||
if ((currPoint == endPoint)
|
||||
|| (Orientation(currPoint, endPoint, points[i]) == -1))
|
||||
{
|
||||
endPoint = points[i];
|
||||
}
|
||||
}
|
||||
|
||||
currPoint = endPoint;
|
||||
|
||||
}
|
||||
while (endPoint != hullPoints[0]);
|
||||
|
||||
return hullPoints;
|
||||
}
|
||||
|
||||
private static int Orientation(Vector2 p1, Vector2 p2, Vector2 p)
|
||||
{
|
||||
// Determinant
|
||||
float Orin = (p2.X - p1.X) * (p.Y - p1.Y) - (p.X - p1.X) * (p2.Y - p1.Y);
|
||||
|
||||
if (Orin > 0)
|
||||
return -1; // (* Orientation is to the left-hand side *)
|
||||
if (Orin < 0)
|
||||
return 1; // (* Orientation is to the right-hand side *)
|
||||
|
||||
return 0; // (* Orientation is neutral aka collinear *)
|
||||
}
|
||||
|
||||
//drawing ----------------------------------------------------
|
||||
|
||||
public static void Draw(SpriteBatch spriteBatch, bool editing = false)
|
||||
{
|
||||
for (int i = 0; i < MapEntity.mapEntityList.Count(); i++ )
|
||||
@@ -109,6 +211,19 @@ namespace Subsurface
|
||||
if (MapEntity.mapEntityList[i].sprite == null || MapEntity.mapEntityList[i].sprite.Depth < 0.5f)
|
||||
MapEntity.mapEntityList[i].Draw(spriteBatch, editing);
|
||||
}
|
||||
|
||||
if (loaded == null) return;
|
||||
|
||||
//foreach (HullBody hb in loaded.hullBodies)
|
||||
//{
|
||||
// spriteBatch.Draw(
|
||||
// hb.shapeTexture,
|
||||
// ConvertUnits.ToDisplayUnits(new Vector2(hb.body.Position.X, -hb.body.Position.Y)),
|
||||
// null,
|
||||
// Color.White,
|
||||
// -hb.body.Rotation,
|
||||
// new Vector2(hb.shapeTexture.Width / 2, hb.shapeTexture.Height / 2), 1.0f, SpriteEffects.None, 0.0f);
|
||||
//}
|
||||
}
|
||||
|
||||
public static void DrawBack(SpriteBatch spriteBatch, bool editing = false)
|
||||
@@ -120,6 +235,8 @@ namespace Subsurface
|
||||
}
|
||||
}
|
||||
|
||||
//math/physics stuff ----------------------------------------------------
|
||||
|
||||
public static Vector2 MouseToWorldGrid(Camera cam)
|
||||
{
|
||||
Vector2 position = new Vector2(PlayerInput.GetMouseState.X, PlayerInput.GetMouseState.Y);
|
||||
@@ -135,8 +252,7 @@ namespace Subsurface
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Rectangle AbsRect(Vector2 pos, Vector2 size)
|
||||
{
|
||||
if (size.X < 0.0f)
|
||||
@@ -173,28 +289,6 @@ namespace Subsurface
|
||||
}
|
||||
}
|
||||
|
||||
public void Move(Vector2 amount, float deltaTime)
|
||||
{
|
||||
if (amount == Vector2.Zero) return;
|
||||
|
||||
Level.Loaded.Move(-amount, deltaTime);
|
||||
|
||||
//foreach (MapEntity e in Structure.mapEntityList)
|
||||
//{
|
||||
// e.Move(amount);
|
||||
//}
|
||||
|
||||
//amount = ConvertUnits.ToSimUnits(amount*deltaTime);
|
||||
//foreach (Character c in Character.characterList)
|
||||
//{
|
||||
// if (c.animController.CurrentHull != null) continue;
|
||||
// foreach (Limb l in c.animController.limbs)
|
||||
// {
|
||||
// l.body.SetTransform(l.body.Position - amount, l.body.Rotation);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
public static Body PickBody(Vector2 rayStart, Vector2 rayEnd, List<Body> ignoredBodies = null)
|
||||
{
|
||||
float closestFraction = 1.0f;
|
||||
@@ -220,8 +314,7 @@ namespace Subsurface
|
||||
lastPickedFraction = closestFraction;
|
||||
return closestBody;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Body CheckVisibility(Vector2 rayStart, Vector2 rayEnd)
|
||||
{
|
||||
Body closestBody = null;
|
||||
@@ -286,7 +379,134 @@ namespace Subsurface
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//movement ----------------------------------------------------
|
||||
|
||||
float collisionRigidness = 1.0f;
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
Translate(ConvertUnits.ToDisplayUnits(hullBody.Position) * collisionRigidness + speed * deltaTime);
|
||||
|
||||
|
||||
CalculateBuoyancy();
|
||||
|
||||
float dragCoefficient = 0.00001f;
|
||||
|
||||
float speedLength = speed.Length();
|
||||
float drag = speedLength * speedLength * dragCoefficient * mass;
|
||||
System.Diagnostics.Debug.WriteLine("speed: "+speed);
|
||||
if (speed!=Vector2.Zero)
|
||||
{
|
||||
ApplyForce(-Vector2.Normalize(speed)*drag);
|
||||
}
|
||||
//hullBodies[0].body.LinearVelocity = -hullBodies[0].body.Position;
|
||||
|
||||
|
||||
|
||||
hullBody.SetTransform(Vector2.Zero , 0.0f);
|
||||
|
||||
if (collidingCell == null)
|
||||
{
|
||||
collisionRigidness = MathHelper.Lerp(collisionRigidness, 1.0f, 0.1f);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (GraphEdge ge in collidingCell.edges)
|
||||
{
|
||||
Body body = PickBody(
|
||||
ConvertUnits.ToSimUnits(ge.point1+ Game1.GameSession.Level.position),
|
||||
ConvertUnits.ToSimUnits(ge.point2 + Game1.GameSession.Level.position), new List<Body>(){collidingCell.body});
|
||||
if (body == null || body.UserData == null) continue;
|
||||
|
||||
Structure structure = body.UserData as Structure;
|
||||
if (structure == null) continue;
|
||||
structure.AddDamage(lastPickedPosition, DamageType.Blunt, 50.0f, 0.0f, 0.0f, true);
|
||||
}
|
||||
|
||||
//hullBodies[0].body.SetTransform(Vector2.Zero, 0.0f);
|
||||
|
||||
//position = hullBodies[0].body.Position;
|
||||
|
||||
//Level.Loaded.Move(-ConvertUnits.ToDisplayUnits(position - prevPosition));
|
||||
|
||||
//prevPosition = hullBodies[0].body.Position;
|
||||
|
||||
}
|
||||
|
||||
private void CalculateBuoyancy()
|
||||
{
|
||||
float waterVolume = 0.0f;
|
||||
float volume = 0.0f;
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
waterVolume += hull.Volume;
|
||||
volume += hull.FullVolume;
|
||||
}
|
||||
|
||||
float waterPercentage = waterVolume / volume;
|
||||
|
||||
float neutralPercentage = 0.1f;
|
||||
|
||||
float buoyancy = neutralPercentage-waterPercentage;
|
||||
buoyancy *= mass * 10.0f;
|
||||
|
||||
ApplyForce(new Vector2(0.0f, buoyancy));
|
||||
}
|
||||
|
||||
public void SetPosition(Vector2 position)
|
||||
{
|
||||
//hullBodies[0].body.SetTransform(position, 0.0f);
|
||||
Translate(position);
|
||||
//prevPosition = position;
|
||||
}
|
||||
|
||||
private void Translate(Vector2 amount)
|
||||
{
|
||||
if (amount == Vector2.Zero) return;
|
||||
|
||||
Level.Loaded.Move(-amount);
|
||||
}
|
||||
|
||||
float mass = 10000.0f;
|
||||
public void ApplyForce(Vector2 force)
|
||||
{
|
||||
speed += force/mass;
|
||||
}
|
||||
|
||||
//public void Move(Vector2 amount)
|
||||
//{
|
||||
// speed = Vector2.Lerp(speed, amount, 0.05f);
|
||||
//}
|
||||
|
||||
VoronoiCell collidingCell;
|
||||
public bool OnCollision(Fixture f1, Fixture f2, Contact contact)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("colliding");
|
||||
VoronoiCell cell = f2.Body.UserData as VoronoiCell;
|
||||
if (cell==null) return true;
|
||||
|
||||
Vector2 normal = contact.Manifold.LocalNormal;
|
||||
float impact = Vector2.Dot(ConvertUnits.ToSimUnits(speed), normal);
|
||||
|
||||
System.Diagnostics.Debug.WriteLine("IMPACT:"+impact);
|
||||
if (impact < 5.0f) return true;
|
||||
|
||||
|
||||
collisionRigidness = 0.8f;
|
||||
|
||||
collidingCell = cell;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnSeparation(Fixture f1, Fixture f2)
|
||||
{
|
||||
collidingCell = null;
|
||||
}
|
||||
|
||||
|
||||
//saving/loading ----------------------------------------------------
|
||||
|
||||
public void Save()
|
||||
{
|
||||
@@ -375,38 +595,6 @@ namespace Subsurface
|
||||
}
|
||||
}
|
||||
|
||||
public Submarine(string filePath, string hash="")
|
||||
{
|
||||
this.filePath = filePath;
|
||||
try
|
||||
{
|
||||
name = Path.GetFileNameWithoutExtension(filePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error loading map " + filePath + "!", e);
|
||||
}
|
||||
|
||||
|
||||
if (hash != "")
|
||||
{
|
||||
this.hash = new Md5Hash(hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
//XDocument doc = OpenDoc(filePath);
|
||||
|
||||
//string md5Hash = ToolBox.GetAttributeString(doc.Root, "md5hash", "");
|
||||
//if (md5Hash == "" || md5Hash.Length < 16)
|
||||
//{
|
||||
// DebugConsole.ThrowError("Couldn't find a valid MD5 hash in the map file");
|
||||
//}
|
||||
|
||||
//this.mapHash = new MapHash(md5Hash);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private XDocument OpenDoc(string file)
|
||||
{
|
||||
XDocument doc = null;
|
||||
@@ -414,7 +602,7 @@ namespace Subsurface
|
||||
|
||||
try
|
||||
{
|
||||
extension = Path.GetExtension(file);
|
||||
extension = System.IO.Path.GetExtension(file);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -469,6 +657,7 @@ namespace Subsurface
|
||||
|
||||
public void Load()
|
||||
{
|
||||
Unload();
|
||||
//string file = filePath;
|
||||
|
||||
XDocument doc = OpenDoc(filePath);
|
||||
@@ -507,16 +696,50 @@ namespace Subsurface
|
||||
|
||||
}
|
||||
|
||||
borders = new Rectangle(0, 0, 1, 1);
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
List<Vector2> convexHull = GenerateConvexHull();
|
||||
for (int i = 0; i < convexHull.Count; i++)
|
||||
{
|
||||
if (hull.Rect.X < borders.X || borders.X == 0) borders.X = hull.Rect.X;
|
||||
if (hull.Rect.Y > borders.Y || borders.Y == 0) borders.Y = hull.Rect.Y;
|
||||
|
||||
if (hull.Rect.X + hull.Rect.Width > borders.X + borders.Width) borders.Width = hull.Rect.X + hull.Rect.Width - borders.X;
|
||||
if (hull.Rect.Y - hull.Rect.Height < borders.Y - borders.Height) borders.Height = borders.Y - (hull.Rect.Y - hull.Rect.Height);
|
||||
convexHull[i] = ConvertUnits.ToSimUnits(convexHull[i]);
|
||||
}
|
||||
|
||||
convexHull.Reverse();
|
||||
|
||||
//get farseer 'vertices' from vectors
|
||||
Vertices _shapevertices = new Vertices(convexHull);
|
||||
|
||||
AABB hullAABB = _shapevertices.GetAABB();
|
||||
|
||||
borders = new Rectangle(
|
||||
(int)ConvertUnits.ToDisplayUnits(hullAABB.LowerBound.X),
|
||||
(int)ConvertUnits.ToDisplayUnits(hullAABB.UpperBound.Y),
|
||||
(int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.X * 2.0f),
|
||||
(int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.Y * 2.0f));
|
||||
|
||||
|
||||
var triangulatedVertices = Triangulate.ConvexPartition(_shapevertices, TriangulationAlgorithm.Bayazit);
|
||||
|
||||
Body hullBody = BodyFactory.CreateCompoundPolygon(Game1.world, triangulatedVertices, 5.0f);
|
||||
hullBody.BodyType = BodyType.Dynamic;
|
||||
|
||||
hullBody.CollisionCategories = Physics.CollisionMisc;
|
||||
hullBody.CollidesWith = Physics.CollisionLevel;
|
||||
hullBody.FixedRotation = true;
|
||||
hullBody.Awake = true;
|
||||
hullBody.SleepingAllowed = false;
|
||||
hullBody.GravityScale = 0.0f;
|
||||
hullBody.OnCollision += OnCollision;
|
||||
hullBody.OnSeparation += OnSeparation;
|
||||
//body.IsSensor = true;
|
||||
|
||||
//body.SetTransform();
|
||||
|
||||
//HullBody hullBody = new HullBody();
|
||||
//hullBody.body = body;
|
||||
////hullBody.shapeTexture = GUI.CreateRectangle(borders.Width, borders.Height);
|
||||
|
||||
//hullBodies = new List<HullBody>();
|
||||
//hullBodies.Add(hullBody);
|
||||
|
||||
MapEntity.LinkAll();
|
||||
foreach (Item item in Item.itemList)
|
||||
{
|
||||
@@ -554,11 +777,17 @@ namespace Subsurface
|
||||
Entity.RemoveAll();
|
||||
|
||||
PhysicsBody.list.Clear();
|
||||
|
||||
|
||||
Ragdoll.list.Clear();
|
||||
|
||||
Game1.world.Clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//class HullBody
|
||||
//{
|
||||
// public Body body;
|
||||
// //public Texture2D shapeTexture;
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace Voronoi2
|
||||
public List<GraphEdge> edges;
|
||||
public Site site;
|
||||
|
||||
public List<Body> bodies;
|
||||
public Body body;
|
||||
|
||||
public Vector2 Center
|
||||
{
|
||||
@@ -132,7 +132,7 @@ namespace Voronoi2
|
||||
{
|
||||
edges = new List<GraphEdge>();
|
||||
|
||||
bodies = new List<Body>();
|
||||
//bodies = new List<Body>();
|
||||
this.site = site;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user