Improved submarine movement (buoyancy & drag), engine and "navigation terminal", new map, optimized levels (less vertices and physics bodies)

This commit is contained in:
Regalis
2015-06-29 02:00:27 +03:00
parent 9237a9efe2
commit 004608acd8
43 changed files with 1199 additions and 527 deletions

View File

@@ -32,7 +32,7 @@ namespace Subsurface
{
this.host = host;
wanderAngle = ToolBox.RandomFloatLocal(0.0f, MathHelper.TwoPi);
wanderAngle = MathUtils.RandomFloatLocal(0.0f, MathHelper.TwoPi);
}
public void SteeringSeek(Vector2 target, float speed = 1.0f)
@@ -90,7 +90,7 @@ namespace Subsurface
float angleChange = 1.5f;
wanderAngle += ToolBox.RandomFloatLocal(0.0f, 1.0f) * angleChange - angleChange * 0.5f;
wanderAngle += MathUtils.RandomFloatLocal(0.0f, 1.0f) * angleChange - angleChange * 0.5f;
Vector2 newSteering = circleCenter + displacement;
float steeringSpeed = (newSteering + host.Steering).Length();

View File

@@ -769,13 +769,13 @@ namespace Subsurface
for (int i = 0; i < 10; i++)
{
Particle p = Game1.particleManager.CreateParticle("waterblood",
torso.SimPosition + new Vector2(ToolBox.RandomFloatLocal(-0.5f, 0.5f), ToolBox.RandomFloatLocal(-0.5f, 0.5f)),
torso.SimPosition + new Vector2(MathUtils.RandomFloatLocal(-0.5f, 0.5f), MathUtils.RandomFloatLocal(-0.5f, 0.5f)),
Vector2.Zero);
if (p!=null) p.Size *= 2.0f;
Game1.particleManager.CreateParticle("bubbles",
torso.SimPosition,
new Vector2(ToolBox.RandomFloatLocal(-0.5f, 0.5f), ToolBox.RandomFloatLocal(-1.0f,0.5f)));
new Vector2(MathUtils.RandomFloatLocal(-0.5f, 0.5f), MathUtils.RandomFloatLocal(-1.0f,0.5f)));
}
foreach (var joint in animController.limbJoints)

View File

@@ -72,7 +72,7 @@ namespace Subsurface
else
{
Limb head = GetLimb(LimbType.Head);
float rotation = ToolBox.WrapAngleTwoPi(head.Rotation);
float rotation = MathUtils.WrapAngleTwoPi(head.Rotation);
rotation = MathHelper.ToDegrees(rotation);
if (rotation < 0.0f) rotation += 360;
@@ -98,12 +98,12 @@ namespace Subsurface
void UpdateSineAnim(float deltaTime)
{
movement = ToolBox.SmoothStep(movement, TargetMovement*swimSpeed, 1.0f);
movement = MathUtils.SmoothStep(movement, TargetMovement*swimSpeed, 1.0f);
if (movement == Vector2.Zero) return;
if (!inWater) movement.Y = Math.Min(0.0f, movement.Y);
float movementAngle = ToolBox.VectorToAngle(movement) - MathHelper.PiOver2;
float movementAngle = MathUtils.VectorToAngle(movement) - MathHelper.PiOver2;
Limb tail = GetLimb(LimbType.Tail);
if (tail != null && waveAmplitude>0.0f)
@@ -112,7 +112,7 @@ namespace Subsurface
float waveRotation = (float)Math.Sin(walkPos / waveLength)*waveAmplitude;
float angle = ToolBox.GetShortestAngle(tail.body.Rotation, movementAngle + waveRotation);
float angle = MathUtils.GetShortestAngle(tail.body.Rotation, movementAngle + waveRotation);
//limbs[tailIndex].body.ApplyTorque((Math.Sign(angle) + Math.Max(Math.Min(angle * 10.0f, 10.0f), -10.0f)) * limbs[tailIndex].body.Mass);
//limbs[tailIndex].body.ApplyTorque(-limbs[tailIndex].body.AngularVelocity * 0.5f * limbs[tailIndex].body.Mass);
@@ -123,7 +123,7 @@ namespace Subsurface
Limb head = GetLimb(LimbType.Head);
if (head != null)
{
float angle = ToolBox.GetShortestAngle(head.body.Rotation, movementAngle);
float angle = MathUtils.GetShortestAngle(head.body.Rotation, movementAngle);
head.body.SmoothRotate(head.body.Rotation+angle, 25.0f);
@@ -179,7 +179,7 @@ namespace Subsurface
void UpdateWalkAnim(float deltaTime)
{
movement = ToolBox.SmoothStep(movement, TargetMovement * walkSpeed, 0.2f);
movement = MathUtils.SmoothStep(movement, TargetMovement * walkSpeed, 0.2f);
if (movement == Vector2.Zero) return;
Limb colliderLimb;

View File

@@ -174,7 +174,7 @@ namespace Subsurface
float footMid = (leftFoot.SimPosition.X + rightFoot.SimPosition.X) / 2.0f;
movement = ToolBox.SmoothStep(movement, TargetMovement, 0.5f);
movement = MathUtils.SmoothStep(movement, TargetMovement, 0.5f);
movement.Y = 0.0f;
//place the anchors of the head and the torso to make the ragdoll stand
@@ -201,12 +201,12 @@ namespace Subsurface
{
torso.pullJoint.Enabled = true;
torso.pullJoint.WorldAnchorB =
ToolBox.SmoothStep(torso.SimPosition,
MathUtils.SmoothStep(torso.SimPosition,
new Vector2(footMid + movement.X * 0.35f, colliderPos.Y + TorsoPosition - Math.Abs(walkPosX * 0.05f)), getUpSpeed);
head.pullJoint.Enabled = true;
head.pullJoint.WorldAnchorB =
ToolBox.SmoothStep(head.SimPosition,
MathUtils.SmoothStep(head.SimPosition,
new Vector2(footMid + movement.X * 0.4f, colliderPos.Y + HeadPosition - Math.Abs(walkPosX * 0.05f)), getUpSpeed);
}
@@ -389,7 +389,7 @@ namespace Subsurface
torso.body.ApplyTorque(torque);
}
movement = ToolBox.SmoothStep(movement, TargetMovement, 0.3f);
movement = MathUtils.SmoothStep(movement, TargetMovement, 0.3f);
//dont try to move upwards if head is already out of water
if (surfaceLimiter > 1.0f)
@@ -513,7 +513,7 @@ namespace Subsurface
onGround = false;
IgnorePlatforms = true;
movement = ToolBox.SmoothStep(movement, TargetMovement, 0.3f);
movement = MathUtils.SmoothStep(movement, TargetMovement, 0.3f);
Vector2 footPos, handPos;
@@ -543,12 +543,12 @@ namespace Subsurface
MoveLimb(leftHand,
new Vector2(handPos.X,
ToolBox.Round(handPos.Y - stepHeight, stepHeight * 2.0f) + stepHeight + ladderSimPos.Y),
MathUtils.Round(handPos.Y - stepHeight, stepHeight * 2.0f) + stepHeight + ladderSimPos.Y),
5.2f);
MoveLimb(rightHand,
new Vector2(handPos.X,
ToolBox.Round(handPos.Y, stepHeight * 2.0f) + ladderSimPos.Y),
MathUtils.Round(handPos.Y, stepHeight * 2.0f) + ladderSimPos.Y),
5.2f);
leftHand.body.ApplyTorque(Dir * 2.0f);
@@ -560,12 +560,12 @@ namespace Subsurface
MoveLimb(leftFoot,
new Vector2(footPos.X,
ToolBox.Round(footPos.Y + stepHeight, stepHeight * 2.0f) - stepHeight + ladderSimPos.Y),
MathUtils.Round(footPos.Y + stepHeight, stepHeight * 2.0f) - stepHeight + ladderSimPos.Y),
7.5f, true);
MoveLimb(rightFoot,
new Vector2(footPos.X,
ToolBox.Round(footPos.Y, stepHeight * 2.0f) + ladderSimPos.Y),
MathUtils.Round(footPos.Y, stepHeight * 2.0f) + ladderSimPos.Y),
7.5f, true);
//apply torque to the legs to make the knees bend
@@ -642,8 +642,8 @@ namespace Subsurface
Vector2 diff = (mousePos - torso.SimPosition) * Dir;
holdAngle = ToolBox.VectorToAngle(new Vector2(diff.X, diff.Y * Dir)) - torso.body.Rotation * Dir;
holdAngle = MathHelper.Clamp(ToolBox.WrapAnglePi(holdAngle), -1.3f, 1.0f);
holdAngle = MathUtils.VectorToAngle(new Vector2(diff.X, diff.Y * Dir)) - torso.body.Rotation * Dir;
holdAngle = MathHelper.Clamp(MathUtils.WrapAnglePi(holdAngle), -1.3f, 1.0f);
itemAngle = (torso.body.Rotation + holdAngle * Dir);
@@ -701,7 +701,7 @@ namespace Subsurface
Vector2 bodyVelocity = torso.body.LinearVelocity / 60.0f;
item.body.ResetDynamics();
item.body.SetTransform(ToolBox.SmoothStep(item.body.Position, transformedHoldPos + bodyVelocity, 0.5f), itemAngle);
item.body.SetTransform(MathUtils.SmoothStep(item.body.Position, transformedHoldPos + bodyVelocity, 0.5f), itemAngle);
//item.body.SmoothRotate(itemAngle, 50.0f);
@@ -723,10 +723,10 @@ namespace Subsurface
float c = ConvertUnits.ToDisplayUnits(Vector2.Distance(transformedHoldPos + transformedHandlePos[i], shoulderPos));
c = MathHelper.Clamp(a + b - 1, b-a, c);
float ang2 = ToolBox.VectorToAngle((transformedHoldPos + transformedHandlePos[i]) - shoulderPos)+MathHelper.PiOver2;
float ang2 = MathUtils.VectorToAngle((transformedHoldPos + transformedHandlePos[i]) - shoulderPos)+MathHelper.PiOver2;
float armAngle = ToolBox.SolveTriangleSSS(a, b, c);
float handAngle = ToolBox.SolveTriangleSSS(b, a, c);
float armAngle = MathUtils.SolveTriangleSSS(a, b, c);
float handAngle = MathUtils.SolveTriangleSSS(b, a, c);
arm.body.SmoothRotate((ang2 - armAngle * Dir), 20.0f);
hand.body.SmoothRotate((ang2 + handAngle * Dir), 100.0f);
@@ -755,7 +755,7 @@ namespace Subsurface
character.SelectedItems[i].body.SetTransform(
torso.SimPosition + Vector2.Transform(difference, -torsoTransform),
ToolBox.WrapAngleTwoPi(-character.SelectedItems[i].body.Rotation));
MathUtils.WrapAngleTwoPi(-character.SelectedItems[i].body.Rotation));
}
}
@@ -775,7 +775,7 @@ namespace Subsurface
break;
default:
if (!inWater) l.body.SetTransform(l.body.Position,
ToolBox.WrapAnglePi(l.body.Rotation * (l.DoesFlip ? -1.0f : 1.0f)));
MathUtils.WrapAnglePi(l.body.Rotation * (l.DoesFlip ? -1.0f : 1.0f)));
break;
}
}

