Exemple #1
0
        //public Vector2[] spriteCorners;

        public BackgroundSprite(BackgroundSpritePrefab prefab, Vector3 position, float scale, float rotation = 0.0f)
        {
            this.Prefab   = prefab;
            this.Position = position;

            this.Scale = scale;

            this.Rotation = rotation;
        }
        public BackgroundSprite(BackgroundSpritePrefab prefab, Vector3 position, float scale, float rotation = 0.0f)
        {
            this.Prefab   = prefab;
            this.Position = position;

            this.Scale = scale;

            this.Rotation = rotation;

            if (prefab.LevelTriggerElement != null)
            {
                Vector2 triggerPosition = prefab.LevelTriggerElement.GetAttributeVector2("position", Vector2.Zero) * scale;

                if (rotation != 0.0f)
                {
                    var ca = (float)Math.Cos(rotation);
                    var sa = (float)Math.Sin(rotation);

                    triggerPosition = new Vector2(
                        ca * triggerPosition.X + sa * triggerPosition.Y,
                        -sa * triggerPosition.X + ca * triggerPosition.Y);
                }

                this.Trigger = new LevelTrigger(prefab.LevelTriggerElement, new Vector2(position.X, position.Y) + triggerPosition, -rotation, scale);
            }

#if CLIENT
            if (prefab.ParticleEmitterPrefabs != null)
            {
                ParticleEmitters = new List <ParticleEmitter>();
                foreach (ParticleEmitterPrefab emitterPrefab in prefab.ParticleEmitterPrefabs)
                {
                    ParticleEmitters.Add(new ParticleEmitter(emitterPrefab));
                }
            }

            if (prefab.SoundElement != null)
            {
                Sound = Sound.Load(prefab.SoundElement, true);
            }
#endif
        }
        private Vector2?FindSpritePosition(Level level, BackgroundSpritePrefab prefab, out GraphEdge closestEdge, out Vector2 edgeNormal)
        {
            closestEdge = null;
            edgeNormal  = Vector2.One;

            Vector2 randomPos = new Vector2(
                Rand.Range(0.0f, level.Size.X, Rand.RandSync.Server),
                Rand.Range(0.0f, level.Size.Y, Rand.RandSync.Server));

            if (prefab.SpawnPos == BackgroundSpritePrefab.SpawnPosType.None)
            {
                return(randomPos);
            }

            List <GraphEdge> edges   = new List <GraphEdge>();
            List <Vector2>   normals = new List <Vector2>();

            System.Diagnostics.Debug.Assert(level.ExtraWalls.Length == 1);
            List <VoronoiCell> cells = new List <VoronoiCell>();

            if (prefab.SpawnPos.HasFlag(BackgroundSpritePrefab.SpawnPosType.Wall))
            {
                cells.AddRange(level.GetCells(randomPos));
            }
            if (prefab.SpawnPos.HasFlag(BackgroundSpritePrefab.SpawnPosType.SeaFloor))
            {
                cells.AddRange(level.ExtraWalls[0].Cells);
            }

            if (cells.Any())
            {
                VoronoiCell cell = cells[Rand.Int(cells.Count, Rand.RandSync.Server)];

                foreach (GraphEdge edge in cell.edges)
                {
                    if (!edge.isSolid || edge.OutsideLevel)
                    {
                        continue;
                    }

                    Vector2 normal = edge.GetNormal(cell);

                    if (prefab.Alignment.HasFlag(Alignment.Bottom) && normal.Y < -0.5f)
                    {
                        edges.Add(edge);
                    }
                    else if (prefab.Alignment.HasFlag(Alignment.Top) && normal.Y > 0.5f)
                    {
                        edges.Add(edge);
                    }
                    else if (prefab.Alignment.HasFlag(Alignment.Left) && normal.X < -0.5f)
                    {
                        edges.Add(edge);
                    }
                    else if (prefab.Alignment.HasFlag(Alignment.Right) && normal.X > 0.5f)
                    {
                        edges.Add(edge);
                    }
                    else
                    {
                        continue;
                    }

                    normals.Add(normal);
                }
            }

            if (prefab.SpawnPos.HasFlag(BackgroundSpritePrefab.SpawnPosType.RuinWall))
            {
                foreach (RuinGeneration.Ruin ruin in Level.Loaded.Ruins)
                {
                    Rectangle expandedArea = ruin.Area;
                    expandedArea.Inflate(ruin.Area.Width, ruin.Area.Height);
                    if (!expandedArea.Contains(randomPos))
                    {
                        continue;
                    }

                    foreach (var ruinShape in ruin.RuinShapes)
                    {
                        foreach (var wall in ruinShape.Walls)
                        {
                            if (!prefab.Alignment.HasFlag(ruinShape.GetLineAlignment(wall)))
                            {
                                continue;
                            }

                            edges.Add(new GraphEdge(wall.A, wall.B));
                            normals.Add((wall.A + wall.B) / 2.0f - ruinShape.Center);
                        }
                    }
                }
            }

            if (!edges.Any())
            {
                return(null);
            }

            int index = Rand.Int(edges.Count, Rand.RandSync.Server);

            closestEdge = edges[index];
            edgeNormal  = normals[index];

            float   length = Vector2.Distance(closestEdge.point1, closestEdge.point2);
            Vector2 dir    = (closestEdge.point1 - closestEdge.point2) / length;
            Vector2 pos    = closestEdge.point2 + dir * Rand.Range(prefab.Sprite.size.X / 2.0f, length - prefab.Sprite.size.X / 2.0f, Rand.RandSync.Server);

            return(pos);
        }
        public void PlaceSprites(Level level, int amount)
        {
            spriteGrid = new List <BackgroundSprite> [
                (int)Math.Ceiling(level.Size.X / GridSize),
                (int)Math.Ceiling((level.Size.Y - level.BottomPos) / GridSize)];

            sprites = new List <BackgroundSprite>();

            for (int i = 0; i < amount; i++)
            {
                BackgroundSpritePrefab prefab = GetRandomPrefab(level.GenerationParams.Name);
                GraphEdge selectedEdge        = null;
                Vector2   edgeNormal          = Vector2.One;
                Vector2?  pos = FindSpritePosition(level, prefab, out selectedEdge, out edgeNormal);

                if (pos == null)
                {
                    continue;
                }

                float rotation = 0.0f;
                if (prefab.AlignWithSurface)
                {
                    rotation = MathUtils.VectorToAngle(new Vector2(edgeNormal.Y, edgeNormal.X));
                }

                rotation += Rand.Range(prefab.RandomRotation.X, prefab.RandomRotation.Y, Rand.RandSync.Server);

                var newSprite = new BackgroundSprite(prefab,
                                                     new Vector3((Vector2)pos, Rand.Range(prefab.DepthRange.X, prefab.DepthRange.Y, Rand.RandSync.Server)), Rand.Range(prefab.Scale.X, prefab.Scale.Y, Rand.RandSync.Server), rotation);

                //calculate the positions of the corners of the rotated sprite
                Vector2 halfSize      = newSprite.Prefab.Sprite.size * newSprite.Scale / 2;
                var     spriteCorners = new List <Vector2>
                {
                    -halfSize, new Vector2(-halfSize.X, halfSize.Y),
                    halfSize, new Vector2(halfSize.X, -halfSize.Y)
                };

                Vector2 pivotOffset = newSprite.Prefab.Sprite.Origin * newSprite.Scale - halfSize;
                pivotOffset.X = -pivotOffset.X;
                pivotOffset   = new Vector2(
                    (float)(pivotOffset.X * Math.Cos(-rotation) - pivotOffset.Y * Math.Sin(-rotation)),
                    (float)(pivotOffset.X * Math.Sin(-rotation) + pivotOffset.Y * Math.Cos(-rotation)));

                for (int j = 0; j < 4; j++)
                {
                    spriteCorners[j] = new Vector2(
                        (float)(spriteCorners[j].X * Math.Cos(-rotation) - spriteCorners[j].Y * Math.Sin(-rotation)),
                        (float)(spriteCorners[j].X * Math.Sin(-rotation) + spriteCorners[j].Y * Math.Cos(-rotation)));

                    spriteCorners[j] += pos.Value + pivotOffset;
                }

                float minX = spriteCorners.Min(c => c.X) - newSprite.Position.Z;
                float maxX = spriteCorners.Max(c => c.X) + newSprite.Position.Z;

                float minY = spriteCorners.Min(c => c.Y) - newSprite.Position.Z - level.BottomPos;
                float maxY = spriteCorners.Max(c => c.Y) + newSprite.Position.Z - level.BottomPos;

#if CLIENT
                if (newSprite.ParticleEmitters != null)
                {
                    foreach (ParticleEmitter emitter in newSprite.ParticleEmitters)
                    {
                        Rectangle particleBounds = emitter.CalculateParticleBounds(pos.Value);
                        minX = Math.Min(minX, particleBounds.X);
                        maxX = Math.Max(maxX, particleBounds.Right);
                        minY = Math.Min(minY, particleBounds.Y - level.BottomPos);
                        maxY = Math.Max(maxY, particleBounds.Bottom - level.BottomPos);
                    }
                }
#endif

                sprites.Add(newSprite);

                int xStart = (int)Math.Floor(minX / GridSize);
                int xEnd   = (int)Math.Floor(maxX / GridSize);
                if (xEnd < 0 || xStart >= spriteGrid.GetLength(0))
                {
                    continue;
                }

                int yStart = (int)Math.Floor(minY / GridSize);
                int yEnd   = (int)Math.Floor(maxY / GridSize);
                if (yEnd < 0 || yStart >= spriteGrid.GetLength(1))
                {
                    continue;
                }

                xStart = Math.Max(xStart, 0);
                xEnd   = Math.Min(xEnd, spriteGrid.GetLength(0) - 1);
                yStart = Math.Max(yStart, 0);
                yEnd   = Math.Min(yEnd, spriteGrid.GetLength(1) - 1);

                for (int x = xStart; x <= xEnd; x++)
                {
                    for (int y = yStart; y <= yEnd; y++)
                    {
                        if (spriteGrid[x, y] == null)
                        {
                            spriteGrid[x, y] = new List <BackgroundSprite>();
                        }
                        spriteGrid[x, y].Add(newSprite);
                    }
                }
            }
        }
