Beispiel #1
0
        private void Timer_Tick(object sender, EventArgs e)
        {
            _timer.IsEnabled = false;
            DateTime startTime = DateTime.UtcNow;

            MapOctree snapshot = _map.LatestSnapshot;

            if (snapshot == null || (_lastSnapshotToken != null && snapshot.Token == _lastSnapshotToken.Value))
            {
                // There is nothing to do, rig the timer to try again later
                ScheduleNextTick(startTime);
                return;
            }

            _lastSnapshotToken = snapshot.Token;
            double gravConstant = this.GravitationalConstant;

            // Build the field on a different thread
            var task = Task.Factory.StartNew(() =>
            {
                _fieldRoot = BuildField(snapshot, gravConstant);
            });

            // After the tree is built, schedule the next build from within this current thread
            task.ContinueWith(resultTask =>
            {
                // Schedule the next snapshot
                ScheduleNextTick(startTime);
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
Beispiel #2
0
        private static FieldOctree <GravityCell> BuildField(MapOctree mapSnapshot, double gravConstant)
        {
            // Dig through the tree, and construct my tree with partially populated leaves (mass but no force)
            List <GravityCell>        allLeavesList = new List <GravityCell>();
            FieldOctree <GravityCell> retVal        = BuildField_Node(allLeavesList, null, mapSnapshot);

            GravityCell[] allLeaves = allLeavesList.ToArray();
            Vector3D[]    forces    = new Vector3D[allLeaves.Length];

            // Calculate the force of gravity for each cell
            //TODO: Individual far away cells shouldn't need to be processed individually, use their parent instead
            BuildField_Forces(allLeaves, forces, gravConstant);

            // Sort on token to make things easier for the swapper
            SortedList <long, int> indicesByToken = new SortedList <long, int>();

            for (int cntr = 0; cntr < allLeaves.Length; cntr++)
            {
                indicesByToken.Add(allLeaves[cntr].Token, cntr);
            }

            // Inject the forces into the leaves
            BuildField_SwapLeaves(retVal, indicesByToken, forces);

            // Exit Function
            return(retVal);
        }
Beispiel #3
0
            private static Brush GetBrush(MapOctree node, Func <MapOctree, double> getValue, double valueMult, Color color)
            {
                const double MAXOPACITY = .25;

                //if (node.Items.Any(o => o.MapObject is ShipPlayer))
                //{
                //    return new SolidColorBrush(UtilityWPF.ColorFromHex("600000FF"));
                //}

                // Add up the resources
                double resourceValue = getValue(node);

                if (resourceValue.IsNearZero())
                {
                    return(null);
                }

                double area = (node.MaxRange.X - node.MinRange.X) * (node.MaxRange.Y - node.MinRange.Y);

                double opacity = (resourceValue * valueMult) / area;

                if (opacity > 1)
                {
                    opacity = 1;
                }

                Color colorFinal = UtilityWPF.AlphaBlend(color, Colors.Transparent, opacity * MAXOPACITY);

                return(new SolidColorBrush(colorFinal));
            }
Beispiel #4
0
        /// <summary>
        /// This fires in an arbitrary thread.  It looks at what's in the map, and builds instructions that will be run in the main thread
        /// (adds/removes)
        /// </summary>
        public void Update_AnyThread(double elapsedTime)
        {
            MapOctree snapshot = _map.LatestSnapshot;

            if (snapshot == null)
            {
                return;
            }

            IEnumerable <MapObjectInfo> allItems = snapshot.GetItems();

            //_map.GetAllItems(true)        //TODO: May want to use this to get disposed items

            // Look for too few/many
            ChangeInstruction[] asteroids = ExamineAsteroids(allItems, _boundry);
            ChangeInstruction[] minerals  = ExamineMinerals(allItems, _boundry, _mineralTypesByValue);

            // Store these instructions for the main thread to do
            if (asteroids != null || minerals != null)
            {
                ChangeInstruction[] instructions = UtilityCore.ArrayAdd(asteroids, minerals);

                if (instructions.Length > MAXCHANGES)
                {
                    instructions = UtilityCore.RandomOrder(instructions, MAXCHANGES).ToArray();
                }

                _instructions = instructions;
            }
        }
            public ResourcesVisual(MapOctree snapshot, Func<MapOctree, double> getValue, Color color, Transform transform)
            {
                //const double STANDARDAREA = 1000000;
                const double STANDARDAREA = 750000;

                //TODO: Use this to get a normalization multiplier
                double totalArea = (snapshot.MaxRange.X - snapshot.MinRange.X) * (snapshot.MaxRange.Y - snapshot.MinRange.Y);
                double valueMult = totalArea / STANDARDAREA;

                _visual = new DrawingVisual();
                using (DrawingContext dc = _visual.RenderOpen())
                {
                    foreach (MapOctree node in snapshot.Descendants(o => o.Children))
                    {
                        if (node.Items == null)
                        {
                            continue;
                        }

                        // Get the color
                        Brush brush = GetBrush(node, getValue, valueMult, color);
                        if (brush == null)
                        {
                            continue;
                        }

                        // Define the rectangle
                        Point min = transform.Transform(new Point(node.MinRange.X, -node.MinRange.Y));      // need to negate Y
                        Point max = transform.Transform(new Point(node.MaxRange.X, -node.MaxRange.Y));

                        double x = min.X;
                        double y = max.Y;       // can't use min, because Y is backward

                        double width = max.X - min.X;
                        double height = Math.Abs(max.Y - min.Y);       // Y is all flipped around

                        // Fill the box
                        dc.DrawRectangle(brush, null, new Rect(x, y, width, height));
                    }
                }
            }
Beispiel #6
0
            public ResourcesVisual(MapOctree snapshot, Func <MapOctree, double> getValue, Color color, Transform transform)
            {
                //const double STANDARDAREA = 1000000;
                const double STANDARDAREA = 750000;

                //TODO: Use this to get a normalization multiplier
                double totalArea = (snapshot.MaxRange.X - snapshot.MinRange.X) * (snapshot.MaxRange.Y - snapshot.MinRange.Y);
                double valueMult = totalArea / STANDARDAREA;

                _visual = new DrawingVisual();
                using (DrawingContext dc = _visual.RenderOpen())
                {
                    foreach (MapOctree node in snapshot.Descendants(o => o.Children))
                    {
                        if (node.Items == null)
                        {
                            continue;
                        }

                        // Get the color
                        Brush brush = GetBrush(node, getValue, valueMult, color);
                        if (brush == null)
                        {
                            continue;
                        }

                        // Define the rectangle
                        Point min = transform.Transform(new Point(node.MinRange.X, -node.MinRange.Y));      // need to negate Y
                        Point max = transform.Transform(new Point(node.MaxRange.X, -node.MaxRange.Y));

                        double x = min.X;
                        double y = max.Y;       // can't use min, because Y is backward

                        double width  = max.X - min.X;
                        double height = Math.Abs(max.Y - min.Y);       // Y is all flipped around

                        // Fill the box
                        dc.DrawRectangle(brush, null, new Rect(x, y, width, height));
                    }
                }
            }
Beispiel #7
0
        private Point3D[] GetNearbyObjects(Point3D center, double radius)
        {
            //TODO: filter what they can drag toward
            //TODO: frequent requests should reuse results of a prev call

            MapOctree snapshot = _map.LatestSnapshot;

            if (snapshot != null)
            {
                // The snapshot is designed for this kind of request, so use it
                return(snapshot.GetItems(center, radius).
                       Where(o => o.MapObject != _selectedItem.Item).   // don't return the item behing dragged
                       Select(o => o.Position).ToArray());
            }

            double radSquared = radius * radius;

            // Do a brute force scan of all objects
            return(_map.GetAllItems().
                   Where(o => o != _selectedItem.Item).     // don't return the item behing dragged
                   Select(o => o.PhysicsBody.Position).
                   Where(o => (center - o).LengthSquared <= radSquared).
                   ToArray());
        }
Beispiel #8
0
        private Tuple<MapObjectInfo, double, ForceSettings_Initial>[] GetNeighbors(MapOctree snapshot, Point3D position)
        {
            // Get nearby items, sort by distance
            double searchRadius = this.SearchRadius;

            var initial = snapshot.GetItems(position, searchRadius).
                Where(o => o.Token != this.Token).
                Select(o => Tuple.Create(o, (o.Position - position).LengthSquared)).
                OrderBy(o => o.Item2).
                ToArray();

            // Get chase settings for each item
            //NOTE: This needs to be done after sorting on distance, because bots will have different settings if too many are actively chased
            var retVal = new List<Tuple<MapObjectInfo, double, ForceSettings_Initial>>();

            int chaseNeighborCount = this.ChaseNeighborCount;
            int currentNeighborCount = 0;

            foreach (var item in initial)
            {
                ForceSettings_Initial chaseProps = GetForceSetting_Initial(ref currentNeighborCount, item.Item1, chaseNeighborCount);

                if (chaseProps != null)
                {
                    retVal.Add(Tuple.Create(item.Item1, item.Item2, chaseProps));
                }
            }

            return retVal.ToArray();
        }
Beispiel #9
0
        private static FieldOctree <GravityCell> BuildField_Node(List <GravityCell> allLeaves, MapOctree[] ancestors, MapOctree node)
        {
            #region Add up mass

            double massOfNode = 0d;
            if (node.Items != null)
            {
                foreach (MapObjectInfo item in node.Items)
                {
                    massOfNode += item.Mass;
                }
            }

            #endregion

            if (!node.HasChildren)
            {
                #region Leaf

                // Exit Function
                GravityCell cell = new GravityCell(BuildField_NodeSprtAncestorMass(ancestors, node.MinRange, node.MaxRange) + massOfNode, node.CenterPoint);
                allLeaves.Add(cell);
                return(new FieldOctree <GravityCell>(node.MinRange, node.MaxRange, node.CenterPoint, cell));

                #endregion
            }

            // Make the return node
            FieldOctree <GravityCell> retVal = new FieldOctree <GravityCell>(node.MinRange, node.MaxRange, node.CenterPoint);

            #region Build ancestor arrays

            // Create new arrays that hold this node's values (to pass to the children)
            MapOctree[] ancestorsNew = null;
            if (ancestors == null)
            {
                // This is the root
                ancestorsNew = new MapOctree[] { node };
            }
            else
            {
                // This is a middle ancestor
                ancestorsNew = new MapOctree[ancestors.Length + 1];
                Array.Copy(ancestors, ancestorsNew, ancestors.Length);
                ancestorsNew[ancestorsNew.Length - 1] = node;
            }

            #endregion

            #region Add the children

            //NOTE: The map's octree will leave children null if there are no items in them.  But this tree always has all 8 children

            if (node.X0_Y0_Z0 == null)
            {
                Point3D childMin = new Point3D(node.MinRange.X, node.MinRange.Y, node.MinRange.Z);
                Point3D childMax = new Point3D(node.CenterPoint.X, node.CenterPoint.Y, node.CenterPoint.Z);
                retVal.X0_Y0_Z0 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X0_Y0_Z0 = BuildField_Node(allLeaves, ancestorsNew, node.X0_Y0_Z0);
            }

            if (node.X0_Y0_Z1 == null)
            {
                Point3D childMin = new Point3D(node.MinRange.X, node.MinRange.Y, node.CenterPoint.Z);
                Point3D childMax = new Point3D(node.CenterPoint.X, node.CenterPoint.Y, node.MaxRange.Z);
                retVal.X0_Y0_Z1 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X0_Y0_Z1 = BuildField_Node(allLeaves, ancestorsNew, node.X0_Y0_Z1);
            }

            if (node.X0_Y1_Z0 == null)
            {
                Point3D childMin = new Point3D(node.MinRange.X, node.CenterPoint.Y, node.MinRange.Z);
                Point3D childMax = new Point3D(node.CenterPoint.X, node.MaxRange.Y, node.CenterPoint.Z);
                retVal.X0_Y1_Z0 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X0_Y1_Z0 = BuildField_Node(allLeaves, ancestorsNew, node.X0_Y1_Z0);
            }

            if (node.X0_Y1_Z1 == null)
            {
                Point3D childMin = new Point3D(node.MinRange.X, node.CenterPoint.Y, node.CenterPoint.Z);
                Point3D childMax = new Point3D(node.CenterPoint.X, node.MaxRange.Y, node.MaxRange.Z);
                retVal.X0_Y1_Z1 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X0_Y1_Z1 = BuildField_Node(allLeaves, ancestorsNew, node.X0_Y1_Z1);
            }

            if (node.X1_Y0_Z0 == null)
            {
                Point3D childMin = new Point3D(node.CenterPoint.X, node.MinRange.Y, node.MinRange.Z);
                Point3D childMax = new Point3D(node.MaxRange.X, node.CenterPoint.Y, node.CenterPoint.Z);
                retVal.X1_Y0_Z0 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X1_Y0_Z0 = BuildField_Node(allLeaves, ancestorsNew, node.X1_Y0_Z0);
            }

            if (node.X1_Y0_Z1 == null)
            {
                Point3D childMin = new Point3D(node.CenterPoint.X, node.MinRange.Y, node.CenterPoint.Z);
                Point3D childMax = new Point3D(node.MaxRange.X, node.CenterPoint.Y, node.MaxRange.Z);
                retVal.X1_Y0_Z1 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X1_Y0_Z1 = BuildField_Node(allLeaves, ancestorsNew, node.X1_Y0_Z1);
            }

            if (node.X1_Y1_Z0 == null)
            {
                Point3D childMin = new Point3D(node.CenterPoint.X, node.CenterPoint.Y, node.MinRange.Z);
                Point3D childMax = new Point3D(node.MaxRange.X, node.MaxRange.Y, node.CenterPoint.Z);
                retVal.X1_Y1_Z0 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X1_Y1_Z0 = BuildField_Node(allLeaves, ancestorsNew, node.X1_Y1_Z0);
            }

            if (node.X1_Y1_Z1 == null)
            {
                Point3D childMin = new Point3D(node.CenterPoint.X, node.CenterPoint.Y, node.CenterPoint.Z);
                Point3D childMax = new Point3D(node.MaxRange.X, node.MaxRange.Y, node.MaxRange.Z);
                retVal.X1_Y1_Z1 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X1_Y1_Z1 = BuildField_Node(allLeaves, ancestorsNew, node.X1_Y1_Z1);
            }

            #endregion

            // Exit Function
            return(retVal);
        }
            private static Brush GetBrush(MapOctree node, Func<MapOctree, double> getValue, double valueMult, Color color)
            {
                const double MAXOPACITY = .25;

                //if (node.Items.Any(o => o.MapObject is ShipPlayer))
                //{
                //    return new SolidColorBrush(UtilityWPF.ColorFromHex("600000FF"));
                //}

                // Add up the resources
                double resourceValue = getValue(node);
                if (resourceValue.IsNearZero())
                {
                    return null;
                }

                double area = (node.MaxRange.X - node.MinRange.X) * (node.MaxRange.Y - node.MinRange.Y);

                double opacity = (resourceValue * valueMult) / area;
                if (opacity > 1)
                {
                    opacity = 1;
                }

                Color colorFinal = UtilityWPF.AlphaBlend(color, Colors.Transparent, opacity * MAXOPACITY);
                return new SolidColorBrush(colorFinal);
            }
Beispiel #11
0
        private void DrawAsteroidsMinerals(Transform transform, bool shouldPopulateCanvas)
        {
            const double MINERALMULT  = 100d;
            const double ASTEROIDMULT = .25d;

            MapOctree snapshot = _map.LatestSnapshot;

            if (snapshot == null)
            {
                return;
            }

            if (snapshot.X0_Y0_Z0 == null && snapshot.X0_Y0_Z1 == null && snapshot.X0_Y1_Z0 == null && snapshot.X0_Y1_Z1 == null && snapshot.X1_Y0_Z0 == null && snapshot.X1_Y0_Z1 == null && snapshot.X1_Y1_Z0 == null && snapshot.X1_Y1_Z1 == null)
            {
                // This was happening because build snapshot wasn't throwing out disposed objects
                return;
            }

            #region GetValue delegates

            // These get the value of the items in that node.  The value will be divided by the area of the node to figure out opacity.
            // So the value/area should be 1 when the node is rich in that resource

            Func <MapOctree, double> getMineralValue = new Func <MapOctree, double>((node) =>
            {
                Mineral[] minerals = node.Items.
                                     Where(o => o.MapObject is Mineral).
                                     Select(o => (Mineral)o.MapObject).
                                     ToArray();

                if (minerals.Length == 0)
                {
                    return(0d);
                }
                else
                {
                    return(minerals.Sum(o => Convert.ToDouble(o.Credits) * MINERALMULT));
                }
            });

            Func <MapOctree, double> getAsteroidValue = new Func <MapOctree, double>((node) =>
            {
                Asteroid[] asteroids = node.Items.
                                       Where(o => o.MapObject is Asteroid).
                                       Select(o => (Asteroid)o.MapObject).
                                       ToArray();

                if (asteroids.Length == 0)
                {
                    return(0d);
                }
                else
                {
                    return(asteroids.Sum(o => o.PhysicsBody.Mass * ASTEROIDMULT));
                }
            });

            #endregion

            // Create the visuals
            _mineralVisual  = new ResourcesVisual(snapshot, getMineralValue, Colors.Lime, transform);
            _asteroidVisual = new ResourcesVisual(snapshot, getAsteroidValue, Colors.LightGray, transform);

            // Show a random one (the timer will swap them every tick)
            if (shouldPopulateCanvas)
            {
                _isShowingMineral = StaticRandom.NextBool();
                canvasMap.Children.Insert(0, _isShowingMineral ? _mineralVisual : _asteroidVisual);
            }

            #region Get Stats

            //double width = snapshot.MaxRange.X - snapshot.MinRange.X;
            //double height = snapshot.MaxRange.Y - snapshot.MinRange.Y;
            //double diagonal = Math3D.Avg(width, height) * Math.Sqrt(2);
            //double area = width * height;
            //double mineralValue = snapshot.Descendants(o => o.Children).Where(o => o.Items != null).Sum(o => getMineralValue(o));
            //double asteroidValue = snapshot.Descendants(o => o.Children).Where(o => o.Items != null).Sum(o => getAsteroidValue(o));

            //string stats = "";
            //stats += string.Format("width\t{0}\r\n", width);
            //stats += string.Format("height\t{0}\r\n", height);
            //stats += string.Format("diagonal\t{0}\r\n", diagonal);
            //stats += string.Format("area\t{0}\r\n", area);
            //stats += string.Format("minerals\t{0}\r\n", mineralValue);
            //stats += string.Format("asteroids\t{0}\r\n", asteroidValue);
            //stats += "\r\n";
            //stats += string.Format("min/diag\t{0}\r\n", mineralValue / diagonal);
            //stats += string.Format("ast/diag\t{0}\r\n", asteroidValue / diagonal);
            //stats += string.Format("min/area\t{0}\r\n", mineralValue / area);
            //stats += string.Format("ast/area\t{0}\r\n", asteroidValue / area);

            //Clipboard.SetText(stats);

            #endregion
        }