View File

@@ -275,7 +275,7 @@ namespace Subsurface
float mid = (armorLimits.X + armorLimits.Y) / 2.0f;
float angleDiff = ToolBox.GetShortestAngle(ToolBox.VectorToAngle(position - SimPosition), mid);
float angleDiff = MathUtils.GetShortestAngle(MathUtils.VectorToAngle(position - SimPosition), mid);
if (Math.Abs(angleDiff) < (armorSector.Y - armorSector.X) / 2.0f)
{
@@ -314,7 +314,7 @@ namespace Subsurface
Game1.particleManager.CreateParticle("blood",
SimPosition,
particleVel * ToolBox.RandomFloatLocal(1.0f, 3.0f));
particleVel * MathUtils.RandomFloatLocal(1.0f, 3.0f));
}
for (int i = 0; i < bloodAmount / 2; i++)
@@ -370,7 +370,7 @@ namespace Subsurface
soundTimer -= deltaTime;
//if (ToolBox.RandomFloat(0.0f, 1000.0f) < Bleeding)
//if (MathUtils.RandomFloat(0.0f, 1000.0f) < Bleeding)
//{
// Game1.particleManager.CreateParticle(
// !inWater ? "blood" : "waterblood",

View File

@@ -290,8 +290,7 @@ namespace Subsurface
{
Vector2 normal = contact.Manifold.LocalNormal;
float impact = Vector2.Dot(f1.Body.LinearVelocity, -normal);
Limb l = (Limb)f1.Body.UserData;
if (impact > 1.0f && l.HitSound != null && l.soundTimer<=0.0f) l.HitSound.Play(Math.Min(impact / 5.0f, 1.0f), impact*100.0f, l.body.FarseerBody);

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8" ?>
<Items>
<Item
name="Engine"
linkable="true"
pickdistance="150">
<Sprite texture ="engine.png" depth="0.8"/>
<Engine minvoltage="0.5" powerperforce="10.0" maxforce="50" canbeselected = "true"/>
<ConnectionPanel canbeselected = "true">
<requireditem name="Screwdriver" type="Equipped"/>
<input name="power_in"/>
<input name="set_force"/>
</ConnectionPanel>
</Item>
<Item
name="Navigation Terminal"
linkable="true"
pickdistance="150">
<Sprite texture ="fabricator.png" depth="0.8"/>
<Steering minvoltage="0.5" canbeselected = "true"/>
<ConnectionPanel canbeselected = "true">
<requireditem name="Screwdriver" type="Equipped"/>
<input name="velocity_in"/>
<output name="velocity_x_out"/>
<output name="velocity_y_out"/>
</ConnectionPanel>
</Item>
</Items>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -11,6 +11,7 @@
<requireditem name="Screwdriver" type="Equipped"/>
<input name="power_in"/>
<input name="toggle"/>
<input name="set_state"/>
<input name="set_active"/>
<input name="set_speed"/>
</ConnectionPanel>
</Item>

View File

@@ -32,8 +32,8 @@ namespace Subsurface
for (int i = 0; i < amount; i++)
{
Vector2 position = (randomWayPoint == null) ? Vector2.Zero : randomWayPoint.SimPosition;
position.X += ToolBox.RandomFloatLocal(-0.5f,0.5f);
position.Y += ToolBox.RandomFloatLocal(-0.5f,0.5f);
position.X += MathUtils.RandomFloatLocal(-0.5f,0.5f);
position.Y += MathUtils.RandomFloatLocal(-0.5f,0.5f);
monsters[i] = new Character(characterFile, position);
}
}