Exemple #5
0
        public void PlaceSprites(Level level, int amount)
        {
            sprites = new List <BackgroundSprite> [
                (int)Math.Ceiling(level.Size.X / GridSize),
                (int)Math.Ceiling(level.Size.Y / GridSize)];

            for (int x = 0; x < sprites.GetLength(0); x++)
            {
                for (int y = 0; y < sprites.GetLength(1); y++)
                {
                    sprites[x, y] = new List <BackgroundSprite>();
                }
            }

            for (int i = 0; i < amount; i++)
            {
                BackgroundSpritePrefab prefab = GetRandomPrefab(level.GenerationParams.Name);
                GraphEdge selectedEdge        = null;
                Vector2   edgeNormal          = Vector2.One;
                Vector2?  pos = FindSpritePosition(level, prefab, out selectedEdge, out edgeNormal);

                if (pos == null)
                {
                    continue;
                }

                float rotation = 0.0f;
                if (prefab.AlignWithSurface)
                {
                    rotation = MathUtils.VectorToAngle(new Vector2(edgeNormal.Y, edgeNormal.X));
                }

                rotation += Rand.Range(prefab.RandomRotation.X, prefab.RandomRotation.Y, Rand.RandSync.ClientOnly);

                var newSprite = new BackgroundSprite(prefab,
                                                     new Vector3((Vector2)pos, Rand.Range(prefab.DepthRange.X, prefab.DepthRange.Y, Rand.RandSync.ClientOnly)), Rand.Range(prefab.Scale.X, prefab.Scale.Y, Rand.RandSync.ClientOnly), rotation);

                //calculate the positions of the corners of the rotated sprite
                Vector2 halfSize      = newSprite.Prefab.Sprite.size * newSprite.Scale / 2;
                var     spriteCorners = new Vector2[]
                {
                    -halfSize, new Vector2(-halfSize.X, halfSize.Y),
                    halfSize, new Vector2(halfSize.X, -halfSize.Y)
                };

                Vector2 pivotOffset = newSprite.Prefab.Sprite.Origin * newSprite.Scale - halfSize;
                pivotOffset.X = -pivotOffset.X;
                pivotOffset   = new Vector2(
                    (float)(pivotOffset.X * Math.Cos(-rotation) - pivotOffset.Y * Math.Sin(-rotation)),
                    (float)(pivotOffset.X * Math.Sin(-rotation) + pivotOffset.Y * Math.Cos(-rotation)));

                for (int j = 0; j < 4; j++)
                {
                    spriteCorners[j] = new Vector2(
                        (float)(spriteCorners[j].X * Math.Cos(-rotation) - spriteCorners[j].Y * Math.Sin(-rotation)),
                        (float)(spriteCorners[j].X * Math.Sin(-rotation) + spriteCorners[j].Y * Math.Cos(-rotation)));

                    spriteCorners[j] += (Vector2)pos + pivotOffset;
                }

                //newSprite.spriteCorners = spriteCorners;

                int minX = (int)Math.Floor((spriteCorners.Min(c => c.X) - newSprite.Position.Z) / GridSize);
                int maxX = (int)Math.Floor((spriteCorners.Max(c => c.X) + newSprite.Position.Z) / GridSize);
                if (minX < 0 || maxX >= sprites.GetLength(0))
                {
                    continue;
                }

                int minY = (int)Math.Floor((spriteCorners.Min(c => c.Y) - newSprite.Position.Z) / GridSize);
                int maxY = (int)Math.Floor((spriteCorners.Max(c => c.Y) + newSprite.Position.Z) / GridSize);
                if (minY < 0 || maxY >= sprites.GetLength(1))
                {
                    continue;
                }

                for (int x = minX; x <= maxX; x++)
                {
                    for (int y = minY; y <= maxY; y++)
                    {
                        sprites[x, y].Add(newSprite);
                    }
                }
            }
        }