Exemple #1
0
        // TODO in case we need this somewhere else it might be a good idea to move this to the EntityFactory
        private void CreateAsteroid(FarPosition position, IUniformRandom random, ContentManager content)
        {
            // Randomly scale and rotate it.
            var scale = (float)random.NextDouble(0.5f, 1f);
            var angle = (float)random.NextDouble() * MathHelper.TwoPi;

            // Determine shape for physics system.
            var textureName = "Textures/Asteroids/rock_" + random.NextInt32(1, 14);
            var texture     = content.Load <Texture2D>(textureName);
            var hull        = new List <Vector2>(TextureConverter.DetectVertices(texture, 8f, textureName: textureName)[0]);

            for (var k = 0; k < hull.Count; ++k)
            {
                hull[k] -= new Vector2(texture.Width / 2f, texture.Height / 2f);
                hull[k]  = XnaUnitConversion.ToSimulationUnits(hull[k]) * scale;
            }
            var polygons = EarClipDecomposer.ConvexPartition(hull);

            // Create physical representation.
            var entity = Manager.AddEntity();
            var body   = Manager.AddBody(entity, position, angle, Body.BodyType.Dynamic);

            foreach (var polygon in polygons)
            {
                Manager.AttachPolygon(body, polygon, density: 1000f, restitution: 0.2f);
            }
            // Slow down to allow reaching sleep state again.
            body.LinearDamping  = 0.05f * Space.Util.Settings.TicksPerSecond;
            body.AngularDamping = 0.025f * Space.Util.Settings.TicksPerSecond;

            // Bounds of the asteroid for rendering culling. We use the diagonal for a loose fit that
            // contains every possible rotated state of the texture.
            var width    = UnitConversion.ToSimulationUnits(texture.Width);
            var height   = UnitConversion.ToSimulationUnits(texture.Height);
            var diagonal = (float)Math.Sqrt(width * width + height * height);
            var bounds   = new FarRectangle(-diagonal / 2, -diagonal / 2, diagonal, diagonal);

            // Rendering stuff.
            Manager.AddComponent <Indexable>(entity).Initialize(bounds, CameraSystem.IndexId);
            Manager.AddComponent <Indexable>(entity).Initialize(bounds, InterpolationSystem.IndexId);
            Manager.AddComponent <SimpleTextureDrawable>(entity).Initialize(textureName, scale);

            // Auto removal.
            Manager.AddComponent <CellDeath>(entity).Initialize(true);
            Manager.AddComponent <Indexable>(entity).Initialize(CellSystem.CellDeathAutoRemoveIndexId);

            // Make it destructible.
            var health = Manager.AddComponent <Health>(entity);

            health.Value        = health.MaxValue = 200 * scale;
            health.Regeneration = 0f;

            // As they don't move on their own, start asteroids as sleeping to save performance.
            body.IsAwake = false;
        }
Exemple #2
0
        private CacheEntry GetCacheEntry(int entity)
        {
            var equipment = (SpaceItemSlot)Manager.GetComponent(entity, ItemSlot.TypeId);
            var hash      = HashEquipment(equipment);

            // Create cache texture if necessary.
            if (!ModelCache.ContainsKey(hash))
            {
                // Simulations may run multi-threaded, so we need to lock out static table here.
                lock (ModelCache)
                {
                    // Maybe we got our entry while waiting for our lock?
                    if (!ModelCache.ContainsKey(hash))
                    {
                        // No cache entry yet, create it. Determine the needed size of the texture.
                        var size = ComputeModelSize(equipment, Vector2.Zero);
                        // Then create it and push it as our current render target.
                        var target = new RenderTarget2D(
                            _spriteBatch.GraphicsDevice,
                            (int)System.Math.Ceiling(size.Width),
                            (int)System.Math.Ceiling(size.Height));

                        var previousRenderTargets = _spriteBatch.GraphicsDevice.GetRenderTargets();
                        _spriteBatch.GraphicsDevice.SetRenderTarget(target);
                        _spriteBatch.GraphicsDevice.Clear(Color.Transparent);
                        _spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);

                        // Render the actual equipment into our texture.
                        RenderEquipment(equipment, new Vector2(-size.X, -size.Y));

                        // Restore the old render state.
                        _spriteBatch.End();
                        _spriteBatch.GraphicsDevice.SetRenderTargets(previousRenderTargets);

                        // Build polygon hull.
                        var abstraction = Manager.GetComponent(entity, Avatar.TypeId) == null
                                              ? NPCModelTolerance
                                              : PlayerModelTolerance;
                        var hull = new List <Vector2>(TextureConverter.DetectVertices(target, abstraction)[0]);
                        for (var i = 0; i < hull.Count; ++i)
                        {
                            // Center at origin.
                            hull[i] += new Vector2(size.X, size.Y);
                            // Scale to simulation units.
                            hull[i] = XnaUnitConversion.ToSimulationUnits(hull[i]);
                        }

                        // Create a new cache entry for this equipment combination.
                        ModelCache[hash] = new CacheEntry
                        {
                            Texture      = target,
                            Offset       = new Vector2(-size.X, -size.Y),
                            PolygonHulls = EarClipDecomposer.ConvexPartition(hull)
                        };
                    }
                }
            }

            // Update last access time.
            ModelCache[hash].Age = 0;

            // Then return the entry!
            return(ModelCache[hash]);
        }