View File

@@ -328,7 +328,7 @@ namespace Subsurface
alpha -= 1.0f - msg.LifeTime;
}
msg.Pos = ToolBox.SmoothStep(msg.Pos, currPos, deltaTime*20.0f);
msg.Pos = MathUtils.SmoothStep(msg.Pos, currPos, deltaTime*20.0f);
spriteBatch.DrawString(font, msg.Text,
new Vector2((int)msg.Pos.X, (int)msg.Pos.Y),

View File

@@ -107,14 +107,17 @@ namespace Subsurface
GUIComponent characterBlock = listBox.GetChild(killedCharacter) as GUIComponent;
if (characterBlock != null) characterBlock.Color = Color.DarkRed * 0.5f;
if (characters.Find(c => !c.IsDead)==null)
{
Game1.GameSession.EndShift(null, null);
}
//if (characters.Find(c => !c.IsDead)==null)
//{
// Game1.GameSession.EndShift(null, null);
//}
}
public void StartShift()
{
listBox.ClearChildren();
characters.Clear();
foreach (CharacterInfo ci in characterInfos)
{
WayPoint randomWayPoint = WayPoint.GetRandom(WayPoint.SpawnType.Human);

View File

@@ -137,7 +137,7 @@ namespace Subsurface
if (endMessage != "" || this.endMessage == null) this.endMessage = endMessage;
Game1.GameSession.EndShift(null, null);
Game1.GameSession.EndShift(endMessage);
}
public static void Init()

View File

@@ -113,8 +113,7 @@ namespace Subsurface
public void StartShift(TimeSpan duration, Level level)
{
if (Submarine.Loaded != submarine) submarine.Load();
submarine.Load();
level.Generate(submarine==null ? 100.0f : Math.Max(Submarine.Borders.Width, Submarine.Borders.Height));
@@ -133,19 +132,17 @@ namespace Subsurface
if (level!=null)
{
submarine.Move(level.StartPosition - submarine.Center, 1.0f);
submarine.SetPosition(level.StartPosition);
}
//crewManager.StartShift();
taskManager.StartShift(scriptedEventCount);
}
public bool EndShift(GUIButton button, object obj)
public void EndShift(string endMessage)
{
if (Game1.Server!=null)
{
string endMessage = gameMode.EndMessage;
{
Game1.Server.EndGame(endMessage);
}
@@ -159,7 +156,7 @@ namespace Subsurface
taskManager.EndShift();
//gameMode.End();
return true;
//return true;
}

View File

@@ -156,7 +156,7 @@ namespace Subsurface
Character.characterList.RemoveAt(i);
}
Game1.GameSession.EndShift(null, null);
Game1.GameSession.EndShift("");
return true;
}

View File

@@ -231,6 +231,7 @@ namespace Subsurface
}
else
{
draggingItem.body.SetTransform(character.SimPosition, 0.0f);
draggingItem.Drop(character);
//draggingItem = null;
}

View File

@@ -0,0 +1,108 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace Subsurface.Items.Components
{
class Engine : Powered
{
float force;
float targetForce;
float maxForce;
float powerPerForce;
[Editable, HasDefaultValue(1.0f, true)]
public float PowerPerForce
{
get { return powerPerForce; }
set
{
powerPerForce = Math.Max(0.0f, value);
}
}
[Editable, HasDefaultValue(50000.0f, true)]
public float MaxForce
{
get { return maxForce; }
set
{
maxForce = Math.Max(0.0f, value);
}
}
public float Force
{
get { return force;}
set { force = MathHelper.Clamp(value, -100.0f, 100.0f); }
}
public Engine(Item item, XElement element)
: base(item, element)
{
isActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
base.Update(deltaTime, cam);
currPowerConsumption = Math.Abs(targetForce) * powerPerForce;
Force = MathHelper.Lerp(force, (voltage < minVoltage) ? 0.0f : targetForce, 0.1f);
if (Force != 0.0f)
{
Submarine.Loaded.ApplyForce(new Vector2((force / 100.0f) * maxForce * (voltage / minVoltage), 0.0f));
}
voltage = 0.0f;
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
//isActive = true;
int width = 300, height = 300;
int x = Game1.GraphicsWidth / 2 - width / 2;
int y = Game1.GraphicsHeight / 2 - height / 2 - 50;
GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true);
spriteBatch.DrawString(GUI.font, "Force: " + (int)targetForce+" %", new Vector2(x + 30, y + 30), Color.White);
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 280, y + 30, 40, 40), "+", true)) targetForce += 1.0f;
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 280, y + 80, 40, 40), "-", true)) targetForce -= 1.0f;
item.NewComponentEvent(this, true);
}
public override void UpdateBroken(float deltaTime, Camera cam)
{
force = MathHelper.Lerp(force, 0.0f, 0.1f);
}
public override void ReceiveSignal(string signal, Connection connection, Item sender)
{
base.ReceiveSignal(signal, connection, sender);
if (connection.name == "set_force")
{
float tempForce;
if (float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out tempForce))
{
Force = tempForce;
}
}
}
}
}

View File

@@ -1,14 +1,16 @@
using System.Collections.Specialized;
using Microsoft.Xna.Framework;
using System.Collections.Specialized;
using System.Globalization;
using System.Xml.Linq;
namespace Subsurface.Items.Components
{
class Pump : Powered
{
float flow;
float flowPercentage;
float maxFlow;
bool flowIn;
//bool flowIn;
Hull hull1, hull2;
@@ -37,9 +39,9 @@ namespace Subsurface.Items.Components
if (hull2 == null && hull1 == null) return;
float powerFactor = (currPowerConsumption==0.0f) ? 1.0f : voltage;
flow = maxFlow * powerFactor;
//flowPercentage = maxFlow * powerFactor;
float deltaVolume = flow * ((flowIn) ? 1.0f : -1.0f);
float deltaVolume = (flowPercentage/100.0f) * maxFlow * powerFactor;
hull1.Volume += deltaVolume;
if (hull2 != null) hull2.Volume -= deltaVolume;
@@ -139,21 +141,31 @@ namespace Subsurface.Items.Components
{
isActive = !isActive;
}
else if (connection.name == "set_state")
else if (connection.name == "set_active")
{
isActive = (signal != "0");
}
else if (connection.name == "set_speed")
{
float tempSpeed;
if (float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out tempSpeed))
{
flowPercentage = MathHelper.Clamp(flowPercentage, -100.0f, 100.0f);
}
}
}
public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message)
{
message.Write(flowIn);
message.Write(flowPercentage);
message.Write(isActive);
}
public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetIncomingMessage message)
{
flowIn = message.ReadBoolean();
flowPercentage = message.ReadFloat();
isActive = message.ReadBoolean();
}
}

