diff --git a/Flocking/Boid.cs b/Flocking/Boid.cs index f8af296..f85cf47 100644 --- a/Flocking/Boid.cs +++ b/Flocking/Boid.cs @@ -42,7 +42,7 @@ namespace Flocking private Random m_rndnums = new Random (Environment.TickCount); private FlockingModel m_model; - private FlowMap m_flowMap; + private FlowField m_flowField; /// @@ -57,13 +57,13 @@ namespace Flocking /// /// Mf. max force / acceleration this boid can extert /// - public Boid (string id, FlockingModel model, FlowMap flowMap) + public Boid (string id, FlockingModel model, FlowField flowField) { m_id = id; m_acc = Vector3.Zero; m_vel = new Vector3 (m_rndnums.Next (-1, 1), m_rndnums.Next (-1, 1), m_rndnums.Next (-1, 1)); m_model = model; - m_flowMap = flowMap; + m_flowField = flowField; } public Vector3 Location { @@ -91,6 +91,7 @@ namespace Flocking Flock (boids); // our first priority is to not hurt ourselves + // so adjust where we would like to go to avoid hitting things AvoidObstacles (); // then we want to avoid any threats @@ -211,51 +212,14 @@ namespace Flocking /// - /// Borders this instance. - /// if we get too close wrap us around - /// CHANGE THIS to navigate away from whatever it is we are too close to + /// navigate away from whatever it is we are too close to /// void AvoidObstacles () { //look tolerance metres ahead - Vector3 normVel = Vector3.Normalize(m_vel); - Vector3 inFront = m_loc + Vector3.Multiply(normVel, m_model.Tolerance); - if( m_flowMap.WouldHitObstacle( m_loc, inFront ) ) { - AdjustVelocityToAvoidObstacles (); - - } + m_acc += m_flowField.AdjustVelocity( m_loc, m_vel, m_model.Tolerance ); } - void AdjustVelocityToAvoidObstacles () - { - for( int i = 1; i < 5; i++ ) { - Vector3 normVel = Vector3.Normalize(m_vel); - int xDelta = m_rndnums.Next (-i, i); - int yDelta = m_rndnums.Next (-i, i); - int zDelta = m_rndnums.Next (-i, i); - normVel.X += xDelta; - normVel.Y += yDelta; - normVel.Z += zDelta; - Vector3 inFront = m_loc + Vector3.Multiply(normVel, m_model.Tolerance); - if( !m_flowMap.WouldHitObstacle( m_loc, inFront ) ) { - m_vel.X += xDelta; - m_vel.Y += yDelta; - m_vel.Z += zDelta; - //m_log.Info("avoided"); - return; - } - } - //m_log.Info("didn't avoid"); - // try increaing our acceleration - // or try decreasing our acceleration - // or turn around - coz where we came from was OK - if (m_loc.X < 5 || m_loc.X > 250) - m_vel.X = -m_vel.X; - if (m_loc.Y < 5 || m_loc.Y > 250) - m_vel.Y = -m_vel.Y; - if (m_loc.Z < 21 || m_loc.Z > 271 ) - m_vel.Z = -m_vel.Z; - } /// /// Separate ourselves from the specified boids. diff --git a/Flocking/Flocking.dll.build b/Flocking/Flocking.dll.build index 8a170df..1705ee0 100644 --- a/Flocking/Flocking.dll.build +++ b/Flocking/Flocking.dll.build @@ -20,6 +20,8 @@ + + @@ -30,12 +32,14 @@ + + diff --git a/Flocking/FlockingModel.cs b/Flocking/FlockingModel.cs index beb0bb0..d14f8dc 100644 --- a/Flocking/FlockingModel.cs +++ b/Flocking/FlockingModel.cs @@ -33,7 +33,7 @@ namespace Flocking public class FlockingModel { private List m_flock = new List(); - private FlowMap m_flowMap; + private FlowField m_flowField; private float m_maxSpeed; private float m_maxForce; private float m_neighbourDistance; @@ -63,21 +63,15 @@ namespace Flocking void AddBoid (string name) { - Boid boid = new Boid (name, this, m_flowMap); + Boid boid = new Boid (name, this, m_flowField); // find an initial random location for this Boid // somewhere not within an obstacle - int xInit = m_rnd.Next(m_flowMap.LengthX); - int yInit = m_rnd.Next(m_flowMap.LengthY); - int zInit = m_rnd.Next(m_flowMap.LengthZ); - - while( m_flowMap.IsWithinObstacle( xInit, yInit, zInit ) ){ - xInit = m_rnd.Next(m_flowMap.LengthX); - yInit = m_rnd.Next(m_flowMap.LengthY); - zInit = m_rnd.Next(m_flowMap.LengthZ); - } - - boid.Location = new Vector3 (Convert.ToSingle(xInit), Convert.ToSingle(yInit), Convert.ToSingle(zInit)); + int xInit = m_rnd.Next(Util.SCENE_SIZE); + int yInit = m_rnd.Next(Util.SCENE_SIZE); + int zInit = m_rnd.Next(Util.SCENE_SIZE); + Vector3 location = new Vector3 (Convert.ToSingle(xInit), Convert.ToSingle(yInit), Convert.ToSingle(zInit)); + boid.Location = location + m_flowField.AdjustVelocity(location, Vector3.UnitZ, 5f); m_flock.Add (boid); } @@ -102,9 +96,9 @@ namespace Flocking } - public void Initialise (int num, FlowMap flowMap) + public void Initialise (int num, FlowField flowField) { - m_flowMap = flowMap; + m_flowField = flowField; for (int i = 0; i < num; i++) { AddBoid ("boid"+i ); } diff --git a/Flocking/FlockingModule.cs b/Flocking/FlockingModule.cs index 92c4de2..f14637d 100644 --- a/Flocking/FlockingModule.cs +++ b/Flocking/FlockingModule.cs @@ -90,7 +90,7 @@ namespace Flocking public void AddRegion (Scene scene) { - m_log.Info ("ADDING FLOCKING"); + //m_log.Info ("ADDING FLOCKING"); m_scene = scene; if (m_enabled) { //register commands @@ -112,11 +112,14 @@ namespace Flocking if (m_enabled) { //make a flow map for this scene - FlowMap flowMap = new FlowMap(scene ); - flowMap.Initialise(); + //FlowMap flowMap = new FlowMap(scene ); + //flowMap.Initialise(); + + //build a proper flow field based on the scene + FlowField field = new FlowField(scene, new Vector3(128f, 128f, 128f), 200, 200, 200); // Generate initial flock values - m_model.Initialise (m_flockSize, flowMap); + m_model.Initialise (m_flockSize, field); // who is the owner for the flock in this region m_owner = m_scene.RegionInfo.EstateSettings.EstateOwner; @@ -282,7 +285,8 @@ namespace Flocking { if (ShouldHandleCmd ()) { bool inWorld = IsInWorldCmd (ref args); - ShowResponse ("Num Boids = " + m_model.Size, inWorld); + string str = "Num Boids = " + m_model.Size; + ShowResponse (str, inWorld); } } diff --git a/Flocking/FlowField.cs b/Flocking/FlowField.cs new file mode 100644 index 0000000..be2a774 --- /dev/null +++ b/Flocking/FlowField.cs @@ -0,0 +1,108 @@ +using System; +using OpenMetaverse; +using OpenSim.Region.Framework.Scenes; + +namespace Flocking +{ + public class FlowField + { + private const int BUFFER = 5; + private Scene m_scene; + private float m_startX; + private float m_startY; + private float m_startZ; + private float m_endX; + private float m_endY; + private float m_endZ; + + /// + /// Initializes a new instance of the class. + /// + /// + /// Scene. + /// + /// + /// Centre. + /// + /// + /// Width. + /// + /// + /// Depth. + /// + /// + /// Height. + /// + /// + public FlowField (Scene scene, Vector3 centre, int width, int depth, int height) + { + m_scene = scene; + + m_startX = Math.Max( BUFFER, centre.X - width/2f); + m_startY = Math.Max( BUFFER, centre.Y - depth/2f); + m_startZ = Math.Max( BUFFER, centre.Z - height/2f); + m_endX = Math.Min( Util.SCENE_SIZE - BUFFER, centre.X + width/2f); + m_endY = Math.Min( Util.SCENE_SIZE - BUFFER, centre.Y + depth/2f); + m_endZ = Math.Min( Util.SCENE_SIZE - BUFFER, centre.Z + height/2f); + + // build the flow field over the given bounds + Initialize(); + } + + /// + /// build a flow field on the scene at the specified centre + /// position in the scene and of extent given by width, depth and height. + /// + public void Initialize() { + foreach( SceneObjectGroup sog in m_scene.Entities.GetAllByType() ) { + float offsetHeight; + Vector3 size = sog.GetAxisAlignedBoundingBox( out offsetHeight ); + Vector3 pos = sog.AbsolutePosition; + + // color in the flow field with the strength at this pos due to + // this sog + for( int x = 0; x < size.X; x++ ) { + for( int y = 0; y < size.Y; y++ ) { + for( int z = 0; z < size.Z; z++ ) { + if( IsWithinFlowField( + } + } + } + + } + } + + public Vector3 AdjustVelocity (Vector3 loc, Vector3 vel, float lookAheadDist) + { + Vector3 normVel = Vector3.Normalize(vel); + Vector3 inFront = loc + normVel * lookAheadDist; + Vector3 adjustedDestintation = inFront + FieldStrength(inFront); + Vector3 newVel = Vector3.Normalize(adjustedDestintation - loc) * Vector3.Mag(vel); + return newVel; + } + + public Vector3 FieldStrength (Vector3 inFront) + { + Vector3 retVal = Vector3.Zero; + + //keep us in bounds + if( inFront.X > m_endX ) retVal.X -= inFront.X - m_endX; + if( inFront.Y > m_endY ) retVal.Y -= inFront.Y - m_endY; + if( inFront.Z > m_endZ ) retVal.Z -= inFront.Z - m_endZ; + if( inFront.X < m_startX ) retVal.X += m_startX - inFront.X; + if( inFront.Y < m_startY ) retVal.Y += m_startY - inFront.Y; + if( inFront.Z < m_startZ ) retVal.Z += m_startZ - inFront.Z; + + //now get the field strength at the inbounds position + Vector3 strength = LookUp( inFront + retVal); + + return retVal + strength; + } + + public Vector3 LookUp (Vector3 par1) + { + return Vector3.Zero; + } + } +} + diff --git a/Flocking/FlowFieldTest.cs b/Flocking/FlowFieldTest.cs new file mode 100644 index 0000000..1aad2bf --- /dev/null +++ b/Flocking/FlowFieldTest.cs @@ -0,0 +1,118 @@ +using System; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + + +namespace Flocking +{ + [TestFixture()] + public class FlowFieldTest + { + [Test()] + public void TestEmptyFlowField () + { + Scene scene = SceneSetupHelpers.SetupScene(); + + Vector3 centre = new Vector3 (100f, 100f, 100f); + FlowField field = new FlowField(scene, centre, 50, 50, 50); + Vector3 strength = field.FieldStrength (centre); + Assert.That( strength == Vector3.Zero); + } + + [Test()] + public void TestWeCanMoveFreely () + { + Scene scene = SceneSetupHelpers.SetupScene(); + + Vector3 centre = new Vector3 (100f, 100f, 100f); + FlowField field = new FlowField(scene, centre, 50, 50, 50); + Vector3 pos = new Vector3(100f, 100f,100f); + Vector3 velocity = new Vector3(20f, 0f, 0f); + Vector3 newVel = field.AdjustVelocity (pos, velocity, 10); + Console.WriteLine( newVel ); + Assert.That(newVel == velocity); + Vector3 newPos = pos+newVel; + Assert.That( newPos.X < 150f); + } + + [Test()] + public void TestWeDontFallOfTheEdge () + { + Scene scene = SceneSetupHelpers.SetupScene(); + + Vector3 centre = new Vector3 (100f, 100f, 100f); + FlowField field = new FlowField(scene, centre, 50, 50, 50); + + Vector3 pos = new Vector3(140f, 100f,100f); + Vector3 velocity = new Vector3(20f, 0f, 0f); + Vector3 newVel = field.AdjustVelocity (pos, velocity, 10); + Console.WriteLine( newVel ); + Vector3 newPos = pos+newVel; + Assert.That( newPos.X < 150f); + Assert.That(velocity != newVel); + + pos = new Vector3(60f, 100f, 100f); + velocity = new Vector3(-20f, 0f, 0f); + newVel = field.AdjustVelocity(pos, velocity, 10); + newPos = pos+newVel; + Assert.That( newPos.X > 50f ); + Assert.That(velocity != newVel); + } + + [Test()] + public void TestWeCanCopeWithCorners () + { + Scene scene = SceneSetupHelpers.SetupScene(); + + Vector3 centre = new Vector3 (100f, 100f, 100f); + FlowField field = new FlowField(scene, centre, 50, 50, 50); + Vector3 pos = new Vector3(140f, 140f,140f); + Vector3 velocity = new Vector3(20f, 20f, 20f); // going to hit the corner + Vector3 newVel = field.AdjustVelocity (pos, velocity, 10); + Console.WriteLine( newVel ); + Vector3 newPos = pos+newVel; + Assert.That( newPos.X < 150f); + Assert.That( newPos.Y < 150f); + Assert.That( newPos.Z < 150f); + Assert.That(velocity != newVel); + } + + [Test()] + [Ignore()] + public void TestNonEmptyFlowField () + { + Scene scene = SceneSetupHelpers.SetupScene(); + Vector3 centre = new Vector3 (100f, 100f, 100f); + SceneObjectGroup sceneObjectGroup = AddSog (centre, new Vector3(10f,10f,10f)); + scene.AddNewSceneObject(sceneObjectGroup, false); + + FlowField field = new FlowField(scene, centre, 50, 50, 50); + Vector3 strength = field.FieldStrength (centre); + Assert.That( strength != Vector3.Zero); + + } + + public static SceneObjectGroup AddSog (Vector3 position, Vector3 size) + { + UUID ownerId = new UUID("00000000-0000-0000-0000-000000000010"); + string part1Name = "part1"; + UUID part1Id = new UUID("00000000-0000-0000-0000-000000000001"); + string part2Name = "part2"; + UUID part2Id = new UUID("00000000-0000-0000-0000-000000000002"); + + SceneObjectPart part1 + = new SceneObjectPart(ownerId, PrimitiveBaseShape.Default, position, Quaternion.Identity, Vector3.Zero) + { Name = part1Name, UUID = part1Id }; + part1.Scale =size; + SceneObjectGroup so = new SceneObjectGroup(part1); + + return so; + + } + } +} + diff --git a/Flocking/Util.cs b/Flocking/Util.cs index b988eb6..50d46e4 100644 --- a/Flocking/Util.cs +++ b/Flocking/Util.cs @@ -29,8 +29,11 @@ using OpenMetaverse; namespace Flocking { + public class Util { + public const int SCENE_SIZE = 256; + public static Vector3 Limit (Vector3 initial, float maxLen) { float currLen = initial.Length (); diff --git a/prebuild.xml b/prebuild.xml index 36e4a8e..839b00c 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -19,7 +19,9 @@ + +