//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); } } } }
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); } } } }