View File

@@ -141,16 +141,34 @@ namespace Subsurface.Items.Components
}
else if (autoTemp)
{
float load = 0.0f;
foreach (MapEntity e in item.linkedTo)
{
Item it = e as Item;
if (it == null) continue;
PowerTransfer pt = it.GetComponent<PowerTransfer>();
if (pt != null) load += pt.PowerLoad;
float load = 0.0f;
List<Connection> connections = item.Connections;
if (connections!=null && connections.Count>0)
{
foreach (Connection connection in connections)
{
foreach (Connection recipient in connection.Recipients)
{
Item it = recipient.Item as Item;
if (it == null) continue;
PowerTransfer pt = it.GetComponent<PowerTransfer>();
if (pt != null) load += pt.PowerLoad;
}
}
}
//foreach (MapEntity e in item.linkedTo)
//{
// Item it = e as Item;
// if (it == null) continue;
// PowerTransfer pt = it.GetComponent<PowerTransfer>();
// if (pt != null) load += pt.PowerLoad;
//}
fissionRate = Math.Min(load / 200.0f, shutDownTemp);
//float target = Math.Min(targetTemp, load);
CoolingRate = coolingRate + (temperature - Math.Min(load, shutDownTemp) + deltaTemp)*0.1f;
@@ -319,8 +337,6 @@ namespace Subsurface.Items.Components
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 450, y + 180, 40, 40), "-", true)) shutDownTemp -= 100.0f;
item.NewComponentEvent(this, true);
}
static void UpdateGraph<T>(IList<T> graph, T newValue)

View File

