public void MoveCamera(float deltaTime, bool allowMove = true, bool allowZoom = true) { prevPosition = position; prevZoom = zoom; float moveSpeed = 20.0f / zoom; Vector2 moveCam = Vector2.Zero; if (targetPos == Vector2.Zero) { Vector2 moveInput = Vector2.Zero; if (allowMove && !Freeze) { if (GUI.KeyboardDispatcher.Subscriber == null) { if (PlayerInput.KeyDown(Keys.LeftShift)) { moveSpeed *= 2.0f; } if (PlayerInput.KeyDown(Keys.LeftControl)) { moveSpeed *= 0.5f; } if (GameMain.Config.KeyBind(InputType.Left).IsDown()) { moveInput.X -= 1.0f; } if (GameMain.Config.KeyBind(InputType.Right).IsDown()) { moveInput.X += 1.0f; } if (GameMain.Config.KeyBind(InputType.Down).IsDown()) { moveInput.Y -= 1.0f; } if (GameMain.Config.KeyBind(InputType.Up).IsDown()) { moveInput.Y += 1.0f; } } velocity = Vector2.Lerp(velocity, moveInput, deltaTime * 10.0f); moveCam = velocity * moveSpeed * deltaTime * 60.0f; if (Screen.Selected == GameMain.GameScreen && FollowSub) { var closestSub = Submarine.FindClosest(WorldViewCenter); if (closestSub != null) { moveCam += FarseerPhysics.ConvertUnits.ToDisplayUnits(closestSub.Velocity * deltaTime); } } } if (allowZoom && GUI.MouseOn == null) { Vector2 mouseInWorld = ScreenToWorld(PlayerInput.MousePosition); Vector2 diffViewCenter; diffViewCenter = ((mouseInWorld - Position) * Zoom); targetZoom = MathHelper.Clamp( targetZoom + (PlayerInput.ScrollWheelSpeed / 1000.0f) * zoom, GameMain.DebugDraw ? MinZoom * 0.1f : MinZoom, MaxZoom); Zoom = MathHelper.Lerp(Zoom, targetZoom, deltaTime * 10.0f); if (!PlayerInput.KeyDown(Keys.F)) { Position = mouseInWorld - (diffViewCenter / Zoom); } } } else if (allowMove) { Vector2 mousePos = PlayerInput.MousePosition; Vector2 offset = mousePos - resolution.ToVector2() / 2; offset.X = offset.X / (resolution.X * 0.4f); offset.Y = -offset.Y / (resolution.Y * 0.3f); if (offset.LengthSquared() > 1.0f) { offset.Normalize(); } offset *= offsetAmount; // Freeze the camera movement by default, when the cursor is on top of an ui element. // Setting a positive value to the OffsetAmount, will override this behaviour. if (GUI.MouseOn != null && offsetAmount > 0) { Freeze = true; } if (CharacterHealth.OpenHealthWindow != null || CrewManager.IsCommandInterfaceOpen || ConversationAction.IsDialogOpen) { offset *= 0; Freeze = false; } if (Freeze) { offset = previousOffset; } else { previousOffset = offset; } //how much to zoom out (zoom completely out when offset is 1000) float zoomOutAmount = Math.Min(offset.Length() / 1000.0f, 1.0f); //zoom amount when resolution is not taken into account float unscaledZoom = MathHelper.Lerp(DefaultZoom, MinZoom, zoomOutAmount); //zoom with resolution taken into account (zoom further out on smaller resolutions) float scaledZoom = unscaledZoom * globalZoomScale; //an ad-hoc way of allowing the players to have roughly the same maximum view distance regardless of the resolution, //while still keeping the zoom around 1.0 when not looking further away (because otherwise we'd always be downsampling //on lower resolutions, which doesn't look that good) float newZoom = MathHelper.Lerp(unscaledZoom, scaledZoom, (GameMain.Config == null || GameMain.Config.EnableMouseLook) ? (float)Math.Sqrt(zoomOutAmount) : 0.3f); Zoom += (newZoom - zoom) / ZoomSmoothness; //force targetzoom to the current zoom value, so the camera stays at the same zoom when switching to freecam targetZoom = Zoom; Vector2 diff = (targetPos + offset) - position; moveCam = diff / MoveSmoothness; } rotation += angularVelocity * deltaTime; angularVelocity *= (1.0f - angularDamping); angularVelocity += -rotation * angularSpring; angularDamping = 0.05f; angularSpring = 0.2f; if (Shake < 0.01f) { shakePosition = Vector2.Zero; shakeTimer = 0.0f; } else { shakeTimer += deltaTime * 5.0f; Vector2 noisePos = new Vector2((float)PerlinNoise.CalculatePerlin(shakeTimer, shakeTimer, 0) - 0.5f, (float)PerlinNoise.CalculatePerlin(shakeTimer, shakeTimer, 0.5f) - 0.5f); shakePosition = noisePos * Shake * 2.0f; Shake = MathHelper.Lerp(Shake, 0.0f, deltaTime * 2.0f); } Translate(moveCam + shakePosition); Freeze = false; }
public void Draw(SpriteBatch spriteBatch, GUICustomComponent mapContainer) { Rectangle rect = mapContainer.Rect; Vector2 viewSize = new Vector2(rect.Width / zoom, rect.Height / zoom); Vector2 edgeBuffer = rect.Size.ToVector2() / 2; DrawOffset.X = MathHelper.Clamp(DrawOffset.X, -Width - edgeBuffer.X + viewSize.X / 2.0f, edgeBuffer.X - viewSize.X / 2.0f); DrawOffset.Y = MathHelper.Clamp(DrawOffset.Y, -Height - edgeBuffer.Y + viewSize.Y / 2.0f, edgeBuffer.Y - viewSize.Y / 2.0f); drawOffsetNoise = new Vector2( (float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.1f % 255, Timing.TotalTime * 0.1f % 255, 0) - 0.5f, (float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.2f % 255, Timing.TotalTime * 0.2f % 255, 0.5f) - 0.5f) * 10.0f; Vector2 viewOffset = DrawOffset + drawOffsetNoise; Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y); Rectangle prevScissorRect = GameMain.Instance.GraphicsDevice.ScissorRectangle; spriteBatch.End(); spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, rect); spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable); Vector2 topLeft = rectCenter + viewOffset; Vector2 bottomRight = rectCenter + (viewOffset + new Vector2(Width, Height)); Vector2 mapTileSize = mapTiles[0, 0].size * generationParams.MapTileScale; int startX = (int)Math.Floor(-topLeft.X / mapTileSize.X) - 1; int startY = (int)Math.Floor(-topLeft.Y / mapTileSize.Y) - 1; int endX = (int)Math.Ceiling((-topLeft.X + rect.Width) / mapTileSize.X); int endY = (int)Math.Ceiling((-topLeft.Y + rect.Height) / mapTileSize.Y); float noiseT = (float)(Timing.TotalTime * 0.01f); cameraNoiseStrength = (float)PerlinNoise.CalculatePerlin(noiseT, noiseT * 0.5f, noiseT * 0.2f); float noiseScale = (float)PerlinNoise.CalculatePerlin(noiseT * 5.0f, noiseT * 2.0f, 0) * 5.0f; for (int x = startX; x <= endX; x++) { for (int y = startY; y <= endY; y++) { int tileX = Math.Abs(x) % mapTiles.GetLength(0); int tileY = Math.Abs(y) % mapTiles.GetLength(1); Vector2 tilePos = rectCenter + (viewOffset + new Vector2(x, y) * mapTileSize) * zoom; mapTiles[tileX, tileY].Draw(spriteBatch, tilePos, Color.White, origin: Vector2.Zero, scale: generationParams.MapTileScale * zoom); if (GameMain.DebugDraw) { continue; } if (!tileDiscovered[tileX, tileY] || x < 0 || y < 0 || x >= tileDiscovered.GetLength(0) || y >= tileDiscovered.GetLength(1)) { generationParams.FogOfWarSprite?.Draw(spriteBatch, tilePos, Color.White * cameraNoiseStrength, origin: Vector2.Zero, scale: generationParams.MapTileScale * zoom); noiseOverlay.DrawTiled(spriteBatch, tilePos, mapTileSize * zoom, startOffset: new Vector2(Rand.Range(0.0f, noiseOverlay.SourceRect.Width), Rand.Range(0.0f, noiseOverlay.SourceRect.Height)), color: Color.White * cameraNoiseStrength * 0.2f, textureScale: Vector2.One * noiseScale); } } } if (GameMain.DebugDraw) { if (topLeft.X > rect.X) { GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, rect.Y, (int)(topLeft.X - rect.X), rect.Height), Color.Black * 0.5f, true); } if (topLeft.Y > rect.Y) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)topLeft.X, rect.Y, (int)(bottomRight.X - topLeft.X), (int)(topLeft.Y - rect.Y)), Color.Black * 0.5f, true); } if (bottomRight.X < rect.Right) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)bottomRight.X, rect.Y, (int)(rect.Right - bottomRight.X), rect.Height), Color.Black * 0.5f, true); } if (bottomRight.Y < rect.Bottom) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)topLeft.X, (int)bottomRight.Y, (int)(bottomRight.X - topLeft.X), (int)(rect.Bottom - bottomRight.Y)), Color.Black * 0.5f, true); } } float rawNoiseScale = 1.0f + PerlinNoise.GetPerlin((int)(Timing.TotalTime * 1 - 1), (int)(Timing.TotalTime * 1 - 1)); cameraNoiseStrength = PerlinNoise.GetPerlin((int)(Timing.TotalTime * 1 - 1), (int)(Timing.TotalTime * 1 - 1)); noiseOverlay.DrawTiled(spriteBatch, rect.Location.ToVector2(), rect.Size.ToVector2(), startOffset: new Vector2(Rand.Range(0.0f, noiseOverlay.SourceRect.Width), Rand.Range(0.0f, noiseOverlay.SourceRect.Height)), color: Color.White * cameraNoiseStrength * 0.1f, textureScale: Vector2.One * rawNoiseScale); noiseOverlay.DrawTiled(spriteBatch, rect.Location.ToVector2(), rect.Size.ToVector2(), startOffset: new Vector2(Rand.Range(0.0f, noiseOverlay.SourceRect.Width), Rand.Range(0.0f, noiseOverlay.SourceRect.Height)), color: new Color(20, 20, 20, 50), textureScale: Vector2.One * rawNoiseScale * 2); noiseOverlay.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight), startOffset: new Vector2(Rand.Range(0.0f, noiseOverlay.SourceRect.Width), Rand.Range(0.0f, noiseOverlay.SourceRect.Height)), color: Color.White * cameraNoiseStrength * 0.1f, textureScale: Vector2.One * noiseScale); Pair <Rectangle, string> tooltip = null; if (generationParams.ShowLocations) { foreach (LocationConnection connection in Connections) { if (IsInFogOfWar(connection.Locations[0]) && IsInFogOfWar(connection.Locations[1])) { continue; } DrawConnection(spriteBatch, connection, rect, viewOffset); } for (int i = 0; i < Locations.Count; i++) { Location location = Locations[i]; if (IsInFogOfWar(location)) { continue; } Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom; Rectangle drawRect = location.Type.Sprite.SourceRect; drawRect.X = (int)pos.X - drawRect.Width / 2; drawRect.Y = (int)pos.Y - drawRect.Width / 2; if (!rect.Intersects(drawRect)) { continue; } if (location == CurrentDisplayLocation) { generationParams.CurrentLocationIndicator.Draw(spriteBatch, rectCenter + (currLocationIndicatorPos + viewOffset) * zoom, generationParams.IndicatorColor, generationParams.CurrentLocationIndicator.Origin, 0, Vector2.One * (generationParams.LocationIconSize / generationParams.CurrentLocationIndicator.size.X) * 1.7f * zoom); } if (location == SelectedLocation) { generationParams.SelectedLocationIndicator.Draw(spriteBatch, rectCenter + (location.MapPosition + viewOffset) * zoom, generationParams.IndicatorColor, generationParams.SelectedLocationIndicator.Origin, 0, Vector2.One * (generationParams.LocationIconSize / generationParams.SelectedLocationIndicator.size.X) * 1.7f * zoom); } Color color = location.Type.SpriteColor; if (!location.Discovered) { color = Color.White; } if (location.Connections.Find(c => c.Locations.Contains(CurrentDisplayLocation)) == null) { color *= 0.5f; } float iconScale = location == CurrentDisplayLocation ? 1.2f : 1.0f; if (location == HighlightedLocation) { iconScale *= 1.2f; } location.Type.Sprite.Draw(spriteBatch, pos, color, scale: generationParams.LocationIconSize / location.Type.Sprite.size.X * iconScale * zoom); if (location.TypeChangeTimer <= 0 && !string.IsNullOrEmpty(location.LastTypeChangeMessage) && generationParams.TypeChangeIcon != null) { Vector2 typeChangeIconPos = pos + new Vector2(1.35f, -0.35f) * generationParams.LocationIconSize * 0.5f * zoom; float typeChangeIconScale = 18.0f / generationParams.TypeChangeIcon.SourceRect.Width; generationParams.TypeChangeIcon.Draw(spriteBatch, typeChangeIconPos, GUI.Style.Red, scale: typeChangeIconScale * zoom); if (Vector2.Distance(PlayerInput.MousePosition, typeChangeIconPos) < generationParams.TypeChangeIcon.SourceRect.Width * zoom) { tooltip = new Pair <Rectangle, string>( new Rectangle(typeChangeIconPos.ToPoint(), new Point(30)), location.LastTypeChangeMessage); } } if (location != CurrentLocation && CurrentLocation.AvailableMissions.Any(m => m.Locations.Contains(location)) && generationParams.MissionIcon != null) { Vector2 missionIconPos = pos + new Vector2(1.35f, 0.35f) * generationParams.LocationIconSize * 0.5f * zoom; float missionIconScale = 18.0f / generationParams.MissionIcon.SourceRect.Width; generationParams.MissionIcon.Draw(spriteBatch, missionIconPos, generationParams.IndicatorColor, scale: missionIconScale * zoom); if (Vector2.Distance(PlayerInput.MousePosition, missionIconPos) < generationParams.MissionIcon.SourceRect.Width * zoom) { var availableMissions = CurrentLocation.AvailableMissions.Where(m => m.Locations.Contains(location)); tooltip = new Pair <Rectangle, string>( new Rectangle(missionIconPos.ToPoint(), new Point(30)), TextManager.Get("mission") + '\n' + string.Join('\n', availableMissions.Select(m => "- " + m.Name))); } } if (GameMain.DebugDraw && location == HighlightedLocation && (!location.Discovered || !location.Type.HasOutpost)) { if (location.Reputation != null) { Vector2 dPos = pos; dPos.Y += 48; string name = $"Reputation: {location.Name}"; Vector2 nameSize = GUI.SmallFont.MeasureString(name); GUI.DrawString(spriteBatch, dPos, name, Color.White, Color.Black * 0.8f, 4, font: GUI.SmallFont); dPos.Y += nameSize.Y + 16; Rectangle bgRect = new Rectangle((int)dPos.X, (int)dPos.Y, 256, 32); bgRect.Inflate(8, 8); Color barColor = ToolBox.GradientLerp(location.Reputation.NormalizedValue, Color.Red, Color.Yellow, Color.LightGreen); GUI.DrawRectangle(spriteBatch, bgRect, Color.Black * 0.8f, isFilled: true); GUI.DrawRectangle(spriteBatch, new Rectangle((int)dPos.X, (int)dPos.Y, (int)(location.Reputation.NormalizedValue * 255), 32), barColor, isFilled: true); string reputationValue = ((int)location.Reputation.Value).ToString(); Vector2 repValueSize = GUI.SubHeadingFont.MeasureString(reputationValue); GUI.DrawString(spriteBatch, dPos + (new Vector2(256, 32) / 2) - (repValueSize / 2), reputationValue, Color.White, Color.Black, font: GUI.SubHeadingFont); GUI.DrawRectangle(spriteBatch, new Rectangle((int)dPos.X, (int)dPos.Y, 256, 32), Color.White); } } } } DrawDecorativeHUD(spriteBatch, rect); if (HighlightedLocation != null) { Vector2 pos = rectCenter + (HighlightedLocation.MapPosition + viewOffset) * zoom; pos.X += 50 * zoom; Vector2 nameSize = GUI.LargeFont.MeasureString(HighlightedLocation.Name); Vector2 typeSize = GUI.Font.MeasureString(HighlightedLocation.Type.Name); Vector2 size = new Vector2(Math.Max(nameSize.X, typeSize.X), nameSize.Y + typeSize.Y); bool showReputation = HighlightedLocation.Discovered && HighlightedLocation.Type.HasOutpost && HighlightedLocation.Reputation != null; string repLabelText = null, repValueText = null; Vector2 repLabelSize = Vector2.Zero, repBarSize = Vector2.Zero; if (showReputation) { repLabelText = TextManager.Get("reputation"); repLabelSize = GUI.Font.MeasureString(repLabelText); size.X = Math.Max(size.X, repLabelSize.X); repBarSize = new Vector2(Math.Max(0.75f * size.X, 100), repLabelSize.Y); size.X = Math.Max(size.X, (4.0f / 3.0f) * repBarSize.X); size.Y += 2 * repLabelSize.Y + 4 + repBarSize.Y; repValueText = ((int)HighlightedLocation.Reputation.Value).ToString(); } GUI.Style.GetComponentStyle("OuterGlow").Sprites[GUIComponent.ComponentState.None][0].Draw( spriteBatch, new Rectangle((int)(pos.X - 60 * GUI.Scale), (int)(pos.Y - size.Y), (int)(size.X + 120 * GUI.Scale), (int)(size.Y * 2.2f)), Color.Black * hudVisibility); var topLeftPos = pos - new Vector2(0.0f, size.Y / 2); GUI.DrawString(spriteBatch, topLeftPos, HighlightedLocation.Name, GUI.Style.TextColor * hudVisibility * 1.5f, font: GUI.LargeFont); topLeftPos += new Vector2(0.0f, nameSize.Y); GUI.DrawString(spriteBatch, topLeftPos, HighlightedLocation.Type.Name, GUI.Style.TextColor * hudVisibility * 1.5f); if (showReputation) { topLeftPos += new Vector2(0.0f, typeSize.Y + repLabelSize.Y); GUI.DrawString(spriteBatch, topLeftPos, repLabelText, GUI.Style.TextColor * hudVisibility * 1.5f); topLeftPos += new Vector2(0.0f, repLabelSize.Y + 4); Rectangle repBarRect = new Rectangle(new Point((int)topLeftPos.X, (int)topLeftPos.Y), new Point((int)repBarSize.X, (int)repBarSize.Y)); RoundSummary.DrawReputationBar(spriteBatch, repBarRect, HighlightedLocation.Reputation.NormalizedValue); GUI.DrawString(spriteBatch, new Vector2(repBarRect.Right + 4, repBarRect.Top), repValueText, GUI.Style.TextColor); } } if (tooltip != null) { GUIComponent.DrawToolTip(spriteBatch, tooltip.Second, tooltip.First); } spriteBatch.End(); GameMain.Instance.GraphicsDevice.ScissorRectangle = prevScissorRect; spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable); }
public void Draw(SpriteBatch spriteBatch, GraphicsDevice graphics, float deltaTime) { if (GameMain.Config.EnableSplashScreen) { try { DrawSplashScreen(spriteBatch, graphics); if (currSplashScreen != null || PendingSplashScreens.Count > 0) { return; } } catch (Exception e) { DebugConsole.ThrowError("Playing splash screen video failed", e); GameMain.Config.EnableSplashScreen = false; } } var titleStyle = GUI.Style?.GetComponentStyle("TitleText"); Sprite titleSprite = null; if (!WaitForLanguageSelection && titleStyle != null && titleStyle.Sprites.ContainsKey(GUIComponent.ComponentState.None)) { titleSprite = titleStyle.Sprites[GUIComponent.ComponentState.None].First()?.Sprite; } drawn = true; currentBackgroundTexture ??= defaultBackgroundTexture; spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, samplerState: GUI.SamplerState); float scale = (GameMain.GraphicsWidth / (float)currentBackgroundTexture.Width) * 1.2f; float paddingX = currentBackgroundTexture.Width * scale - GameMain.GraphicsWidth; float paddingY = currentBackgroundTexture.Height * scale - GameMain.GraphicsHeight; double noiseT = (Timing.TotalTime * 0.02f); Vector2 pos = new Vector2((float)PerlinNoise.CalculatePerlin(noiseT, noiseT, 0) - 0.5f, (float)PerlinNoise.CalculatePerlin(noiseT, noiseT, 0.5f) - 0.5f); pos = new Vector2(pos.X * paddingX, pos.Y * paddingY); spriteBatch.Draw(currentBackgroundTexture, new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) / 2 + pos, null, Color.White, 0.0f, new Vector2(currentBackgroundTexture.Width / 2, currentBackgroundTexture.Height / 2), scale, SpriteEffects.None, 0.0f); spriteBatch.Draw(overlay, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), null, Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f); float noiseStrength = (float)PerlinNoise.CalculatePerlin(noiseT, noiseT, 0); float noiseScale = (float)PerlinNoise.CalculatePerlin(noiseT * 5.0f, noiseT * 2.0f, 0) * 4.0f; noiseSprite.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight), startOffset: new Vector2(Rand.Range(0.0f, noiseSprite.SourceRect.Width), Rand.Range(0.0f, noiseSprite.SourceRect.Height)), color: Color.White * noiseStrength * 0.1f, textureScale: Vector2.One * noiseScale); titleSprite?.Draw(spriteBatch, new Vector2(GameMain.GraphicsWidth * 0.05f, GameMain.GraphicsHeight * 0.125f), Color.White, origin: new Vector2(0.0f, titleSprite.SourceRect.Height / 2.0f), scale: GameMain.GraphicsHeight / 2000.0f); if (WaitForLanguageSelection) { DrawLanguageSelectionPrompt(spriteBatch, graphics); } else if (DrawLoadingText) { if (TextManager.Initialized) { string loadText; if (LoadState == 100.0f) { #if DEBUG if (GameMain.Config.AutomaticQuickStartEnabled || GameMain.Config.AutomaticCampaignLoadEnabled && GameMain.FirstLoad) { loadText = "QUICKSTARTING ..."; } else { #endif loadText = TextManager.Get("PressAnyKey"); #if DEBUG } #endif } else { loadText = TextManager.Get("Loading"); if (LoadState != null) { loadText += " " + (int)LoadState + " %"; } } if (GUI.LargeFont != null) { GUI.LargeFont.DrawString(spriteBatch, loadText.ToUpper(), new Vector2(GameMain.GraphicsWidth / 2.0f - GUI.LargeFont.MeasureString(loadText.ToUpper()).X / 2.0f, GameMain.GraphicsHeight * 0.75f), Color.White); } } if (GUI.Font != null && selectedTip != null) { string wrappedTip = ToolBox.WrapText(selectedTip, GameMain.GraphicsWidth * 0.5f, GUI.Font); string[] lines = wrappedTip.Split('\n'); float lineHeight = GUI.Font.MeasureString(selectedTip).Y; for (int i = 0; i < lines.Length; i++) { GUI.Font.DrawString(spriteBatch, lines[i], new Vector2((int)(GameMain.GraphicsWidth / 2.0f - GUI.Font.MeasureString(lines[i]).X / 2.0f), (int)(GameMain.GraphicsHeight * 0.8f + i * lineHeight)), Color.White); } } } spriteBatch.End(); spriteBatch.Begin(blendState: BlendState.Additive); Vector2 decorativeScale = new Vector2(GameMain.GraphicsHeight / 1080.0f); float noiseVal = (float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.25f, Timing.TotalTime * 0.5f, 0); decorativeGraph.Draw(spriteBatch, (int)(decorativeGraph.FrameCount * noiseVal), new Vector2(GameMain.GraphicsWidth * 0.001f, GameMain.GraphicsHeight * 0.24f), Color.White, Vector2.Zero, 0.0f, decorativeScale, SpriteEffects.FlipVertically); decorativeMap.Draw(spriteBatch, (int)(decorativeMap.FrameCount * noiseVal), new Vector2(GameMain.GraphicsWidth * 0.99f, GameMain.GraphicsHeight * 0.66f), Color.White, decorativeMap.FrameSize.ToVector2(), 0.0f, decorativeScale); if (noiseVal < 0.2f) { //SCP-CB reference randText = (new string[] { "NIL", "black white gray", "Sometimes we would have had time to scream", "e8m106]af", "NO" }).GetRandom(); } else if (noiseVal < 0.3f) { randText = ToolBox.RandomSeed(9); } else if (noiseVal < 0.5f) { randText = Rand.Int(100).ToString().PadLeft(2, '0') + " " + Rand.Int(100).ToString().PadLeft(2, '0') + " " + Rand.Int(100).ToString().PadLeft(2, '0') + " " + Rand.Int(100).ToString().PadLeft(2, '0'); } GUI.LargeFont?.DrawString(spriteBatch, randText, new Vector2(GameMain.GraphicsWidth - decorativeMap.FrameSize.X * decorativeScale.X * 0.8f, GameMain.GraphicsHeight * 0.57f), Color.White * (1.0f - noiseVal)); spriteBatch.End(); }
void UpdateDying(float deltaTime) { if (deathAnimDuration <= 0.0f) { return; } float noise = (PerlinNoise.GetPerlin(WalkPos * 0.002f, WalkPos * 0.003f) - 0.5f) * 5.0f; float animStrength = (1.0f - deathAnimTimer / deathAnimDuration); Limb baseLimb = GetLimb(LimbType.Head); //if head is the main limb, it technically can't be severed - the rest of the limbs are considered severed if the head gets cut off if (baseLimb == MainLimb) { int connectedToHeadCount = GetConnectedLimbs(baseLimb).Count; //if there's nothing connected to the head, don't make it wiggle by itself if (connectedToHeadCount == 1) { baseLimb = null; } Limb torso = GetLimb(LimbType.Torso, excludeSevered: false); if (torso != null) { //if there are more limbs connected to the torso than to the head, make the torso wiggle instead int connectedToTorsoCount = GetConnectedLimbs(torso).Count; if (connectedToTorsoCount > connectedToHeadCount) { baseLimb = torso; } } } else if (baseLimb == null) { baseLimb = GetLimb(LimbType.Torso, excludeSevered: true); if (baseLimb == null) { return; } } var connectedToBaseLimb = GetConnectedLimbs(baseLimb); Limb tail = GetLimb(LimbType.Tail); if (baseLimb != null) { baseLimb.body.ApplyTorque((float)(Math.Sqrt(baseLimb.Mass) * Dir * (Math.Sin(WalkPos) + noise)) * 30.0f * animStrength); } if (tail != null && connectedToBaseLimb.Contains(tail)) { tail.body.ApplyTorque((float)(Math.Sqrt(tail.Mass) * -Dir * (Math.Sin(WalkPos) + noise)) * 30.0f * animStrength); } WalkPos += deltaTime * 10.0f * animStrength; Vector2 centerOfMass = GetCenterOfMass(); foreach (Limb limb in Limbs) { if (!connectedToBaseLimb.Contains(limb)) { continue; } #if CLIENT if (limb.LightSource != null) { limb.LightSource.Color = Color.Lerp(limb.InitialLightSourceColor, Color.TransparentBlack, deathAnimTimer / deathAnimDuration); if (limb.InitialLightSpriteAlpha.HasValue) { limb.LightSource.OverrideLightSpriteAlpha = MathHelper.Lerp(limb.InitialLightSpriteAlpha.Value, 0.0f, deathAnimTimer / deathAnimDuration); } } #endif if (limb.type == LimbType.Head || limb.type == LimbType.Tail || limb.IsSevered || !limb.body.Enabled) { continue; } if (limb.Mass <= 0.0f) { string errorMsg = "Creature death animation error: invalid limb mass on character \"" + character.SpeciesName + "\" (type: " + limb.type + ", mass: " + limb.Mass + ")"; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("FishAnimController.UpdateDying:InvalidMass" + character.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); deathAnimTimer = deathAnimDuration; return; } Vector2 diff = (centerOfMass - limb.SimPosition); if (!MathUtils.IsValid(diff)) { string errorMsg = "Creature death animation error: invalid diff (center of mass: " + centerOfMass + ", limb position: " + limb.SimPosition + ")"; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("FishAnimController.UpdateDying:InvalidDiff" + character.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); deathAnimTimer = deathAnimDuration; return; } limb.body.ApplyForce(diff * (float)(Math.Sin(WalkPos) * Math.Sqrt(limb.Mass)) * 30.0f * animStrength, maxVelocity: 10.0f); } }
void UpdateDying(float deltaTime) { if (deathAnimDuration <= 0.0f) { return; } float noise = (PerlinNoise.GetPerlin(WalkPos * 0.002f, WalkPos * 0.003f) - 0.5f) * 5.0f; float animStrength = (1.0f - deathAnimTimer / deathAnimDuration); Limb head = GetLimb(LimbType.Head); if (head != null && head.IsSevered) { return; } Limb tail = GetLimb(LimbType.Tail); if (head != null && !head.IsSevered) { head.body.ApplyTorque((float)(Math.Sqrt(head.Mass) * Dir * (Math.Sin(WalkPos) + noise)) * 30.0f * animStrength); } if (tail != null && !tail.IsSevered) { tail.body.ApplyTorque((float)(Math.Sqrt(tail.Mass) * -Dir * (Math.Sin(WalkPos) + noise)) * 30.0f * animStrength); } WalkPos += deltaTime * 10.0f * animStrength; Vector2 centerOfMass = GetCenterOfMass(); foreach (Limb limb in Limbs) { #if CLIENT if (limb.LightSource != null) { limb.LightSource.Color = Color.Lerp(limb.InitialLightSourceColor, Color.TransparentBlack, deathAnimTimer / deathAnimDuration); } #endif if (limb.type == LimbType.Head || limb.type == LimbType.Tail || limb.IsSevered || !limb.body.Enabled) { continue; } if (limb.Mass <= 0.0f) { string errorMsg = "Creature death animation error: invalid limb mass on character \"" + character.SpeciesName + "\" (type: " + limb.type + ", mass: " + limb.Mass + ")"; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("FishAnimController.UpdateDying:InvalidMass" + character.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); deathAnimTimer = deathAnimDuration; return; } Vector2 diff = (centerOfMass - limb.SimPosition); if (!MathUtils.IsValid(diff)) { string errorMsg = "Creature death animation error: invalid diff (center of mass: " + centerOfMass + ", limb position: " + limb.SimPosition + ")"; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("FishAnimController.UpdateDying:InvalidDiff" + character.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); deathAnimTimer = deathAnimDuration; return; } limb.body.ApplyForce(diff * (float)(Math.Sin(WalkPos) * Math.Sqrt(limb.Mass)) * 30.0f * animStrength, maxVelocity: 10.0f); } }
public void Draw(SpriteBatch spriteBatch, GUICustomComponent mapContainer) { Rectangle rect = mapContainer.Rect; Vector2 viewSize = new Vector2(rect.Width / zoom, rect.Height / zoom); float edgeBuffer = size * (BackgroundScale - 1.0f) / 2; drawOffset.X = MathHelper.Clamp(drawOffset.X, -size - edgeBuffer + viewSize.X / 2.0f, edgeBuffer - viewSize.X / 2.0f); drawOffset.Y = MathHelper.Clamp(drawOffset.Y, -size - edgeBuffer + viewSize.Y / 2.0f, edgeBuffer - viewSize.Y / 2.0f); drawOffsetNoise = new Vector2( (float)PerlinNoise.Perlin(Timing.TotalTime * 0.1f % 255, Timing.TotalTime * 0.1f % 255, 0) - 0.5f, (float)PerlinNoise.Perlin(Timing.TotalTime * 0.2f % 255, Timing.TotalTime * 0.2f % 255, 0.5f) - 0.5f) * 10.0f; Vector2 viewOffset = drawOffset + drawOffsetNoise; Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y); Rectangle prevScissorRect = GameMain.Instance.GraphicsDevice.ScissorRectangle; spriteBatch.End(); spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, rect); spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable); for (int x = 0; x < mapTiles.GetLength(0); x++) { for (int y = 0; y < mapTiles.GetLength(1); y++) { Vector2 mapPos = new Vector2( x * generationParams.TileSpriteSpacing.X + ((y % 2 == 0) ? 0.0f : generationParams.TileSpriteSpacing.X * 0.5f), y * generationParams.TileSpriteSpacing.Y); mapPos.X -= size / 2 * (BackgroundScale - 1.0f); mapPos.Y -= size / 2 * (BackgroundScale - 1.0f); Vector2 scale = new Vector2( generationParams.TileSpriteSize.X / mapTiles[x, y].Sprite.size.X, generationParams.TileSpriteSize.Y / mapTiles[x, y].Sprite.size.Y); mapTiles[x, y].Sprite.Draw(spriteBatch, rectCenter + (mapPos + viewOffset) * zoom, Color.White, origin: new Vector2(256.0f, 256.0f), rotate: 0, scale: scale * zoom, spriteEffect: mapTiles[x, y].SpriteEffect); } } #if DEBUG if (generationParams.ShowNoiseMap) { GUI.DrawRectangle(spriteBatch, rectCenter + (borders.Location.ToVector2() + viewOffset) * zoom, borders.Size.ToVector2() * zoom, Color.White, true); } #endif Vector2 topLeft = rectCenter + viewOffset * zoom; topLeft.X = (int)topLeft.X; topLeft.Y = (int)topLeft.Y; Vector2 bottomRight = rectCenter + (viewOffset + new Vector2(size, size)) * zoom; bottomRight.X = (int)bottomRight.X; bottomRight.Y = (int)bottomRight.Y; spriteBatch.Draw(noiseTexture, destinationRectangle: new Rectangle((int)topLeft.X, (int)topLeft.Y, (int)(bottomRight.X - topLeft.X), (int)(bottomRight.Y - topLeft.Y)), sourceRectangle: null, color: Color.White); if (topLeft.X > rect.X) { GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, rect.Y, (int)(topLeft.X - rect.X), rect.Height), Color.Black * 0.8f, true); } if (topLeft.Y > rect.Y) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)topLeft.X, rect.Y, (int)(bottomRight.X - topLeft.X), (int)(topLeft.Y - rect.Y)), Color.Black * 0.8f, true); } if (bottomRight.X < rect.Right) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)bottomRight.X, rect.Y, (int)(rect.Right - bottomRight.X), rect.Height), Color.Black * 0.8f, true); } if (bottomRight.Y < rect.Bottom) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)topLeft.X, (int)bottomRight.Y, (int)(bottomRight.X - topLeft.X), (int)(rect.Bottom - bottomRight.Y)), Color.Black * 0.8f, true); } var sourceRect = rect; float rawNoiseScale = 1.0f + Noise[(int)(Timing.TotalTime * 100 % Noise.GetLength(0) - 1), (int)(Timing.TotalTime * 100 % Noise.GetLength(1) - 1)]; cameraNoiseStrength = Noise[(int)(Timing.TotalTime * 10 % Noise.GetLength(0) - 1), (int)(Timing.TotalTime * 10 % Noise.GetLength(1) - 1)]; rawNoiseSprite.DrawTiled(spriteBatch, rect.Location.ToVector2(), rect.Size.ToVector2(), startOffset: new Point(Rand.Range(0, rawNoiseSprite.SourceRect.Width), Rand.Range(0, rawNoiseSprite.SourceRect.Height)), color: Color.White * cameraNoiseStrength * 0.5f, textureScale: Vector2.One * rawNoiseScale); if (generationParams.ShowLocations) { foreach (LocationConnection connection in connections) { Color connectionColor; if (GameMain.DebugDraw) { float sizeFactor = MathUtils.InverseLerp( MapGenerationParams.Instance.SmallLevelConnectionLength, MapGenerationParams.Instance.LargeLevelConnectionLength, connection.Length); connectionColor = ToolBox.GradientLerp(sizeFactor, Color.LightGreen, Color.Orange, Color.Red); } else { connectionColor = ToolBox.GradientLerp(connection.Difficulty / 100.0f, MapGenerationParams.Instance.LowDifficultyColor, MapGenerationParams.Instance.MediumDifficultyColor, MapGenerationParams.Instance.HighDifficultyColor); } int width = (int)(3 * zoom); if (selectedLocation != currentLocation && (connection.Locations.Contains(selectedLocation) && connection.Locations.Contains(currentLocation))) { connectionColor = Color.Gold; } else if (highlightedLocation != currentLocation && (connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(currentLocation))) { connectionColor = Color.Lerp(connectionColor, Color.White, 0.5f); width *= 2; } else if (!connection.Passed) { //crackColor *= 0.5f; } for (int i = 0; i < connection.CrackSegments.Count; i++) { var segment = connection.CrackSegments[i]; Vector2 start = rectCenter + (segment[0] + viewOffset) * zoom; Vector2 end = rectCenter + (segment[1] + viewOffset) * zoom; if (!rect.Contains(start) && !rect.Contains(end)) { continue; } else { Vector2?intersection = MathUtils.GetLineRectangleIntersection(start, end, new Rectangle(rect.X, rect.Y + rect.Height, rect.Width, rect.Height)); if (intersection != null) { if (!rect.Contains(start)) { start = (Vector2)intersection; } else { end = (Vector2)intersection; } } } float distFromPlayer = Vector2.Distance(currentLocation.MapPosition, (segment[0] + segment[1]) / 2.0f); float dist = Vector2.Distance(start, end); float a = GameMain.DebugDraw ? 1.0f : (200.0f - distFromPlayer) / 200.0f; spriteBatch.Draw(generationParams.ConnectionSprite.Texture, new Rectangle((int)start.X, (int)start.Y, (int)(dist - 1 * zoom), width), null, connectionColor * MathHelper.Clamp(a, 0.1f, 0.5f), MathUtils.VectorToAngle(end - start), new Vector2(0, 16), SpriteEffects.None, 0.01f); } if (GameMain.DebugDraw && zoom > 1.0f && generationParams.ShowLevelTypeNames) { Vector2 center = rectCenter + (connection.CenterPos + viewOffset) * zoom; if (rect.Contains(center)) { GUI.DrawString(spriteBatch, center, connection.Biome.Name + " (" + connection.Difficulty + ")", Color.White); } } } rect.Inflate(8, 8); GUI.DrawRectangle(spriteBatch, rect, Color.Black, false, 0.0f, 8); GUI.DrawRectangle(spriteBatch, rect, Color.LightGray); for (int i = 0; i < locations.Count; i++) { Location location = locations[i]; Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom; float iconScale = MapGenerationParams.Instance.LocationIconSize / location.Type.Sprite.size.X; Rectangle drawRect = location.Type.Sprite.SourceRect; drawRect.X = (int)pos.X - drawRect.Width / 2; drawRect.Y = (int)pos.Y - drawRect.Width / 2; if (!rect.Intersects(drawRect)) { continue; } Color color = location.Type.SpriteColor; if (location.Connections.Find(c => c.Locations.Contains(currentLocation)) == null) { color *= 0.5f; } //color *= (location.Discovered) ? 0.8f : 0.5f; //if (location != currentLocation) color *= 1.0f; if (location == highlightedLocation) { iconScale *= 1.1f; color = Color.Lerp(color, Color.White, 0.5f); } location.Type.Sprite.Draw(spriteBatch, pos, color, scale: iconScale * zoom); } } DrawDecorativeHUD(spriteBatch, rect); for (int i = 0; i < 3; i++) { Location location = (i == 0) ? highlightedLocation : selectedLocation; if (i == 2) { location = currentLocation; } if (location == null) { continue; } Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom; //pos.X = (int)(pos.X + location.Type.Sprite.SourceRect.Width * 0.6f); pos.Y = (int)(pos.Y + 15 * zoom); GUI.DrawString(spriteBatch, pos - GUI.Font.MeasureString(location.Name) * 0.5f, location.Name, Color.White * hudOpenState, Color.Black * 0.8f * hudOpenState, 3); GUI.DrawString(spriteBatch, pos + Vector2.UnitY * 25 - GUI.Font.MeasureString(location.Type.DisplayName) * 0.5f, location.Type.DisplayName, Color.White * hudOpenState, Color.Black * 0.8f * hudOpenState, 3); } GameMain.Instance.GraphicsDevice.ScissorRectangle = prevScissorRect; spriteBatch.End(); spriteBatch.Begin(SpriteSortMode.Deferred); }
partial void GenerateNoiseMapProjSpecific() { if (noiseTexture == null) { noiseTexture = new Texture2D(GameMain.Instance.GraphicsDevice, generationParams.NoiseResolution, generationParams.NoiseResolution); rawNoiseTexture = new Texture2D(GameMain.Instance.GraphicsDevice, generationParams.NoiseResolution, generationParams.NoiseResolution); rawNoiseSprite = new Sprite(rawNoiseTexture, null, null); } Color[] crackTextureData = new Color[generationParams.NoiseResolution * generationParams.NoiseResolution]; Color[] noiseTextureData = new Color[generationParams.NoiseResolution * generationParams.NoiseResolution]; Color[] rawNoiseTextureData = new Color[generationParams.NoiseResolution * generationParams.NoiseResolution]; for (int x = 0; x < generationParams.NoiseResolution; x++) { for (int y = 0; y < generationParams.NoiseResolution; y++) { noiseTextureData[x + y * generationParams.NoiseResolution] = Color.Lerp(Color.Black, Color.Transparent, Noise[x, y]); rawNoiseTextureData[x + y * generationParams.NoiseResolution] = Color.Lerp(Color.Black, Color.White, Rand.Range(0.0f, 1.0f)); } } float mapRadius = size / 2; Vector2 mapCenter = Vector2.One * mapRadius; foreach (LocationConnection connection in connections) { float centerDist = Vector2.Distance(connection.CenterPos, mapCenter); Vector2 connectionStart = connection.Locations[0].MapPosition; Vector2 connectionEnd = connection.Locations[1].MapPosition; float connectionLength = Vector2.Distance(connectionStart, connectionEnd); int iterations = (int)(Math.Sqrt(connectionLength * generationParams.ConnectionIndicatorIterationMultiplier)); connection.CrackSegments = MathUtils.GenerateJaggedLine( connectionStart, connectionEnd, iterations, connectionLength * generationParams.ConnectionIndicatorDisplacementMultiplier); iterations = (int)(Math.Sqrt(connectionLength * generationParams.ConnectionIterationMultiplier)); var visualCrackSegments = MathUtils.GenerateJaggedLine( connectionStart, connectionEnd, iterations, connectionLength * generationParams.ConnectionDisplacementMultiplier); float totalLength = Vector2.Distance(visualCrackSegments[0][0], visualCrackSegments.Last()[1]); for (int i = 0; i < visualCrackSegments.Count; i++) { Vector2 start = visualCrackSegments[i][0] * (generationParams.NoiseResolution / (float)size); Vector2 end = visualCrackSegments[i][1] * (generationParams.NoiseResolution / (float)size); float length = Vector2.Distance(start, end); for (float x = 0; x < 1; x += 1.0f / length) { Vector2 pos = Vector2.Lerp(start, end, x); SetNoiseColorOnArea(pos, MathHelper.Clamp((int)(totalLength / 30), 2, 5) + Rand.Range(-1, 1), Color.Transparent); } } } void SetNoiseColorOnArea(Vector2 pos, int dist, Color color) { for (int x = -dist; x < dist; x++) { for (int y = -dist; y < dist; y++) { float d = 1.0f - new Vector2(x, y).Length() / dist; if (d <= 0) { continue; } int xIndex = (int)pos.X + x; if (xIndex < 0 || xIndex >= generationParams.NoiseResolution) { continue; } int yIndex = (int)pos.Y + y; if (yIndex < 0 || yIndex >= generationParams.NoiseResolution) { continue; } float perlin = (float)PerlinNoise.Perlin( xIndex / (float)generationParams.NoiseResolution * 100.0f, yIndex / (float)generationParams.NoiseResolution * 100.0f, 0); byte a = Math.Max(crackTextureData[xIndex + yIndex * generationParams.NoiseResolution].A, (byte)((d * perlin) * 255)); crackTextureData[xIndex + yIndex * generationParams.NoiseResolution].A = a; } } } for (int i = 0; i < noiseTextureData.Length; i++) { float darken = noiseTextureData[i].A / 255.0f; Color pathColor = Color.Lerp(Color.White, Color.Transparent, noiseTextureData[i].A / 255.0f); noiseTextureData[i] = Color.Lerp(noiseTextureData[i], pathColor, crackTextureData[i].A / 255.0f * 0.5f); } noiseTexture.SetData(noiseTextureData); rawNoiseTexture.SetData(rawNoiseTextureData); }
public void Draw(SpriteBatch spriteBatch, GUICustomComponent mapContainer) { Rectangle rect = mapContainer.Rect; Vector2 viewSize = new Vector2(rect.Width / zoom, rect.Height / zoom); float edgeBuffer = size * (BackgroundScale - 1.0f) / 2; drawOffset.X = MathHelper.Clamp(drawOffset.X, -size - edgeBuffer + viewSize.X / 2.0f, edgeBuffer - viewSize.X / 2.0f); drawOffset.Y = MathHelper.Clamp(drawOffset.Y, -size - edgeBuffer + viewSize.Y / 2.0f, edgeBuffer - viewSize.Y / 2.0f); drawOffsetNoise = new Vector2( (float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.1f % 255, Timing.TotalTime * 0.1f % 255, 0) - 0.5f, (float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.2f % 255, Timing.TotalTime * 0.2f % 255, 0.5f) - 0.5f) * 10.0f; Vector2 viewOffset = drawOffset + drawOffsetNoise; Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y) + CenterOffset; Rectangle prevScissorRect = GameMain.Instance.GraphicsDevice.ScissorRectangle; spriteBatch.End(); spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, rect); spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable); for (int x = 0; x < mapTiles.GetLength(0); x++) { for (int y = 0; y < mapTiles.GetLength(1); y++) { Vector2 mapPos = new Vector2( x * generationParams.TileSpriteSpacing.X + ((y % 2 == 0) ? 0.0f : generationParams.TileSpriteSpacing.X * 0.5f), y * generationParams.TileSpriteSpacing.Y); mapPos.X -= size / 2 * (BackgroundScale - 1.0f); mapPos.Y -= size / 2 * (BackgroundScale - 1.0f); Vector2 scale = new Vector2( generationParams.TileSpriteSize.X / mapTiles[x, y].Sprite.size.X, generationParams.TileSpriteSize.Y / mapTiles[x, y].Sprite.size.Y); mapTiles[x, y].Sprite.Draw(spriteBatch, rectCenter + (mapPos + viewOffset) * zoom, Color.White, origin: new Vector2(256.0f, 256.0f), rotate: 0, scale: scale * zoom, spriteEffect: mapTiles[x, y].SpriteEffect); } } #if DEBUG if (generationParams.ShowNoiseMap) { GUI.DrawRectangle(spriteBatch, rectCenter + (borders.Location.ToVector2() + viewOffset) * zoom, borders.Size.ToVector2() * zoom, Color.White, true); } #endif Vector2 topLeft = rectCenter + viewOffset * zoom; topLeft.X = (int)topLeft.X; topLeft.Y = (int)topLeft.Y; Vector2 bottomRight = rectCenter + (viewOffset + new Vector2(size, size)) * zoom; bottomRight.X = (int)bottomRight.X; bottomRight.Y = (int)bottomRight.Y; spriteBatch.Draw(noiseTexture, destinationRectangle: new Rectangle((int)topLeft.X, (int)topLeft.Y, (int)(bottomRight.X - topLeft.X), (int)(bottomRight.Y - topLeft.Y)), sourceRectangle: null, color: Color.White); if (topLeft.X > rect.X) { GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, rect.Y, (int)(topLeft.X - rect.X), rect.Height), Color.Black * 0.8f, true); } if (topLeft.Y > rect.Y) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)topLeft.X, rect.Y, (int)(bottomRight.X - topLeft.X), (int)(topLeft.Y - rect.Y)), Color.Black * 0.8f, true); } if (bottomRight.X < rect.Right) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)bottomRight.X, rect.Y, (int)(rect.Right - bottomRight.X), rect.Height), Color.Black * 0.8f, true); } if (bottomRight.Y < rect.Bottom) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)topLeft.X, (int)bottomRight.Y, (int)(bottomRight.X - topLeft.X), (int)(rect.Bottom - bottomRight.Y)), Color.Black * 0.8f, true); } var sourceRect = rect; float rawNoiseScale = 1.0f + Noise[(int)(Timing.TotalTime * 100 % Noise.GetLength(0) - 1), (int)(Timing.TotalTime * 100 % Noise.GetLength(1) - 1)]; cameraNoiseStrength = Noise[(int)(Timing.TotalTime * 10 % Noise.GetLength(0) - 1), (int)(Timing.TotalTime * 10 % Noise.GetLength(1) - 1)]; rawNoiseSprite.DrawTiled(spriteBatch, rect.Location.ToVector2(), rect.Size.ToVector2(), startOffset: new Point(Rand.Range(0, rawNoiseSprite.SourceRect.Width), Rand.Range(0, rawNoiseSprite.SourceRect.Height)), color: Color.White * cameraNoiseStrength * 0.5f, textureScale: Vector2.One * rawNoiseScale); rawNoiseSprite.DrawTiled(spriteBatch, rect.Location.ToVector2(), rect.Size.ToVector2(), startOffset: new Point(Rand.Range(0, rawNoiseSprite.SourceRect.Width), Rand.Range(0, rawNoiseSprite.SourceRect.Height)), color: new Color(20, 20, 20, 100), textureScale: Vector2.One * rawNoiseScale * 2); if (generationParams.ShowLocations) { foreach (LocationConnection connection in connections) { Color connectionColor; if (GameMain.DebugDraw) { float sizeFactor = MathUtils.InverseLerp( MapGenerationParams.Instance.SmallLevelConnectionLength, MapGenerationParams.Instance.LargeLevelConnectionLength, connection.Length); connectionColor = ToolBox.GradientLerp(sizeFactor, Color.LightGreen, GUI.Style.Orange, GUI.Style.Red); } else { connectionColor = ToolBox.GradientLerp(connection.Difficulty / 100.0f, MapGenerationParams.Instance.LowDifficultyColor, MapGenerationParams.Instance.MediumDifficultyColor, MapGenerationParams.Instance.HighDifficultyColor); } int width = (int)(3 * zoom); if (SelectedLocation != CurrentLocation && (connection.Locations.Contains(SelectedLocation) && connection.Locations.Contains(CurrentLocation))) { connectionColor = Color.Gold; width *= 2; } else if (highlightedLocation != CurrentLocation && (connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(CurrentLocation))) { connectionColor = Color.Lerp(connectionColor, Color.White, 0.5f); width *= 2; } else if (!connection.Passed) { //crackColor *= 0.5f; } for (int i = 0; i < connection.CrackSegments.Count; i++) { var segment = connection.CrackSegments[i]; Vector2 start = rectCenter + (segment[0] + viewOffset) * zoom; Vector2 end = rectCenter + (segment[1] + viewOffset) * zoom; if (!rect.Contains(start) && !rect.Contains(end)) { continue; } else { if (MathUtils.GetLineRectangleIntersection(start, end, new Rectangle(rect.X, rect.Y + rect.Height, rect.Width, rect.Height), out Vector2 intersection)) { if (!rect.Contains(start)) { start = intersection; } else { end = intersection; } } } float distFromPlayer = Vector2.Distance(CurrentLocation.MapPosition, (segment[0] + segment[1]) / 2.0f); float dist = Vector2.Distance(start, end); float a = GameMain.DebugDraw ? 1.0f : (200.0f - distFromPlayer) / 200.0f; spriteBatch.Draw(generationParams.ConnectionSprite.Texture, new Rectangle((int)start.X, (int)start.Y, (int)(dist - 1 * zoom), width), null, connectionColor * MathHelper.Clamp(a, 0.1f, 0.5f), MathUtils.VectorToAngle(end - start), new Vector2(0, 16), SpriteEffects.None, 0.01f); } if (GameMain.DebugDraw && zoom > 1.0f && generationParams.ShowLevelTypeNames) { Vector2 center = rectCenter + (connection.CenterPos + viewOffset) * zoom; if (rect.Contains(center)) { GUI.DrawString(spriteBatch, center, connection.Biome.Identifier + " (" + connection.Difficulty + ")", Color.White); } } } rect.Inflate(8, 8); GUI.DrawRectangle(spriteBatch, rect, Color.Black, false, 0.0f, 8); GUI.DrawRectangle(spriteBatch, rect, Color.LightGray); for (int i = 0; i < Locations.Count; i++) { Location location = Locations[i]; Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom; Rectangle drawRect = location.Type.Sprite.SourceRect; drawRect.X = (int)pos.X - drawRect.Width / 2; drawRect.Y = (int)pos.Y - drawRect.Width / 2; if (!rect.Intersects(drawRect)) { continue; } Color color = location.Type.SpriteColor; if (location.Connections.Find(c => c.Locations.Contains(CurrentLocation)) == null) { color *= 0.5f; } float iconScale = location == CurrentLocation ? 1.2f : 1.0f; if (location == highlightedLocation) { iconScale *= 1.1f; color = Color.Lerp(color, Color.White, 0.5f); } float distFromPlayer = Vector2.Distance(CurrentLocation.MapPosition, location.MapPosition); color *= MathHelper.Clamp((1000.0f - distFromPlayer) / 500.0f, 0.1f, 1.0f); location.Type.Sprite.Draw(spriteBatch, pos, color, scale: MapGenerationParams.Instance.LocationIconSize / location.Type.Sprite.size.X * iconScale * zoom); MapGenerationParams.Instance.LocationIndicator.Draw(spriteBatch, pos, color, scale: MapGenerationParams.Instance.LocationIconSize / MapGenerationParams.Instance.LocationIndicator.size.X * iconScale * zoom * 1.4f); } //PLACEHOLDER until the stuff at the center of the map is implemented float centerIconSize = 50.0f; Vector2 centerPos = rectCenter + (new Vector2(size / 2) + viewOffset) * zoom; bool mouseOn = Vector2.Distance(PlayerInput.MousePosition, centerPos) < centerIconSize * zoom; var centerLocationType = LocationType.List.Last(); Color centerColor = centerLocationType.SpriteColor * (mouseOn ? 1.0f : 0.6f); centerLocationType.Sprite.Draw(spriteBatch, centerPos, centerColor, scale: centerIconSize / centerLocationType.Sprite.size.X * zoom); MapGenerationParams.Instance.LocationIndicator.Draw(spriteBatch, centerPos, centerColor, scale: centerIconSize / MapGenerationParams.Instance.LocationIndicator.size.X * zoom * 1.2f); if (mouseOn && PlayerInput.PrimaryMouseButtonClicked() && !messageBoxOpen) { if (TextManager.ContainsTag("centerarealockedheader") && TextManager.ContainsTag("centerarealockedtext")) { var messageBox = new GUIMessageBox( TextManager.Get("centerarealockedheader"), TextManager.Get("centerarealockedtext")); messageBoxOpen = true; CoroutineManager.StartCoroutine(WaitForMessageBoxClosed(messageBox)); } else { //if the message cannot be shown in the selected language, //show the campaign roadmap (which mentions the center location not being reachable) var messageBox = new GUIMessageBox(TextManager.Get("CampaignRoadMapTitle"), TextManager.Get("CampaignRoadMapText")); messageBoxOpen = true; CoroutineManager.StartCoroutine(WaitForMessageBoxClosed(messageBox)); } } } DrawDecorativeHUD(spriteBatch, rect); for (int i = 0; i < 2; i++) { Location location = (i == 0) ? highlightedLocation : CurrentLocation; if (location == null) { continue; } Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom; pos.X += 25 * zoom; pos.Y -= 5 * zoom; Vector2 size = GUI.LargeFont.MeasureString(location.Name); GUI.Style.GetComponentStyle("OuterGlow").Sprites[GUIComponent.ComponentState.None][0].Draw( spriteBatch, new Rectangle((int)pos.X - 30, (int)(pos.Y - 10), (int)size.X + 60, (int)(size.Y + 50 * GUI.Scale)), Color.Black * hudOpenState * 0.7f); GUI.DrawString(spriteBatch, pos, location.Name, Color.White * hudOpenState * 1.5f, font: GUI.LargeFont); GUI.DrawString(spriteBatch, pos + Vector2.UnitY * size.Y * 0.8f, location.Type.Name, Color.White * hudOpenState * 1.5f); } spriteBatch.End(); GameMain.Instance.GraphicsDevice.ScissorRectangle = prevScissorRect; spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable); }
public void Update(float deltaTime) { position += new Vector2(velocity.X, velocity.Y) * deltaTime; depth = MathHelper.Clamp(depth + velocity.Z * deltaTime, Prefab.MinDepth, Prefab.MaxDepth * 10); if (Prefab.FlashInterval > 0.0f) { flashTimer -= deltaTime; if (flashTimer > 0.0f) { alpha = 0.0f; } else { //value goes from 0 to 1 and back to 0 during the flash alpha = (float)Math.Sin(-flashTimer / Prefab.FlashDuration * MathHelper.Pi) * PerlinNoise.GetPerlin((float)Timing.TotalTime * 0.1f, (float)Timing.TotalTime * 0.2f); if (flashTimer < -Prefab.FlashDuration) { flashTimer = Prefab.FlashInterval; } } } checkWallsTimer -= deltaTime; if (checkWallsTimer <= 0.0f && Level.Loaded != null) { checkWallsTimer = CheckWallsInterval; obstacleDiff = Vector2.Zero; if (position.Y > Level.Loaded.Size.Y) { obstacleDiff = Vector2.UnitY; } else if (position.Y < 0.0f) { obstacleDiff = -Vector2.UnitY; } else if (position.X < 0.0f) { obstacleDiff = Vector2.UnitX; } else if (position.X > Level.Loaded.Size.X) { obstacleDiff = -Vector2.UnitX; } else { var cells = Level.Loaded.GetCells(position, 1); if (cells.Count > 0) { int cellCount = 0; foreach (Voronoi2.VoronoiCell cell in cells) { Vector2 diff = cell.Center - position; if (diff.LengthSquared() > 5000.0f * 5000.0f) { continue; } obstacleDiff += diff; cellCount++; } if (cellCount > 0) { obstacleDiff /= cellCount; obstacleDist = obstacleDiff.Length(); obstacleDiff = Vector2.Normalize(obstacleDiff); } } } } if (Swarm != null) { Vector2 midPoint = Swarm.MidPoint(); float midPointDist = Vector2.Distance(SimPosition, midPoint) * 100.0f; if (midPointDist > Swarm.MaxDistance) { steeringManager.SteeringSeek(midPoint, ((midPointDist / Swarm.MaxDistance) - 1.0f) * Prefab.Speed); } steeringManager.SteeringManual(deltaTime, Swarm.AvgVelocity() * Swarm.Cohesion); } if (Prefab.WanderAmount > 0.0f) { steeringManager.SteeringWander(Prefab.Speed); } if (obstacleDiff != Vector2.Zero) { steeringManager.SteeringManual(deltaTime, -obstacleDiff * (1.0f - obstacleDist / 5000.0f) * Prefab.Speed); } steeringManager.Update(Prefab.Speed); if (Prefab.WanderZAmount > 0.0f) { wanderZPhase += Rand.Range(-Prefab.WanderZAmount, Prefab.WanderZAmount); velocity.Z = (float)Math.Sin(wanderZPhase) * Prefab.Speed; } velocity = Vector3.Lerp(velocity, new Vector3(Steering.X, Steering.Y, velocity.Z), deltaTime); UpdateDeformations(deltaTime); }
public void MoveCamera(float deltaTime, bool allowMove = true, bool allowZoom = true, bool?followSub = null) { prevPosition = position; prevZoom = zoom; float moveSpeed = 20.0f / zoom; Vector2 moveCam = Vector2.Zero; if (TargetPos == Vector2.Zero) { Vector2 moveInput = Vector2.Zero; if (allowMove && !Freeze) { if (GUI.KeyboardDispatcher.Subscriber == null) { if (PlayerInput.KeyDown(Keys.LeftShift)) { moveSpeed *= 2.0f; } if (PlayerInput.KeyDown(Keys.LeftControl)) { moveSpeed *= 0.5f; } if (GameMain.Config.KeyBind(InputType.Left).IsDown()) { moveInput.X -= 1.0f; } if (GameMain.Config.KeyBind(InputType.Right).IsDown()) { moveInput.X += 1.0f; } if (GameMain.Config.KeyBind(InputType.Down).IsDown()) { moveInput.Y -= 1.0f; } if (GameMain.Config.KeyBind(InputType.Up).IsDown()) { moveInput.Y += 1.0f; } } velocity = Vector2.Lerp(velocity, moveInput, deltaTime * 10.0f); moveCam = velocity * moveSpeed * deltaTime * FreeCamMoveSpeed * 60.0f; if (Screen.Selected == GameMain.GameScreen && (followSub ?? FollowSub)) { var closestSub = Submarine.FindClosest(WorldViewCenter); if (closestSub != null) { moveCam += FarseerPhysics.ConvertUnits.ToDisplayUnits(closestSub.Velocity * deltaTime); } } } if (allowZoom) { Vector2 mouseInWorld = ScreenToWorld(PlayerInput.MousePosition); Vector2 diffViewCenter; diffViewCenter = (mouseInWorld - Position) * Zoom; targetZoom = MathHelper.Clamp( targetZoom + PlayerInput.ScrollWheelSpeed / 1000.0f * zoom, GameMain.DebugDraw ? MinZoom * 0.1f : MinZoom, MaxZoom); if (PlayerInput.KeyDown(Keys.LeftControl)) { Zoom += (targetZoom - zoom) / (ZoomSmoothness * 10.0f); } else { Zoom = MathHelper.Lerp(Zoom, targetZoom, deltaTime * 10.0f); } if (!PlayerInput.KeyDown(Keys.F)) { Position = mouseInWorld - (diffViewCenter / Zoom); } } } else if (allowMove) { Vector2 mousePos = PlayerInput.MousePosition; Vector2 offset = mousePos - Resolution.ToVector2() / 2; offset.X = offset.X / (Resolution.X * 0.4f); offset.Y = -offset.Y / (Resolution.Y * 0.3f); if (offset.LengthSquared() > 1.0f) { offset.Normalize(); } float offsetUnscaledLen = offset.Length(); offset *= OffsetAmount; // Freeze the camera movement by default, when the cursor is on top of an ui element. // Setting a positive value to the OffsetAmount, will override this behaviour. if (GUI.MouseOn != null && OffsetAmount > 0) { Freeze = true; } if (CharacterHealth.OpenHealthWindow != null || CrewManager.IsCommandInterfaceOpen || ConversationAction.IsDialogOpen) { offset *= 0; Freeze = false; } if (Freeze) { if (offset.LengthSquared() > 0.001f) { offset = previousOffset; } } else { previousOffset = offset; } if (allowZoom) { //how much to zoom out (zoom completely out when offset is 1000) float zoomOutAmount = GetZoomAmount(offset); //scaled zoom amount float scaledZoom = MathHelper.Lerp(DefaultZoom, MinZoom, zoomOutAmount) * globalZoomScale; //zoom in further if zoomOutAmount is low and resolution is lower than reference float newZoom = scaledZoom * (MathHelper.Lerp(0.3f * (1f - Math.Min(globalZoomScale, 1f)), 0f, (GameMain.Config == null || GameMain.Config.EnableMouseLook) ? (float)Math.Sqrt(offsetUnscaledLen) : 0.3f) + 1f); Zoom += (newZoom - zoom) / ZoomSmoothness; } //force targetzoom to the current zoom value, so the camera stays at the same zoom when switching to freecam targetZoom = Zoom; Vector2 diff = (TargetPos + offset) - position; moveCam = diff / MoveSmoothness; } rotation += angularVelocity * deltaTime; angularVelocity *= (1.0f - angularDamping); angularVelocity += -rotation * angularSpring; angularDamping = 0.05f; angularSpring = 0.2f; if (Shake < 0.01f) { shakePosition = Vector2.Zero; shakeTimer = 0.0f; } else { shakeTimer += deltaTime * 5.0f; Vector2 noisePos = new Vector2((float)PerlinNoise.CalculatePerlin(shakeTimer, shakeTimer, 0) - 0.5f, (float)PerlinNoise.CalculatePerlin(shakeTimer, shakeTimer, 0.5f) - 0.5f); shakePosition = noisePos * Shake * 2.0f; Shake = MathHelper.Lerp(Shake, 0.0f, deltaTime * 2.0f); } Translate(moveCam + shakePosition); Freeze = false; }