├── .gitignore ├── Demo.ContentShim ├── Demo.ContentShim.csproj ├── Properties │ └── AssemblyInfo.cs ├── bin │ └── x86 │ │ └── Release │ │ ├── Demo.ContentShim.dll │ │ └── Demo.ContentShim.pdb └── obj │ └── x86 │ └── Release │ ├── ContentPipeline-{5057B41F-613F-4C6B-A522-42B15B54F3EF}.xml │ ├── Demo.ContentShim.csproj.FileListAbsolute.txt │ ├── Demo.ContentShim.dll │ ├── Demo.ContentShim.pdb │ ├── Microsoft.Xna.Framework.RuntimeProfile.txt │ └── cachefile-{5057B41F-613F-4C6B-A522-42B15B54F3EF}-targetpath.txt ├── Demo ├── AnnotationService.cs ├── Camera.cs ├── Clock.cs ├── DeferredDraw.cs ├── Demo.cs ├── Demo.csproj ├── Draw.cs ├── Extensions.cs ├── IPlugIn.cs ├── PlugIn.cs ├── PlugIns │ ├── AirCombat │ │ ├── AirCombatPlugin.cs │ │ ├── Fighter.cs │ │ └── Missile.cs │ ├── Arrival │ │ └── ArrivalPlugIn.cs │ ├── Boids │ │ ├── Boid.cs │ │ └── BoidsPlugIn.cs │ ├── Ctf │ │ ├── CtfBase.cs │ │ ├── CtfEnemy.cs │ │ ├── CtfPlugIn.cs │ │ ├── CtfSeeker.cs │ │ └── Globals.cs │ ├── FlowField │ │ ├── FlowFieldFollower.cs │ │ └── FlowFieldPlugIn.cs │ ├── GatewayPathFollowing │ │ └── GatewayPathFollowingPlugin.cs │ ├── LowSpeedTurn │ │ ├── LowSpeedTurn.cs │ │ └── LowSpeedTurnPlugIn.cs │ ├── MapDrive │ │ ├── GCRoute.cs │ │ ├── MapDrivePlugIn.cs │ │ ├── MapDriver.cs │ │ └── TerrainMap.cs │ ├── MeshPathFollowing │ │ ├── MeshPathFollowingPlugin.cs │ │ └── PathWalker.cs │ ├── MultiplePursuit │ │ ├── MpBase.cs │ │ ├── MpPlugIn.cs │ │ ├── MpPursuer.cs │ │ └── MpWanderer.cs │ ├── OneTurning │ │ ├── OneTurning.cs │ │ └── OneTurningPlugIn.cs │ ├── Pedestrian │ │ ├── Globals.cs │ │ ├── Pedestrian.cs │ │ └── PedestrianPlugIn.cs │ └── Soccer │ │ ├── AABBox.cs │ │ ├── Ball.cs │ │ ├── Globals.cs │ │ ├── Player.cs │ │ └── SoccerPlugIn.cs ├── PolylinePathway.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── SimpleFlowField.cs └── Trail.cs ├── License.txt ├── Local.testsettings ├── SharpSteer2.Tests ├── LocalSpaceBasisHelpersTest.cs ├── LocalityQueryProximityDatabaseTest.cs ├── MeshPathTest.cs ├── NullAnnotationTest.cs ├── Properties │ └── AssemblyInfo.cs ├── SharpSteer2.Tests.csproj ├── SimpleVehicleTest.cs ├── SphericalObstacleTests.cs ├── UtilitiesTest.cs └── Vector3HelpersTest.cs ├── SharpSteer2.WinDemoContent ├── Fonts │ └── SegoeUiMono.spritefont └── SharpSteer2.WinDemoContent.contentproj ├── SharpSteer2.ncrunchsolution ├── SharpSteer2.sln ├── SharpSteer2 ├── AssemblyAttributes.cs ├── BaseVehicle.cs ├── Database │ ├── IProximityDatabase.cs │ ├── ITokenForProximityDatabase.cs │ ├── LocalityQueryDatabase.cs │ └── LocalityQueryProximityDatabase.cs ├── Helpers │ ├── Colors.cs │ ├── LocalSpaceBasisHelpers.cs │ ├── MatrixHelpers.cs │ ├── PathwayHelpers.cs │ ├── RandomHelpers.cs │ ├── Utilities.cs │ ├── Vector3Helpers.cs │ └── VehicleHelpers.cs ├── IAnnotationService.cs ├── IFlowField.cs ├── ILocalSpaceBasis.cs ├── IVehicle.cs ├── LocalSpace.cs ├── NullAnnotationService.cs ├── Obstacles │ ├── IObstacle.cs │ └── SphericalObstacle.cs ├── Pathway │ ├── GatewayPathway.cs │ ├── IPathway.cs │ ├── PolylinePathway.cs │ └── TrianglePathway.cs ├── Properties │ └── AssemblyInfo.cs ├── SharpSteer2.csproj ├── SimpleVehicle.cs └── SteerLibrary.cs ├── push-all.ps1 └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.suo 2 | *.user 3 | *.cachefile 4 | *.xnb 5 | *.sln.docstates 6 | *.cache 7 | *.ncrunchproject 8 | *.ncrunchsolution 9 | *.vsmdi 10 | *.testsettings 11 | SharpSteer2/bin 12 | SharpSteer2/obj 13 | Demo/bin 14 | Demo/obj 15 | SharpSteer2.WinDemoContent/bin 16 | SharpSteer2.WinDemoContent/obj 17 | SharpSteer2.Tests/bin 18 | SharpSteer2.Tests/obj 19 | _Resharper.* -------------------------------------------------------------------------------- /Demo.ContentShim/Demo.ContentShim.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | {0001D035-FE3A-4334-9773-56D4D774A4F9} 5 | {6D335F3A-9D43-41b4-9D22-F6F17C4BE596};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 6 | Debug 7 | x86 8 | Library 9 | Properties 10 | Demo.ContentShim 11 | Demo.ContentShim 12 | v4.0 13 | Client 14 | v4.0 15 | Windows 16 | Reach 17 | c619d010-4536-4408-93da-5cb8cb4fa9af 18 | Library 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\x86\Debug 25 | DEBUG;TRACE;WINDOWS 26 | prompt 27 | 4 28 | true 29 | false 30 | x86 31 | false 32 | 33 | 34 | pdbonly 35 | true 36 | bin\x86\Release 37 | TRACE;WINDOWS 38 | prompt 39 | 4 40 | true 41 | false 42 | x86 43 | true 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 4.0 55 | 56 | 57 | 4.0 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | {5057B41F-613F-4C6B-A522-42B15B54F3EF} 67 | SharpSteer2.WinDemoContent 68 | Content 69 | 70 | 71 | 72 | 73 | 81 | -------------------------------------------------------------------------------- /Demo.ContentShim/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Demo.ContentShim")] 9 | [assembly: AssemblyProduct("Demo.ContentShim")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyCopyright("Copyright © 2015")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. Only Windows 19 | // assemblies support COM. 20 | [assembly: ComVisible(false)] 21 | 22 | // On Windows, the following GUID is for the ID of the typelib if this 23 | // project is exposed to COM. On other platforms, it unique identifies the 24 | // title storage container when deploying this assembly to the device. 25 | [assembly: Guid("cf1257ce-22a6-48ce-be33-84f517cd27af")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | [assembly: AssemblyVersion("1.0.0.0")] -------------------------------------------------------------------------------- /Demo.ContentShim/bin/x86/Release/Demo.ContentShim.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindevans/SharpSteer2/d8138fe95e81b38b62b864e457b23b94d9750199/Demo.ContentShim/bin/x86/Release/Demo.ContentShim.dll -------------------------------------------------------------------------------- /Demo.ContentShim/bin/x86/Release/Demo.ContentShim.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindevans/SharpSteer2/d8138fe95e81b38b62b864e457b23b94d9750199/Demo.ContentShim/bin/x86/Release/Demo.ContentShim.pdb -------------------------------------------------------------------------------- /Demo.ContentShim/obj/x86/Release/ContentPipeline-{5057B41F-613F-4C6B-A522-42B15B54F3EF}.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Fonts\SegoeUiMono.spritefont 6 | Fonts\SegoeUiMono 7 | FontDescriptionImporter 8 | FontDescriptionProcessor 9 | None 10 | C:\Users\Martin\Documents\dotnet\SharpSteer2\Demo.ContentShim\bin\x86\Release\Content\Fonts\SegoeUiMono.xnb 11 | 12 | 13 | true 14 | 15 | {5057B41F-613F-4C6B-A522-42B15B54F3EF} 16 | Windows 17 | Reach 18 | Release 19 | true 20 | C:\Users\Martin\Documents\dotnet\SharpSteer2\SharpSteer2.WinDemoContent\ 21 | C:\Users\Martin\Documents\dotnet\SharpSteer2\Demo.ContentShim\ 22 | C:\Users\Martin\Documents\dotnet\SharpSteer2\Demo.ContentShim\obj\x86\Release\ 23 | C:\Users\Martin\Documents\dotnet\SharpSteer2\Demo.ContentShim\bin\x86\Release\Content\ 24 | 25 | 26 | 27 | C:\Program Files (x86)\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86\Microsoft.Xna.Framework.Content.Pipeline.XImporter.dll 28 | 2011-09-01T16:22:30+01:00 29 | 30 | 31 | C:\Program Files (x86)\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86\Microsoft.Xna.Framework.Content.Pipeline.VideoImporters.dll 32 | 2011-09-01T16:22:30+01:00 33 | 34 | 35 | C:\Program Files (x86)\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86\Microsoft.Xna.Framework.Content.Pipeline.TextureImporter.dll 36 | 2011-09-01T16:22:30+01:00 37 | 38 | 39 | C:\Program Files (x86)\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86\Microsoft.Xna.Framework.Content.Pipeline.FBXImporter.dll 40 | 2011-09-01T16:22:30+01:00 41 | 42 | 43 | C:\Program Files (x86)\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86\Microsoft.Xna.Framework.Content.Pipeline.EffectImporter.dll 44 | 2011-09-01T16:22:30+01:00 45 | 46 | 47 | C:\Program Files (x86)\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86\Microsoft.Xna.Framework.Content.Pipeline.AudioImporters.dll 48 | 2011-09-01T16:22:30+01:00 49 | 50 | 51 | C:\WINDOWS\Microsoft.Net\assembly\GAC_32\Microsoft.Xna.Framework.Content.Pipeline\v4.0_4.0.0.0__842cf8be1de50553\Microsoft.Xna.Framework.Content.Pipeline.dll 52 | 2015-08-02T14:16:37.6210915+01:00 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Demo.ContentShim/obj/x86/Release/Demo.ContentShim.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | C:\Users\Martin\Documents\dotnet\SharpSteer2\Demo.ContentShim\bin\x86\Release\Demo.ContentShim.dll 2 | C:\Users\Martin\Documents\dotnet\SharpSteer2\Demo.ContentShim\bin\x86\Release\Demo.ContentShim.pdb 3 | C:\Users\Martin\Documents\dotnet\SharpSteer2\Demo.ContentShim\obj\x86\Release\Demo.ContentShim.csprojResolveAssemblyReference.cache 4 | C:\Users\Martin\Documents\dotnet\SharpSteer2\Demo.ContentShim\obj\x86\Release\Microsoft.Xna.Framework.RuntimeProfile.txt 5 | C:\Users\Martin\Documents\dotnet\SharpSteer2\Demo.ContentShim\obj\x86\Release\Demo.ContentShim.dll 6 | C:\Users\Martin\Documents\dotnet\SharpSteer2\Demo.ContentShim\obj\x86\Release\Demo.ContentShim.pdb 7 | C:\Users\Martin\Documents\dotnet\SharpSteer2\Demo.ContentShim\bin\x86\Release\Content\Fonts\SegoeUiMono.xnb 8 | -------------------------------------------------------------------------------- /Demo.ContentShim/obj/x86/Release/Demo.ContentShim.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindevans/SharpSteer2/d8138fe95e81b38b62b864e457b23b94d9750199/Demo.ContentShim/obj/x86/Release/Demo.ContentShim.dll -------------------------------------------------------------------------------- /Demo.ContentShim/obj/x86/Release/Demo.ContentShim.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindevans/SharpSteer2/d8138fe95e81b38b62b864e457b23b94d9750199/Demo.ContentShim/obj/x86/Release/Demo.ContentShim.pdb -------------------------------------------------------------------------------- /Demo.ContentShim/obj/x86/Release/Microsoft.Xna.Framework.RuntimeProfile.txt: -------------------------------------------------------------------------------- 1 | Windows.v4.0.Reach 2 | -------------------------------------------------------------------------------- /Demo.ContentShim/obj/x86/Release/cachefile-{5057B41F-613F-4C6B-A522-42B15B54F3EF}-targetpath.txt: -------------------------------------------------------------------------------- 1 | Content\Fonts\SegoeUiMono.xnb 2 | -------------------------------------------------------------------------------- /Demo/AnnotationService.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using Microsoft.Xna.Framework; 12 | using SharpSteer2; 13 | using Vector3 = System.Numerics.Vector3; 14 | 15 | namespace Demo 16 | { 17 | public sealed class Annotation : IAnnotationService 18 | { 19 | bool _isEnabled; 20 | 21 | //HACK: change the IDraw to a IDrawService 22 | public static Drawing Drawer; 23 | 24 | // constructor 25 | public Annotation() 26 | { 27 | _isEnabled = true; 28 | } 29 | 30 | /// 31 | /// Indicates whether annotation is enabled. 32 | /// 33 | public bool IsEnabled 34 | { 35 | get { return _isEnabled; } 36 | set { _isEnabled = value; } 37 | } 38 | 39 | // ------------------------------------------------------------------------ 40 | // drawing of lines, circles and (filled) disks to annotate steering 41 | // behaviors. When called during OpenSteerDemo's simulation update phase, 42 | // these functions call a "deferred draw" routine which buffer the 43 | // arguments for use during the redraw phase. 44 | // 45 | // note: "circle" means unfilled 46 | // "disk" means filled 47 | // "XZ" means on a plane parallel to the X and Z axes (perp to Y) 48 | // "3d" means the circle is perpendicular to the given "axis" 49 | // "segments" is the number of line segments used to draw the circle 50 | 51 | // draw an opaque colored line segment between two locations in space 52 | public void Line(Vector3 startPoint, Vector3 endPoint, Vector3 color, float opacity = 1) 53 | { 54 | if (_isEnabled && Drawer != null) 55 | { 56 | Drawer.Line(startPoint, endPoint, new Color(new Microsoft.Xna.Framework.Vector3(color.X, color.Y, color.Z)), opacity); 57 | } 58 | } 59 | 60 | // draw a circle on the XZ plane 61 | public void CircleXZ(float radius, Vector3 center, Vector3 color, int segments) 62 | { 63 | CircleOrDiskXZ(radius, center, color, segments, false); 64 | } 65 | 66 | // draw a disk on the XZ plane 67 | public void DiskXZ(float radius, Vector3 center, Vector3 color, int segments) 68 | { 69 | CircleOrDiskXZ(radius, center, color, segments, true); 70 | } 71 | 72 | // draw a circle perpendicular to the given axis 73 | public void Circle3D(float radius, Vector3 center, Vector3 axis, Vector3 color, int segments) 74 | { 75 | CircleOrDisk3D(radius, center, axis, color, segments, false); 76 | } 77 | 78 | // draw a disk perpendicular to the given axis 79 | public void Disk3D(float radius, Vector3 center, Vector3 axis, Vector3 color, int segments) 80 | { 81 | CircleOrDisk3D(radius, center, axis, color, segments, true); 82 | } 83 | 84 | // ------------------------------------------------------------------------ 85 | // support for annotation circles 86 | public void CircleOrDiskXZ(float radius, Vector3 center, Vector3 color, int segments, bool filled) 87 | { 88 | CircleOrDisk(radius, Vector3.Zero, center, color, segments, filled, false); 89 | } 90 | 91 | public void CircleOrDisk3D(float radius, Vector3 center, Vector3 axis, Vector3 color, int segments, bool filled) 92 | { 93 | CircleOrDisk(radius, axis, center, color, segments, filled, true); 94 | } 95 | 96 | public void CircleOrDisk(float radius, Vector3 axis, Vector3 center, Vector3 color, int segments, bool filled, bool in3D) 97 | { 98 | if (_isEnabled && Drawer != null) 99 | { 100 | Drawer.CircleOrDisk(radius, axis, center, new Color(new Microsoft.Xna.Framework.Vector3(color.X, color.Y, color.Z)), segments, filled, in3D); 101 | } 102 | } 103 | 104 | // called when steerToAvoidObstacles decides steering is required 105 | // (default action is to do nothing, layered classes can overload it) 106 | public void AvoidObstacle(float minDistanceToCollision) 107 | { 108 | } 109 | 110 | // called when steerToFollowPath decides steering is required 111 | // (default action is to do nothing, layered classes can overload it) 112 | public void PathFollowing(Vector3 future, Vector3 onPath, Vector3 target, float outside) 113 | { 114 | } 115 | 116 | // called when steerToAvoidCloseNeighbors decides steering is required 117 | // (default action is to do nothing, layered classes can overload it) 118 | public void AvoidCloseNeighbor(IVehicle other, float additionalDistance) 119 | { 120 | } 121 | 122 | // called when steerToAvoidNeighbors decides steering is required 123 | // (default action is to do nothing, layered classes can overload it) 124 | public void AvoidNeighbor(IVehicle threat, float steer, Vector3 ourFuture, Vector3 threatFuture) 125 | { 126 | } 127 | 128 | public void VelocityAcceleration(IVehicle vehicle) 129 | { 130 | VelocityAcceleration(vehicle, 3, 3); 131 | } 132 | 133 | public void VelocityAcceleration(IVehicle vehicle, float maxLength) 134 | { 135 | VelocityAcceleration(vehicle, maxLength, maxLength); 136 | } 137 | 138 | public void VelocityAcceleration(IVehicle vehicle, float maxLengthAcceleration, float maxLengthVelocity) 139 | { 140 | Vector3 vColor = new Vector3(255, 102, 255); // pinkish 141 | Vector3 aColor = new Vector3(102, 102, 255); // bluish 142 | 143 | float aScale = maxLengthAcceleration / vehicle.MaxForce; 144 | float vScale = maxLengthVelocity / vehicle.MaxSpeed; 145 | Vector3 p = vehicle.Position; 146 | 147 | Line(p, p + (vehicle.Velocity * vScale), vColor); 148 | Line(p, p + (vehicle.Acceleration * aScale), aColor); 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /Demo/DeferredDraw.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System.Collections.Generic; 12 | using Microsoft.Xna.Framework; 13 | using Vector3 = System.Numerics.Vector3; 14 | 15 | namespace Demo 16 | { 17 | public class DeferredLine 18 | { 19 | static DeferredLine() 20 | { 21 | _deferredLines = new List(SIZE); 22 | } 23 | 24 | public static void AddToBuffer(Vector3 s, Vector3 e, Color c) 25 | { 26 | if (_index >= _deferredLines.Count) 27 | _deferredLines.Add(new DeferredLine()); 28 | 29 | _deferredLines[_index]._startPoint = s; 30 | _deferredLines[_index]._endPoint = e; 31 | _deferredLines[_index]._color = c; 32 | 33 | _index++; 34 | } 35 | 36 | public static void DrawAll() 37 | { 38 | // draw all lines in the buffer 39 | for (int i = 0; i < _index; i++) 40 | { 41 | DeferredLine dl = _deferredLines[i]; 42 | Drawing.iDrawLine(dl._startPoint, dl._endPoint, dl._color); 43 | } 44 | 45 | // reset buffer index 46 | _index = 0; 47 | } 48 | 49 | Vector3 _startPoint; 50 | Vector3 _endPoint; 51 | Color _color; 52 | 53 | static int _index = 0; 54 | const int SIZE = 1000; 55 | static readonly List _deferredLines; 56 | } 57 | 58 | public class DeferredCircle 59 | { 60 | static DeferredCircle() 61 | { 62 | _deferredCircleArray = new DeferredCircle[SIZE]; 63 | for (int i = 0; i < SIZE; i++) 64 | { 65 | _deferredCircleArray[i] = new DeferredCircle(); 66 | } 67 | } 68 | 69 | public static void AddToBuffer(float radius, Vector3 axis, Vector3 center, Color color, int segments, bool filled, bool in3D) 70 | { 71 | if (_index < SIZE) 72 | { 73 | _deferredCircleArray[_index]._radius = radius; 74 | _deferredCircleArray[_index]._axis = axis; 75 | _deferredCircleArray[_index]._center = center; 76 | _deferredCircleArray[_index]._color = color; 77 | _deferredCircleArray[_index]._segments = segments; 78 | _deferredCircleArray[_index]._filled = filled; 79 | _deferredCircleArray[_index]._in3D = in3D; 80 | _index++; 81 | } 82 | } 83 | 84 | public static void DrawAll() 85 | { 86 | // draw all circles in the buffer 87 | for (int i = 0; i < _index; i++) 88 | { 89 | DeferredCircle dc = _deferredCircleArray[i]; 90 | Drawing.DrawCircleOrDisk(dc._radius, dc._axis, dc._center, dc._color, dc._segments, dc._filled, dc._in3D); 91 | } 92 | 93 | // reset buffer index 94 | _index = 0; 95 | } 96 | 97 | float _radius; 98 | Vector3 _axis; 99 | Vector3 _center; 100 | Color _color; 101 | int _segments; 102 | bool _filled; 103 | bool _in3D; 104 | 105 | static int _index = 0; 106 | const int SIZE = 500; 107 | static readonly DeferredCircle[] _deferredCircleArray; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Demo/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace Demo 5 | { 6 | static class Extensions 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static Vector3 FromXna(this Microsoft.Xna.Framework.Vector3 v) 10 | { 11 | return new Vector3(v.X, v.Y, v.Z); 12 | } 13 | 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static Microsoft.Xna.Framework.Vector3 ToXna(this Vector3 v) 16 | { 17 | return new Microsoft.Xna.Framework.Vector3(v.X, v.Y, v.Z); 18 | } 19 | 20 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 | public static Vector2 FromXna(this Microsoft.Xna.Framework.Vector2 v) 22 | { 23 | return new Vector2(v.X, v.Y); 24 | } 25 | 26 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 27 | public static Microsoft.Xna.Framework.Vector2 ToXna(this Vector2 v) 28 | { 29 | return new Microsoft.Xna.Framework.Vector2(v.X, v.Y); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Demo/IPlugIn.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // All rights reserved. 5 | // 6 | // This software is licensed as described in the file license.txt, which 7 | // you should have received as part of this distribution. The terms 8 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 9 | 10 | using System; 11 | using System.Collections.Generic; 12 | using Microsoft.Xna.Framework.Input; 13 | using SharpSteer2; 14 | 15 | namespace Demo 16 | { 17 | public interface IPlugIn 18 | { 19 | // generic PlugIn actions: open, update, redraw, close and reset 20 | void Open(); 21 | void Update(float currentTime, float elapsedTime); 22 | void Redraw(float currentTime, float elapsedTime); 23 | void Close(); 24 | void Reset(); 25 | 26 | // return a pointer to this instance's character string name 27 | String Name { get; } 28 | 29 | // numeric sort key used to establish user-visible PlugIn ordering 30 | // ("built ins" have keys greater than 0 and less than 1) 31 | float SelectionOrderSortKey { get; } 32 | 33 | // allows a PlugIn to nominate itself as OpenSteerDemo's initially selected 34 | // (default) PlugIn, which is otherwise the first in "selection order" 35 | bool RequestInitialSelection { get; } 36 | 37 | // handle function keys (which are reserved by SterTest for PlugIns) 38 | void HandleFunctionKeys(Keys key); 39 | 40 | // print "mini help" documenting function keys handled by this PlugIn 41 | void PrintMiniHelpForFunctionKeys(); 42 | 43 | // return an AVGroup (an STL vector of AbstractVehicle pointers) of 44 | // all vehicles(/agents/characters) defined by the PlugIn 45 | IEnumerable Vehicles { get; } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Demo/PlugIn.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // All rights reserved. 5 | // 6 | // This software is licensed as described in the file license.txt, which 7 | // you should have received as part of this distribution. The terms 8 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 9 | 10 | using System; 11 | using System.Collections.Generic; 12 | using Microsoft.Xna.Framework.Input; 13 | using SharpSteer2; 14 | 15 | namespace Demo 16 | { 17 | public abstract class PlugIn : IPlugIn 18 | { 19 | public abstract void Open(); 20 | public abstract void Update(float currentTime, float elapsedTime); 21 | public abstract void Redraw(float currentTime, float elapsedTime); 22 | public abstract void Close(); 23 | public abstract String Name { get; } 24 | public abstract IEnumerable Vehicles { get; } 25 | 26 | // prototypes for function pointers used with PlugIns 27 | public delegate void PlugInCallBackFunction(PlugIn clientObject); 28 | public delegate void VoidCallBackFunction(); 29 | public delegate void TimestepCallBackFunction(float currentTime, float elapsedTime); 30 | 31 | protected readonly IAnnotationService Annotations; 32 | 33 | // constructor 34 | protected PlugIn(IAnnotationService annotations) 35 | { 36 | Annotations = annotations; 37 | 38 | // save this new instance in the registry 39 | AddToRegistry(); 40 | } 41 | 42 | // default reset method is to do a close then an open 43 | public virtual void Reset() 44 | { 45 | Close(); 46 | Open(); 47 | } 48 | 49 | // default sort key (after the "built ins") 50 | public virtual float SelectionOrderSortKey { get { return 1.0f; } } 51 | 52 | // default is to NOT request to be initially selected 53 | public virtual bool RequestInitialSelection { get { return false; } } 54 | 55 | // default function key handler: ignore all 56 | public virtual void HandleFunctionKeys(Keys key) { } 57 | 58 | // default "mini help": print nothing 59 | public virtual void PrintMiniHelpForFunctionKeys() { } 60 | 61 | // returns pointer to the next PlugIn in "selection order" 62 | public PlugIn Next() 63 | { 64 | for (int i = 0; i < _itemsInRegistry; i++) 65 | { 66 | if (this == _registry[i]) 67 | { 68 | bool atEnd = (i == (_itemsInRegistry - 1)); 69 | return _registry[atEnd ? 0 : i + 1]; 70 | } 71 | } 72 | return null; 73 | } 74 | 75 | // format instance to characters for printing to stream 76 | public override string ToString() 77 | { 78 | return String.Format("", Name); 79 | } 80 | 81 | // CLASS FUNCTIONS 82 | 83 | // search the class registry for a Plugin with the given name 84 | public static IPlugIn FindByName(String name) 85 | { 86 | if (String.IsNullOrEmpty(name) == false) 87 | { 88 | for (int i = 0; i < _itemsInRegistry; i++) 89 | { 90 | PlugIn pi = _registry[i]; 91 | String s = pi.Name; 92 | if (String.IsNullOrEmpty(s) && name == s) 93 | return pi; 94 | } 95 | } 96 | return null; 97 | } 98 | 99 | // apply a given function to all PlugIns in the class registry 100 | public static void ApplyToAll(PlugInCallBackFunction f) 101 | { 102 | for (int i = 0; i < _itemsInRegistry; i++) 103 | { 104 | f(_registry[i]); 105 | } 106 | } 107 | 108 | // sort PlugIn registry by "selection order" 109 | public static void SortBySelectionOrder() 110 | { 111 | // I know, I know, just what the world needs: 112 | // another inline shell sort implementation... 113 | 114 | // starting at each of the first n-1 elements of the array 115 | for (int i = 0; i < _itemsInRegistry - 1; i++) 116 | { 117 | // scan over subsequent pairs, swapping if larger value is first 118 | for (int j = i + 1; j < _itemsInRegistry; j++) 119 | { 120 | float iKey = _registry[i].SelectionOrderSortKey; 121 | float jKey = _registry[j].SelectionOrderSortKey; 122 | 123 | if (iKey > jKey) 124 | { 125 | PlugIn temporary = _registry[i]; 126 | _registry[i] = _registry[j]; 127 | _registry[j] = temporary; 128 | } 129 | } 130 | } 131 | } 132 | 133 | // returns pointer to default PlugIn (currently, first in registry) 134 | public static PlugIn FindDefault() 135 | { 136 | // return NULL if no PlugIns exist 137 | if (_itemsInRegistry == 0) return null; 138 | 139 | // otherwise, return the first PlugIn that requests initial selection 140 | for (int i = 0; i < _itemsInRegistry; i++) 141 | { 142 | if (_registry[i].RequestInitialSelection) return _registry[i]; 143 | } 144 | 145 | // otherwise, return the "first" PlugIn (in "selection order") 146 | return _registry[0]; 147 | } 148 | 149 | // save this instance in the class's registry of instances 150 | void AddToRegistry() 151 | { 152 | // save this instance in the registry 153 | _registry[_itemsInRegistry++] = this; 154 | } 155 | 156 | // This array stores a list of all PlugIns. It is manipulated by the 157 | // constructor and destructor, and used in findByName and applyToAll. 158 | const int TOTAL_SIZE_OF_REGISTRY = 1000; 159 | static int _itemsInRegistry = 0; 160 | static readonly PlugIn[] _registry = new PlugIn[TOTAL_SIZE_OF_REGISTRY]; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /Demo/PlugIns/AirCombat/AirCombatPlugin.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Microsoft.Xna.Framework; 4 | using SharpSteer2; 5 | using SharpSteer2.Database; 6 | using SharpSteer2.Helpers; 7 | using Vector3 = System.Numerics.Vector3; 8 | 9 | namespace Demo.PlugIns.AirCombat 10 | { 11 | class AirCombatPlugin 12 | :PlugIn 13 | { 14 | private readonly List _team1 = new List(); 15 | private readonly List _team2 = new List(); 16 | 17 | private readonly List _missiles = new List(); 18 | 19 | private IProximityDatabase _pd; 20 | 21 | public AirCombatPlugin(IAnnotationService annotations) 22 | :base(annotations) 23 | { 24 | } 25 | 26 | public override void Open() 27 | { 28 | CreateDatabase(); 29 | _missiles.Clear(); 30 | 31 | _team1.Add(new Fighter(_pd, Annotations, FireMissile) 32 | { 33 | Position = new Vector3(20, 0, 0), 34 | Forward = Vector3Helpers.RandomUnitVector(), 35 | Color = Color.Green, 36 | Enemy = _team2 37 | }); 38 | _team1.Add(new Fighter(_pd, Annotations, FireMissile) 39 | { 40 | Position = new Vector3(15, 0, 5), 41 | Forward = Vector3Helpers.RandomUnitVector(), 42 | Color = Color.Green, 43 | Enemy = _team2 44 | }); 45 | _team1.Add(new Fighter(_pd, Annotations, FireMissile) 46 | { 47 | Position = new Vector3(15, 0, -5), 48 | Forward = Vector3Helpers.RandomUnitVector(), 49 | Color = Color.Green, 50 | Enemy = _team2 51 | }); 52 | 53 | _team2.Add(new Fighter(_pd, Annotations, FireMissile) 54 | { 55 | Position = new Vector3(-20, 0, 0), 56 | Forward = Vector3Helpers.RandomUnitVector(), 57 | Color = Color.Blue, 58 | Enemy = _team1 59 | }); 60 | _team2.Add(new Fighter(_pd, Annotations, FireMissile) 61 | { 62 | Position = new Vector3(-15, 0, 5), 63 | Forward = Vector3Helpers.RandomUnitVector(), 64 | Color = Color.Blue, 65 | Enemy = _team1 66 | }); 67 | _team2.Add(new Fighter(_pd, Annotations, FireMissile) 68 | { 69 | Position = new Vector3(-15, 0, -5), 70 | Forward = Vector3Helpers.RandomUnitVector(), 71 | Color = Color.Blue, 72 | Enemy = _team1 73 | }); 74 | } 75 | 76 | private void CreateDatabase() 77 | { 78 | Vector3 center = Vector3.Zero; 79 | const float DIV = 10.0f; 80 | Vector3 divisions = new Vector3(DIV, DIV, DIV); 81 | const float DIAMETER = Fighter.WORLD_RADIUS * 2; 82 | Vector3 dimensions = new Vector3(DIAMETER, DIAMETER, DIAMETER); 83 | _pd = new LocalityQueryProximityDatabase(center, dimensions, divisions); 84 | } 85 | 86 | private void FireMissile(Fighter launcher, Fighter target) 87 | { 88 | if (_missiles.Count(m => m.Target == target) < 3) 89 | { 90 | _missiles.Add(new Missile(_pd, target, Annotations) 91 | { 92 | Position = launcher.Position, 93 | Forward = Vector3.Normalize(launcher.Forward * 0.9f + Vector3Helpers.RandomUnitVector() * 0.1f), 94 | Speed = launcher.Speed, 95 | Color = _team1.Contains(launcher) ? Color.Black : Color.White 96 | }); 97 | } 98 | } 99 | 100 | public override void Update(float currentTime, float elapsedTime) 101 | { 102 | foreach (var fighter in _team1) 103 | fighter.Update(currentTime, elapsedTime); 104 | foreach (var fighter in _team2) 105 | fighter.Update(currentTime, elapsedTime); 106 | 107 | foreach (var missile in _missiles) 108 | missile.Update(currentTime, elapsedTime); 109 | _missiles.RemoveAll(m => m.IsDead); 110 | } 111 | 112 | public override void Redraw(float currentTime, float elapsedTime) 113 | { 114 | Demo.UpdateCamera(elapsedTime, _team1[0]); 115 | 116 | foreach (var fighter in _team1) 117 | fighter.Draw(); 118 | foreach (var fighter in _team2) 119 | fighter.Draw(); 120 | 121 | foreach (var missile in _missiles) 122 | missile.Draw(); 123 | } 124 | 125 | public override void Close() 126 | { 127 | _team1.Clear(); 128 | _team2.Clear(); 129 | _missiles.Clear(); 130 | _pd = null; 131 | } 132 | 133 | public override string Name 134 | { 135 | get { return "Air Combat"; } 136 | } 137 | 138 | public override IEnumerable Vehicles 139 | { 140 | get 141 | { 142 | foreach (var fighter in _team1) 143 | yield return fighter; 144 | foreach (var fighter in _team2) 145 | yield return fighter; 146 | foreach (var missile in _missiles) 147 | yield return missile; 148 | } 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /Demo/PlugIns/AirCombat/Fighter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.Xna.Framework; 5 | using SharpSteer2; 6 | using SharpSteer2.Database; 7 | using SharpSteer2.Helpers; 8 | using Vector3 = System.Numerics.Vector3; 9 | 10 | namespace Demo.PlugIns.AirCombat 11 | { 12 | class Fighter 13 | :SimpleVehicle 14 | { 15 | private readonly Trail _trail; 16 | private readonly ITokenForProximityDatabase _proximityToken; 17 | 18 | public List Enemy { get; set; } 19 | private readonly List _neighbours = new List(); 20 | 21 | public override float MaxForce 22 | { 23 | get { return 7; } 24 | } 25 | public override float MaxSpeed 26 | { 27 | get { return 15; } 28 | } 29 | 30 | public const float WORLD_RADIUS = 30; 31 | 32 | private float _lastFired = -100; 33 | private const float REFIRE_TIME = 2f; 34 | private readonly Action _fireMissile; 35 | 36 | public Color Color = Color.White; 37 | 38 | public Fighter(IProximityDatabase proximity, IAnnotationService annotation, Action fireMissile) 39 | :base(annotation) 40 | { 41 | _trail = new Trail(5, 50) 42 | { 43 | TrailColor = Color.WhiteSmoke, 44 | TickColor = Color.LightGray 45 | }; 46 | _proximityToken = proximity.AllocateToken(this); 47 | 48 | _fireMissile = fireMissile; 49 | } 50 | 51 | public void Update(float currentTime, float elapsedTime) 52 | { 53 | _trail.Record(currentTime, Position); 54 | 55 | _neighbours.Clear(); 56 | _proximityToken.FindNeighbors(Position, 50, _neighbours); 57 | 58 | var target = ClosestEnemy(_neighbours); 59 | 60 | //if (Vector3.Dot(Vector3.Normalize(Enemy.Position - Position), Forward) > 0.7f) 61 | { 62 | if (currentTime - _lastFired > REFIRE_TIME && target != null) 63 | { 64 | _fireMissile(this, ClosestEnemy(_neighbours)); 65 | _lastFired = currentTime; 66 | } 67 | } 68 | 69 | Vector3 otherPlaneForce = SteerToAvoidCloseNeighbors(3, _neighbours); 70 | if (target != null) 71 | otherPlaneForce += SteerForPursuit(target); 72 | 73 | var boundary = HandleBoundary(); 74 | 75 | var evasion = _neighbours 76 | .Where(v => v is Missile) 77 | .Cast() 78 | .Where(m => m.Target == this) 79 | .Select(m => SteerForEvasion(m, 1)) 80 | .Aggregate(Vector3.Zero, (a, b) => a + b); 81 | 82 | ApplySteeringForce(otherPlaneForce + boundary + evasion * 0.5f + SteerForWander(elapsedTime) * 0.1f, elapsedTime); 83 | 84 | _proximityToken.UpdateForNewPosition(Position); 85 | } 86 | 87 | private Fighter ClosestEnemy(List neighbours) 88 | { 89 | if (_neighbours.Count == 0) 90 | return null; 91 | 92 | var enemyFighterNeighbours = _neighbours 93 | .Where(v => v is Fighter) 94 | .Cast() 95 | .Where(f => f.Enemy != Enemy); 96 | 97 | if (!enemyFighterNeighbours.Any()) 98 | return null; 99 | 100 | return enemyFighterNeighbours 101 | .Select(f => new { Distance = (Position - f.Position).LengthSquared(), Fighter = f }) 102 | .Aggregate((a, b) => a.Distance < b.Distance ? a : b) 103 | .Fighter; 104 | } 105 | 106 | protected override void RegenerateLocalSpace(Vector3 newVelocity, float elapsedTime) 107 | { 108 | RegenerateLocalSpaceForBanking(newVelocity, elapsedTime); 109 | } 110 | 111 | private Vector3 HandleBoundary() 112 | { 113 | // while inside the sphere do noting 114 | if (Position.Length() < WORLD_RADIUS) 115 | return Vector3.Zero; 116 | 117 | // steer back when outside 118 | Vector3 seek = SteerForSeek(Vector3.Zero); 119 | Vector3 lateral = Vector3Helpers.PerpendicularComponent(seek, Forward); 120 | return lateral; 121 | 122 | } 123 | 124 | public void Draw() 125 | { 126 | _trail.Draw(annotation); 127 | Drawing.DrawBasic3dSphericalVehicle(this, Color); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Demo/PlugIns/AirCombat/Missile.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using SharpSteer2; 3 | using SharpSteer2.Database; 4 | 5 | namespace Demo.PlugIns.AirCombat 6 | { 7 | class Missile 8 | :SimpleVehicle 9 | { 10 | private readonly Trail _trail; 11 | private ITokenForProximityDatabase _proximityToken; 12 | 13 | public readonly IVehicle Target; 14 | 15 | public bool IsDead 16 | { 17 | get { return _timer <= 0; } 18 | } 19 | private float _timer = 15; 20 | 21 | public override float MaxForce 22 | { 23 | get { return 400; } 24 | } 25 | public override float MaxSpeed 26 | { 27 | get { return 50; } 28 | } 29 | 30 | public Color Color = Color.Red; 31 | 32 | public Missile(IProximityDatabase proximity, IVehicle target, IAnnotationService annotation) 33 | :base(annotation) 34 | { 35 | _trail = new Trail(1, 10) 36 | { 37 | TrailColor = Color.Red, 38 | TickColor = Color.DarkRed 39 | }; 40 | _proximityToken = proximity.AllocateToken(this); 41 | Target = target; 42 | } 43 | 44 | public void Update(float currentTime, float elapsedTime) 45 | { 46 | _timer -= elapsedTime; 47 | if (!IsDead) 48 | { 49 | _trail.Record(currentTime, Position); 50 | ApplySteeringForce(SteerForPursuit(Target, 1) * 0.95f + SteerForWander(elapsedTime) * 0.05f, elapsedTime); 51 | _proximityToken.UpdateForNewPosition(Position); 52 | } 53 | else if (_proximityToken != null) 54 | { 55 | _proximityToken.Dispose(); 56 | _proximityToken = null; 57 | } 58 | } 59 | 60 | public void Draw() 61 | { 62 | _trail.Draw(annotation); 63 | Drawing.DrawBasic3dSphericalVehicle(this, Color); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Demo/PlugIns/Arrival/ArrivalPlugIn.cs: -------------------------------------------------------------------------------- 1 | using Demo.PlugIns.Ctf; 2 | using SharpSteer2; 3 | 4 | namespace Demo.PlugIns.Arrival 5 | { 6 | public class ArrivalPlugIn 7 | : CtfPlugIn 8 | { 9 | public override string Name 10 | { 11 | get { return "Arrival"; } 12 | } 13 | 14 | public ArrivalPlugIn(IAnnotationService annotations) 15 | :base(annotations, 0, true, 0.5f, 100) 16 | { 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Demo/PlugIns/Ctf/CtfBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System.Collections.Generic; 12 | using System.Linq; 13 | using Microsoft.Xna.Framework; 14 | using SharpSteer2; 15 | using SharpSteer2.Helpers; 16 | using SharpSteer2.Obstacles; 17 | using Vector3 = System.Numerics.Vector3; 18 | 19 | namespace Demo.PlugIns.Ctf 20 | { // spherical obstacle group 21 | 22 | public class CtfBase : SimpleVehicle 23 | { 24 | protected readonly CtfPlugIn Plugin; 25 | private readonly float _baseRadius; 26 | 27 | protected Trail Trail; 28 | 29 | public override float MaxForce { get { return 3; } } 30 | public override float MaxSpeed { get { return 3; } } 31 | 32 | // constructor 33 | protected CtfBase(CtfPlugIn plugin, IAnnotationService annotations = null, float baseRadius = 1.5f) 34 | :base(annotations) 35 | { 36 | Plugin = plugin; 37 | _baseRadius = baseRadius; 38 | 39 | Reset(); 40 | } 41 | 42 | // reset state 43 | public override void Reset() 44 | { 45 | base.Reset(); // reset the vehicle 46 | 47 | Speed = 3; // speed along Forward direction. 48 | 49 | Avoiding = false; // not actively avoiding 50 | 51 | RandomizeStartingPositionAndHeading(); // new starting position 52 | 53 | Trail = new Trail(); 54 | Trail.Clear(); // prevent long streaks due to teleportation 55 | } 56 | 57 | // draw this character/vehicle into the scene 58 | public virtual void Draw() 59 | { 60 | Drawing.DrawBasic2dCircularVehicle(this, BodyColor); 61 | Trail.Draw(annotation); 62 | } 63 | 64 | // annotate when actively avoiding obstacles 65 | // xxx perhaps this should be a call to a general purpose annotation 66 | // xxx for "local xxx axis aligned box in XZ plane" -- same code in in 67 | // xxx Pedestrian.cpp 68 | public void AnnotateAvoidObstacle(float minDistanceToCollision) 69 | { 70 | Vector3 boxSide = Side * Radius; 71 | Vector3 boxFront = Forward * minDistanceToCollision; 72 | Vector3 fr = Position + boxFront - boxSide; 73 | Vector3 fl = Position + boxFront + boxSide; 74 | Vector3 br = Position - boxSide; 75 | Vector3 bl = Position + boxSide; 76 | annotation.Line(fr, fl, Color.White.ToVector3().FromXna()); 77 | annotation.Line(fl, bl, Color.White.ToVector3().FromXna()); 78 | annotation.Line(bl, br, Color.White.ToVector3().FromXna()); 79 | annotation.Line(br, fr, Color.White.ToVector3().FromXna()); 80 | } 81 | 82 | public void DrawHomeBase() 83 | { 84 | Vector3 up = new Vector3(0, 0.01f, 0); 85 | Color atColor = new Color((byte)(255.0f * 0.3f), (byte)(255.0f * 0.3f), (byte)(255.0f * 0.5f)); 86 | Color noColor = Color.Gray; 87 | bool reached = Plugin.CtfSeeker.State == SeekerState.AtGoal; 88 | Color baseColor = (reached ? atColor : noColor); 89 | Drawing.DrawXZDisk(_baseRadius, Globals.HomeBaseCenter, baseColor, 40); 90 | Drawing.DrawXZDisk(_baseRadius / 15, Globals.HomeBaseCenter + up, Color.Black, 20); 91 | } 92 | 93 | private void RandomizeStartingPositionAndHeading() 94 | { 95 | // randomize position on a ring between inner and outer radii 96 | // centered around the home base 97 | float rRadius = RandomHelpers.Random(Globals.MIN_START_RADIUS, Globals.MAX_START_RADIUS); 98 | Vector3 randomOnRing = Vector3Helpers.RandomUnitVectorOnXZPlane() * rRadius; 99 | Position = (Globals.HomeBaseCenter + randomOnRing); 100 | 101 | // are we are too close to an obstacle? 102 | if (MinDistanceToObstacle(Position) < Radius * 5) 103 | { 104 | // if so, retry the randomization (this recursive call may not return 105 | // if there is too little free space) 106 | RandomizeStartingPositionAndHeading(); 107 | } 108 | else 109 | { 110 | // otherwise, if the position is OK, randomize 2D heading 111 | RandomizeHeadingOnXZPlane(); 112 | } 113 | } 114 | 115 | public enum SeekerState 116 | { 117 | Running, 118 | Tagged, 119 | AtGoal 120 | } 121 | 122 | // for draw method 123 | protected Color BodyColor; 124 | 125 | // xxx store steer sub-state for anotation 126 | protected bool Avoiding; 127 | 128 | // dynamic obstacle registry 129 | public static void InitializeObstacles(float radius, int obstacles) 130 | { 131 | // start with 40% of possible obstacles 132 | if (ObstacleCount == -1) 133 | { 134 | ObstacleCount = 0; 135 | for (int i = 0; i < obstacles; i++) 136 | AddOneObstacle(radius); 137 | } 138 | } 139 | 140 | public static void AddOneObstacle(float radius) 141 | { 142 | // pick a random center and radius, 143 | // loop until no overlap with other obstacles and the home base 144 | float r; 145 | Vector3 c; 146 | float minClearance; 147 | float requiredClearance = Globals.Seeker.Radius * 4; // 2 x diameter 148 | do 149 | { 150 | r = RandomHelpers.Random(1.5f, 4); 151 | c = Vector3Helpers.RandomVectorOnUnitRadiusXZDisk() * Globals.MAX_START_RADIUS * 1.1f; 152 | minClearance = AllObstacles.Aggregate(float.MaxValue, (current, t) => TestOneObstacleOverlap(current, r, t.Radius, c, t.Center)); 153 | 154 | minClearance = TestOneObstacleOverlap(minClearance, r, radius - requiredClearance, c, Globals.HomeBaseCenter); 155 | } 156 | while (minClearance < requiredClearance); 157 | 158 | // add new non-overlapping obstacle to registry 159 | AllObstacles.Add(new SphericalObstacle(r, c)); 160 | ObstacleCount++; 161 | } 162 | 163 | public static void RemoveOneObstacle() 164 | { 165 | if (ObstacleCount <= 0) 166 | return; 167 | 168 | ObstacleCount--; 169 | AllObstacles.RemoveAt(ObstacleCount); 170 | } 171 | 172 | private static float MinDistanceToObstacle(Vector3 point) 173 | { 174 | const float R = 0; 175 | Vector3 c = point; 176 | return AllObstacles.Aggregate(float.MaxValue, (current, t) => TestOneObstacleOverlap(current, R, t.Radius, c, t.Center)); 177 | } 178 | 179 | static float TestOneObstacleOverlap(float minClearance, float r, float radius, Vector3 c, Vector3 center) 180 | { 181 | float d = Vector3.Distance(c, center); 182 | float clearance = d - (r + radius); 183 | if (minClearance > clearance) minClearance = clearance; 184 | return minClearance; 185 | } 186 | 187 | protected static int ObstacleCount = -1; 188 | public static readonly List AllObstacles = new List(); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /Demo/PlugIns/Ctf/CtfEnemy.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using Microsoft.Xna.Framework; 12 | using SharpSteer2; 13 | using Vector3 = System.Numerics.Vector3; 14 | 15 | namespace Demo.PlugIns.Ctf 16 | { 17 | public class CtfEnemy : CtfBase 18 | { 19 | // constructor 20 | public CtfEnemy(CtfPlugIn plugin, IAnnotationService annotations = null) 21 | : base(plugin, annotations) 22 | { 23 | Reset(); 24 | } 25 | 26 | // reset state 27 | public override void Reset() 28 | { 29 | base.Reset(); 30 | BodyColor = new Color((byte)(255.0f * 0.6f), (byte)(255.0f * 0.4f), (byte)(255.0f * 0.4f)); // redish 31 | } 32 | 33 | // per frame simulation update 34 | public void Update(float currentTime, float elapsedTime) 35 | { 36 | // determine upper bound for pursuit prediction time 37 | float seekerToGoalDist = Vector3.Distance(Globals.HomeBaseCenter, Globals.Seeker.Position); 38 | float adjustedDistance = seekerToGoalDist - Radius - Plugin.BaseRadius; 39 | float seekerToGoalTime = ((adjustedDistance < 0) ? 0 : (adjustedDistance / Globals.Seeker.Speed)); 40 | float maxPredictionTime = seekerToGoalTime * 0.9f; 41 | 42 | // determine steering (pursuit, obstacle avoidance, or braking) 43 | Vector3 steer = Vector3.Zero; 44 | if (Globals.Seeker.State == SeekerState.Running) 45 | { 46 | Vector3 avoidance = SteerToAvoidObstacles(Globals.AVOIDANCE_PREDICT_TIME_MIN, AllObstacles); 47 | 48 | // saved for annotation 49 | Avoiding = (avoidance == Vector3.Zero); 50 | 51 | steer = Avoiding ? SteerForPursuit(Globals.Seeker, maxPredictionTime) : avoidance; 52 | } 53 | else 54 | { 55 | ApplyBrakingForce(Globals.BRAKING_RATE, elapsedTime); 56 | } 57 | ApplySteeringForce(steer, elapsedTime); 58 | 59 | // annotation 60 | annotation.VelocityAcceleration(this); 61 | Trail.Record(currentTime, Position); 62 | 63 | // detect and record interceptions ("tags") of seeker 64 | float seekerToMeDist = Vector3.Distance(Position, Globals.Seeker.Position); 65 | float sumOfRadii = Radius + Globals.Seeker.Radius; 66 | if (seekerToMeDist < sumOfRadii) 67 | { 68 | if (Globals.Seeker.State == SeekerState.Running) Globals.Seeker.State = SeekerState.Tagged; 69 | 70 | // annotation: 71 | if (Globals.Seeker.State == SeekerState.Tagged) 72 | { 73 | Color color = new Color((byte)(255.0f * 0.8f), (byte)(255.0f * 0.5f), (byte)(255.0f * 0.5f)); 74 | annotation.DiskXZ(sumOfRadii, (Position + Globals.Seeker.Position) / 2, color.ToVector3().FromXna(), 20); 75 | } 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Demo/PlugIns/Ctf/Globals.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using Microsoft.Xna.Framework; 12 | using Vector3 = System.Numerics.Vector3; 13 | 14 | namespace Demo.PlugIns.Ctf 15 | { 16 | class Globals 17 | { 18 | public static readonly Vector3 HomeBaseCenter = new Vector3(0, 0, 0); 19 | 20 | public const float MIN_START_RADIUS = 30; 21 | public const float MAX_START_RADIUS = 40; 22 | 23 | public const float BRAKING_RATE = 0.75f; 24 | 25 | public static readonly Color EvadeColor = new Color((byte)(255.0f * 0.6f), (byte)(255.0f * 0.6f), (byte)(255.0f * 0.3f)); // annotation 26 | public static readonly Color SeekColor = new Color((byte)(255.0f * 0.3f), (byte)(255.0f * 0.6f), (byte)(255.0f * 0.6f)); // annotation 27 | public static readonly Color ClearPathColor = new Color((byte)(255.0f * 0.3f), (byte)(255.0f * 0.6f), (byte)(255.0f * 0.3f)); // annotation 28 | 29 | public const float AVOIDANCE_PREDICT_TIME_MIN = 0.9f; 30 | public const float AVOIDANCE_PREDICT_TIME_MAX = 2; 31 | public static float AvoidancePredictTime = AVOIDANCE_PREDICT_TIME_MIN; 32 | 33 | public static CtfSeeker Seeker = null; 34 | 35 | // count the number of times the simulation has reset (e.g. for overnight runs) 36 | public static int ResetCount = 0; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Demo/PlugIns/FlowField/FlowFieldFollower.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Demo.PlugIns.Ctf; 3 | using Microsoft.Xna.Framework; 4 | using SharpSteer2; 5 | using SharpSteer2.Database; 6 | using SharpSteer2.Helpers; 7 | using Vector3 = System.Numerics.Vector3; 8 | 9 | namespace Demo.PlugIns.FlowField 10 | { 11 | public class FlowFieldFollower 12 | : SimpleVehicle 13 | { 14 | private readonly FlowFieldPlugIn _plugin; 15 | private Trail _trail; 16 | 17 | private readonly ITokenForProximityDatabase _proximityToken; 18 | 19 | public override float MaxSpeed { get { return 2; } } 20 | public override float MaxForce { get { return 4; } } 21 | 22 | public FlowFieldFollower(FlowFieldPlugIn plugin) 23 | : base(plugin.Annotations) 24 | { 25 | _plugin = plugin; 26 | 27 | _proximityToken = plugin.Database.AllocateToken(this); 28 | } 29 | 30 | public override void Reset() 31 | { 32 | base.Reset(); 33 | 34 | RandomizeStartingPositionAndHeading(); // new starting position 35 | 36 | _trail = new Trail(7.5f, 600); 37 | _trail.Clear(); 38 | } 39 | 40 | private void RandomizeStartingPositionAndHeading() 41 | { 42 | // randomize position on a ring between inner and outer radii 43 | // centered around the home base 44 | float rRadius = RandomHelpers.Random(10, 50); 45 | Vector3 randomOnRing = Vector3Helpers.RandomUnitVectorOnXZPlane() * rRadius; 46 | Position = (Globals.HomeBaseCenter + randomOnRing); 47 | RandomizeHeadingOnXZPlane(); 48 | } 49 | 50 | public void Update(float currentTime, float elapsedTime) 51 | { 52 | ApplySteeringForce(SteeringForce(), elapsedTime); 53 | 54 | annotation.VelocityAcceleration(this); 55 | _trail.Record(currentTime, Position); 56 | 57 | _proximityToken.UpdateForNewPosition(Position); 58 | } 59 | 60 | private Vector3 SteeringForce() 61 | { 62 | if (Position.X > 25 || Position.X < -25 || Position.Z > 25 || Position.Z < -25) 63 | return SteerForSeek(Vector3.Zero); 64 | 65 | var flowField = SteerToFollowFlowField(_plugin.FlowField, _plugin.PredictionTime); 66 | 67 | const float CA_LEAD_TIME = 3; 68 | 69 | // find all neighbors within maxRadius using proximity database 70 | // (radius is largest distance between vehicles traveling head-on 71 | // where a collision is possible within caLeadTime seconds.) 72 | float maxRadius = CA_LEAD_TIME * MaxSpeed * 2; 73 | var neighbours = new List(); 74 | _proximityToken.FindNeighbors(Position, maxRadius, neighbours); 75 | 76 | if (neighbours.Count > 0) 77 | { 78 | var avoid = SteerToAvoidNeighbors(CA_LEAD_TIME, neighbours) * 10; 79 | if (avoid != Vector3.Zero) 80 | return avoid; 81 | } 82 | 83 | return flowField; 84 | } 85 | 86 | protected override Vector3 AdjustRawSteeringForce(Vector3 force, float deltaTime) 87 | { 88 | return base.AdjustRawSteeringForce(new Vector3(force.X, 0, force.Z), deltaTime); 89 | } 90 | 91 | internal void Draw() 92 | { 93 | Drawing.DrawBasic2dCircularVehicle(this, Color.GhostWhite); 94 | _trail.Draw(annotation); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Demo/PlugIns/FlowField/FlowFieldPlugIn.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Microsoft.Xna.Framework; 4 | using SharpSteer2; 5 | using SharpSteer2.Database; 6 | using Vector3 = System.Numerics.Vector3; 7 | 8 | namespace Demo.PlugIns.FlowField 9 | { 10 | public class FlowFieldPlugIn 11 | : PlugIn 12 | { 13 | private const int FOLLOWER_COUNT = 15; 14 | private readonly List _followers = new List(FOLLOWER_COUNT); 15 | 16 | public IFlowField FlowField { get; private set; } 17 | public float PredictionTime { get; private set; } 18 | 19 | public IProximityDatabase Database { get; private set; } 20 | 21 | public override IEnumerable Vehicles 22 | { 23 | get { return _followers; } 24 | } 25 | 26 | public new IAnnotationService Annotations 27 | { 28 | get { return base.Annotations; } 29 | } 30 | 31 | public override string Name 32 | { 33 | get { return "Flow Field Following"; } 34 | } 35 | 36 | public FlowFieldPlugIn(IAnnotationService annotations) : base(annotations) 37 | { 38 | PredictionTime = 1; 39 | Database = new LocalityQueryProximityDatabase(Vector3.Zero, new Vector3(250, 250, 250), new Vector3(10)); 40 | } 41 | 42 | public override void Open() 43 | { 44 | // create the specified number of enemies, 45 | // storing pointers to them in an array. 46 | for (int i = 0; i < FOLLOWER_COUNT; i++) 47 | _followers.Add(new FlowFieldFollower(this)); 48 | 49 | // initialize camera 50 | Demo.Init2dCamera(_followers.First()); 51 | Demo.Camera.Mode = Camera.CameraMode.Fixed; 52 | Demo.Camera.FixedTarget = Vector3.Zero; 53 | Demo.Camera.FixedTarget.X = 15; 54 | Demo.Camera.FixedPosition.X = 80; 55 | Demo.Camera.FixedPosition.Y = 60; 56 | Demo.Camera.FixedPosition.Z = 0; 57 | 58 | FlowField = GenerateFlowField(); 59 | } 60 | 61 | private static IFlowField GenerateFlowField() 62 | { 63 | var f = new SimpleFlowField(50, 1, 50, new Vector3(25, 0.5f, 25)); 64 | 65 | //Start random 66 | f.Randomize(1); 67 | 68 | //Swirl around center 69 | //Half the field is a swirl (basically just concentric circles) while the other half has a slight bias to spiral inwards towards the center 70 | f.Func(pos => Vector3.Lerp(pos / 5, Vector3.Normalize(Vector3.Cross(pos, Vector3.UnitY)), pos.X > 0.5f ? 0.75f : 0.9f), 0.85f); 71 | 72 | //Keep it flat on the plane 73 | f.ClampXZ(); 74 | 75 | //Clean NaN values 76 | f.Clean(); 77 | 78 | return f; 79 | } 80 | 81 | public override void Update(float currentTime, float elapsedTime) 82 | { 83 | foreach (var flowFieldFollower in _followers) 84 | { 85 | flowFieldFollower.Update(currentTime, elapsedTime); 86 | } 87 | } 88 | 89 | public override void Redraw(float currentTime, float elapsedTime) 90 | { 91 | // selected vehicle (user can mouse click to select another) 92 | IVehicle selected = Demo.SelectedVehicle; 93 | 94 | Demo.UpdateCamera(elapsedTime, selected); 95 | Demo.GridUtility(Vector3.Zero); 96 | 97 | //Draw flow field 98 | const float RANGE = 50; 99 | const int SAMPLES = 25; 100 | for (int i = 0; i < SAMPLES; i++) 101 | { 102 | for (int j = 0; j < SAMPLES; j++) 103 | { 104 | Vector3 location = new Vector3(RANGE / SAMPLES * i - RANGE / 2, 0, RANGE / SAMPLES * j - RANGE / 2); 105 | var flow = FlowField.Sample(location); 106 | Annotations.Line(location, location + flow, Color.Black.ToVector3().FromXna()); 107 | } 108 | } 109 | 110 | // draw vehicles 111 | foreach (var vehicle in _followers) 112 | vehicle.Draw(); 113 | } 114 | 115 | public override void Close() 116 | { 117 | _followers.Clear(); 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Demo/PlugIns/GatewayPathFollowing/GatewayPathFollowingPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Demo.PlugIns.MeshPathFollowing; 5 | using Microsoft.Xna.Framework; 6 | using SharpSteer2; 7 | using SharpSteer2.Helpers; 8 | using SharpSteer2.Pathway; 9 | using Vector3 = System.Numerics.Vector3; 10 | 11 | namespace Demo.PlugIns.GatewayPathFollowing 12 | { 13 | public class GatewayPathFollowingPlugin 14 | :PlugIn 15 | { 16 | private GatewayPathway _path; 17 | private readonly List _walkers = new List(); 18 | 19 | public override bool RequestInitialSelection 20 | { 21 | get 22 | { 23 | return true; 24 | } 25 | } 26 | 27 | public GatewayPathFollowingPlugin(IAnnotationService annotations) 28 | :base(annotations) 29 | { 30 | } 31 | 32 | public override void Open() 33 | { 34 | GeneratePath(); 35 | 36 | _walkers.Clear(); 37 | for (int i = 0; i < 7; i++) 38 | { 39 | _walkers.Add(new PathWalker(_path, Annotations, _walkers) 40 | { 41 | Position = new Vector3(i * 1 * 2, 0, 0), 42 | Forward = new Vector3(0, 0, 1), 43 | }); 44 | } 45 | } 46 | 47 | private void GeneratePath() 48 | { 49 | var rand = new Random(); 50 | 51 | float xOffsetDeriv = 0; 52 | float xOffset = 0; 53 | 54 | var gateways = new List(); 55 | for (var i = 0; i < 200; i++) 56 | { 57 | xOffsetDeriv = Utilities.Clamp((float)rand.NextDouble() * 2 - (xOffsetDeriv * 0.0125f), -15, 15); 58 | xOffset += xOffsetDeriv; 59 | 60 | if (i % 3 == 0) 61 | { 62 | gateways.Add(new GatewayPathway.Gateway( 63 | new Vector3(xOffset + 1, 0, i) * 5, 64 | new Vector3(xOffset - 1, 0, i) * 5 65 | )); 66 | } 67 | else 68 | { 69 | gateways.Add(new GatewayPathway.Gateway( 70 | new Vector3(xOffset - 1, 0, i) * 5, 71 | new Vector3(xOffset + 1, 0, i) * 5 72 | )); 73 | } 74 | } 75 | 76 | _path = new GatewayPathway(gateways); 77 | } 78 | 79 | public override void Update(float currentTime, float elapsedTime) 80 | { 81 | foreach (var walker in _walkers) 82 | walker.Update(elapsedTime); 83 | } 84 | 85 | public override void Redraw(float currentTime, float elapsedTime) 86 | { 87 | Demo.UpdateCamera(elapsedTime, _walkers[0]); 88 | foreach (var walker in _walkers) 89 | walker.Draw(); 90 | 91 | var tri = _path.TrianglePathway.Triangles.ToArray(); 92 | foreach (var triangle in tri) 93 | { 94 | Drawing.Draw2dLine(triangle.A, triangle.A + triangle.Edge0, Color.Black); 95 | Drawing.Draw2dLine(triangle.A, triangle.A + triangle.Edge1, Color.Black); 96 | Drawing.Draw2dLine(triangle.A + triangle.Edge0, triangle.A + triangle.Edge1, Color.Black); 97 | } 98 | 99 | var points = _path.Centerline.Points.ToArray(); 100 | for (int i = 0; i < points.Length - 1; i++) 101 | { 102 | Drawing.Draw2dLine(points[i], points[i + 1], Color.Gray); 103 | } 104 | } 105 | 106 | public override void Close() 107 | { 108 | 109 | } 110 | 111 | public override string Name 112 | { 113 | get { return "Gateway Path Following"; } 114 | } 115 | 116 | public override IEnumerable Vehicles 117 | { 118 | get 119 | { 120 | return _walkers; 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Demo/PlugIns/LowSpeedTurn/LowSpeedTurn.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using Microsoft.Xna.Framework; 12 | using SharpSteer2; 13 | using Vector3 = System.Numerics.Vector3; 14 | 15 | namespace Demo.PlugIns.LowSpeedTurn 16 | { 17 | public class LowSpeedTurn : SimpleVehicle 18 | { 19 | Trail _trail; 20 | 21 | public override float MaxForce { get { return 0.3f; } } 22 | public override float MaxSpeed { get { return 1.5f; } } 23 | 24 | // constructor 25 | public LowSpeedTurn(IAnnotationService annotations = null) 26 | :base(annotations) 27 | { 28 | Reset(); 29 | } 30 | 31 | // reset state 32 | public override void Reset() 33 | { 34 | // reset vehicle state 35 | base.Reset(); 36 | 37 | // speed along Forward direction. 38 | Speed = _startSpeed; 39 | 40 | // initial position along X axis 41 | Position = new Vector3(_startX, 0, 0); 42 | 43 | // for next instance: step starting location 44 | _startX += 2; 45 | 46 | // for next instance: step speed 47 | _startSpeed += 0.15f; 48 | 49 | // 15 seconds and 150 points along the trail 50 | _trail = new Trail(15, 150); 51 | } 52 | 53 | // draw into the scene 54 | public void Draw() 55 | { 56 | Drawing.DrawBasic2dCircularVehicle(this, Color.Gray); 57 | _trail.Draw(annotation); 58 | } 59 | 60 | // per frame simulation update 61 | public void Update(float currentTime, float elapsedTime) 62 | { 63 | ApplySteeringForce(Steering, elapsedTime); 64 | 65 | // annotation 66 | annotation.VelocityAcceleration(this); 67 | _trail.Record(currentTime, Position); 68 | } 69 | 70 | // reset starting positions 71 | public static void ResetStarts() 72 | { 73 | _startX = 0; 74 | _startSpeed = 0; 75 | } 76 | 77 | // constant steering force 78 | private static Vector3 Steering 79 | { 80 | get { return new Vector3(1, 0, -1); } 81 | } 82 | 83 | // for stepping the starting conditions for next vehicle 84 | static float _startX; 85 | static float _startSpeed; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Demo/PlugIns/LowSpeedTurn/LowSpeedTurnPlugIn.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System; 12 | using System.Collections.Generic; 13 | using Microsoft.Xna.Framework; 14 | using SharpSteer2; 15 | using Vector3 = System.Numerics.Vector3; 16 | 17 | namespace Demo.PlugIns.LowSpeedTurn 18 | { 19 | class LowSpeedTurnPlugIn : PlugIn 20 | { 21 | const int LST_COUNT = 5; 22 | const float LST_LOOK_DOWN_DISTANCE = 18; 23 | static readonly Vector3 _lstViewCenter = new Vector3(7, 0, -2); 24 | static readonly Vector3 _lstPlusZ = new Vector3(0, 0, 1); 25 | 26 | public LowSpeedTurnPlugIn(IAnnotationService annotations) 27 | :base(annotations) 28 | { 29 | _all = new List(); 30 | } 31 | 32 | public override String Name { get { return "Low Speed Turn"; } } 33 | 34 | public override float SelectionOrderSortKey { get { return 0.05f; } } 35 | 36 | public override void Open() 37 | { 38 | // create a given number of agents with stepped inital parameters, 39 | // store pointers to them in an array. 40 | LowSpeedTurn.ResetStarts(); 41 | for (int i = 0; i < LST_COUNT; i++) 42 | _all.Add(new LowSpeedTurn(Annotations)); 43 | 44 | // initial selected vehicle 45 | Demo.SelectedVehicle = _all[0]; 46 | 47 | // initialize camera 48 | Demo.Camera.Mode = Camera.CameraMode.Fixed; 49 | Demo.Camera.FixedUp = _lstPlusZ; 50 | Demo.Camera.FixedTarget = _lstViewCenter; 51 | Demo.Camera.FixedPosition = _lstViewCenter; 52 | Demo.Camera.FixedPosition.Y += LST_LOOK_DOWN_DISTANCE; 53 | Demo.Camera.LookDownDistance = LST_LOOK_DOWN_DISTANCE; 54 | Demo.Camera.FixedDistanceVerticalOffset = Demo.CAMERA2_D_ELEVATION; 55 | Demo.Camera.FixedDistanceDistance = Demo.CAMERA_TARGET_DISTANCE; 56 | } 57 | 58 | public override void Update(float currentTime, float elapsedTime) 59 | { 60 | // update, draw and annotate each agent 61 | foreach (LowSpeedTurn t in _all) 62 | t.Update(currentTime, elapsedTime); 63 | } 64 | 65 | public override void Redraw(float currentTime, float elapsedTime) 66 | { 67 | // selected vehicle (user can mouse click to select another) 68 | IVehicle selected = Demo.SelectedVehicle; 69 | 70 | // vehicle nearest mouse (to be highlighted) 71 | IVehicle nearMouse = Demo.VehicleNearestToMouse(); 72 | 73 | // update camera 74 | Demo.UpdateCamera(elapsedTime, selected); 75 | 76 | // draw "ground plane" 77 | Demo.GridUtility(selected.Position); 78 | 79 | // update, draw and annotate each agent 80 | foreach (LowSpeedTurn agent in _all) 81 | { 82 | agent.Draw(); 83 | 84 | // display speed near agent's screen position 85 | Color textColor = new Color(new Vector3(0.8f, 0.8f, 1.0f).ToXna()); 86 | Vector3 textOffset = new Vector3(0, 0.25f, 0); 87 | Vector3 textPosition = agent.Position + textOffset; 88 | String annote = String.Format("{0:0.00}", agent.Speed); 89 | Drawing.Draw2dTextAt3dLocation(annote, textPosition, textColor); 90 | } 91 | 92 | // highlight vehicle nearest mouse 93 | Demo.HighlightVehicleUtility(nearMouse); 94 | } 95 | 96 | public override void Close() 97 | { 98 | _all.Clear(); 99 | } 100 | 101 | public override void Reset() 102 | { 103 | // reset each agent 104 | LowSpeedTurn.ResetStarts(); 105 | foreach (LowSpeedTurn t in _all) 106 | t.Reset(); 107 | } 108 | 109 | public override IEnumerable Vehicles 110 | { 111 | get { return _all.ConvertAll(v => (IVehicle) v); } 112 | } 113 | 114 | readonly List _all; // for allVehicles 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Demo/PlugIns/MapDrive/GCRoute.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System; 12 | using System.Collections.Generic; 13 | using System.Numerics; 14 | 15 | namespace Demo.PlugIns.MapDrive 16 | { 17 | // A variation on PolylinePathway (whose path tube radius is constant) 18 | // GCRoute (Grand Challenge Route) has an array of radii-per-segment 19 | // 20 | // XXX The OpenSteer path classes are long overdue for a rewrite. When 21 | // XXX that happens, support should be provided for constant-radius, 22 | // XXX radius-per-segment (as in GCRoute), and radius-per-vertex. 23 | public class GCRoute : PolylinePathway 24 | { 25 | // construct a GCRoute given the number of points (vertices), an 26 | // array of points, an array of per-segment path radii, and a flag 27 | // indiating if the path is connected at the end. 28 | public GCRoute(Vector3[] points, IList radii, bool cyclic) 29 | { 30 | Initialize(points, radii[0], cyclic); 31 | 32 | Radii = new float[PointCount]; 33 | 34 | // loop over all points 35 | for (int i = 0; i < PointCount; i++) 36 | { 37 | // copy in point locations, closing cycle when appropriate 38 | bool closeCycle = Cyclic && (i == PointCount - 1); 39 | int j = closeCycle ? 0 : i; 40 | Points[i] = points[j]; 41 | Radii[i] = radii[i]; 42 | } 43 | } 44 | 45 | // override the PolylinePathway method to allow for GCRoute-style 46 | // per-leg radii 47 | 48 | // Given an arbitrary point ("A"), returns the nearest point ("P") on 49 | // this path. Also returns, via output arguments, the path tangent at 50 | // P and a measure of how far A is outside the Pathway's "tube". Note 51 | // that a negative distance indicates A is inside the Pathway. 52 | public override Vector3 MapPointToPath(Vector3 point, out Vector3 tangent, out float outside) 53 | { 54 | Vector3 onPath = Vector3.Zero; 55 | tangent = Vector3.Zero; 56 | outside = float.MaxValue; 57 | 58 | // loop over all segments, find the one nearest to the given point 59 | for (int i = 1; i < PointCount; i++) 60 | { 61 | Vector3 chosen; 62 | float d = PointToSegmentDistance(point, Points[i - 1], Points[i], Tangents[i], Lengths[i], out chosen); 63 | 64 | // measure how far original point is outside the Pathway's "tube" 65 | // (negative values (from 0 to -radius) measure "insideness") 66 | float o = d - Radii[i]; 67 | 68 | // when this is the smallest "outsideness" seen so far, take 69 | // note and save the corresponding point-on-path and tangent 70 | if (o < outside) 71 | { 72 | outside = o; 73 | onPath = chosen; 74 | tangent = Tangents[i]; 75 | } 76 | } 77 | 78 | // return point on path 79 | return onPath; 80 | } 81 | 82 | // ignore that "tangent" output argument which is never used 83 | // XXX eventually move this to Pathway class 84 | public Vector3 MapPointToPath(Vector3 point, out float outside) 85 | { 86 | Vector3 tangent; 87 | return MapPointToPath(point, out tangent, out outside); 88 | } 89 | 90 | // get the index number of the path segment nearest the given point 91 | // XXX consider moving this to path class 92 | public int IndexOfNearestSegment(Vector3 point) 93 | { 94 | int index = 0; 95 | float minDistance = float.MaxValue; 96 | 97 | // loop over all segments, find the one nearest the given point 98 | for (int i = 1; i < PointCount; i++) 99 | { 100 | Vector3 chosen; 101 | float d = PointToSegmentDistance(point, Points[i - 1], Points[i], Tangents[i], Lengths[i], out chosen); 102 | if (d < minDistance) 103 | { 104 | minDistance = d; 105 | index = i; 106 | } 107 | } 108 | return index; 109 | } 110 | 111 | // returns the dot product of the tangents of two path segments, 112 | // used to measure the "angle" at a path vertex: how sharp is the turn? 113 | public float DotSegmentUnitTangents(int segmentIndex0, int segmentIndex1) 114 | { 115 | return Vector3.Dot(Tangents[segmentIndex0], Tangents[segmentIndex1]); 116 | } 117 | 118 | // return path tangent at given point (its projection on path) 119 | public Vector3 TangentAt(Vector3 point) 120 | { 121 | return Tangents[IndexOfNearestSegment(point)]; 122 | } 123 | 124 | // return path tangent at given point (its projection on path), 125 | // multiplied by the given pathfollowing direction (+1/-1 = 126 | // upstream/downstream). Near path vertices (waypoints) use the 127 | // tangent of the "next segment" in the given direction 128 | public Vector3 TangentAt(Vector3 point, int pathFollowDirection) 129 | { 130 | int segmentIndex = IndexOfNearestSegment(point); 131 | int nextIndex = segmentIndex + pathFollowDirection; 132 | bool insideNextSegment = IsInsidePathSegment(point, nextIndex); 133 | int i = (segmentIndex + (insideNextSegment ? pathFollowDirection : 0)); 134 | return Tangents[i] * pathFollowDirection; 135 | } 136 | 137 | // is the given point "near" a waypoint of this path? ("near" == closer 138 | // to the waypoint than the max of radii of two adjacent segments) 139 | public bool NearWaypoint(Vector3 point) 140 | { 141 | // loop over all waypoints 142 | for (int i = 1; i < PointCount; i++) 143 | { 144 | // return true if near enough to this waypoint 145 | float r = Math.Max(Radii[i], Radii[(i + 1) % PointCount]); 146 | float d = (point - Points[i]).Length(); 147 | if (d < r) return true; 148 | } 149 | return false; 150 | } 151 | 152 | // is the given point inside the path tube of the given segment 153 | // number? (currently not used. this seemed like a useful utility, 154 | // but wasn't right for the problem I was trying to solve) 155 | private bool IsInsidePathSegment(Vector3 point, int segmentIndex) 156 | { 157 | if (segmentIndex < 1 || segmentIndex >= PointCount) return false; 158 | 159 | int i = segmentIndex; 160 | 161 | Vector3 chosen; 162 | float d = PointToSegmentDistance(point, Points[i - 1], Points[i], Tangents[i], Lengths[i], out chosen); 163 | 164 | // measure how far original point is outside the Pathway's "tube" 165 | // (negative values (from 0 to -radius) measure "insideness") 166 | float o = d - Radii[i]; 167 | 168 | // return true if point is inside the tube 169 | return o < 0; 170 | } 171 | 172 | // per-segment radius (width) array 173 | public readonly float[] Radii; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /Demo/PlugIns/MapDrive/TerrainMap.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System; 12 | using Microsoft.Xna.Framework; 13 | using SharpSteer2; 14 | using SharpSteer2.Helpers; 15 | using Vector3 = System.Numerics.Vector3; 16 | 17 | namespace Demo.PlugIns.MapDrive 18 | { 19 | public class TerrainMap 20 | { 21 | public TerrainMap(Vector3 c, float x, float z, int r) 22 | { 23 | Center = c; 24 | XSize = x; 25 | ZSize = z; 26 | Resolution = r; 27 | _outsideValue = false; 28 | 29 | _map = new bool[Resolution * Resolution]; 30 | for (int i = 0; i < Resolution * Resolution; i++) 31 | { 32 | _map[i] = false; 33 | } 34 | } 35 | 36 | // clear the map (to false) 37 | public void Clear() 38 | { 39 | for (int i = 0; i < Resolution; i++) 40 | for (int j = 0; j < Resolution; j++) 41 | SetMapBit(i, j, false); 42 | } 43 | 44 | // get and set a bit based on 2d integer map index 45 | public bool GetMapBit(int i, int j) 46 | { 47 | return _map[MapAddress(i, j)]; 48 | } 49 | 50 | public void SetMapBit(int i, int j, bool value) 51 | { 52 | _map[MapAddress(i, j)] = value; 53 | } 54 | 55 | // get a value based on a position in 3d world space 56 | private bool GetMapValue(Vector3 point) 57 | { 58 | Vector3 local = point - Center; 59 | local.Y = 0; 60 | Vector3 localXZ = local; 61 | 62 | float hxs = XSize / 2; 63 | float hzs = ZSize / 2; 64 | 65 | float x = localXZ.X; 66 | float z = localXZ.Z; 67 | 68 | bool isOut = (x > +hxs) || (x < -hxs) || (z > +hzs) || (z < -hzs); 69 | 70 | if (isOut) 71 | { 72 | return _outsideValue; 73 | } 74 | else 75 | { 76 | int i = (int)Utilities.RemapInterval(x, -hxs, hxs, 0.0f, Resolution); 77 | int j = (int)Utilities.RemapInterval(z, -hzs, hzs, 0.0f, Resolution); 78 | return GetMapBit(i, j); 79 | } 80 | } 81 | 82 | public void xxxDrawMap() 83 | { 84 | float xs = XSize / Resolution; 85 | float zs = ZSize / Resolution; 86 | Vector3 alongRow = new Vector3(xs, 0, 0); 87 | Vector3 nextRow = new Vector3(-XSize, 0, zs); 88 | Vector3 g = new Vector3((XSize - xs) / -2, 0, (ZSize - zs) / -2); 89 | g += Center; 90 | for (int j = 0; j < Resolution; j++) 91 | { 92 | for (int i = 0; i < Resolution; i++) 93 | { 94 | if (GetMapBit(i, j)) 95 | { 96 | // spikes 97 | // Vector3 spikeTop (0, 5.0f, 0); 98 | // drawLine (g, g+spikeTop, gWhite); 99 | 100 | // squares 101 | const float ROCK_HEIGHT = 0; 102 | Vector3 v1 = new Vector3(+xs / 2, ROCK_HEIGHT, +zs / 2); 103 | Vector3 v2 = new Vector3(+xs / 2, ROCK_HEIGHT, -zs / 2); 104 | Vector3 v3 = new Vector3(-xs / 2, ROCK_HEIGHT, -zs / 2); 105 | Vector3 v4 = new Vector3(-xs / 2, ROCK_HEIGHT, +zs / 2); 106 | // Vector3 redRockColor (0.6f, 0.1f, 0.0f); 107 | Color orangeRockColor = new Color((byte)(255.0f * 0.5f), (byte)(255.0f * 0.2f), (byte)(255.0f * 0.0f)); 108 | Drawing.DrawQuadrangle(g + v1, g + v2, g + v3, g + v4, orangeRockColor); 109 | 110 | // pyramids 111 | // Vector3 top (0, xs/2, 0); 112 | // Vector3 redRockColor (0.6f, 0.1f, 0.0f); 113 | // Vector3 orangeRockColor (0.5f, 0.2f, 0.0f); 114 | // drawTriangle (g+v1, g+v2, g+top, redRockColor); 115 | // drawTriangle (g+v2, g+v3, g+top, orangeRockColor); 116 | // drawTriangle (g+v3, g+v4, g+top, redRockColor); 117 | // drawTriangle (g+v4, g+v1, g+top, orangeRockColor); 118 | } 119 | g += alongRow; 120 | } 121 | g += nextRow; 122 | } 123 | } 124 | 125 | public float MinSpacing() 126 | { 127 | return Math.Min(XSize, ZSize) / Resolution; 128 | } 129 | 130 | // used to detect if vehicle body is on any obstacles 131 | public bool ScanLocalXZRectangle(ILocalSpaceBasis localSpace, float xMin, float xMax, float zMin, float zMax) 132 | { 133 | float spacing = MinSpacing() / 2; 134 | 135 | for (float x = xMin; x < xMax; x += spacing) 136 | { 137 | for (float z = zMin; z < zMax; z += spacing) 138 | { 139 | Vector3 sample = new Vector3(x, 0, z); 140 | Vector3 global = localSpace.GlobalizePosition(sample); 141 | if (GetMapValue(global)) return true; 142 | } 143 | } 144 | return false; 145 | } 146 | 147 | // Scans along a ray (directed line segment) on the XZ plane, sampling 148 | // the map for a "true" cell. Returns the index of the first sample 149 | // that gets a "hit", or zero if no hits found. 150 | public int ScanXZray(Vector3 origin, Vector3 sampleSpacing, int sampleCount) 151 | { 152 | Vector3 samplePoint = origin; 153 | 154 | for (int i = 1; i <= sampleCount; i++) 155 | { 156 | samplePoint += sampleSpacing; 157 | if (GetMapValue(samplePoint)) return i; 158 | } 159 | 160 | return 0; 161 | } 162 | 163 | public int Cellwidth() { return Resolution; } // xxx cwr 164 | public int Cellheight() { return Resolution; } // xxx cwr 165 | public bool IsPassable(Vector3 point) { return !GetMapValue(point); } 166 | 167 | 168 | public Vector3 Center; 169 | public readonly float XSize; 170 | public readonly float ZSize; 171 | public readonly int Resolution; 172 | 173 | private readonly bool _outsideValue; 174 | 175 | int MapAddress(int i, int j) { return i + (j * Resolution); } 176 | 177 | readonly bool[] _map; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /Demo/PlugIns/MeshPathFollowing/MeshPathFollowingPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.Xna.Framework; 5 | using SharpSteer2; 6 | using SharpSteer2.Pathway; 7 | using Vector3 = System.Numerics.Vector3; 8 | 9 | namespace Demo.PlugIns.MeshPathFollowing 10 | { 11 | public class MeshPathFollowingPlugin 12 | :PlugIn 13 | { 14 | private TrianglePathway _path; 15 | private readonly List _walkers = new List(); 16 | 17 | public override bool RequestInitialSelection 18 | { 19 | get 20 | { 21 | return true; 22 | } 23 | } 24 | 25 | public MeshPathFollowingPlugin(IAnnotationService annotations) 26 | :base(annotations) 27 | { 28 | } 29 | 30 | public override void Open() 31 | { 32 | GeneratePath(); 33 | 34 | _walkers.Clear(); 35 | for (int i = 0; i < 7; i++) 36 | { 37 | _walkers.Add(new PathWalker(_path, Annotations, _walkers) 38 | { 39 | Position = new Vector3(i * 1 * 2, 0, 0), 40 | Forward = new Vector3(0, 0, 1) 41 | }); 42 | } 43 | } 44 | 45 | private void GeneratePath() 46 | { 47 | var rand = new Random(); 48 | 49 | float xOffsetDeriv = 0; 50 | float xOffset = 0; 51 | 52 | var points = new List(); 53 | for (var i = 0; i < 200; i++) 54 | { 55 | xOffsetDeriv = MathHelper.Clamp((float)rand.NextDouble() * 2 - (xOffsetDeriv * 0.0125f), -15, 15); 56 | xOffset += xOffsetDeriv; 57 | 58 | points.Add(new Vector3(xOffset + 1, 0, i) * 5); 59 | points.Add(new Vector3(xOffset - 1, 0, i) * 5); 60 | } 61 | 62 | _path = new TrianglePathway(Enumerable.Range(0, points.Count - 2).Select(i => new TrianglePathway.Triangle(points[i], points[i + 1], points[i + 2]))); 63 | } 64 | 65 | public override void Update(float currentTime, float elapsedTime) 66 | { 67 | foreach (var walker in _walkers) 68 | walker.Update(elapsedTime); 69 | } 70 | 71 | public override void Redraw(float currentTime, float elapsedTime) 72 | { 73 | Demo.UpdateCamera(elapsedTime, _walkers[0]); 74 | foreach (var walker in _walkers) 75 | walker.Draw(); 76 | 77 | var tri = _path.Triangles.ToArray(); 78 | foreach (var triangle in tri) 79 | { 80 | Drawing.Draw2dLine(triangle.A, triangle.A + triangle.Edge0, Color.Black); 81 | Drawing.Draw2dLine(triangle.A, triangle.A + triangle.Edge1, Color.Black); 82 | Drawing.Draw2dLine(triangle.A + triangle.Edge0, triangle.A + triangle.Edge1, Color.Black); 83 | } 84 | 85 | var points = _path.Centerline.Points.ToArray(); 86 | for (int i = 0; i < points.Length - 1; i++) 87 | { 88 | Drawing.Draw2dLine(points[i], points[i + 1], Color.Gray); 89 | } 90 | } 91 | 92 | public override void Close() 93 | { 94 | 95 | } 96 | 97 | public override string Name 98 | { 99 | get { return "Nav Mesh Path Following"; } 100 | } 101 | 102 | public override IEnumerable Vehicles 103 | { 104 | get 105 | { 106 | return _walkers; 107 | } 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Demo/PlugIns/MeshPathFollowing/PathWalker.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Microsoft.Xna.Framework; 4 | using SharpSteer2; 5 | using SharpSteer2.Helpers; 6 | using SharpSteer2.Pathway; 7 | using Vector3 = System.Numerics.Vector3; 8 | 9 | namespace Demo.PlugIns.MeshPathFollowing 10 | { 11 | public class PathWalker 12 | :SimpleVehicle 13 | { 14 | public readonly IPathway Path; 15 | private readonly List _vehicles; 16 | 17 | public override float MaxForce { get { return 1; } } 18 | public override float MaxSpeed { get { return 10; } } 19 | 20 | private readonly Trail _trail = new Trail(30, 300); 21 | 22 | public PathWalker(IPathway path, IAnnotationService annotation, List vehicles) 23 | :base(annotation) 24 | { 25 | Path = path; 26 | _vehicles = vehicles; 27 | } 28 | 29 | private float _time; 30 | public void Update(float dt) 31 | { 32 | const float PREDICTION = 3; 33 | 34 | //Avoid other vehicles, and follow the path 35 | var avoid = SteerToAvoidCloseNeighbors(0.25f, _vehicles.Except(new[] { this })); 36 | if (avoid != Vector3.Zero) 37 | ApplySteeringForce(avoid, dt); 38 | else 39 | { 40 | var f = SteerToFollowPath(true, PREDICTION, Path); 41 | ApplySteeringForce(f, dt); 42 | } 43 | 44 | //If the vehicle leaves the path, penalise it by applying a braking force 45 | if (Path.HowFarOutsidePath(Position) > 0) 46 | ApplyBrakingForce(0.3f, dt); 47 | 48 | _time += dt; 49 | _trail.Record(_time, Position); 50 | 51 | annotation.VelocityAcceleration(this); 52 | } 53 | 54 | internal void Draw() 55 | { 56 | Drawing.DrawBasic2dCircularVehicle(this, Color.Gray); 57 | 58 | _trail.Draw(annotation); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Demo/PlugIns/MultiplePursuit/MpBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // All rights reserved. 5 | // 6 | // This software is licensed as described in the file license.txt, which 7 | // you should have received as part of this distribution. The terms 8 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 9 | 10 | using Microsoft.Xna.Framework; 11 | using SharpSteer2; 12 | 13 | namespace Demo.PlugIns.MultiplePursuit 14 | { 15 | public class MpBase : SimpleVehicle 16 | { 17 | protected Trail Trail; 18 | 19 | public override float MaxForce { get { return 5; } } 20 | public override float MaxSpeed { get { return 3; } } 21 | 22 | // constructor 23 | protected MpBase(IAnnotationService annotations = null) 24 | :base(annotations) 25 | { 26 | Reset(); 27 | } 28 | 29 | // reset state 30 | public override void Reset() 31 | { 32 | base.Reset(); // reset the vehicle 33 | 34 | Speed = 0; // speed along Forward direction. 35 | Trail = new Trail(); 36 | Trail.Clear(); // prevent long streaks due to teleportation 37 | } 38 | 39 | // draw into the scene 40 | public void Draw() 41 | { 42 | Drawing.DrawBasic2dCircularVehicle(this, BodyColor); 43 | Trail.Draw(annotation); 44 | } 45 | 46 | // for draw method 47 | protected Color BodyColor; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Demo/PlugIns/MultiplePursuit/MpPlugIn.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // All rights reserved. 5 | // 6 | // This software is licensed as described in the file license.txt, which 7 | // you should have received as part of this distribution. The terms 8 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 9 | 10 | using System; 11 | using System.Collections.Generic; 12 | using SharpSteer2; 13 | 14 | namespace Demo.PlugIns.MultiplePursuit 15 | { 16 | public class MpPlugIn : PlugIn 17 | { 18 | public MpPlugIn(IAnnotationService annotations) 19 | :base(annotations) 20 | { 21 | _allMp = new List(); 22 | } 23 | 24 | public override String Name { get { return "Multiple Pursuit"; } } 25 | 26 | public override float SelectionOrderSortKey { get { return 0.04f; } } 27 | 28 | public override void Open() 29 | { 30 | // create the wanderer, saving a pointer to it 31 | _wanderer = new MpWanderer(Annotations); 32 | _allMp.Add(_wanderer); 33 | 34 | // create the specified number of pursuers, save pointers to them 35 | const int PURSUER_COUNT = 30; 36 | for (int i = 0; i < PURSUER_COUNT; i++) 37 | _allMp.Add(new MpPursuer(_wanderer, Annotations)); 38 | //pBegin = allMP.begin() + 1; // iterator pointing to first pursuer 39 | //pEnd = allMP.end(); // iterator pointing to last pursuer 40 | 41 | // initialize camera 42 | Demo.SelectedVehicle = _wanderer; 43 | Demo.Camera.Mode = Camera.CameraMode.StraightDown; 44 | Demo.Camera.FixedDistanceDistance = Demo.CAMERA_TARGET_DISTANCE; 45 | Demo.Camera.FixedDistanceVerticalOffset = Demo.CAMERA2_D_ELEVATION; 46 | } 47 | 48 | public override void Update(float currentTime, float elapsedTime) 49 | { 50 | // update the wanderer 51 | _wanderer.Update(currentTime, elapsedTime); 52 | 53 | // update each pursuer 54 | for (int i = 1; i < _allMp.Count; i++) 55 | { 56 | ((MpPursuer)_allMp[i]).Update(currentTime, elapsedTime); 57 | } 58 | } 59 | 60 | public override void Redraw(float currentTime, float elapsedTime) 61 | { 62 | // selected vehicle (user can mouse click to select another) 63 | IVehicle selected = Demo.SelectedVehicle; 64 | 65 | // vehicle nearest mouse (to be highlighted) 66 | IVehicle nearMouse = Demo.VehicleNearestToMouse(); 67 | 68 | // update camera 69 | Demo.UpdateCamera(elapsedTime, selected); 70 | 71 | // draw "ground plane" 72 | Demo.GridUtility(selected.Position); 73 | 74 | // draw each vehicles 75 | foreach (MpBase mp in _allMp) 76 | mp.Draw(); 77 | 78 | // highlight vehicle nearest mouse 79 | Demo.HighlightVehicleUtility(nearMouse); 80 | Demo.CircleHighlightVehicleUtility(selected); 81 | } 82 | 83 | public override void Close() 84 | { 85 | // delete wanderer, all pursuers, and clear list 86 | _allMp.Clear(); 87 | } 88 | 89 | public override void Reset() 90 | { 91 | // reset wanderer and pursuers 92 | _wanderer.Reset(); 93 | for (int i = 1; i < _allMp.Count; i++) _allMp[i].Reset(); 94 | 95 | // immediately jump to default camera position 96 | Demo.Camera.DoNotSmoothNextMove(); 97 | Demo.Camera.ResetLocalSpace(); 98 | } 99 | 100 | //const AVGroup& allVehicles () {return (const AVGroup&) allMP;} 101 | public override IEnumerable Vehicles 102 | { 103 | get { return _allMp.ConvertAll(m => (IVehicle) m); } 104 | } 105 | 106 | // a group (STL vector) of all vehicles 107 | readonly List _allMp; 108 | 109 | MpWanderer _wanderer; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Demo/PlugIns/MultiplePursuit/MpPursuer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using Microsoft.Xna.Framework; 12 | using SharpSteer2; 13 | using SharpSteer2.Helpers; 14 | using Vector3 = System.Numerics.Vector3; 15 | 16 | namespace Demo.PlugIns.MultiplePursuit 17 | { 18 | public class MpPursuer : MpBase 19 | { 20 | // constructor 21 | public MpPursuer(MpWanderer w, IAnnotationService annotations = null) 22 | :base(annotations) 23 | { 24 | _wanderer = w; 25 | Reset(); 26 | } 27 | 28 | // reset state 29 | public override void Reset() 30 | { 31 | base.Reset(); 32 | BodyColor = new Color((byte)(255.0f * 0.6f), (byte)(255.0f * 0.4f), (byte)(255.0f * 0.4f)); // redish 33 | if(_wanderer != null) RandomizeStartingPositionAndHeading(); 34 | } 35 | 36 | // one simulation step 37 | public void Update(float currentTime, float elapsedTime) 38 | { 39 | // when pursuer touches quarry ("wanderer"), reset its position 40 | float d = Vector3.Distance(Position, _wanderer.Position); 41 | float r = Radius + _wanderer.Radius; 42 | if (d < r) Reset(); 43 | 44 | const float MAX_TIME = 20; // xxx hard-to-justify value 45 | ApplySteeringForce(SteerForPursuit(_wanderer, MAX_TIME), elapsedTime); 46 | 47 | // for annotation 48 | Trail.Record(currentTime, Position); 49 | } 50 | 51 | // reset position 52 | private void RandomizeStartingPositionAndHeading() 53 | { 54 | // randomize position on a ring between inner and outer radii 55 | // centered around the home base 56 | const float INNER = 20; 57 | const float OUTER = 30; 58 | float radius = RandomHelpers.Random(INNER, OUTER); 59 | Vector3 randomOnRing = Vector3Helpers.RandomUnitVectorOnXZPlane() * radius; 60 | Position = (_wanderer.Position + randomOnRing); 61 | 62 | // randomize 2D heading 63 | RandomizeHeadingOnXZPlane(); 64 | } 65 | 66 | readonly MpWanderer _wanderer; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Demo/PlugIns/MultiplePursuit/MpWanderer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using Microsoft.Xna.Framework; 12 | using SharpSteer2; 13 | using Vector3 = System.Numerics.Vector3; 14 | 15 | namespace Demo.PlugIns.MultiplePursuit 16 | { 17 | public class MpWanderer : MpBase 18 | { 19 | // constructor 20 | public MpWanderer(IAnnotationService annotations = null) 21 | :base(annotations) 22 | { 23 | Reset(); 24 | } 25 | 26 | // reset state 27 | public override void Reset() 28 | { 29 | base.Reset(); 30 | BodyColor = new Color((byte)(255.0f * 0.4f), (byte)(255.0f * 0.6f), (byte)(255.0f * 0.4f)); // greenish 31 | } 32 | 33 | // one simulation step 34 | public void Update(float currentTime, float elapsedTime) 35 | { 36 | Vector3 wander2D = SteerForWander(elapsedTime); 37 | wander2D.Y = 0; 38 | 39 | Vector3 steer = Forward + (wander2D * 3); 40 | ApplySteeringForce(steer, elapsedTime); 41 | 42 | // for annotation 43 | Trail.Record(currentTime, Position); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Demo/PlugIns/OneTurning/OneTurning.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using Microsoft.Xna.Framework; 12 | using SharpSteer2; 13 | using Vector3 = System.Numerics.Vector3; 14 | 15 | namespace Demo.PlugIns.OneTurning 16 | { 17 | public class OneTurning : SimpleVehicle 18 | { 19 | Trail _trail; 20 | 21 | public override float MaxForce { get { return 0.3f; } } 22 | public override float MaxSpeed { get { return 5; } } 23 | 24 | // constructor 25 | public OneTurning(IAnnotationService annotations = null) 26 | :base(annotations) 27 | { 28 | Reset(); 29 | } 30 | 31 | // reset state 32 | public override void Reset() 33 | { 34 | base.Reset(); // reset the vehicle 35 | Speed = 1.5f; // speed along Forward direction. 36 | _trail = new Trail(); 37 | _trail.Clear(); // prevent long streaks due to teleportation 38 | } 39 | 40 | // per frame simulation update 41 | public void Update(float currentTime, float elapsedTime) 42 | { 43 | ApplySteeringForce(new Vector3(-2, 0, -3), elapsedTime); 44 | annotation.VelocityAcceleration(this); 45 | _trail.Record(currentTime, Position); 46 | } 47 | 48 | // draw this character/vehicle into the scene 49 | public void Draw() 50 | { 51 | Drawing.DrawBasic2dCircularVehicle(this, Color.Gray); 52 | _trail.Draw(annotation); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Demo/PlugIns/OneTurning/OneTurningPlugIn.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System; 12 | using System.Collections.Generic; 13 | using Microsoft.Xna.Framework; 14 | using SharpSteer2; 15 | using Vector3 = System.Numerics.Vector3; 16 | 17 | namespace Demo.PlugIns.OneTurning 18 | { 19 | public class OneTurningPlugIn : PlugIn 20 | { 21 | public OneTurningPlugIn(IAnnotationService annotations) 22 | :base(annotations) 23 | { 24 | _theVehicle = new List(); 25 | } 26 | 27 | public override String Name { get { return "One Turning Away"; } } 28 | 29 | public override float SelectionOrderSortKey { get { return 0.06f; } } 30 | 31 | public override void Open() 32 | { 33 | _oneTurning = new OneTurning(Annotations); 34 | Demo.SelectedVehicle = _oneTurning; 35 | _theVehicle.Add(_oneTurning); 36 | 37 | // initialize camera 38 | Demo.Init2dCamera(_oneTurning); 39 | Demo.Camera.Position = new Vector3(10, Demo.CAMERA2_D_ELEVATION, 10); 40 | Demo.Camera.FixedPosition = new Vector3(40); 41 | } 42 | 43 | public override void Update(float currentTime, float elapsedTime) 44 | { 45 | // update simulation of test vehicle 46 | _oneTurning.Update(currentTime, elapsedTime); 47 | } 48 | 49 | public override void Redraw(float currentTime, float elapsedTime) 50 | { 51 | // draw "ground plane" 52 | Demo.GridUtility(_oneTurning.Position); 53 | 54 | // draw test vehicle 55 | _oneTurning.Draw(); 56 | 57 | // textual annotation (following the test vehicle's screen position) 58 | String annote = String.Format(" speed: {0:0.00}", _oneTurning.Speed); 59 | Drawing.Draw2dTextAt3dLocation(annote, _oneTurning.Position, Color.Red); 60 | Drawing.Draw2dTextAt3dLocation("start", Vector3.Zero, Color.Green); 61 | 62 | // update camera, tracking test vehicle 63 | Demo.UpdateCamera(elapsedTime, _oneTurning); 64 | } 65 | 66 | public override void Close() 67 | { 68 | _theVehicle.Clear(); 69 | _oneTurning = null; 70 | } 71 | 72 | public override void Reset() 73 | { 74 | // reset vehicle 75 | _oneTurning.Reset(); 76 | } 77 | 78 | public override IEnumerable Vehicles 79 | { 80 | get { return _theVehicle.ConvertAll(v => (IVehicle) v); } 81 | } 82 | 83 | OneTurning _oneTurning; 84 | readonly List _theVehicle; // for allVehicles 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Demo/PlugIns/Pedestrian/Globals.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System.Collections.Generic; 12 | using System.Numerics; 13 | using SharpSteer2.Obstacles; 14 | 15 | namespace Demo.PlugIns.Pedestrian 16 | { 17 | class Globals 18 | { 19 | // create path for PlugIn 20 | // 21 | // 22 | // | gap | 23 | // 24 | // f b 25 | // |\ /\ - 26 | // | \ / \ ^ 27 | // | \/ \ | 28 | // | /\ \ | 29 | // | / \ c top 30 | // |/ \g / | 31 | // / / | 32 | // /| / V z y=0 33 | // / |______/ - ^ 34 | // / e d | 35 | // a/ | 36 | // |<---out-->| o----> x 37 | // 38 | public static PolylinePathway GetTestPath() 39 | { 40 | if (_testPath == null) 41 | { 42 | const float PATH_RADIUS = 2; 43 | 44 | const int PATH_POINT_COUNT = 7; 45 | const float SIZE = 30; 46 | const float TOP = 2 * SIZE; 47 | const float GAP = 1.2f * SIZE; 48 | const float OUTTER = 2 * SIZE; 49 | const float H = 0.5f; 50 | Vector3[] pathPoints = new Vector3[PATH_POINT_COUNT] 51 | { 52 | new Vector3 (H+GAP-OUTTER, 0, H+TOP-OUTTER), // 0 a 53 | new Vector3 (H+GAP, 0, H+TOP), // 1 b 54 | new Vector3 (H+GAP+(TOP/2), 0, H+TOP/2), // 2 c 55 | new Vector3 (H+GAP, 0, H), // 3 d 56 | new Vector3 (H, 0, H), // 4 e 57 | new Vector3 (H, 0, H+TOP), // 5 f 58 | new Vector3 (H+GAP, 0, H+TOP/2) // 6 g 59 | }; 60 | 61 | Obstacle1.Center = Vector3.Lerp(pathPoints[0], pathPoints[1], 0.2f); 62 | Obstacle2.Center = Vector3.Lerp(pathPoints[2], pathPoints[3], 0.5f); 63 | Obstacle1.Radius = 3; 64 | Obstacle2.Radius = 5; 65 | Obstacles.Add(Obstacle1); 66 | Obstacles.Add(Obstacle2); 67 | 68 | Endpoint0 = pathPoints[0]; 69 | Endpoint1 = pathPoints[PATH_POINT_COUNT - 1]; 70 | 71 | _testPath = new PolylinePathway(pathPoints, 72 | PATH_RADIUS, 73 | false); 74 | } 75 | return _testPath; 76 | } 77 | 78 | private static PolylinePathway _testPath = null; 79 | public static readonly SphericalObstacle Obstacle1 = new SphericalObstacle(); 80 | public static readonly SphericalObstacle Obstacle2 = new SphericalObstacle(); 81 | public static readonly List Obstacles = new List(); 82 | public static Vector3 Endpoint0 = Vector3.Zero; 83 | public static Vector3 Endpoint1 = Vector3.Zero; 84 | public static bool UseDirectedPathFollowing = true; 85 | 86 | // this was added for debugging tool, but I might as well leave it in 87 | public static bool WanderSwitch = true; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Demo/PlugIns/Soccer/AABBox.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using Microsoft.Xna.Framework; 12 | using Vector3 = System.Numerics.Vector3; 13 | 14 | namespace Demo.PlugIns.Soccer 15 | { 16 | public class AABBox 17 | { 18 | public AABBox(Vector3 min, Vector3 max) 19 | { 20 | _min = min; 21 | _max = max; 22 | } 23 | public bool IsInsideX(Vector3 p) 24 | { 25 | return !(p.X < _min.X || p.X > _max.X); 26 | } 27 | public bool IsInsideZ(Vector3 p) 28 | { 29 | return !(p.Z < _min.Z || p.Z > _max.Z); 30 | } 31 | public void Draw() 32 | { 33 | Vector3 b = new Vector3(_min.X, 0, _max.Z); 34 | Vector3 c = new Vector3(_max.X, 0, _min.Z); 35 | Color color = new Color(255, 255, 0); 36 | Drawing.DrawLineAlpha(_min, b, color, 1.0f); 37 | Drawing.DrawLineAlpha(b, _max, color, 1.0f); 38 | Drawing.DrawLineAlpha(_max, c, color, 1.0f); 39 | Drawing.DrawLineAlpha(c, _min, color, 1.0f); 40 | } 41 | 42 | Vector3 _min; 43 | Vector3 _max; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Demo/PlugIns/Soccer/Ball.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using Microsoft.Xna.Framework; 12 | using SharpSteer2; 13 | using Vector3 = System.Numerics.Vector3; 14 | 15 | namespace Demo.PlugIns.Soccer 16 | { 17 | public class Ball : SimpleVehicle 18 | { 19 | Trail _trail; 20 | 21 | public override float MaxForce { get { return 9; } } 22 | public override float MaxSpeed { get { return 9; } } 23 | 24 | public Ball(AABBox bbox, IAnnotationService annotations = null) 25 | :base(annotations) 26 | { 27 | _mBbox = bbox; 28 | Reset(); 29 | } 30 | 31 | // reset state 32 | public override void Reset() 33 | { 34 | base.Reset(); // reset the vehicle 35 | Speed = 0.0f; // speed along Forward direction. 36 | 37 | Position = new Vector3(0, 0, 0); 38 | if (_trail == null) _trail = new Trail(100, 6000); 39 | _trail.Clear(); // prevent long streaks due to teleportation 40 | } 41 | 42 | // per frame simulation update 43 | public void Update(float currentTime, float elapsedTime) 44 | { 45 | ApplyBrakingForce(1.5f, elapsedTime); 46 | ApplySteeringForce(Velocity, elapsedTime); 47 | // are we now outside the field? 48 | if (!_mBbox.IsInsideX(Position)) 49 | { 50 | Vector3 d = Velocity; 51 | RegenerateOrthonormalBasis(new Vector3(-d.X, d.Y, d.Z)); 52 | ApplySteeringForce(Velocity, elapsedTime); 53 | } 54 | if (!_mBbox.IsInsideZ(Position)) 55 | { 56 | Vector3 d = Velocity; 57 | RegenerateOrthonormalBasis(new Vector3(d.X, d.Y, -d.Z)); 58 | ApplySteeringForce(Velocity, elapsedTime); 59 | } 60 | _trail.Record(currentTime, Position); 61 | } 62 | 63 | public void Kick(Vector3 dir) 64 | { 65 | Speed = (dir.Length()); 66 | RegenerateOrthonormalBasis(dir); 67 | } 68 | 69 | // draw this character/vehicle into the scene 70 | public void Draw() 71 | { 72 | Drawing.DrawBasic2dCircularVehicle(this, Color.Green); 73 | _trail.Draw(annotation); 74 | } 75 | 76 | readonly AABBox _mBbox; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Demo/PlugIns/Soccer/Globals.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System.Numerics; 12 | 13 | namespace Demo.PlugIns.Soccer 14 | { 15 | class Globals 16 | { 17 | public static readonly Vector3[] PlayerPosition = { 18 | new Vector3(4,0,0), 19 | new Vector3(7,0,-5), 20 | new Vector3(7,0,5), 21 | new Vector3(10,0,-3), 22 | new Vector3(10,0,3), 23 | new Vector3(15,0, -8), 24 | new Vector3(15,0,0), 25 | new Vector3(15,0,8), 26 | new Vector3(4,0,0) 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Demo/PlugIns/Soccer/Player.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System.Collections.Generic; 12 | using Microsoft.Xna.Framework; 13 | using SharpSteer2; 14 | using SharpSteer2.Helpers; 15 | using Vector3 = System.Numerics.Vector3; 16 | 17 | namespace Demo.PlugIns.Soccer 18 | { 19 | public class Player : SimpleVehicle 20 | { 21 | Trail _trail; 22 | 23 | public override float MaxForce { get { return 3000.7f; } } 24 | public override float MaxSpeed { get { return 10; } } 25 | 26 | // constructor 27 | public Player(List others, List allplayers, Ball ball, bool isTeamA, int id, IAnnotationService annotations = null) 28 | :base(annotations) 29 | { 30 | _allPlayers = allplayers; 31 | _ball = ball; 32 | _imTeamA = isTeamA; 33 | _myID = id; 34 | 35 | Reset(); 36 | } 37 | 38 | // reset state 39 | public override void Reset() 40 | { 41 | base.Reset(); // reset the vehicle 42 | Speed = 0.0f; // speed along Forward direction. 43 | 44 | // Place me on my part of the field, looking at oponnents goal 45 | Position = new Vector3(_imTeamA ? RandomHelpers.Random() * 20 : -RandomHelpers.Random() * 20, 0, (RandomHelpers.Random() - 0.5f) * 20); 46 | if (_myID < 9) 47 | { 48 | Position = _imTeamA ? (Globals.PlayerPosition[_myID]) : (new Vector3(-Globals.PlayerPosition[_myID].X, Globals.PlayerPosition[_myID].Y, Globals.PlayerPosition[_myID].Z)); 49 | } 50 | _home = Position; 51 | 52 | if (_trail == null) _trail = new Trail(10, 60); 53 | _trail.Clear(); // prevent long streaks due to teleportation 54 | } 55 | 56 | // per frame simulation update 57 | public void Update(float elapsedTime) 58 | { 59 | // if I hit the ball, kick it. 60 | float distToBall = Vector3.Distance(Position, _ball.Position); 61 | float sumOfRadii = Radius + _ball.Radius; 62 | if (distToBall < sumOfRadii) 63 | _ball.Kick((_ball.Position - Position) * 50); 64 | 65 | // otherwise consider avoiding collisions with others 66 | Vector3 collisionAvoidance = SteerToAvoidNeighbors(1, _allPlayers); 67 | if (collisionAvoidance != Vector3.Zero) 68 | ApplySteeringForce(collisionAvoidance, elapsedTime); 69 | else 70 | { 71 | float distHomeToBall = Vector3.Distance(_home, _ball.Position); 72 | if (distHomeToBall < 12) 73 | { 74 | // go for ball if I'm on the 'right' side of the ball 75 | if (_imTeamA ? Position.X > _ball.Position.X : Position.X < _ball.Position.X) 76 | { 77 | Vector3 seekTarget = SteerForSeek(_ball.Position); 78 | ApplySteeringForce(seekTarget, elapsedTime); 79 | } 80 | else 81 | { 82 | if (distHomeToBall < 12) 83 | { 84 | float z = _ball.Position.Z - Position.Z > 0 ? -1.0f : 1.0f; 85 | Vector3 behindBall = _ball.Position + (_imTeamA ? new Vector3(2, 0, z) : new Vector3(-2, 0, z)); 86 | Vector3 behindBallForce = SteerForSeek(behindBall); 87 | annotation.Line(Position, behindBall, Color.Green.ToVector3().FromXna()); 88 | Vector3 evadeTarget = SteerForFlee(_ball.Position); 89 | ApplySteeringForce(behindBallForce * 10 + evadeTarget, elapsedTime); 90 | } 91 | } 92 | } 93 | else // Go home 94 | { 95 | Vector3 seekTarget = SteerForSeek(_home); 96 | Vector3 seekHome = SteerForSeek(_home); 97 | ApplySteeringForce(seekTarget + seekHome, elapsedTime); 98 | } 99 | 100 | } 101 | } 102 | 103 | // draw this character/vehicle into the scene 104 | public void Draw() 105 | { 106 | Drawing.DrawBasic2dCircularVehicle(this, _imTeamA ? Color.Red : Color.Blue); 107 | _trail.Draw(annotation); 108 | } 109 | 110 | // per-instance reference to its group 111 | readonly List _allPlayers; 112 | readonly Ball _ball; 113 | readonly bool _imTeamA; 114 | readonly int _myID; 115 | Vector3 _home; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Demo/PlugIns/Soccer/SoccerPlugIn.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System; 12 | using System.Collections.Generic; 13 | using System.Text; 14 | using Microsoft.Xna.Framework; 15 | using SharpSteer2; 16 | using Vector3 = System.Numerics.Vector3; 17 | 18 | namespace Demo.PlugIns.Soccer 19 | { 20 | public class SoccerPlugIn : PlugIn 21 | { 22 | public SoccerPlugIn(IAnnotationService annotations = null) 23 | :base(annotations) 24 | { 25 | _teamA = new List(); 26 | _teamB = new List(); 27 | _allPlayers = new List(); 28 | } 29 | 30 | public override String Name { get { return "Michael's Simple Soccer"; } } 31 | 32 | public override void Open() 33 | { 34 | // Make a field 35 | _bbox = new AABBox(new Vector3(-20, 0, -10), new Vector3(20, 0, 10)); 36 | // Red goal 37 | _teamAGoal = new AABBox(new Vector3(-21, 0, -7), new Vector3(-19, 0, 7)); 38 | // Blue Goal 39 | _teamBGoal = new AABBox(new Vector3(19, 0, -7), new Vector3(21, 0, 7)); 40 | // Make a ball 41 | _ball = new Ball(_bbox); 42 | // Build team A 43 | const int PLAYER_COUNT_A = 8; 44 | for (int i = 0; i < PLAYER_COUNT_A; i++) 45 | { 46 | Player pMicTest = new Player(_teamA, _allPlayers, _ball, true, i, Annotations); 47 | Demo.SelectedVehicle = pMicTest; 48 | _teamA.Add(pMicTest); 49 | _allPlayers.Add(pMicTest); 50 | } 51 | // Build Team B 52 | const int PLAYER_COUNT_B = 8; 53 | for (int i = 0; i < PLAYER_COUNT_B; i++) 54 | { 55 | Player pMicTest = new Player(_teamB, _allPlayers, _ball, false, i, Annotations); 56 | Demo.SelectedVehicle = pMicTest; 57 | _teamB.Add(pMicTest); 58 | _allPlayers.Add(pMicTest); 59 | } 60 | // initialize camera 61 | Demo.Init2dCamera(_ball); 62 | Demo.Camera.Position = new Vector3(10, Demo.CAMERA2_D_ELEVATION, 10); 63 | Demo.Camera.FixedPosition = new Vector3(40); 64 | Demo.Camera.Mode = Camera.CameraMode.Fixed; 65 | _redScore = 0; 66 | _blueScore = 0; 67 | } 68 | 69 | public override void Update(float currentTime, float elapsedTime) 70 | { 71 | // update simulation of test vehicle 72 | foreach (Player player in _teamA) 73 | player.Update(elapsedTime); 74 | foreach (Player player in _teamB) 75 | player.Update(elapsedTime); 76 | _ball.Update(currentTime, elapsedTime); 77 | 78 | if (_teamAGoal.IsInsideX(_ball.Position) && _teamAGoal.IsInsideZ(_ball.Position)) 79 | { 80 | _ball.Reset(); // Ball in blue teams goal, red scores 81 | _redScore++; 82 | } 83 | if (_teamBGoal.IsInsideX(_ball.Position) && _teamBGoal.IsInsideZ(_ball.Position)) 84 | { 85 | _ball.Reset(); // Ball in red teams goal, blue scores 86 | _blueScore++; 87 | } 88 | } 89 | 90 | public override void Redraw(float currentTime, float elapsedTime) 91 | { 92 | // draw "ground plane" 93 | Demo.GridUtility(Vector3.Zero); 94 | 95 | // draw test vehicle 96 | foreach (Player player in _teamA) 97 | player.Draw(); 98 | foreach (Player player in _teamB) 99 | player.Draw(); 100 | _ball.Draw(); 101 | _bbox.Draw(); 102 | _teamAGoal.Draw(); 103 | _teamBGoal.Draw(); 104 | 105 | StringBuilder annote = new StringBuilder(); 106 | annote.AppendFormat("Red: {0}", _redScore); 107 | Drawing.Draw2dTextAt3dLocation(annote.ToString(), new Vector3(23, 0, 0), new Color((byte)(255.0f * 1), (byte)(255.0f * 0.7f), (byte)(255.0f * 0.7f))); 108 | 109 | annote = new StringBuilder(); 110 | annote.AppendFormat("Blue: {0}", _blueScore); 111 | Drawing.Draw2dTextAt3dLocation(annote.ToString(), new Vector3(-23, 0, 0), new Color((byte)(255.0f * 0.7f), (byte)(255.0f * 0.7f), (byte)(255.0f * 1))); 112 | 113 | // textual annotation (following the test vehicle's screen position) 114 | #if IGNORED 115 | for (int i = 0; i < TeamA.Count; i++) 116 | { 117 | String anno = String.Format(" speed: {0:0.00} ID: {1} ", TeamA[i].speed(), i); 118 | Drawing.Draw2dTextAt3dLocation(anno, TeamA[i].position(), Color.Red); 119 | } 120 | Drawing.Draw2dTextAt3dLocation("start", Vector3.zero, Color.Green); 121 | #endif 122 | // update camera, tracking test vehicle 123 | Demo.UpdateCamera(elapsedTime, Demo.SelectedVehicle); 124 | } 125 | 126 | public override void Close() 127 | { 128 | _teamA.Clear(); 129 | _teamB.Clear(); 130 | _allPlayers.Clear(); 131 | } 132 | 133 | public override void Reset() 134 | { 135 | // reset vehicle 136 | foreach (Player player in _teamA) 137 | player.Reset(); 138 | foreach (Player player in _teamB) 139 | player.Reset(); 140 | _ball.Reset(); 141 | } 142 | 143 | //const AVGroup& allVehicles () {return (const AVGroup&) TeamA;} 144 | public override IEnumerable Vehicles 145 | { 146 | get { return _teamA.ConvertAll(p => (IVehicle) p); } 147 | } 148 | 149 | readonly List _teamA; 150 | readonly List _teamB; 151 | readonly List _allPlayers; 152 | 153 | Ball _ball; 154 | AABBox _bbox; 155 | AABBox _teamAGoal; 156 | AABBox _teamBGoal; 157 | int _redScore; 158 | int _blueScore; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Demo/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // All rights reserved. 5 | // 6 | // This software is licensed as described in the file license.txt, which 7 | // you should have received as part of this distribution. The terms 8 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 9 | 10 | // SharpSteer - Steering Behaviors for Autonomous Characters 11 | namespace Demo 12 | { 13 | static class Program 14 | { 15 | /// 16 | /// The main entry point for the application. 17 | /// 18 | static void Main(string[] args) 19 | { 20 | using (Demo demo = new Demo()) 21 | { 22 | demo.Run(); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Demo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("SharpSteer Demo")] 8 | [assembly: AssemblyProduct("SharpSteer Demo")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyCompany("")] 11 | 12 | [assembly: AssemblyCopyright("Copyright © 2007")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("6eda8076-3da1-407a-9cf9-5aea2fa44752")] 23 | 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | [assembly: AssemblyVersion("1.0.0.0")] 33 | -------------------------------------------------------------------------------- /Demo/SimpleFlowField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | using SharpSteer2; 4 | using SharpSteer2.Helpers; 5 | 6 | namespace Demo 7 | { 8 | public class SimpleFlowField 9 | : IFlowField 10 | { 11 | private readonly Vector3 _center; 12 | 13 | private readonly Vector3[,,] _field; 14 | 15 | public SimpleFlowField(int x, int y, int z, Vector3 center) 16 | { 17 | _center = center; 18 | _field = new Vector3[x, y, z]; 19 | } 20 | 21 | public Vector3 Sample(Vector3 location) 22 | { 23 | var sampleLocation = location + _center; 24 | var sample = _field[ 25 | (int)Utilities.Clamp(sampleLocation.X, 0, _field.GetLength(0) - 1), 26 | (int)Utilities.Clamp(sampleLocation.Y, 0, _field.GetLength(1) - 1), 27 | (int)Utilities.Clamp(sampleLocation.Z, 0, _field.GetLength(2) - 1) 28 | ]; 29 | 30 | return sample; 31 | } 32 | 33 | public void Func(Func func, float weight) 34 | { 35 | for (int i = 0; i < _field.GetLength(0); i++) 36 | { 37 | for (int j = 0; j < _field.GetLength(1); j++) 38 | { 39 | for (int k = 0; k < _field.GetLength(2); k++) 40 | { 41 | var pos = new Vector3(i, j, k) - _center; 42 | _field[i, j, k] = Vector3.Lerp(_field[i, j, k], func(pos), weight); 43 | } 44 | } 45 | } 46 | } 47 | 48 | public void Randomize(float weight) 49 | { 50 | Func(_ => Vector3Helpers.RandomUnitVector(), weight); 51 | } 52 | 53 | public void ClampXZ() 54 | { 55 | for (int i = 0; i < _field.GetLength(0); i++) 56 | { 57 | for (int j = 0; j < _field.GetLength(1); j++) 58 | { 59 | for (int k = 0; k < _field.GetLength(2); k++) 60 | { 61 | _field[i, j, k] = new Vector3(_field[i, j, k].X, 0, _field[i, j, k].Z); 62 | } 63 | } 64 | } 65 | } 66 | 67 | public void Normalize() 68 | { 69 | for (int i = 0; i < _field.GetLength(0); i++) 70 | { 71 | for (int j = 0; j < _field.GetLength(1); j++) 72 | { 73 | for (int k = 0; k < _field.GetLength(2); k++) 74 | { 75 | _field[i, j, k] = Vector3.Normalize(_field[i, j, k]); 76 | } 77 | } 78 | } 79 | } 80 | 81 | public void Clean() 82 | { 83 | for (int i = 0; i < _field.GetLength(0); i++) 84 | { 85 | for (int j = 0; j < _field.GetLength(1); j++) 86 | { 87 | for (int k = 0; k < _field.GetLength(2); k++) 88 | { 89 | var v = _field[i, j, k]; 90 | if (float.IsNaN(v.X) || float.IsNaN(v.Y) || float.IsNaN(v.Z)) 91 | _field[i, j, k] = Vector3.Zero; 92 | } 93 | } 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Demo/Trail.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Xna.Framework; 3 | using SharpSteer2; 4 | using Vector3 = System.Numerics.Vector3; 5 | 6 | namespace Demo 7 | { 8 | /// 9 | /// Provides support to visualize the recent path of a vehicle. 10 | /// 11 | public class Trail 12 | { 13 | int _currentIndex; // Array index of most recently recorded point 14 | readonly float _sampleInterval; // Desired interval between taking samples 15 | float _lastSampleTime; // Global time when lat sample was taken 16 | int _dottedPhase; // Dotted line: draw segment or not 17 | Vector3 _currentPosition; // Last reported position of vehicle 18 | readonly Vector3[] _vertices; // Array (ring) of recent points along trail 19 | readonly byte[] _flags; // Array (ring) of flag bits for trail points 20 | Color _trailColor; // Color of the trail 21 | Color _tickColor; // Color of the ticks 22 | 23 | /// 24 | /// Initializes a new instance of Trail. 25 | /// 26 | public Trail() 27 | : this(5, 100) 28 | { 29 | } 30 | 31 | /// 32 | /// Initializes a new instance of Trail. 33 | /// 34 | /// The amount of time the trail represents. 35 | /// The number of smaples along the trails length. 36 | public Trail(float duration, int vertexCount) 37 | { 38 | // Set internal trail state 39 | _currentIndex = 0; 40 | _lastSampleTime = 0; 41 | _sampleInterval = duration / vertexCount; 42 | _dottedPhase = 1; 43 | 44 | // Initialize ring buffers 45 | _vertices = new Vector3[vertexCount]; 46 | _flags = new byte[vertexCount]; 47 | 48 | _trailColor = Color.LightGray; 49 | _tickColor = Color.White; 50 | } 51 | 52 | /// 53 | /// Gets or sets the color of the trail. 54 | /// 55 | public Color TrailColor 56 | { 57 | get { return _trailColor; } 58 | set { _trailColor = value; } 59 | } 60 | 61 | /// 62 | /// Gets or sets the color of the ticks. 63 | /// 64 | public Color TickColor 65 | { 66 | get { return _tickColor; } 67 | set { _tickColor = value; } 68 | } 69 | 70 | /// 71 | /// Records a position for the current time, called once per update. 72 | /// 73 | /// 74 | /// 75 | public void Record(float currentTime, Vector3 position) 76 | { 77 | float timeSinceLastTrailSample = currentTime - _lastSampleTime; 78 | if (timeSinceLastTrailSample > _sampleInterval) 79 | { 80 | _currentIndex = (_currentIndex + 1) % _vertices.Length; 81 | _vertices[_currentIndex] = position; 82 | _dottedPhase = (_dottedPhase + 1) % 2; 83 | bool tick = (Math.Floor(currentTime) > Math.Floor(_lastSampleTime)); 84 | _flags[_currentIndex] = (byte)(_dottedPhase | (tick ? 2 : 0)); 85 | _lastSampleTime = currentTime; 86 | } 87 | _currentPosition = position; 88 | } 89 | 90 | /// 91 | /// Draws the trail as a dotted line, fading away with age. 92 | /// 93 | public void Draw(IAnnotationService annotation) 94 | { 95 | int index = _currentIndex; 96 | for (int j = 0; j < _vertices.Length; j++) 97 | { 98 | // index of the next vertex (mod around ring buffer) 99 | int next = (index + 1) % _vertices.Length; 100 | 101 | // "tick mark": every second, draw a segment in a different color 102 | bool tick = ((_flags[index] & 2) != 0 || (_flags[next] & 2) != 0); 103 | Color color = tick ? _tickColor : _trailColor; 104 | 105 | // draw every other segment 106 | if ((_flags[index] & 1) != 0) 107 | { 108 | if (j == 0) 109 | { 110 | // draw segment from current position to first trail point 111 | annotation.Line(_currentPosition, _vertices[index], color.ToVector3().FromXna()); 112 | } 113 | else 114 | { 115 | // draw trail segments with opacity decreasing with age 116 | const float MIN_O = 0.05f; // minimum opacity 117 | float fraction = (float)j / _vertices.Length; 118 | float opacity = (fraction * (1 - MIN_O)) + MIN_O; 119 | annotation.Line(_vertices[index], _vertices[next], color.ToVector3().FromXna(), opacity); 120 | } 121 | } 122 | index = next; 123 | } 124 | } 125 | 126 | /// 127 | /// Clear trail history. Used to prevent long streaks due to teleportation. 128 | /// 129 | public void Clear() 130 | { 131 | _currentIndex = 0; 132 | _lastSampleTime = 0; 133 | _dottedPhase = 1; 134 | 135 | for (int i = 0; i < _vertices.Length; i++) 136 | { 137 | _vertices[i] = Vector3.Zero; 138 | _flags[i] = 0; 139 | } 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindevans/SharpSteer2/d8138fe95e81b38b62b864e457b23b94d9750199/License.txt -------------------------------------------------------------------------------- /Local.testsettings: -------------------------------------------------------------------------------- 1 |  2 | 3 | These are default test settings for a local test run. 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /SharpSteer2.Tests/LocalSpaceBasisHelpersTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System.Numerics; 4 | using SharpSteer2.Helpers; 5 | 6 | namespace SharpSteer2.Tests 7 | { 8 | [TestClass] 9 | public class LocalSpaceBasisHelpersTest 10 | { 11 | // ReSharper disable once InconsistentNaming 12 | public const float PiOver2 = (float)Math.PI / 2f; 13 | 14 | private static ILocalSpaceBasis Basis(Matrix4x4 m) 15 | { 16 | return new LocalSpace(m); 17 | } 18 | 19 | [TestMethod] 20 | public void GlobalizeDirectionTest() 21 | { 22 | Matrix4x4 m = Matrix4x4.CreateRotationX(-PiOver2); 23 | ILocalSpaceBasis basis = Basis(m); 24 | 25 | var v = Vector3.Normalize(new Vector3(1, 2, 3)); 26 | Assert.AreEqual(Vector3.TransformNormal(v, m), basis.GlobalizeDirection(v)); 27 | } 28 | 29 | [TestMethod] 30 | public void GlobalizePositionTest() 31 | { 32 | Matrix4x4 m = Matrix4x4.CreateRotationX(-PiOver2) * Matrix4x4.CreateTranslation(10, 20, 30); 33 | ILocalSpaceBasis basis = Basis(m); 34 | 35 | var v = Vector3.Normalize(new Vector3(1, 2, 3)); 36 | Assert.AreEqual(Vector3.Transform(v, m), basis.GlobalizePosition(v)); 37 | } 38 | 39 | [TestMethod] 40 | public void LocalizeDirectionTest() 41 | { 42 | Matrix4x4 m = Matrix4x4.CreateRotationX(-PiOver2); 43 | ILocalSpaceBasis basis = Basis(m); 44 | 45 | var v = Vector3.Normalize(new Vector3(1, 2, 3)); 46 | Matrix4x4 inv; 47 | Matrix4x4.Invert(m, out inv); 48 | Assert.AreEqual(Vector3.TransformNormal(v, inv), basis.LocalizeDirection(v)); 49 | } 50 | 51 | [TestMethod] 52 | public void LocalizePositionTest() 53 | { 54 | Matrix4x4 m = Matrix4x4.CreateRotationX(-PiOver2) * Matrix4x4.CreateTranslation(10, 20, 30); 55 | ILocalSpaceBasis basis = Basis(m); 56 | 57 | var v = Vector3.Normalize(new Vector3(1, 2, 3)); 58 | Matrix4x4 inv; 59 | Matrix4x4.Invert(m, out inv); 60 | Assert.AreEqual(Vector3.Transform(v, inv), basis.LocalizePosition(v)); 61 | } 62 | 63 | [TestMethod] 64 | public void LocalRotateForwardToSideTest() 65 | { 66 | var f = new Vector3(0, 0, 1); 67 | var s = new Vector3(-1, 0, 0); 68 | 69 | Assert.AreEqual(s, LocalSpaceBasisHelpers.LocalRotateForwardToSide(null, f)); 70 | } 71 | 72 | [TestMethod] 73 | public void RegenerateOrthonormalBasisTest() 74 | { 75 | var f = Vector3.UnitZ * 2; 76 | var u = Vector3.UnitY; 77 | 78 | Vector3 s; 79 | LocalSpaceBasisHelpers.RegenerateOrthonormalBasis(f, u, out f, out s, out u); 80 | 81 | Assert.AreEqual(Vector3.UnitZ, f); 82 | Assert.AreEqual(u, Vector3.UnitY); 83 | Assert.AreEqual(Vector3.Cross(f, u), s); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /SharpSteer2.Tests/LocalityQueryProximityDatabaseTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System.Numerics; 5 | using SharpSteer2.Database; 6 | 7 | namespace SharpSteer2.Tests 8 | { 9 | [TestClass] 10 | public class LocalityQueryProximityDatabaseTest 11 | { 12 | [TestMethod] 13 | public void Construct() 14 | { 15 | var db = new LocalityQueryProximityDatabase(Vector3.Zero, new Vector3(10, 10, 10), new Vector3(2, 2, 2)); 16 | 17 | Assert.AreEqual(0, db.Count); 18 | } 19 | 20 | [TestMethod] 21 | public void AllocateToken() 22 | { 23 | var db = new LocalityQueryProximityDatabase(Vector3.Zero, new Vector3(10, 10, 10), new Vector3(2, 2, 2)); 24 | 25 | var obj = new object(); 26 | var token = db.AllocateToken(obj); 27 | token.UpdateForNewPosition(Vector3.Zero); 28 | 29 | Assert.AreEqual(1, db.Count); 30 | 31 | token.UpdateForNewPosition(Vector3.Zero); 32 | } 33 | 34 | private static ITokenForProximityDatabase CreateToken(IProximityDatabase db, Vector3 position, IDictionary lookup) 35 | { 36 | var obj = new object(); 37 | 38 | if (lookup != null) 39 | lookup.Add(obj, position); 40 | 41 | var token = db.AllocateToken(obj); 42 | token.UpdateForNewPosition(position); 43 | 44 | return token; 45 | } 46 | 47 | [TestMethod] 48 | public void LocateNeighbours() 49 | { 50 | var db = new LocalityQueryProximityDatabase(Vector3.Zero, new Vector3(10, 10, 10), new Vector3(2, 2, 2)); 51 | 52 | Dictionary positionLookup = new Dictionary(); 53 | 54 | var xyz000 = CreateToken(db, new Vector3(0, 0, 0), positionLookup); 55 | var xyz100 = CreateToken(db, new Vector3(1, 0, 0), positionLookup); 56 | CreateToken(db, new Vector3(3, 0, 0), positionLookup); 57 | 58 | var list = new List(); 59 | xyz000.FindNeighbors(Vector3.Zero, 2, list); 60 | 61 | Assert.AreEqual(2, list.Count); 62 | Assert.AreEqual(1, list.Count(a => positionLookup[a] == new Vector3(0, 0, 0))); 63 | Assert.AreEqual(1, list.Count(a => positionLookup[a] == new Vector3(1, 0, 0))); 64 | 65 | //Check tokens handle being disposed twice 66 | xyz000.Dispose(); 67 | xyz000.Dispose(); 68 | 69 | list.Clear(); 70 | xyz100.FindNeighbors(Vector3.Zero, 1.5f, list); 71 | 72 | Assert.AreEqual(1, list.Count); 73 | Assert.AreEqual(new Vector3(1, 0, 0), positionLookup[list[0]]); 74 | } 75 | 76 | [TestMethod] 77 | public void LocateNeighboursOutsideSuperbrick() 78 | { 79 | var db = new LocalityQueryProximityDatabase(Vector3.Zero, new Vector3(1, 1, 1), new Vector3(1, 1, 1)); 80 | 81 | Dictionary positionLookup = new Dictionary(); 82 | 83 | var token = CreateToken(db, new Vector3(0, 0, 0), positionLookup); 84 | CreateToken(db, new Vector3(3, 0, 0), positionLookup); 85 | CreateToken(db, new Vector3(4, 0, 0), positionLookup); 86 | 87 | var list = new List(); 88 | token.FindNeighbors(Vector3.Zero, 2, list); 89 | Assert.AreEqual(1, list.Count); 90 | 91 | list.Clear(); 92 | token.FindNeighbors(new Vector3(3, 0, 0), 0.1f, list); 93 | Assert.AreEqual(1, list.Count); 94 | 95 | list.Clear(); 96 | token.FindNeighbors(new Vector3(3, 0, 0),1.1f, list); 97 | Assert.AreEqual(2, list.Count); 98 | } 99 | 100 | [TestMethod] 101 | public void RemoveItem() 102 | { 103 | var db = new LocalityQueryProximityDatabase(Vector3.Zero, new Vector3(100, 100, 100), new Vector3(1, 1, 1)); 104 | 105 | var a = CreateToken(db, new Vector3(1, 0, 0), null); 106 | var b = CreateToken(db, new Vector3(2, 0, 0), null); 107 | 108 | Assert.AreEqual(2, db.Count); 109 | 110 | b.Dispose(); 111 | 112 | Assert.AreEqual(1, db.Count); 113 | 114 | a.Dispose(); 115 | 116 | Assert.AreEqual(0, db.Count); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /SharpSteer2.Tests/NullAnnotationTest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using System.Numerics; 3 | using SharpSteer2.Helpers; 4 | 5 | namespace SharpSteer2.Tests 6 | { 7 | [TestClass] 8 | public class NullAnnotationTest 9 | { 10 | [TestMethod] 11 | public void NullAnnotationsDoNotThrow() 12 | { 13 | var a = new NullAnnotationService(); 14 | 15 | a.AvoidCloseNeighbor(null, 0); 16 | a.AvoidNeighbor(null, 0, Vector3.Zero, Vector3.Zero); 17 | a.AvoidObstacle(0); 18 | a.Circle3D(0, Vector3.Zero, Vector3.Zero, Colors.White, 0); 19 | a.CircleOrDisk(0, Vector3.Zero, Vector3.Zero, Colors.White, 0, true, true); 20 | a.CircleOrDisk3D(0, Vector3.Zero, Vector3.Zero, Colors.White, 0, true); 21 | a.CircleOrDiskXZ(0, Vector3.Zero, Colors.White, 0, true); 22 | a.CircleXZ(0, Vector3.Zero, Colors.White, 0); 23 | a.Disk3D(0, Vector3.Zero, Vector3.Zero, Colors.White, 0); 24 | a.DiskXZ(0, Vector3.Zero, Colors.White, 0); 25 | a.Line(Vector3.Zero, Vector3.Zero, Colors.White); 26 | a.PathFollowing(Vector3.Zero, Vector3.Zero, Vector3.Zero, 0); 27 | a.VelocityAcceleration(null); 28 | a.VelocityAcceleration(null, 0); 29 | a.VelocityAcceleration(null, 0, 0); 30 | a.IsEnabled = !a.IsEnabled; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /SharpSteer2.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("SharpSteer2.Tests")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("SharpSteer2.Tests")] 12 | [assembly: AssemblyCopyright("Copyright © 2012")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("71db1166-92c5-4c45-afdd-62ad1918c2df")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | [assembly: AssemblyVersion("1.0.0.0")] 34 | [assembly: AssemblyFileVersion("1.0.0.0")] 35 | -------------------------------------------------------------------------------- /SharpSteer2.Tests/SharpSteer2.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 7 | 8 | 2.0 9 | {A7952769-CC98-43B4-99D5-E172417F4453} 10 | Library 11 | Properties 12 | SharpSteer2.Tests 13 | SharpSteer2.Tests 14 | v4.6 15 | 512 16 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 17 | 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | false 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | false 37 | 38 | 39 | 40 | 41 | 42 | 3.5 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | False 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | {724bca39-40b0-4787-9604-985e30740fd6} 69 | SharpSteer2 70 | 71 | 72 | 73 | 80 | -------------------------------------------------------------------------------- /SharpSteer2.Tests/SimpleVehicleTest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using System.Numerics; 3 | 4 | namespace SharpSteer2.Tests 5 | { 6 | [TestClass] 7 | public class SimpleVehicleTest 8 | { 9 | private readonly SimpleVehicle _vehicle = new SimpleVehicle(); 10 | 11 | [TestMethod] 12 | public void Construct() 13 | { 14 | Assert.AreEqual(Vector3.Zero, _vehicle.Acceleration); 15 | Assert.AreEqual(-Vector3.UnitZ, _vehicle.Forward); 16 | Assert.AreEqual(Vector3.Zero, _vehicle.Velocity); 17 | Assert.AreEqual(0, _vehicle.Speed); 18 | Assert.AreEqual(Vector3.Zero, _vehicle.SmoothedPosition); 19 | } 20 | 21 | [TestMethod] 22 | public void ApplyForce() 23 | { 24 | _vehicle.ApplySteeringForce(-Vector3.UnitZ, 1); 25 | 26 | Assert.AreEqual(-Vector3.UnitZ * _vehicle.Speed, _vehicle.Velocity); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SharpSteer2.Tests/SphericalObstacleTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using System.Numerics; 3 | using SharpSteer2.Obstacles; 4 | 5 | namespace SharpSteer2.Tests 6 | { 7 | [TestClass] 8 | public class SphericalObstacleTests 9 | { 10 | private readonly SphericalObstacle _obstacle = new SphericalObstacle(10, Vector3.Zero); 11 | 12 | private readonly SimpleVehicle _vehicle = new SimpleVehicle(); 13 | 14 | [TestMethod] 15 | public void SteerToAvoidReturnsZeroVectorIfThereIsNoIntersection() 16 | { 17 | _vehicle.Position = new Vector3(100, 100, 100); 18 | 19 | Assert.AreEqual(Vector3.Zero, _obstacle.SteerToAvoid(_vehicle, 1)); 20 | } 21 | 22 | [TestMethod] 23 | public void SteerToAvoidReturnsNonZeroVectorForStationaryVehicleInsideObstacle() 24 | { 25 | _vehicle.Position = new Vector3(0, 0, 1); 26 | 27 | Assert.AreNotEqual(Vector3.Zero, _obstacle.SteerToAvoid(_vehicle, 1)); 28 | } 29 | 30 | [TestMethod] 31 | public void SteerToAvoidReturnsNonZeroVectorForMovingVehicleOutsideObstacle() 32 | { 33 | _vehicle.Position = -_vehicle.Forward * 11; 34 | _vehicle.ApplySteeringForce(_vehicle.Forward, 3); 35 | 36 | var f = _obstacle.SteerToAvoid(_vehicle, 10); 37 | var dot = Vector3.Dot(_vehicle.Position - _obstacle.Center, f); 38 | 39 | Assert.IsTrue(dot >= 0); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /SharpSteer2.Tests/UtilitiesTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System.Numerics; 4 | using SharpSteer2.Helpers; 5 | 6 | namespace SharpSteer2.Tests 7 | { 8 | /// 9 | ///This is a test class for UtilitiesTest and is intended 10 | ///to contain all UtilitiesTest Unit Tests 11 | /// 12 | [TestClass] 13 | public class UtilitiesTest 14 | { 15 | [TestMethod] 16 | public void Random() 17 | { 18 | } 19 | 20 | [TestMethod] 21 | public void ScalarRandomWalk() 22 | { 23 | var rands = Enumerable.Range(1, 1000).Select(a => Utilities.ScalarRandomWalk(0, 10, -5, 5)); 24 | 25 | foreach (var rand in rands) 26 | { 27 | Assert.IsTrue(rand >= -5); 28 | Assert.IsTrue(rand <= 5); 29 | } 30 | } 31 | 32 | [TestMethod] 33 | public void BoundedRandom() 34 | { 35 | const int LOWER = -17; 36 | const int UPPER = 24; 37 | 38 | var rand = RandomHelpers.Random(LOWER, UPPER); 39 | Assert.IsTrue(LOWER <= rand); 40 | Assert.IsTrue(UPPER >= rand); 41 | } 42 | 43 | [TestMethod] 44 | public void BoundedRandomInt() 45 | { 46 | const int LOWER = -17; 47 | const int UPPER = 24; 48 | 49 | var rand = RandomHelpers.RandomInt(LOWER, UPPER); 50 | Assert.IsTrue(LOWER <= rand); 51 | Assert.IsTrue(UPPER >= rand); 52 | } 53 | 54 | [TestMethod] 55 | public void RemapIntervalChangeUpperBound() 56 | { 57 | const int A = 0; 58 | const int B = 10; 59 | 60 | const int C = 0; 61 | const int D = 20; 62 | 63 | const int X = 5; 64 | 65 | // 5 is halfway between 0->10, so result is halfway between 0->20 (i.e. 10) 66 | Assert.AreEqual(10, Utilities.RemapInterval(X, A, B, C, D)); 67 | } 68 | 69 | [TestMethod] 70 | public void RemapIntervalChangeLowerBound() 71 | { 72 | const int A = 0; 73 | const int B = 10; 74 | 75 | const int C = -10; 76 | const int D = 10; 77 | 78 | const int X = 5; 79 | 80 | // 5 is halfway between 0->10, so result is halfway between -10->10 (i.e. 0) 81 | Assert.AreEqual(0, Utilities.RemapInterval(X, A, B, C, D)); 82 | } 83 | 84 | [TestMethod] 85 | public void RemapIntervalChangeBothBounds() 86 | { 87 | const int A = 0; 88 | const int B = 10; 89 | 90 | const int C = -20; 91 | const int D = 40; 92 | 93 | const int X = 5; 94 | 95 | // 5 is halfway between 0->10, so result is halfway between -20->40 (i.e. 10) 96 | Assert.AreEqual(10, Utilities.RemapInterval(X, A, B, C, D)); 97 | } 98 | 99 | [TestMethod] 100 | public void RemapIntervalBeyondBound() 101 | { 102 | const int A = 0; 103 | const int B = 10; 104 | 105 | const int C = 0; 106 | const int D = 20; 107 | 108 | const int X = 20; 109 | 110 | // 20 is the entire range width (10) above max (10), so result is entire range width (20) above max (20) (i.e. 40) 111 | Assert.AreEqual(40, Utilities.RemapInterval(X, A, B, C, D)); 112 | } 113 | 114 | [TestMethod] 115 | public void RemapIntervalClip() 116 | { 117 | const int A = 0; 118 | const int B = 10; 119 | 120 | const int C = 0; 121 | const int D = 20; 122 | 123 | const int X = 20; 124 | 125 | Assert.AreEqual(20, Utilities.RemapIntervalClip(X, A, B, C, D)); 126 | } 127 | 128 | [TestMethod] 129 | public void IntervalComparison() 130 | { 131 | Assert.AreEqual(-1, Utilities.IntervalComparison(0, 1, 2)); 132 | Assert.AreEqual(0, Utilities.IntervalComparison(1.5f, 1, 2)); 133 | Assert.AreEqual(+1, Utilities.IntervalComparison(3, 1, 2)); 134 | } 135 | 136 | [TestMethod] 137 | public void FloatBlendIntoAccumulator() 138 | { 139 | float smoothedValue = 1; 140 | Utilities.BlendIntoAccumulator(0.5f, 2, ref smoothedValue); 141 | 142 | Assert.AreEqual(Utilities.Lerp(1, 2, 0.5f), smoothedValue); 143 | } 144 | 145 | [TestMethod] 146 | public void Vector3BlendIntoAccumulator() 147 | { 148 | Vector3 smoothedValue = Vector3.One; 149 | Utilities.BlendIntoAccumulator(0.5f, new Vector3(2, 2, 2), ref smoothedValue); 150 | 151 | Assert.AreEqual(Vector3.Lerp(Vector3.One, new Vector3(2), 0.5f), smoothedValue); 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /SharpSteer2.WinDemoContent/Fonts/SegoeUiMono.spritefont: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 | 10 | 11 | 14 | Segoe UI Mono 15 | 16 | 20 | 10 21 | 22 | 26 | 0 27 | 28 | 32 | true 33 | 34 | 38 | 39 | 40 | 44 | 45 | 46 | 53 | 54 | 55 | 56 | ~ 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /SharpSteer2.WinDemoContent/SharpSteer2.WinDemoContent.contentproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | {5057B41F-613F-4C6B-A522-42B15B54F3EF} 5 | {96E2B04D-8817-42c6-938A-82C39BA4D311};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 6 | Debug 7 | x86 8 | Library 9 | Properties 10 | v4.0 11 | v4.0 12 | bin\$(Platform)\$(Configuration) 13 | Content 14 | 15 | 16 | x86 17 | 18 | 19 | x86 20 | 21 | 22 | SharpSteer2.WinDemoContent 23 | 24 | 25 | 26 | False 27 | 28 | 29 | False 30 | 31 | 32 | False 33 | 34 | 35 | False 36 | 37 | 38 | False 39 | 40 | 41 | False 42 | 43 | 44 | 45 | 46 | SegoeUiMono 47 | FontDescriptionImporter 48 | FontDescriptionProcessor 49 | 50 | 51 | 52 | 59 | -------------------------------------------------------------------------------- /SharpSteer2.ncrunchsolution: -------------------------------------------------------------------------------- 1 | 2 | 1 3 | True 4 | true 5 | true 6 | UseDynamicAnalysis 7 | UseStaticAnalysis 8 | UseStaticAnalysis 9 | UseStaticAnalysis 10 | Run all tests automatically:BFRydWU=;Run all tests manually:BUZhbHNl;Run impacted tests automatically, others manually (experimental!):CklzSW1wYWN0ZWQ=;Run pinned tests automatically, others manually:CElzUGlubmVk 11 | 12 | 13 | -------------------------------------------------------------------------------- /SharpSteer2.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpSteer2.Tests", "SharpSteer2.Tests\SharpSteer2.Tests.csproj", "{A7952769-CC98-43B4-99D5-E172417F4453}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{274F6D7B-4D5A-419F-A0BD-5AFA2182B2C2}" 9 | ProjectSection(SolutionItems) = preProject 10 | Local.testsettings = Local.testsettings 11 | SharpSteer2.vsmdi = SharpSteer2.vsmdi 12 | TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings 13 | EndProjectSection 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpSteer2", "SharpSteer2\SharpSteer2.csproj", "{724BCA39-40B0-4787-9604-985E30740FD6}" 16 | EndProject 17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo", "Demo\Demo.csproj", "{DA0517F7-5AAE-475A-A549-02152DD20716}" 18 | EndProject 19 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo.ContentShim", "Demo.ContentShim\Demo.ContentShim.csproj", "{0001D035-FE3A-4334-9773-56D4D774A4F9}" 20 | EndProject 21 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpSteer2.WinDemoContent", "SharpSteer2.WinDemoContent\SharpSteer2.WinDemoContent.contentproj", "{5057B41F-613F-4C6B-A522-42B15B54F3EF}" 22 | EndProject 23 | Global 24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 25 | Debug|Any CPU = Debug|Any CPU 26 | Release|Any CPU = Release|Any CPU 27 | EndGlobalSection 28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 29 | {A7952769-CC98-43B4-99D5-E172417F4453}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {A7952769-CC98-43B4-99D5-E172417F4453}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {A7952769-CC98-43B4-99D5-E172417F4453}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {A7952769-CC98-43B4-99D5-E172417F4453}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {724BCA39-40B0-4787-9604-985E30740FD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {724BCA39-40B0-4787-9604-985E30740FD6}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {724BCA39-40B0-4787-9604-985E30740FD6}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {724BCA39-40B0-4787-9604-985E30740FD6}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {DA0517F7-5AAE-475A-A549-02152DD20716}.Debug|Any CPU.ActiveCfg = Debug|x86 38 | {DA0517F7-5AAE-475A-A549-02152DD20716}.Debug|Any CPU.Build.0 = Debug|x86 39 | {DA0517F7-5AAE-475A-A549-02152DD20716}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {DA0517F7-5AAE-475A-A549-02152DD20716}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {0001D035-FE3A-4334-9773-56D4D774A4F9}.Debug|Any CPU.ActiveCfg = Debug|x86 42 | {0001D035-FE3A-4334-9773-56D4D774A4F9}.Debug|Any CPU.Build.0 = Debug|x86 43 | {0001D035-FE3A-4334-9773-56D4D774A4F9}.Release|Any CPU.ActiveCfg = Release|x86 44 | {5057B41F-613F-4C6B-A522-42B15B54F3EF}.Debug|Any CPU.ActiveCfg = Debug|x86 45 | {5057B41F-613F-4C6B-A522-42B15B54F3EF}.Release|Any CPU.ActiveCfg = Release|x86 46 | EndGlobalSection 47 | GlobalSection(SolutionProperties) = preSolution 48 | HideSolutionNode = FALSE 49 | EndGlobalSection 50 | GlobalSection(TestCaseManagementSettings) = postSolution 51 | CategoryFile = SharpSteer2.vsmdi 52 | EndGlobalSection 53 | EndGlobal 54 | -------------------------------------------------------------------------------- /SharpSteer2/AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("SharpSteer2.Tests")] -------------------------------------------------------------------------------- /SharpSteer2/BaseVehicle.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System.Numerics; 12 | 13 | namespace SharpSteer2 14 | { 15 | public abstract class BaseVehicle : LocalSpace, IVehicle 16 | { 17 | public abstract float Mass { get; set; } 18 | public abstract float Radius { get; set; } 19 | public abstract Vector3 Velocity { get; } 20 | public abstract Vector3 Acceleration { get; } 21 | public abstract float Speed { get; set; } 22 | 23 | public abstract Vector3 PredictFuturePosition(float predictionTime); 24 | 25 | public abstract float MaxForce { get; } 26 | public abstract float MaxSpeed { get; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /SharpSteer2/Database/IProximityDatabase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // All rights reserved. 5 | // 6 | // This software is licensed as described in the file license.txt, which 7 | // you should have received as part of this distribution. The terms 8 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 9 | 10 | 11 | namespace SharpSteer2.Database 12 | { 13 | public interface IProximityDatabase 14 | { 15 | /// 16 | /// allocate a token to represent a given client object in this database 17 | /// 18 | /// 19 | /// 20 | ITokenForProximityDatabase AllocateToken(ContentType parentObject); 21 | 22 | /// 23 | /// returns the number of tokens in the proximity database 24 | /// 25 | int Count { get; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SharpSteer2/Database/ITokenForProximityDatabase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System; 12 | using System.Collections.Generic; 13 | using System.Numerics; 14 | 15 | namespace SharpSteer2.Database 16 | { 17 | public interface ITokenForProximityDatabase : IDisposable 18 | { 19 | /// 20 | /// the client object calls this each time its position changes 21 | /// 22 | /// 23 | void UpdateForNewPosition(Vector3 position); 24 | 25 | /// 26 | /// find all neighbors within the given sphere (as center and radius) 27 | /// 28 | /// 29 | /// 30 | /// 31 | void FindNeighbors(Vector3 center, float radius, List results); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /SharpSteer2/Database/LocalityQueryProximityDatabase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | /* ------------------------------------------------------------------ */ 12 | /* */ 13 | /* Locality Query (LQ) Facility */ 14 | /* */ 15 | /* ------------------------------------------------------------------ */ 16 | /* 17 | 18 | This utility is a spatial database which stores objects each of 19 | which is associated with a 3d point (a location in a 3d space). 20 | The points serve as the "search key" for the associated object. 21 | It is intended to efficiently answer "sphere inclusion" queries, 22 | also known as range queries: basically questions like: 23 | 24 | Which objects are within a radius R of the location L? 25 | 26 | In this context, "efficiently" means significantly faster than the 27 | naive, brute force O(n) testing of all known points. Additionally 28 | it is assumed that the objects move along unpredictable paths, so 29 | that extensive preprocessing (for example, constructing a Delaunay 30 | triangulation of the point set) may not be practical. 31 | 32 | The implementation is a "bin lattice": a 3d rectangular array of 33 | brick-shaped (rectangular parallelepipeds) regions of space. Each 34 | region is represented by a pointer to a (possibly empty) doubly- 35 | linked list of objects. All of these sub-bricks are the same 36 | size. All bricks are aligned with the global coordinate axes. 37 | 38 | Terminology used here: the region of space associated with a bin 39 | is called a sub-brick. The collection of all sub-bricks is called 40 | the super-brick. The super-brick should be specified to surround 41 | the region of space in which (almost) all the key-points will 42 | exist. If key-points move outside the super-brick everything will 43 | continue to work, but without the speed advantage provided by the 44 | spatial subdivision. For more details about how to specify the 45 | super-brick's position, size and subdivisions see lqCreateDatabase 46 | below. 47 | 48 | Overview of usage: an application using this facility would first 49 | create a database with lqCreateDatabase. For each client object 50 | the application wants to put in the database it creates a 51 | lqClientProxy and initializes it with lqInitClientProxy. When a 52 | client object moves, the application calls lqUpdateForNewLocation. 53 | To perform a query lqMapOverAllObjectsInLocality is passed an 54 | application-supplied call-back function to be applied to all 55 | client objects in the locality. See lqCallBackFunction below for 56 | more detail. The lqFindNearestNeighborWithinRadius function can 57 | be used to find a single nearest neighbor using the database. 58 | 59 | Note that "locality query" is also known as neighborhood query, 60 | neighborhood search, near neighbor search, and range query. For 61 | additional information on this and related topics see: 62 | http://www.red3d.com/cwr/boids/ips.html 63 | 64 | For some description and illustrations of this database in use, 65 | see this paper: http://www.red3d.com/cwr/papers/2000/pip.html 66 | 67 | */ 68 | 69 | using System; 70 | using System.Collections.Generic; 71 | using System.Numerics; 72 | 73 | namespace SharpSteer2.Database 74 | { 75 | /// 76 | /// A AbstractProximityDatabase-style wrapper for the LQ bin lattice system 77 | /// 78 | public class LocalityQueryProximityDatabase : IProximityDatabase where T : class 79 | { 80 | /// 81 | /// "token" to represent objects stored in the database 82 | /// 83 | private sealed class TokenType : ITokenForProximityDatabase 84 | { 85 | LocalityQueryDatabase.ClientProxy _proxy; 86 | readonly LocalityQueryDatabase _lq; 87 | 88 | public TokenType(T parentObject, LocalityQueryProximityDatabase lqsd) 89 | { 90 | _proxy = new LocalityQueryDatabase.ClientProxy(parentObject); 91 | _lq = lqsd._lq; 92 | } 93 | 94 | public void Dispose() 95 | { 96 | if (_proxy == null) 97 | return; 98 | 99 | _lq.RemoveFromBin(_proxy); 100 | _proxy = null; 101 | } 102 | 103 | // the client obj calls this each time its position changes 104 | public void UpdateForNewPosition(Vector3 p) 105 | { 106 | _lq.UpdateForNewLocation(_proxy, p); 107 | } 108 | 109 | // find all neighbors within the given sphere (as center and radius) 110 | public void FindNeighbors(Vector3 center, float radius, List results) 111 | { 112 | _lq.MapOverAllObjectsInLocality(center, radius, perNeighborCallBackFunction, results); 113 | } 114 | 115 | // called by LQ for each clientObject in the specified neighborhood: 116 | // push that clientObject onto the ContentType vector in void* 117 | // clientQueryState 118 | private static void perNeighborCallBackFunction(Object clientObject, float distanceSquared, Object clientQueryState) 119 | { 120 | List results = (List)clientQueryState; 121 | results.Add((T)clientObject); 122 | } 123 | } 124 | 125 | readonly LocalityQueryDatabase _lq; 126 | 127 | // constructor 128 | public LocalityQueryProximityDatabase(Vector3 center, Vector3 dimensions, Vector3 divisions) 129 | { 130 | Vector3 halfsize = dimensions * 0.5f; 131 | Vector3 origin = center - halfsize; 132 | 133 | _lq = new LocalityQueryDatabase(origin, dimensions, (int)Math.Round(divisions.X), (int)Math.Round(divisions.Y), (int)Math.Round(divisions.Z)); 134 | } 135 | 136 | // allocate a token to represent a given client obj in this database 137 | public ITokenForProximityDatabase AllocateToken(T parentObject) 138 | { 139 | return new TokenType(parentObject, this); 140 | } 141 | 142 | // count the number of tokens currently in the database 143 | public int Count 144 | { 145 | get 146 | { 147 | int count = 0; 148 | _lq.MapOverAllObjects((a, b, c) => count++, count); 149 | return count; 150 | } 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /SharpSteer2/Helpers/Colors.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace SharpSteer2.Helpers 4 | { 5 | internal static class Colors 6 | { 7 | public static readonly Vector3 White = new Vector3(1, 1, 1); 8 | 9 | public static readonly Vector3 Orange = new Vector3(1, 165f / 255f, 0); 10 | 11 | public static readonly Vector3 OrangeRed = new Vector3(1, 69f / 255f, 9); 12 | 13 | public static readonly Vector3 Gold = new Vector3(1, 215f / 255f, 0); 14 | 15 | public static readonly Vector3 Red = new Vector3(1, 0, 0); 16 | 17 | public static readonly Vector3 Green = new Vector3(0, 1, 0); 18 | 19 | public static readonly Vector3 DarkGray = new Vector3(87f / 255f, 87f / 255f, 87f / 255f); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SharpSteer2/Helpers/MatrixHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace SharpSteer2.Helpers 5 | { 6 | public static class MatrixHelpers 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static void Right(ref Matrix4x4 m, ref Vector3 v) 10 | { 11 | m.M11 = v.X; 12 | m.M12 = v.Y; 13 | m.M13 = v.Z; 14 | } 15 | 16 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 17 | public static Vector3 Right(ref Matrix4x4 m) 18 | { 19 | return new Vector3 { 20 | X = m.M11, 21 | Y = m.M12, 22 | Z = m.M13 23 | }; 24 | } 25 | 26 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 27 | public static void Up(ref Matrix4x4 m, ref Vector3 v) 28 | { 29 | m.M21 = v.X; 30 | m.M22 = v.Y; 31 | m.M23 = v.Z; 32 | } 33 | 34 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 35 | public static Vector3 Up(ref Matrix4x4 m) 36 | { 37 | return new Vector3 { 38 | X = m.M21, 39 | Y = m.M22, 40 | Z = m.M23 41 | }; 42 | } 43 | 44 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 45 | public static void Backward(ref Matrix4x4 m, ref Vector3 v) 46 | { 47 | m.M31 = v.X; 48 | m.M32 = v.Y; 49 | m.M33 = v.Z; 50 | } 51 | 52 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 53 | public static Vector3 Backward(ref Matrix4x4 m) 54 | { 55 | return new Vector3 { 56 | X = m.M31, 57 | Y = m.M32, 58 | Z = m.M33 59 | }; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /SharpSteer2/Helpers/PathwayHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using SharpSteer2.Pathway; 3 | 4 | namespace SharpSteer2.Helpers 5 | { 6 | public static class PathwayHelpers 7 | { 8 | /// 9 | /// is the given point inside the path tube? 10 | /// 11 | /// 12 | /// 13 | /// 14 | public static bool IsInsidePath(this IPathway pathway, Vector3 point) 15 | { 16 | float outside; 17 | Vector3 tangent; 18 | pathway.MapPointToPath(point, out tangent, out outside); 19 | return outside < 0; 20 | } 21 | 22 | /// 23 | /// how far outside path tube is the given point? (negative is inside) 24 | /// 25 | /// 26 | /// 27 | /// 28 | public static float HowFarOutsidePath(this IPathway pathway, Vector3 point) 29 | { 30 | float outside; 31 | Vector3 tangent; 32 | pathway.MapPointToPath(point, out tangent, out outside); 33 | return outside; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SharpSteer2/Helpers/RandomHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SharpSteer2.Helpers 4 | { 5 | public class RandomHelpers 6 | { 7 | [ThreadStatic] 8 | private static Random _rng; 9 | 10 | private static Random rng 11 | { 12 | get 13 | { 14 | if (_rng == null) 15 | _rng = new Random(); 16 | return _rng; 17 | } 18 | } 19 | 20 | /// 21 | /// Returns a float randomly distributed between 0 and 1 22 | /// 23 | /// 24 | public static float Random() 25 | { 26 | return (float)rng.NextDouble(); 27 | } 28 | 29 | /// 30 | /// Returns a float randomly distributed between lowerBound and upperBound 31 | /// 32 | /// 33 | /// 34 | /// 35 | public static float Random(float lowerBound, float upperBound) 36 | { 37 | return lowerBound + (Random() * (upperBound - lowerBound)); 38 | } 39 | 40 | public static int RandomInt(int min, int max) 41 | { 42 | return (int)Random(min, max); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /SharpSteer2/Helpers/Utilities.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System.Numerics; 12 | 13 | namespace SharpSteer2.Helpers 14 | { 15 | public class Utilities 16 | { 17 | /// 18 | /// Linearly interpolate from A to B by amount T 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | public static float Lerp(float a, float b, float t) 25 | { 26 | return a + (b - a) * t; 27 | } 28 | 29 | /// 30 | /// Clamp value between min and max 31 | /// 32 | /// 33 | /// 34 | /// 35 | /// 36 | public static float Clamp(float value, float min, float max) 37 | { 38 | if (value < min) 39 | return min; 40 | if (value > max) 41 | return max; 42 | return value; 43 | } 44 | 45 | /// 46 | /// remap a value specified relative to a pair of bounding values to the corresponding value relative to another pair of bounds. 47 | /// 48 | /// Inspired by (dyna:remap-interval y y0 y1 z0 z1) 49 | /// A value 50 | /// Starting lower bound 51 | /// Starting upper bound 52 | /// Ending lower bound 53 | /// Ending upper bound 54 | /// 55 | public static float RemapInterval(float x, float in0, float in1, float out0, float out1) 56 | { 57 | // uninterpolate: what is x relative to the interval in0:in1? 58 | float relative = (x - in0) / (in1 - in0); 59 | 60 | // now interpolate between output interval based on relative x 61 | return Lerp(out0, out1, relative); 62 | } 63 | 64 | /// 65 | /// Like remapInterval but the result is clipped to remain between out0 and out1 66 | /// 67 | /// A value 68 | /// Starting lower bound 69 | /// Starting upper bound 70 | /// Ending lower bound 71 | /// Ending upper bound 72 | /// 73 | public static float RemapIntervalClip(float x, float in0, float in1, float out0, float out1) 74 | { 75 | // uninterpolate: what is x relative to the interval in0:in1? 76 | float relative = (x - in0) / (in1 - in0); 77 | 78 | // now interpolate between output interval based on relative x 79 | return Lerp(out0, out1, Clamp(relative, 0, 1)); 80 | } 81 | 82 | /// 83 | /// classify a value relative to the interval between two bounds: 84 | /// returns -1 when below the lower bound, returns 0 when between the bounds (inside the interval), returns +1 when above the upper bound 85 | /// 86 | /// 87 | /// 88 | /// 89 | /// 90 | public static int IntervalComparison(float x, float lowerBound, float upperBound) 91 | { 92 | if (x < lowerBound) return -1; 93 | if (x > upperBound) return +1; 94 | return 0; 95 | } 96 | 97 | public static float ScalarRandomWalk(float initial, float walkspeed, float min, float max) 98 | { 99 | float next = initial + (((RandomHelpers.Random() * 2) - 1) * walkspeed); 100 | if (next < min) return min; 101 | if (next > max) return max; 102 | return next; 103 | } 104 | 105 | /// 106 | /// blends new values into an accumulator to produce a smoothed time series 107 | /// 108 | /// 109 | /// Modifies its third argument, a reference to the float accumulator holding 110 | /// the "smoothed time series." 111 | /// 112 | /// The first argument (smoothRate) is typically made proportional to "dt" the 113 | /// simulation time step. If smoothRate is 0 the accumulator will not change, 114 | /// if smoothRate is 1 the accumulator will be set to the new value with no 115 | /// smoothing. Useful values are "near zero". 116 | /// 117 | /// 118 | /// 119 | /// 120 | /// blendIntoAccumulator (dt * 0.4f, currentFPS, smoothedFPS) 121 | public static void BlendIntoAccumulator(float smoothRate, float newValue, ref float smoothedAccumulator) 122 | { 123 | smoothedAccumulator = Lerp(smoothedAccumulator, newValue, Clamp(smoothRate, 0, 1)); 124 | } 125 | 126 | public static void BlendIntoAccumulator(float smoothRate, Vector3 newValue, ref Vector3 smoothedAccumulator) 127 | { 128 | smoothedAccumulator = Vector3.Lerp(smoothedAccumulator, newValue, Clamp(smoothRate, 0, 1)); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /SharpSteer2/IFlowField.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace SharpSteer2 4 | { 5 | /// 6 | /// A flow field which can be sampled at arbitrary locations 7 | /// 8 | public interface IFlowField 9 | { 10 | /// 11 | /// Sample the flow field at the given location 12 | /// 13 | /// 14 | /// 15 | Vector3 Sample(Vector3 location); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /SharpSteer2/ILocalSpaceBasis.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System.Numerics; 12 | 13 | namespace SharpSteer2 14 | { 15 | /// 16 | /// transformation as three orthonormal unit basis vectors and the 17 | /// origin of the local space. These correspond to the "rows" of 18 | /// a 3x4 transformation matrix with [0 0 0 1] as the final column 19 | /// 20 | public interface ILocalSpaceBasis 21 | { 22 | /// 23 | /// side-pointing unit basis vector 24 | /// 25 | Vector3 Side { get; } 26 | 27 | /// 28 | /// upward-pointing unit basis vector 29 | /// 30 | Vector3 Up { get; } 31 | 32 | /// 33 | /// forward-pointing unit basis vector 34 | /// 35 | Vector3 Forward { get; } 36 | 37 | /// 38 | /// origin of local space 39 | /// 40 | Vector3 Position { get; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /SharpSteer2/IVehicle.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System.Numerics; 12 | 13 | namespace SharpSteer2 14 | { 15 | public interface IVehicle : ILocalSpaceBasis 16 | { 17 | /// 18 | /// mass (defaults to unity so acceleration=force) 19 | /// 20 | float Mass { get; } 21 | 22 | /// 23 | /// size of bounding sphere, for obstacle avoidance, etc. 24 | /// 25 | float Radius { get; } 26 | 27 | /// 28 | /// velocity of vehicle 29 | /// 30 | Vector3 Velocity { get; } 31 | 32 | /// 33 | /// Gets the acceleration of the vehicle. 34 | /// 35 | Vector3 Acceleration { get; } 36 | 37 | /// 38 | /// speed of vehicle (may be faster than taking magnitude of velocity) 39 | /// 40 | float Speed { get; } 41 | 42 | /// 43 | /// predict position of this vehicle at some time in the future (assumes velocity remains constant) 44 | /// 45 | /// 46 | /// 47 | Vector3 PredictFuturePosition(float predictionTime); 48 | 49 | /// 50 | /// the maximum steering force this vehicle can apply 51 | /// 52 | float MaxForce { get; } 53 | 54 | /// 55 | /// the maximum speed this vehicle is allowed to move 56 | /// 57 | float MaxSpeed { get; } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /SharpSteer2/LocalSpace.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System.Numerics; 12 | using SharpSteer2.Helpers; 13 | 14 | namespace SharpSteer2 15 | { 16 | /// 17 | /// transformation as three orthonormal unit basis vectors and the 18 | /// origin of the local space. These correspond to the "rows" of 19 | /// a 3x4 transformation matrix with [0 0 0 1] as the final column 20 | /// 21 | public class LocalSpaceBasis 22 | : ILocalSpaceBasis 23 | { 24 | protected Vector3 SideField; 25 | 26 | /// 27 | /// side-pointing unit basis vector 28 | /// 29 | public Vector3 Side 30 | { 31 | get { return SideField; } 32 | set { SideField = value; } 33 | } 34 | 35 | protected Vector3 UpField; 36 | 37 | /// 38 | /// upward-pointing unit basis vector 39 | /// 40 | public Vector3 Up 41 | { 42 | get { return UpField; } 43 | set { UpField = value; } 44 | } 45 | 46 | protected Vector3 ForwardField; 47 | 48 | /// 49 | /// forward-pointing unit basis vector 50 | /// 51 | public Vector3 Forward 52 | { 53 | get { return ForwardField; } 54 | set { ForwardField = value; } 55 | } 56 | 57 | protected Vector3 PositionField; 58 | 59 | /// 60 | /// origin of local space 61 | /// 62 | public Vector3 Position 63 | { 64 | get { return PositionField; } 65 | set { PositionField = value; } 66 | } 67 | } 68 | 69 | /// 70 | /// LocalSpaceMixin is a mixin layer, a class template with a paramterized base 71 | /// class. Allows "LocalSpace-ness" to be layered on any class. 72 | /// 73 | public class LocalSpace : LocalSpaceBasis 74 | { 75 | public LocalSpace() 76 | { 77 | ResetLocalSpace(); 78 | } 79 | 80 | public LocalSpace(Vector3 up, Vector3 forward, Vector3 position) 81 | { 82 | Up = up; 83 | Forward = forward; 84 | Position = position; 85 | SetUnitSideFromForwardAndUp(); 86 | } 87 | 88 | public LocalSpace(Matrix4x4 transformation) 89 | { 90 | LocalSpaceBasisHelpers.FromMatrix(transformation, out ForwardField, out SideField, out UpField, out PositionField); 91 | } 92 | 93 | // ------------------------------------------------------------------------ 94 | // reset transform: set local space to its identity state, equivalent to a 95 | // 4x4 homogeneous transform like this: 96 | // 97 | // [ X 0 0 0 ] 98 | // [ 0 1 0 0 ] 99 | // [ 0 0 1 0 ] 100 | // [ 0 0 0 1 ] 101 | // 102 | // where X is 1 for a left-handed system and -1 for a right-handed system. 103 | public void ResetLocalSpace() 104 | { 105 | LocalSpaceBasisHelpers.ResetLocalSpace(out ForwardField, out SideField, out UpField, out PositionField); 106 | } 107 | 108 | // ------------------------------------------------------------------------ 109 | // set "side" basis vector to normalized cross product of forward and up 110 | public void SetUnitSideFromForwardAndUp() 111 | { 112 | LocalSpaceBasisHelpers.SetUnitSideFromForwardAndUp(ref ForwardField, out SideField, ref UpField); 113 | } 114 | 115 | // ------------------------------------------------------------------------ 116 | // regenerate the orthonormal basis vectors given a new forward 117 | //(which is expected to have unit length) 118 | public void RegenerateOrthonormalBasisUF(Vector3 newUnitForward) 119 | { 120 | LocalSpaceBasisHelpers.RegenerateOrthonormalBasisUF(newUnitForward, out ForwardField, out SideField, ref UpField); 121 | } 122 | 123 | // for when the new forward is NOT know to have unit length 124 | public void RegenerateOrthonormalBasis(Vector3 newForward) 125 | { 126 | LocalSpaceBasisHelpers.RegenerateOrthonormalBasis(newForward, out ForwardField, out SideField, ref UpField); 127 | } 128 | 129 | // for supplying both a new forward and and new up 130 | public void RegenerateOrthonormalBasis(Vector3 newForward, Vector3 newUp) 131 | { 132 | LocalSpaceBasisHelpers.RegenerateOrthonormalBasis(newForward, newUp, out ForwardField, out SideField, out UpField); 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /SharpSteer2/NullAnnotationService.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.Numerics; 3 | 4 | namespace SharpSteer2 5 | { 6 | class NullAnnotationService 7 | :IAnnotationService 8 | { 9 | public bool IsEnabled 10 | { 11 | get 12 | { 13 | return false; 14 | } 15 | set 16 | { 17 | } 18 | } 19 | 20 | public void Line(Vector3 startPoint, Vector3 endPoint, Vector3 color, float opacity = 1) 21 | { 22 | 23 | } 24 | 25 | public void CircleXZ(float radius, Vector3 center, Vector3 color, int segments) 26 | { 27 | 28 | } 29 | 30 | public void DiskXZ(float radius, Vector3 center, Vector3 color, int segments) 31 | { 32 | 33 | } 34 | 35 | public void Circle3D(float radius, Vector3 center, Vector3 axis, Vector3 color, int segments) 36 | { 37 | 38 | } 39 | 40 | public void Disk3D(float radius, Vector3 center, Vector3 axis, Vector3 color, int segments) 41 | { 42 | 43 | } 44 | 45 | public void CircleOrDiskXZ(float radius, Vector3 center, Vector3 color, int segments, bool filled) 46 | { 47 | 48 | } 49 | 50 | public void CircleOrDisk3D(float radius, Vector3 center, Vector3 axis, Vector3 color, int segments, bool filled) 51 | { 52 | 53 | } 54 | 55 | public void CircleOrDisk(float radius, Vector3 axis, Vector3 center, Vector3 color, int segments, bool filled, bool in3D) 56 | { 57 | 58 | } 59 | 60 | public void AvoidObstacle(float minDistanceToCollision) 61 | { 62 | 63 | } 64 | 65 | public void PathFollowing(Vector3 future, Vector3 onPath, Vector3 target, float outside) 66 | { 67 | 68 | } 69 | 70 | public void AvoidCloseNeighbor(IVehicle other, float additionalDistance) 71 | { 72 | 73 | } 74 | 75 | public void AvoidNeighbor(IVehicle threat, float steer, Vector3 ourFuture, Vector3 threatFuture) 76 | { 77 | 78 | } 79 | 80 | public void VelocityAcceleration(IVehicle vehicle) 81 | { 82 | 83 | } 84 | 85 | public void VelocityAcceleration(IVehicle vehicle, float maxLength) 86 | { 87 | 88 | } 89 | 90 | public void VelocityAcceleration(IVehicle vehicle, float maxLengthAcceleration, float maxLengthVelocity) 91 | { 92 | 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /SharpSteer2/Obstacles/IObstacle.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System.Numerics; 12 | 13 | namespace SharpSteer2.Obstacles 14 | { 15 | /// 16 | /// Obstacle: a pure virtual base class for an abstract shape in space, to be 17 | /// used with obstacle avoidance. 18 | /// 19 | public interface IObstacle 20 | { 21 | Vector3 SteerToAvoid(IVehicle v, float minTimeToCollision); 22 | 23 | float? NextIntersection(IVehicle vehicle); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SharpSteer2/Obstacles/SphericalObstacle.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System; 12 | using System.Numerics; 13 | using SharpSteer2.Helpers; 14 | 15 | namespace SharpSteer2.Obstacles 16 | { 17 | /// 18 | /// SphericalObstacle a simple concrete type of obstacle. 19 | /// 20 | public class SphericalObstacle : IObstacle 21 | { 22 | public float Radius; 23 | public Vector3 Center; 24 | 25 | public SphericalObstacle() 26 | : this(1, Vector3.Zero) 27 | { 28 | } 29 | 30 | public SphericalObstacle(float r, Vector3 c) 31 | { 32 | Radius = r; 33 | Center = c; 34 | } 35 | 36 | // xxx couldn't this be made more compact using localizePosition? 37 | /// 38 | /// Checks for intersection of the given spherical obstacle with a 39 | /// volume of "likely future vehicle positions": a cylinder along the 40 | /// current path, extending minTimeToCollision seconds along the 41 | /// forward axis from current position. 42 | /// 43 | /// If they intersect, a collision is imminent and this function returns 44 | /// a steering force pointing laterally away from the obstacle's center. 45 | /// 46 | /// Returns a zero vector if the obstacle is outside the cylinder 47 | /// 48 | /// 49 | /// 50 | /// 51 | public Vector3 SteerToAvoid(IVehicle v, float minTimeToCollision) 52 | { 53 | // Capsule x Sphere collision detection 54 | //http://www.altdev.co/2011/04/26/more-collision-detection-for-dummies/ 55 | 56 | var capStart = v.Position; 57 | var capEnd = v.PredictFuturePosition(minTimeToCollision); 58 | 59 | var alongCap = capEnd - capStart; 60 | var capLength = alongCap.Length(); 61 | 62 | //If the vehicle is going very slowly then simply test vehicle sphere against obstacle sphere 63 | if (capLength <= 0.05) 64 | { 65 | var distance = Vector3.Distance(Center, v.Position); 66 | if (distance < Radius + v.Radius) 67 | return (v.Position - Center); 68 | return Vector3.Zero; 69 | } 70 | 71 | var capAxis = alongCap / capLength; 72 | 73 | //Project vector onto capsule axis 74 | var b = Utilities.Clamp(Vector3.Dot(Center - capStart, capAxis), 0, capLength); 75 | 76 | //Get point on axis (closest point to sphere center) 77 | var r = capStart + capAxis * b; 78 | 79 | //Get distance from circle center to closest point 80 | var dist = Vector3.Distance(Center, r); 81 | 82 | //Basic sphere sphere collision about the closest point 83 | var inCircle = dist < Radius + v.Radius; 84 | if (!inCircle) 85 | return Vector3.Zero; 86 | 87 | //avoidance vector calculation 88 | Vector3 avoidance = Vector3Helpers.PerpendicularComponent(v.Position - Center, v.Forward); 89 | //if no avoidance was calculated this is because the vehicle is moving exactly forward towards the sphere, add in some random sideways deflection 90 | if (avoidance == Vector3.Zero) 91 | avoidance = -v.Forward + v.Side * 0.01f * RandomHelpers.Random(); 92 | 93 | avoidance = Vector3.Normalize(avoidance); 94 | avoidance *= v.MaxForce; 95 | avoidance += v.Forward * v.MaxForce * 0.75f; 96 | return avoidance; 97 | } 98 | 99 | // xxx experiment cwr 9-6-02 100 | public float? NextIntersection(IVehicle vehicle) 101 | { 102 | // This routine is based on the Paul Bourke's derivation in: 103 | // Intersection of a Line and a Sphere (or circle) 104 | // http://www.swin.edu.au/astronomy/pbourke/geometry/sphereline/ 105 | 106 | // find "local center" (lc) of sphere in boid's coordinate space 107 | Vector3 lc = vehicle.LocalizePosition(Center); 108 | 109 | // computer line-sphere intersection parameters 110 | float b = -2 * lc.Z; 111 | var totalRadius = Radius + vehicle.Radius; 112 | float c = (lc.X * lc.X) + (lc.Y * lc.Y) + (lc.Z * lc.Z) - (totalRadius * totalRadius); 113 | float d = (b * b) - (4 * c); 114 | 115 | // when the path does not intersect the sphere 116 | if (d < 0) 117 | return null; 118 | 119 | // otherwise, the path intersects the sphere in two points with 120 | // parametric coordinates of "p" and "q". 121 | // (If "d" is zero the two points are coincident, the path is tangent) 122 | float s = (float)Math.Sqrt(d); 123 | float p = (-b + s) / 2; 124 | float q = (-b - s) / 2; 125 | 126 | // both intersections are behind us, so no potential collisions 127 | if ((p < 0) && (q < 0)) 128 | return null; 129 | 130 | // at least one intersection is in front of us 131 | return 132 | ((p > 0) && (q > 0)) ? 133 | // both intersections are in front of us, find nearest one 134 | ((p < q) ? p : q) : 135 | // otherwise only one intersections is in front, select it 136 | ((p > 0) ? p : q); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /SharpSteer2/Pathway/GatewayPathway.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using System.Collections.Generic; 3 | 4 | namespace SharpSteer2.Pathway 5 | { 6 | /// 7 | /// A path consisting of a series of gates which must be passed through 8 | /// 9 | public class GatewayPathway 10 | : IPathway 11 | { 12 | public PolylinePathway Centerline 13 | { 14 | get 15 | { 16 | return _trianglePathway.Centerline; 17 | } 18 | } 19 | 20 | private readonly TrianglePathway _trianglePathway; 21 | public TrianglePathway TrianglePathway 22 | { 23 | get 24 | { 25 | return _trianglePathway; 26 | } 27 | } 28 | 29 | public GatewayPathway(IEnumerable gateways, bool cyclic = false) 30 | { 31 | List triangles = new List(); 32 | 33 | bool first = true; 34 | Gateway previous = default(Gateway); 35 | Vector3 previousNormalized = Vector3.Zero; 36 | foreach (var gateway in gateways) 37 | { 38 | var n = Vector3.Normalize(gateway.B - gateway.A); 39 | 40 | if (!first) 41 | { 42 | if (Vector3.Dot(n, previousNormalized) < 0) 43 | { 44 | triangles.Add(new TrianglePathway.Triangle(previous.A, previous.B, gateway.A)); 45 | triangles.Add(new TrianglePathway.Triangle(previous.A, gateway.A, gateway.B)); 46 | } 47 | else 48 | { 49 | triangles.Add(new TrianglePathway.Triangle(previous.A, previous.B, gateway.A)); 50 | triangles.Add(new TrianglePathway.Triangle(previous.B, gateway.A, gateway.B)); 51 | } 52 | } 53 | first = false; 54 | 55 | previousNormalized = n; 56 | previous = gateway; 57 | } 58 | 59 | _trianglePathway = new TrianglePathway(triangles, cyclic); 60 | 61 | } 62 | 63 | public struct Gateway 64 | { 65 | public readonly Vector3 A; 66 | public readonly Vector3 B; 67 | 68 | public Gateway(Vector3 a, Vector3 b) 69 | : this() 70 | { 71 | A = a; 72 | B = b; 73 | } 74 | } 75 | 76 | public Vector3 MapPointToPath(Vector3 point, out Vector3 tangent, out float outside) 77 | { 78 | return _trianglePathway.MapPointToPath(point, out tangent, out outside); 79 | } 80 | 81 | public Vector3 MapPathDistanceToPoint(float pathDistance) 82 | { 83 | return _trianglePathway.MapPathDistanceToPoint(pathDistance); 84 | } 85 | 86 | public float MapPointToPathDistance(Vector3 point) 87 | { 88 | return _trianglePathway.MapPointToPathDistance(point); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /SharpSteer2/Pathway/IPathway.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace SharpSteer2.Pathway 4 | { 5 | public interface IPathway 6 | { 7 | /// 8 | /// Given an arbitrary point ("A"), returns the nearest point ("P") on 9 | /// this path. Also returns, via output arguments, the path tangent at 10 | /// P and a measure of how far A is outside the Pathway's "tube". Note 11 | /// that a negative distance indicates A is inside the Pathway. 12 | /// 13 | /// 14 | /// 15 | /// 16 | /// 17 | Vector3 MapPointToPath(Vector3 point, out Vector3 tangent, out float outside); 18 | 19 | /// 20 | /// given a distance along the path, convert it to a point on the path 21 | /// 22 | /// 23 | /// 24 | Vector3 MapPathDistanceToPoint(float pathDistance); 25 | 26 | /// 27 | /// Given an arbitrary point, convert it to a distance along the path. 28 | /// 29 | /// 30 | /// 31 | float MapPointToPathDistance(Vector3 point); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /SharpSteer2/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("SharpSteer2")] 8 | [assembly: AssemblyProduct("SharpSteer2")] 9 | [assembly: AssemblyDescription("A .Net Port of OpenSteer")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyCopyright("Copyright © 2007")] 12 | [assembly: AssemblyTrademark("")] 13 | [assembly: AssemblyCulture("")] 14 | 15 | // Setting ComVisible to false makes the types in this assembly not visible 16 | // to COM components. 17 | // This should never be true for Xbox 360 assemblies. 18 | [assembly: ComVisible(false)] 19 | 20 | // The following GUID is for the ID of the typelib if this project is exposed to COM 21 | [assembly: Guid("0ca5925b-429d-4a61-b21a-cbf4c9807e42")] 22 | 23 | // Version information for an assembly consists of the following four values: 24 | // 25 | // Major Version 26 | // Minor Version 27 | // Build Number 28 | // Revision 29 | // 30 | [assembly: AssemblyVersion("10.0.0")] -------------------------------------------------------------------------------- /SharpSteer2/SharpSteer2.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {724BCA39-40B0-4787-9604-985E30740FD6} 8 | Library 9 | Properties 10 | SharpSteer2 11 | SharpSteer2 12 | v4.6 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 86 | -------------------------------------------------------------------------------- /SharpSteer2/SteerLibrary.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2002-2003, Sony Computer Entertainment America 2 | // Copyright (c) 2002-2003, Craig Reynolds 3 | // Copyright (C) 2007 Bjoern Graf 4 | // Copyright (C) 2007 Michael Coles 5 | // All rights reserved. 6 | // 7 | // This software is licensed as described in the file license.txt, which 8 | // you should have received as part of this distribution. The terms 9 | // are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx. 10 | 11 | using System.Collections.Generic; 12 | using System.Numerics; 13 | using SharpSteer2.Helpers; 14 | using SharpSteer2.Obstacles; 15 | using SharpSteer2.Pathway; 16 | 17 | namespace SharpSteer2 18 | { 19 | public abstract class SteerLibrary : BaseVehicle 20 | { 21 | protected IAnnotationService annotation { get; private set; } 22 | 23 | // Constructor: initializes state 24 | protected SteerLibrary(IAnnotationService annotationService = null) 25 | { 26 | annotation = annotationService ?? new NullAnnotationService(); 27 | 28 | // set inital state 29 | Reset(); 30 | } 31 | 32 | // reset state 33 | public virtual void Reset() 34 | { 35 | // initial state of wander behavior 36 | _wanderSide = 0; 37 | _wanderUp = 0; 38 | } 39 | 40 | #region steering behaviours 41 | private float _wanderSide; 42 | private float _wanderUp; 43 | protected Vector3 SteerForWander(float dt) 44 | { 45 | return this.SteerForWander(dt, ref _wanderSide, ref _wanderUp); 46 | } 47 | 48 | protected Vector3 SteerForFlee(Vector3 target) 49 | { 50 | return this.SteerForFlee(target, MaxSpeed); 51 | } 52 | 53 | protected Vector3 SteerForSeek(Vector3 target) 54 | { 55 | return this.SteerForSeek(target, MaxSpeed); 56 | } 57 | 58 | protected Vector3 SteerForArrival(Vector3 target, float slowingDistance) 59 | { 60 | return this.SteerForArrival(target, MaxSpeed, slowingDistance, annotation); 61 | } 62 | 63 | protected Vector3 SteerToFollowFlowField(IFlowField field, float predictionTime) 64 | { 65 | return this.SteerToFollowFlowField(field, MaxSpeed, predictionTime, annotation); 66 | } 67 | 68 | protected Vector3 SteerToFollowPath(bool direction, float predictionTime, IPathway path) 69 | { 70 | return this.SteerToFollowPath(direction, predictionTime, path, MaxSpeed, annotation); 71 | } 72 | 73 | protected Vector3 SteerToStayOnPath(float predictionTime, IPathway path) 74 | { 75 | return this.SteerToStayOnPath(predictionTime, path, MaxSpeed, annotation); 76 | } 77 | 78 | protected Vector3 SteerToAvoidObstacle(float minTimeToCollision, IObstacle obstacle) 79 | { 80 | return this.SteerToAvoidObstacle(minTimeToCollision, obstacle, annotation); 81 | } 82 | 83 | protected Vector3 SteerToAvoidObstacles(float minTimeToCollision, IEnumerable obstacles) 84 | { 85 | return this.SteerToAvoidObstacles(minTimeToCollision, obstacles, annotation); 86 | } 87 | 88 | protected Vector3 SteerToAvoidNeighbors(float minTimeToCollision, IEnumerable others) 89 | { 90 | return this.SteerToAvoidNeighbors(minTimeToCollision, others, annotation); 91 | } 92 | 93 | protected Vector3 SteerToAvoidCloseNeighbors(float minSeparationDistance, IEnumerable others) where TVehicle : IVehicle 94 | { 95 | return this.SteerToAvoidCloseNeighbors(minSeparationDistance, others, annotation); 96 | } 97 | 98 | protected Vector3 SteerForSeparation(float maxDistance, float cosMaxAngle, IEnumerable flock) 99 | { 100 | return this.SteerForSeparation(maxDistance, cosMaxAngle, flock, annotation); 101 | } 102 | 103 | protected Vector3 SteerForAlignment(float maxDistance, float cosMaxAngle, IEnumerable flock) 104 | { 105 | return this.SteerForAlignment(maxDistance, cosMaxAngle, flock, annotation); 106 | } 107 | 108 | protected Vector3 SteerForCohesion(float maxDistance, float cosMaxAngle, IEnumerable flock) 109 | { 110 | return this.SteerForCohesion(maxDistance, cosMaxAngle, flock, annotation); 111 | } 112 | 113 | protected Vector3 SteerForPursuit(IVehicle quarry, float maxPredictionTime = float.MaxValue) 114 | { 115 | return this.SteerForPursuit(quarry, maxPredictionTime, MaxSpeed, annotation); 116 | } 117 | 118 | protected Vector3 SteerForEvasion(IVehicle menace, float maxPredictionTime) 119 | { 120 | return this.SteerForEvasion(menace, maxPredictionTime, MaxSpeed, annotation); 121 | } 122 | 123 | protected Vector3 SteerForTargetSpeed(float targetSpeed) 124 | { 125 | return this.SteerForTargetSpeed(targetSpeed, MaxForce, annotation); 126 | } 127 | #endregion 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /push-all.ps1: -------------------------------------------------------------------------------- 1 | function Push-Nuget($path, $csproj) { 2 | $fullPathToCsprog = Join-Path -Path $path -ChildPath $csproj -resolve; 3 | 4 | nuget pack $fullPathToCsprog -Prop Configuration=Release -IncludeReferencedProjects 5 | 6 | get-childitem -Filter *.nupkg -name | foreach ($_) { 7 | Write-Host "Pushing " $_ -backgroundcolor darkgreen -foregroundcolor white; 8 | 9 | nuget push $_ 10 | Remove-Item $_ 11 | 12 | Write-Host "Done " $_ -backgroundcolor darkgreen -foregroundcolor white; 13 | } 14 | } 15 | 16 | Push-Nuget "SharpSteer2" "SharpSteer2.csproj" -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | SharpSteer is a C# port of OpenSteer. Like OpenSteer, the aim of SharpSteer is to help construct steering behaviors for autonomous characters in games and animation. 2 | 3 | Like OpenSteer, SharpSteer provides a XNA-based application which demonstrates predefined steering behaviors. The user can quickly prototype, visualize, annotate and debug new steering behaviors by writing a plug-in for this Demo application. 4 | 5 | This fork of SharpSteer includes: 6 | 7 | - Proper use of C# features such as extension methods to make the library easier to use. 8 | - Changes to improve code quality/neatness. 9 | - Total separation of the demo and the library applications. 10 | - Some behaviours mentioned in the [original paper](http://www.red3d.com/cwr/papers/1999/gdc99steer.html) but never implemented in OpenSteer. 11 | - Good intentions to have 100% unit test coverage (lots of work needed here). 12 | - Modified to completely remove XNA dependency from the library 13 | 14 | ### Nuget 15 | 16 | SharpSteer2 is [available](https://www.nuget.org/packages/SharpSteer2/) as a nuget package. Package releases use [semantic versioning](http://semver.org/). 17 | 18 | ### Documentation 19 | 20 | The original steering behaviours are documented [here](http://www.red3d.com/cwr/papers/1999/gdc99steer.html) --------------------------------------------------------------------------------