@@ -269,7 +269,7 @@ namespace Subsurface.Items.Components
spriteBatch.Draw(sprite.Texture,
ConvertUnits.ToDisplayUnits(start), null, Color.White,
ToolBox.VectorToAngle(end - start),
MathUtils.VectorToAngle(end - start),
new Vector2(0.0f, sprite.size.Y / 2.0f),
new Vector2((ConvertUnits.ToDisplayUnits(Vector2.Distance(start, end))) / sprite.Texture.Width, 1.0f),
SpriteEffects.None,

View File

@@ -175,9 +175,22 @@ namespace Subsurface.Items.Components
bool mouseInRect = panelRect.Contains(PlayerInput.MousePosition);
Wire equippedWire = null;
//if the character using the panel has a wire item equipped
//and the wire hasn't been connected yet, draw it on the panel
for (int i = 0; i < character.SelectedItems.Length; i++)
{
Item selectedItem = character.SelectedItems[i];
if (selectedItem == null) continue;
Wire wireComponent = selectedItem.GetComponent<Wire>();
if (wireComponent != null) equippedWire = wireComponent;
}
Vector2 rightPos = new Vector2(x + width - 110, y + 20);
Vector2 leftPos = new Vector2(x + 110, y + 20);
float wireInterval = 10.0f;
float rightWireX = x+width / 2 + wireInterval;
@@ -199,8 +212,9 @@ namespace Subsurface.Items.Components
if (c.isOutput)
{
c.Draw(spriteBatch, panel.Item, rightPos,
new Vector2(rightPos.X + 20, rightPos.Y),
new Vector2(rightWireX, y + height), mouseInRect);
new Vector2(rightPos.X + 20, rightPos.Y),
new Vector2(rightWireX, y + height),
mouseInRect, equippedWire != null);
rightPos.Y += 30;
rightWireX += wireInterval;
@@ -209,59 +223,41 @@ namespace Subsurface.Items.Components
{
c.Draw(spriteBatch, panel.Item, leftPos,
new Vector2(leftPos.X - 100, leftPos.Y),
new Vector2(leftWireX, y + height), mouseInRect);
new Vector2(leftWireX, y + height),
mouseInRect, equippedWire != null);
leftPos.Y += 30;
leftWireX -= wireInterval;
}
}
//draw a wire for all the items that are linked to this item, but not to any of the signal connections
//foreach (MapEntity entity in panel.Item.linkedTo)
//{
// Item linked = entity as Item;
// if (linked == null) continue;
// //if the item is already connected, don't draw it again
// if (panel.connections.Find(c => c.linked.Contains()) != null) continue;
// DrawWire(spriteBatch, false, linked,
// new Vector2(leftPos.X + (leftPos.Y - y), y + height- 50),
// new Vector2(leftPos.X + (leftPos.Y - y), y + height), mouseInRect);
// leftPos.Y += 30.0f;
//}
//if the character using the panel has a wire item equipped
//and the wire hasn't been connected yet, draw it on the panel
for (int i = 0; i < character.SelectedItems.Length; i++ )
if (equippedWire!=null)
{
Item selectedItem = character.SelectedItems[i];
if (selectedItem == null) continue;
Wire wireComponent = selectedItem.GetComponent<Wire>();
if (wireComponent != null &&
panel.connections.Find(c => c.wires.Contains(wireComponent)) == null)
if (panel.connections.Find(c => c.wires.Contains(equippedWire)) == null)
{
DrawWire(spriteBatch, selectedItem, selectedItem,
DrawWire(spriteBatch, equippedWire.Item, equippedWire.Item,
new Vector2(x + width / 2, y + height - 100),
new Vector2(x + width / 2, y + height), mouseInRect);
new Vector2(x + width / 2, y + height), mouseInRect, false);
if (draggingConnected == selectedItem) Inventory.draggingItem = selectedItem;
if (draggingConnected == equippedWire.Item) Inventory.draggingItem = equippedWire.Item;
break;
//break;
}
}
//for (int i = 0; i < character.SelectedItems.Length; i++ )
//{
// Item selectedItem = character.SelectedItems[i];
// if (selectedItem == null) continue;
// Wire wireComponent = selectedItem.GetComponent<Wire>();
//}
//stop dragging a wire item if cursor is outside the panel
if (mouseInRect) Inventory.draggingItem = null;
@@ -275,7 +271,7 @@ namespace Subsurface.Items.Components
}
}
private void Draw(SpriteBatch spriteBatch, Item item, Vector2 position, Vector2 labelPos, Vector2 wirePosition, bool mouseIn)
private void Draw(SpriteBatch spriteBatch, Item item, Vector2 position, Vector2 labelPos, Vector2 wirePosition, bool mouseIn, bool wireEquipped)
{
spriteBatch.DrawString(GUI.font, name, new Vector2(labelPos.X, labelPos.Y-10), Color.White);
@@ -289,7 +285,7 @@ namespace Subsurface.Items.Components
Connection recipient = wires[i].OtherConnection(this);
DrawWire(spriteBatch, wires[i].Item, (recipient == null) ? wires[i].Item : recipient.item, position, wirePosition, mouseIn);
DrawWire(spriteBatch, wires[i].Item, (recipient == null) ? wires[i].Item : recipient.item, position, wirePosition, mouseIn, wireEquipped);
wirePosition.X += (isOutput) ? -20 : 20;
}
@@ -318,6 +314,9 @@ namespace Subsurface.Items.Components
if (index>-1)
{
wires[index].RemoveConnection(this);
wires[index].Item.SetTransform(item.SimPosition, 0.0f);
wires[index].Item.Drop();
wires[index].Item.body.Enabled = true;
wires[index] = null;
}
}
@@ -326,7 +325,7 @@ namespace Subsurface.Items.Components
}
private static void DrawWire(SpriteBatch spriteBatch, Item wireItem, Item item, Vector2 end, Vector2 start, bool mouseIn)
private static void DrawWire(SpriteBatch spriteBatch, Item wireItem, Item item, Vector2 end, Vector2 start, bool mouseIn, bool wireEquipped)
{
if (draggingConnected == wireItem)
{
@@ -339,27 +338,29 @@ namespace Subsurface.Items.Components
int textX = (int)start.X;
float connLength = 10.0f;
Color color = (wireEquipped) ? Color.Gray : Color.White;
if (Math.Abs(end.X-start.X)<connLength*6.0f)
{
wireVertical.DrawTiled(spriteBatch,
new Vector2(end.X - wireVertical.size.X / 2, end.Y + connLength),
new Vector2(wireVertical.size.X, (float)Math.Abs(end.Y - start.Y)), Color.White);
new Vector2(wireVertical.size.X, (float)Math.Abs(end.Y - start.Y)), color);
textX = (int)end.X;
connector.Draw(spriteBatch, end);
connector.Draw(spriteBatch, end, color);
}
else
{
Vector2 pos = new Vector2(start.X, end.Y + wireCorner.size.Y) - wireVertical.size / 2;
Vector2 size = new Vector2(wireVertical.size.X, (float)Math.Abs((end.Y + wireCorner.size.Y) - start.Y));
wireVertical.DrawTiled(spriteBatch, pos, size, Color.White);
wireVertical.DrawTiled(spriteBatch, pos, size, color);
Rectangle rect = new Rectangle((int)pos.X, (int)pos.Y, (int)size.X, (int)size.Y);
if (rect.Contains(PlayerInput.MousePosition)) mouseOn = true;
if (!wireEquipped && rect.Contains(PlayerInput.MousePosition)) mouseOn = true;
float dir = (end.X > start.X) ? -1.0f : 1.0f;
wireCorner.Draw(spriteBatch,
new Vector2(start.X, end.Y), 0.0f, 1.0f,
new Vector2(start.X, end.Y), color, 0.0f, 1.0f,
(end.X > start.X) ? SpriteEffects.None : SpriteEffects.FlipHorizontally);
float wireStartX = start.X - wireCorner.size.X / 2 * dir;
@@ -368,14 +369,14 @@ namespace Subsurface.Items.Components
pos = new Vector2(Math.Min(wireStartX,wireEndX), end.Y - wireVertical.size.Y / 2);
size = new Vector2(Math.Abs(wireStartX - wireEndX), wireHorizontal.size.Y);
wireHorizontal.DrawTiled(spriteBatch, pos, size, Color.White);
wireHorizontal.DrawTiled(spriteBatch, pos, size, color);
rect = new Rectangle((int)pos.X, (int)pos.Y, (int)size.X, (int)size.Y);
if (rect.Contains(PlayerInput.MousePosition)) mouseOn = true;
if (!wireEquipped && rect.Contains(PlayerInput.MousePosition)) mouseOn = true;
connector.Draw(spriteBatch, end, -MathHelper.PiOver2*dir);
connector.Draw(spriteBatch, end, color, -MathHelper.PiOver2*dir);
}
if (draggingConnected == null)
if (draggingConnected == null && !wireEquipped)
{
if (mouseOn || Vector2.Distance(end, PlayerInput.MousePosition)<20.0f)
{
@@ -387,7 +388,7 @@ namespace Subsurface.Items.Components
spriteBatch.DrawString(GUI.font, item.Name,
new Vector2(textX, start.Y-30),
mouseOn ? Color.Gold : Color.White,
(mouseOn && !wireEquipped) ? Color.Gold : Color.White,
MathHelper.PiOver2,
GUI.font.MeasureString(item.Name)*0.5f,
1.0f, SpriteEffects.None, 0.0f);
@@ -431,7 +432,6 @@ namespace Subsurface.Items.Components
Item wireItem = MapEntity.FindEntityByID(wireId[i]) as Item;
if (wireItem == null) continue;
wires[i] = wireItem.GetComponent<Wire>();
if (wires[i]!=null)

View File

@@ -122,15 +122,15 @@ namespace Subsurface.Items.Components
item.FindHull();
Vector2 position = item.Position;
position.X = ToolBox.Round(item.Position.X, nodeDistance);
position.X = MathUtils.Round(item.Position.X, nodeDistance);
if (item.currentHull == null)
{
position.Y = ToolBox.Round(item.Position.Y, nodeDistance);
position.Y = MathUtils.Round(item.Position.Y, nodeDistance);
}
else
{
position.Y -= item.currentHull.Rect.Y - item.currentHull.Rect.Height;
position.Y = Math.Max(ToolBox.Round(position.Y, nodeDistance), heightFromFloor);
position.Y = Math.Max(MathUtils.Round(position.Y, nodeDistance), heightFromFloor);
position.Y += item.currentHull.Rect.Y - item.currentHull.Rect.Height;
}
@@ -258,7 +258,7 @@ namespace Subsurface.Items.Components
spriteBatch.Draw(wireSprite.Texture,
start, null, color,
ToolBox.VectorToAngle(end - start),
MathUtils.VectorToAngle(end - start),
new Vector2(0.0f, wireSprite.size.Y / 2.0f),
new Vector2((Vector2.Distance(start, end)) / wireSprite.Texture.Width, 0.3f),
SpriteEffects.None,

View File

@@ -0,0 +1,84 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace Subsurface.Items.Components
{
class Steering : ItemComponent
{
Vector2 currVelocity;
Vector2 targetVelocity;
public Steering(Item item, XElement element)
: base(item, element)
{
isActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
base.Update(deltaTime, cam);
item.SendSignal(targetVelocity.X.ToString(), "velocity_x_out", item);
item.SendSignal(targetVelocity.Y.ToString(), "velocity_y_out", item);
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
//isActive = true;
int width = 300, height = 300;
int x = Game1.GraphicsWidth / 2 - width / 2;
int y = Game1.GraphicsHeight / 2 - height / 2 - 50;
GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true);
Rectangle velRect = new Rectangle(x+20, y+20, 100, 100);
GUI.DrawRectangle(spriteBatch, velRect, Color.White, false);
GUI.DrawLine(spriteBatch,
new Vector2(velRect.Center.X,velRect.Center.Y),
new Vector2(velRect.Center.X + currVelocity.X, velRect.Center.Y - currVelocity.Y),
Color.Gray);
Vector2 targetVelPos = new Vector2(velRect.Center.X + targetVelocity.X, velRect.Center.Y - targetVelocity.Y);
GUI.DrawLine(spriteBatch,
new Vector2(velRect.Center.X, velRect.Center.Y),
targetVelPos,
Color.LightGray);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)targetVelPos.X - 5, (int)targetVelPos.Y - 5, 10, 10), Color.White);
if (Vector2.Distance(PlayerInput.MousePosition, targetVelPos)<10.0f)
{
GUI.DrawRectangle(spriteBatch, new Rectangle((int)targetVelPos.X -10, (int)targetVelPos.Y - 10, 20, 20), Color.Red);
if (PlayerInput.LeftButtonDown())
{
targetVelocity = PlayerInput.MousePosition - new Vector2(velRect.Center.X, velRect.Center.Y);
targetVelocity.Y = -targetVelocity.Y;
}
}
//spriteBatch.DrawString(GUI.font, "Force: " + (int)force + " %", new Vector2(x + 30, y + 30), Color.White);
//if (GUI.DrawButton(spriteBatch, new Rectangle(x + 280, y + 30, 40, 40), "+", true)) targetForce += 1.0f;
//if (GUI.DrawButton(spriteBatch, new Rectangle(x + 280, y + 80, 40, 40), "-", true)) targetForce -= 1.0f;
item.NewComponentEvent(this, true);
}
public override void ReceiveSignal(string signal, Connection connection, Item sender)
{
if (connection.name == "velocity_in")
{
currVelocity = ToolBox.ParseToVector2(signal, false);
}
}
}
}

View File

@@ -112,11 +112,11 @@ namespace Subsurface.Items.Components
if (targetRotation < minRotation || targetRotation > maxRotation)
{
float diff = ToolBox.WrapAngleTwoPi(targetRotation - (minRotation + maxRotation) / 2.0f);
float diff = MathUtils.WrapAngleTwoPi(targetRotation - (minRotation + maxRotation) / 2.0f);
targetRotation = (diff > Math.PI) ? minRotation : maxRotation;
}
rotation = ToolBox.CurveAngle(rotation, targetRotation, 0.05f);
rotation = MathUtils.CurveAngle(rotation, targetRotation, 0.05f);
//if (!prefab.FocusOnSelected) return;
@@ -131,7 +131,7 @@ namespace Subsurface.Items.Components
Vector2 offset = character.CursorPosition - centerPos;
offset.Y = -offset.Y;
targetRotation = ToolBox.WrapAngleTwoPi(ToolBox.VectorToAngle(offset));
targetRotation = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(offset));
isActive = true;

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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])),

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
//}
}

View File

@@ -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;
}
}

187
Subsurface/MathUtils.cs Normal file
View File

@@ -0,0 +1,187 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Subsurface
{
static class MathUtils
{
public static Vector2 SmoothStep(Vector2 v1, Vector2 v2, float amount)
{
return new Vector2(
MathHelper.SmoothStep(v1.X, v2.X, amount),
MathHelper.SmoothStep(v1.Y, v2.Y, amount));
}
public static float Round(float value, float div)
{
return (float)Math.Floor(value / div) * div;
}
public static float RandomFloat(int minimum, int maximum)
{
return RandomFloat((float)minimum, (float)maximum);
}
public static float RandomFloat(float minimum, float maximum)
{
return (float)Game1.random.NextDouble() * (maximum - minimum) + minimum;
}
public static int RandomInt(int minimum, int maximum)
{
return Game1.random.Next(maximum - minimum) + minimum;
}
public static float RandomFloatLocal(float minimum, float maximum)
{
return (float)Game1.localRandom.NextDouble() * (maximum - minimum) + minimum;
}
public static int RandomIntLocal(int minimum, int maximum)
{
return Game1.localRandom.Next(maximum - minimum) + minimum;
}
public static float VectorToAngle(Vector2 vector)
{
return (float)Math.Atan2(vector.Y, vector.X);
}
public static float CurveAngle(float from, float to, float step)
{
// Ensure that 0 <= angle < 2pi for both "from" and "to"
while (from < 0)
from += MathHelper.TwoPi;
while (from >= MathHelper.TwoPi)
from -= MathHelper.TwoPi;
while (to < 0)
to += MathHelper.TwoPi;
while (to >= MathHelper.TwoPi)
to -= MathHelper.TwoPi;
if (Math.Abs(from - to) < MathHelper.Pi)
{
// The simple case - a straight lerp will do.
return MathHelper.Lerp(from, to, step);
}
// If we get here we have the more complex case.
// First, increment the lesser value to be greater.
if (from < to)
from += MathHelper.TwoPi;
else
to += MathHelper.TwoPi;
float retVal = MathHelper.Lerp(from, to, step);
// Now ensure the return value is between 0 and 2pi
if (retVal >= MathHelper.TwoPi)
retVal -= MathHelper.TwoPi;
return retVal;
}
public static float WrapAngleTwoPi(float angle)
{
// Ensure that 0 <= angle < 2pi for both "from" and "to"
while (angle < 0)
angle += MathHelper.TwoPi;
while (angle >= MathHelper.TwoPi)
angle -= MathHelper.TwoPi;
return angle;
}
public static float WrapAnglePi(float angle)
{
// Ensure that -pi <= angle < pi for both "from" and "to"
while (angle < -MathHelper.Pi)
angle += MathHelper.TwoPi;
while (angle >= MathHelper.Pi)
angle -= MathHelper.TwoPi;
return angle;
}
public static float GetShortestAngle(float from, float to)
{
// Ensure that 0 <= angle < 2pi for both "from" and "to"
from = WrapAngleTwoPi(from);
to = WrapAngleTwoPi(to);
if (Math.Abs(from - to) < MathHelper.Pi)
{
return to - from;
}
// If we get here we have the more complex case.
// First, increment the lesser value to be greater.
if (from < to)
from += MathHelper.TwoPi;
else
to += MathHelper.TwoPi;
return to - from;
}
/// <summary>
/// solves the angle opposite to side a (parameters: lengths of each side)
/// </summary>
public static float SolveTriangleSSS(float a, float b, float c)
{
float A = (float)Math.Acos((b * b + c * c - a * a) / (2 * b * c));
if (float.IsNaN(A)) A = 1.0f;
return A;
}
public static byte AngleToByte(float angle)
{
angle = WrapAngleTwoPi(angle);
angle = angle * (255.0f / MathHelper.TwoPi);
return Convert.ToByte(angle);
}
public static float ByteToAngle(byte b)
{
float angle = (float)b;
angle = angle * (MathHelper.TwoPi / 255.0f);
return angle;
}
}
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);
}
}
}

View File

@@ -327,7 +327,7 @@ namespace Subsurface.Networking
Game1.NetLobbyScreen.Select();
if (Game1.GameSession!=null) Game1.GameSession.EndShift(null, null);
if (Game1.GameSession!=null) Game1.GameSession.EndShift("");
DebugConsole.ThrowError(endMessage);

View File

@@ -66,7 +66,7 @@ namespace Subsurface.Particles
velocity = speed;
this.rotation = rotation + ToolBox.RandomFloatLocal(prefab.startRotationMin, prefab.startRotationMax);
this.rotation = rotation + MathUtils.RandomFloatLocal(prefab.startRotationMin, prefab.startRotationMax);
prevRotation = rotation;
float rand = (float)Game1.localRandom.NextDouble();
@@ -96,7 +96,7 @@ namespace Subsurface.Particles
if (prefab.rotateToDirection)
{
rotation = ToolBox.VectorToAngle(velocity);
rotation = MathUtils.VectorToAngle(velocity);
}
else
{

View File

@@ -8,21 +8,19 @@ namespace Subsurface
{
private static double alpha;
public const Category CollisionNone = Category.None;
public const Category CollisionAll = Category.All;
public const Category CollisionWall = Category.Cat1;
public const Category CollisionCharacter = Category.Cat2;
public const Category CollisionPlatform = Category.Cat3;
public const Category CollisionStairs = Category.Cat4;
public const Category CollisionMisc = Category.Cat5;
public const Category CollisionProjectile = Category.Cat6;
public const Category CollisionNone = Category.None;
public const Category CollisionAll = Category.All;
public const Category CollisionWall = Category.Cat1;
public const Category CollisionCharacter = Category.Cat2;
public const Category CollisionPlatform = Category.Cat3;
public const Category CollisionStairs = Category.Cat4;
public const Category CollisionMisc = Category.Cat5;
public const Category CollisionProjectile = Category.Cat6;
public const Category CollisionLevel = Category.Cat7;
public static double accumulator;
public static double step = 1.0f/60.0f;
public static bool updated;
public const float DisplayToSimRation = 100.0f;
public static double Alpha

View File

@@ -297,7 +297,7 @@ namespace Subsurface
{
float nextAngle = body.Rotation + body.AngularVelocity * (float)Physics.step;
float angle = ToolBox.GetShortestAngle(nextAngle, targetRotation);
float angle = MathUtils.GetShortestAngle(nextAngle, targetRotation);
float torque = body.Mass * angle * 60.0f * (force/100.0f);

View File

@@ -57,7 +57,7 @@ namespace Subsurface
AmbientSoundManager.Update();
if (Game1.GameSession.Level!=null)
if (Game1.GameSession!=null && Game1.GameSession.Level != null)
{
Vector2 targetMovement = Vector2.Zero;
if (PlayerInput.KeyDown(Keys.I)) targetMovement.Y += 1.0f;
@@ -65,7 +65,7 @@ namespace Subsurface
if (PlayerInput.KeyDown(Keys.J)) targetMovement.X -= 1.0f;
if (PlayerInput.KeyDown(Keys.L)) targetMovement.X += 1.0f;
Game1.GameSession.Submarine.Move(targetMovement*1000.0f, (float)deltaTime);
Game1.GameSession.Submarine.ApplyForce(targetMovement*100000.0f);
}
if (Game1.GameSession!=null) Game1.GameSession.Update((float)deltaTime);
@@ -94,6 +94,8 @@ namespace Subsurface
Ragdoll.UpdateAll((float)Physics.step);
if (Game1.GameSession != null && Game1.GameSession.Level != null) Game1.GameSession.Submarine.Update((float)Physics.step);
Game1.world.Step((float)Physics.step);
Physics.accumulator -= Physics.step;
@@ -256,6 +258,12 @@ namespace Subsurface
cam.Transform);
Submarine.DrawFront(spriteBatch);
if (Game1.GameSession != null && Game1.GameSession.Level != null)
{
Game1.GameSession.Level.RenderLines(spriteBatch);
//Game1.GameSession.Level.SetObserverPosition(cam.WorldViewCenter);
}
spriteBatch.End();

View File

@@ -80,6 +80,7 @@
<Compile Include="Items\CharacterInventory.cs" />
<Compile Include="Items\Components\Fabricator.cs" />
<Compile Include="Items\Components\MiniMap.cs" />
<Compile Include="Items\Components\Engine.cs" />
<Compile Include="Items\Components\Pump.cs" />
<Compile Include="Items\Components\Signal\OxygenDetector.cs" />
<Compile Include="Items\Components\Signal\LightComponent.cs" />
@@ -88,6 +89,7 @@
<Compile Include="Items\Components\Signal\AndComponent.cs" />
<Compile Include="Items\Components\Signal\ConnectionPanel.cs" />
<Compile Include="Items\Components\Signal\RegExFindComponent.cs" />
<Compile Include="Items\Components\Steering.cs" />
<Compile Include="Items\Components\Throwable.cs" />
<Compile Include="Items\Components\Turret.cs" />
<Compile Include="Items\Components\Signal\Wire.cs" />
@@ -132,6 +134,7 @@
<Compile Include="Map\Md5Hash.cs" />
<Compile Include="Map\Voronoi.cs" />
<Compile Include="Map\VoronoiElements.cs" />
<Compile Include="MathUtils.cs" />
<Compile Include="Physics\PhysicsBody.cs" />
<Compile Include="Networking\NetworkEvent.cs" />
<Compile Include="Networking\NetworkMember.cs" />
@@ -191,10 +194,6 @@
<Compile Include="Map\Hull.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="FarseerPhysics MonoGame, Version=3.5.0.30657, Culture=neutral, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
<HintPath>.\FarseerPhysics MonoGame.dll</HintPath>
</Reference>
<Reference Include="Lidgren.Network, Version=3.3.0.2069, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>.\Lidgren.Network.dll</HintPath>
@@ -309,6 +308,15 @@
<Content Include="Content\Items\Door\windowedDoor.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\Items\Engine\engine.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\Items\Engine\engine.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\Items\Engine\fabricator.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\Items\Fabricators\fabricator.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -701,6 +709,10 @@
<Folder Include="Data\Saves\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Lataukset\Selain-lataukset\Farseer Physics Engine 3.5\Farseer Physics Engine 3.5\Farseer Physics MonoGame.csproj">
<Project>{0aad36e3-51a5-4a07-ab60-5c8a66bd38b7}</Project>
<Name>Farseer Physics MonoGame</Name>
</ProjectReference>
<ProjectReference Include="..\Subsurface_content\Subsurface_content\Subsurface_content.csproj">
<Project>{1e6bf44d-6e31-40cc-8321-3d5958c983e7}</Project>
<Name>Subsurface_content</Name>

View File

@@ -11,178 +11,6 @@ namespace Subsurface
{
static class ToolBox
{
public static Vector2 SmoothStep(Vector2 v1, Vector2 v2, float amount)
{
return new Vector2(
MathHelper.SmoothStep(v1.X, v2.X, amount),
MathHelper.SmoothStep(v1.Y, v2.Y, amount));
}
public static float Round(float value, float div)
{
return (float)Math.Floor(value / div) * div;
}
public static float RandomFloat(float minimum, float maximum)
{
return (float)Game1.random.NextDouble() * (maximum - minimum) + minimum;
}
public static int RandomInt(int minimum, int maximum)
{
return Game1.random.Next(maximum - minimum) + minimum;
}
public static float RandomFloatLocal(float minimum, float maximum)
{
return (float)Game1.localRandom.NextDouble() * (maximum - minimum) + minimum;
}
public static int RandomIntLocal(int minimum, int maximum)
{
return Game1.localRandom.Next(maximum - minimum) + minimum;
}
public static float VectorToAngle(Vector2 vector)
{
return (float)Math.Atan2(vector.Y, vector.X);
}
public static float CurveAngle(float from, float to, float step)
{
// Ensure that 0 <= angle < 2pi for both "from" and "to"
while (from < 0)
from += MathHelper.TwoPi;
while (from >= MathHelper.TwoPi)
from -= MathHelper.TwoPi;
while (to < 0)
to += MathHelper.TwoPi;
while (to >= MathHelper.TwoPi)
to -= MathHelper.TwoPi;
if (Math.Abs(from - to) < MathHelper.Pi)
{
// The simple case - a straight lerp will do.
return MathHelper.Lerp(from, to, step);
}
// If we get here we have the more complex case.
// First, increment the lesser value to be greater.
if (from < to)
from += MathHelper.TwoPi;
else
to += MathHelper.TwoPi;
float retVal = MathHelper.Lerp(from, to, step);
// Now ensure the return value is between 0 and 2pi
if (retVal >= MathHelper.TwoPi)
retVal -= MathHelper.TwoPi;
return retVal;
}
public static float WrapAngleTwoPi(float angle)
{
// Ensure that 0 <= angle < 2pi for both "from" and "to"
while (angle < 0)
angle += MathHelper.TwoPi;
while (angle >= MathHelper.TwoPi)
angle -= MathHelper.TwoPi;
return angle;
}
public static float WrapAnglePi(float angle)
{
// Ensure that -pi <= angle < pi for both "from" and "to"
while (angle < -MathHelper.Pi)
angle += MathHelper.TwoPi;
while (angle >= MathHelper.Pi)
angle -= MathHelper.TwoPi;
return angle;
}
public static float GetShortestAngle(float from, float to)
{
// Ensure that 0 <= angle < 2pi for both "from" and "to"
from = WrapAngleTwoPi(from);
to = WrapAngleTwoPi(to);
if (Math.Abs(from - to) < MathHelper.Pi)
{
return to - from;
}
// If we get here we have the more complex case.
// First, increment the lesser value to be greater.
if (from < to)
from += MathHelper.TwoPi;
else
to += MathHelper.TwoPi;
return to - from;
}
/// <summary>
/// solves the angle opposite to side a (parameters: lengths of each side)
/// </summary>
public static float SolveTriangleSSS(float a, float b, float c)
{
float A = (float)Math.Acos((b*b + c*c - a*a) / (2*b*c));
if (float.IsNaN(A)) A = 1.0f;
return A;
}
//public static void CompressStringToFile(string fileName, string value)
//{
// // A.
// // Write string to temporary file.
// string temp = Path.GetTempFileName();
// File.WriteAllText(temp, value);
// // B.
// // Read file into byte array buffer.
// byte[] b;
// using (FileStream f = new FileStream(temp, FileMode.Open))
// {
// b = new byte[f.Length];
// f.Read(b, 0, (int)f.Length);
// }
// // C.
// // Use GZipStream to write compressed bytes to target file.
// using (FileStream f2 = new FileStream(fileName, FileMode.Create))
// using (GZipStream gz = new GZipStream(f2, CompressionMode.Compress, false))
// {
// gz.Write(b, 0, b.Length);
// }
//}
//public static Stream DecompressFiletoStream(string fileName)
//{
// if (!File.Exists(fileName))
// {
// DebugConsole.ThrowError("File ''"+fileName+" doesn't exist!");
// return null;
// }
// using (FileStream originalFileStream = new FileStream(fileName, FileMode.Open))
// {
// MemoryStream decompressedFileStream = new MemoryStream();
// using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
// {
// decompressionStream.CopyTo(decompressedFileStream);
// return decompressedFileStream;
// }
// }
//}
public static XDocument TryLoadXml(string filePath)
{
XDocument doc;
@@ -352,7 +180,7 @@ namespace Subsurface
return ParseToVector4(val);
}
public static Vector2 ParseToVector2(string stringVector2)
public static Vector2 ParseToVector2(string stringVector2, bool errorMessages = true)
{
string[] components = stringVector2.Split(',');
@@ -360,6 +188,7 @@ namespace Subsurface
if (components.Length!=2)
{
if (!errorMessages) return vector;
DebugConsole.ThrowError("Failed to parse the string "+stringVector2+" to Vector2");
return vector;
}
@@ -375,8 +204,6 @@ namespace Subsurface
return vector.X.ToString("G", CultureInfo.InvariantCulture) + "," + vector.Y.ToString("G", CultureInfo.InvariantCulture);
}
public static Vector4 ParseToVector4(string stringVector4)
{
string[] components = stringVector4.Split(',');
@@ -489,22 +316,5 @@ namespace Subsurface
return "";
}
}
public static byte AngleToByte(float angle)
{
angle = WrapAngleTwoPi(angle);
angle = angle * (255.0f / MathHelper.TwoPi);
return Convert.ToByte(angle);
}
public static float ByteToAngle(byte b)
{
float angle = (float)b;
angle = angle * (MathHelper.TwoPi / 255.0f);
return angle;
}
}
}

View File

@@ -14,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Performance1.psess = Performance1.psess
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Farseer Physics MonoGame", "..\Lataukset\Selain-lataukset\Farseer Physics Engine 3.5\Farseer Physics Engine 3.5\Farseer Physics MonoGame.csproj", "{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Android|Any CPU = Android|Any CPU
@@ -162,6 +164,51 @@ Global
{1E6BF44D-6E31-40CC-8321-3D5958C983E7}.Windows8|Mixed Platforms.ActiveCfg = Windows8|Any CPU
{1E6BF44D-6E31-40CC-8321-3D5958C983E7}.Windows8|Mixed Platforms.Build.0 = Windows8|Any CPU
{1E6BF44D-6E31-40CC-8321-3D5958C983E7}.Windows8|x86.ActiveCfg = Windows8|Any CPU
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Android|Any CPU.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Android|Mixed Platforms.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Android|Mixed Platforms.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Android|x86.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Android|x86.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Debug|Any CPU.ActiveCfg = Debug|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Debug|Mixed Platforms.Build.0 = Debug|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Debug|x86.ActiveCfg = Debug|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Debug|x86.Build.0 = Debug|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.iOS|Any CPU.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.iOS|Mixed Platforms.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.iOS|Mixed Platforms.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.iOS|x86.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.iOS|x86.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Linux|Any CPU.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Linux|Mixed Platforms.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Linux|Mixed Platforms.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Linux|x86.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Linux|x86.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.OSX|Any CPU.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.OSX|Mixed Platforms.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.OSX|Mixed Platforms.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.OSX|x86.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.OSX|x86.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.PSM|Any CPU.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.PSM|Mixed Platforms.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.PSM|Mixed Platforms.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.PSM|x86.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.PSM|x86.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Release|Any CPU.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Release|Mixed Platforms.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Release|Mixed Platforms.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Release|x86.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Release|x86.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Windows|Any CPU.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Windows|Mixed Platforms.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Windows|Mixed Platforms.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Windows|x86.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Windows|x86.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Windows8|Any CPU.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Windows8|Mixed Platforms.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Windows8|Mixed Platforms.Build.0 = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Windows8|x86.ActiveCfg = Release|x86
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Windows8|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

Binary file not shown.