public void DebugDrawHUD(SpriteBatch spriteBatch, int y) { foreach (ScriptedEvent scriptedEvent in activeEvents.Where(ev => !ev.IsFinished && ev is ScriptedEvent).Cast <ScriptedEvent>()) { DrawEventTargetTags(spriteBatch, scriptedEvent); } GUI.DrawString(spriteBatch, new Vector2(10, y), "EventManager", Color.White, Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 20), "Event cooldown: " + (int)Math.Max(eventCoolDown, 0), Color.White, Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 35), "Current intensity: " + (int)Math.Round(currentIntensity * 100), Color.Lerp(Color.White, GUI.Style.Red, currentIntensity), Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 50), "Target intensity: " + (int)Math.Round(targetIntensity * 100), Color.Lerp(Color.White, GUI.Style.Red, targetIntensity), Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 65), "AvgHealth: " + (int)Math.Round(avgCrewHealth * 100), Color.Lerp(GUI.Style.Red, GUI.Style.Green, avgCrewHealth), Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 80), "AvgHullIntegrity: " + (int)Math.Round(avgHullIntegrity * 100), Color.Lerp(GUI.Style.Red, GUI.Style.Green, avgHullIntegrity), Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 95), "FloodingAmount: " + (int)Math.Round(floodingAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, floodingAmount), Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 110), "FireAmount: " + (int)Math.Round(fireAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, fireAmount), Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 125), "EnemyDanger: " + (int)Math.Round(enemyDanger * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, enemyDanger), Color.Black * 0.6f, 0, GUI.SmallFont); #if DEBUG if (PlayerInput.KeyDown(Microsoft.Xna.Framework.Input.Keys.LeftAlt) && PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.T)) { eventCoolDown = 1.0f; } #endif if (intensityGraph == null) { intensityGraph = new Graph(); targetIntensityGraph = new Graph(); } intensityGraphUpdateInterval = 5.0f; if (Timing.TotalTime > lastIntensityUpdate + intensityGraphUpdateInterval) { intensityGraph.Update(currentIntensity); targetIntensityGraph.Update(targetIntensity); lastIntensityUpdate = (float)Timing.TotalTime; } Rectangle graphRect = new Rectangle(15, y + 150, 150, 50); GUI.DrawRectangle(spriteBatch, graphRect, Color.Black * 0.5f, true); intensityGraph.Draw(spriteBatch, graphRect, 1.0f, 0.0f, Color.Lerp(Color.White, GUI.Style.Red, currentIntensity)); targetIntensityGraph.Draw(spriteBatch, graphRect, 1.0f, 0.0f, Color.Lerp(Color.White, GUI.Style.Red, targetIntensity) * 0.5f); GUI.DrawLine(spriteBatch, new Vector2(graphRect.Right, graphRect.Y + graphRect.Height * (1.0f - eventThreshold)), new Vector2(graphRect.Right + 5, graphRect.Y + graphRect.Height * (1.0f - eventThreshold)), Color.Orange, 0, 1); y = graphRect.Bottom + 20; int x = graphRect.X; if (isCrewAway && crewAwayDuration < settings.FreezeDurationWhenCrewAway) { GUI.DrawString(spriteBatch, new Vector2(x, y), "Events frozen (crew away from sub): " + ToolBox.SecondsToReadableTime(settings.FreezeDurationWhenCrewAway - crewAwayDuration), Color.LightGreen * 0.8f, null, 0, GUI.SmallFont); y += 15; } else if (crewAwayResetTimer > 0.0f) { GUI.DrawString(spriteBatch, new Vector2(x, y), "Events frozen (crew just returned to the sub): " + ToolBox.SecondsToReadableTime(crewAwayResetTimer), Color.LightGreen * 0.8f, null, 0, GUI.SmallFont); y += 15; } else if (eventCoolDown > 0.0f) { GUI.DrawString(spriteBatch, new Vector2(x, y), "Event cooldown active: " + ToolBox.SecondsToReadableTime(eventCoolDown), Color.LightGreen * 0.8f, null, 0, GUI.SmallFont); y += 15; } else if (currentIntensity > eventThreshold) { GUI.DrawString(spriteBatch, new Vector2(x, y), "Intensity too high for new events: " + (int)(currentIntensity * 100) + "%/" + (int)(eventThreshold * 100) + "%", Color.LightGreen * 0.8f, null, 0, GUI.SmallFont); y += 15; } foreach (EventSet eventSet in pendingEventSets) { if (Submarine.MainSub == null) { break; } GUI.DrawString(spriteBatch, new Vector2(x, y), "New event (ID " + eventSet.DebugIdentifier + ") after: ", Color.Orange * 0.8f, null, 0, GUI.SmallFont); y += 12; if (eventSet.PerCave) { GUI.DrawString(spriteBatch, new Vector2(x, y), " submarine near cave", Color.Orange * 0.8f, null, 0, GUI.SmallFont); y += 12; } if (eventSet.PerWreck) { GUI.DrawString(spriteBatch, new Vector2(x, y), " submarine near the wreck", Color.Orange * 0.8f, null, 0, GUI.SmallFont); y += 12; } if (eventSet.PerRuin) { GUI.DrawString(spriteBatch, new Vector2(x, y), " submarine near the ruins", Color.Orange * 0.8f, null, 0, GUI.SmallFont); y += 12; } if (roundDuration < eventSet.MinMissionTime) { GUI.DrawString(spriteBatch, new Vector2(x, y), " " + (int)(eventSet.MinDistanceTraveled * 100.0f) + "% travelled (current: " + (int)(distanceTraveled * 100.0f) + " %)", ((Submarine.MainSub == null || distanceTraveled < eventSet.MinDistanceTraveled) ? Color.Lerp(GUI.Style.Yellow, GUI.Style.Red, eventSet.MinDistanceTraveled - distanceTraveled) : GUI.Style.Green) * 0.8f, null, 0, GUI.SmallFont); y += 12; } if (CurrentIntensity < eventSet.MinIntensity || CurrentIntensity > eventSet.MaxIntensity) { GUI.DrawString(spriteBatch, new Vector2(x, y), " intensity between " + ((int)eventSet.MinIntensity) + " and " + ((int)eventSet.MaxIntensity), Color.Orange * 0.8f, null, 0, GUI.SmallFont); y += 12; } if (roundDuration < eventSet.MinMissionTime) { GUI.DrawString(spriteBatch, new Vector2(x, y), " " + (int)(eventSet.MinMissionTime - roundDuration) + " s", Color.Lerp(GUI.Style.Yellow, GUI.Style.Red, (eventSet.MinMissionTime - roundDuration)), null, 0, GUI.SmallFont); } y += 15; if (y > GameMain.GraphicsHeight * 0.9f) { y = graphRect.Bottom + 35; x += 250; } } GUI.DrawString(spriteBatch, new Vector2(x, y), "Current events: ", Color.White * 0.9f, null, 0, GUI.SmallFont); y += 15; foreach (Event ev in activeEvents.Where(ev => !ev.IsFinished || PlayerInput.IsShiftDown())) { GUI.DrawString(spriteBatch, new Vector2(x + 5, y), ev.ToString(), (!ev.IsFinished ? Color.White : Color.Red) * 0.8f, null, 0, GUI.SmallFont); Rectangle rect = new Rectangle(new Point(x + 5, y), GUI.SmallFont.MeasureString(ev.ToString()).ToPoint()); Rectangle outlineRect = new Rectangle(rect.Location, rect.Size); outlineRect.Inflate(4, 4); if (PinnedEvent == ev) { GUI.DrawRectangle(spriteBatch, outlineRect, Color.White); } if (rect.Contains(PlayerInput.MousePosition)) { GUI.MouseCursor = CursorState.Hand; GUI.DrawRectangle(spriteBatch, outlineRect, Color.White); if (ev != PinnedEvent) { DrawEvent(spriteBatch, ev, rect); } else if (PlayerInput.SecondaryMouseButtonHeld() || PlayerInput.SecondaryMouseButtonDown()) { PinnedEvent = null; } if (PlayerInput.PrimaryMouseButtonHeld() || PlayerInput.PrimaryMouseButtonDown()) { PinnedEvent = ev; } } y += 18; if (y > GameMain.GraphicsHeight * 0.9f) { y = graphRect.Bottom + 35; x += 250; } } }
public void DebugDrawHUD(SpriteBatch spriteBatch, int y) { GUI.DrawString(spriteBatch, new Vector2(10, y), "EventManager", Color.White, Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 20), "Event cooldown: " + eventCoolDown, Color.White, Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 35), "Current intensity: " + (int)(currentIntensity * 100), Color.Lerp(Color.White, Color.Red, currentIntensity), Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 50), "Target intensity: " + (int)(targetIntensity * 100), Color.Lerp(Color.White, Color.Red, targetIntensity), Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 65), "AvgHealth: " + (int)(avgCrewHealth * 100), Color.Lerp(Color.Red, Color.Green, avgCrewHealth), Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 80), "AvgHullIntegrity: " + (int)(avgHullIntegrity * 100), Color.Lerp(Color.Red, Color.Green, avgHullIntegrity), Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 95), "FloodingAmount: " + (int)(floodingAmount * 100), Color.Lerp(Color.Green, Color.Red, floodingAmount), Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 110), "FireAmount: " + (int)(fireAmount * 100), Color.Lerp(Color.Green, Color.Red, fireAmount), Color.Black * 0.6f, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(15, y + 125), "EnemyDanger: " + (int)(enemyDanger * 100), Color.Lerp(Color.Green, Color.Red, enemyDanger), Color.Black * 0.6f, 0, GUI.SmallFont); #if DEBUG if (PlayerInput.KeyDown(Microsoft.Xna.Framework.Input.Keys.LeftAlt) && PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.T)) { eventCoolDown = 1.0f; } #endif if (intensityGraph == null) { intensityGraph = new Graph(); targetIntensityGraph = new Graph(); } intensityGraphUpdateInterval = 5.0f; if (Timing.TotalTime > lastIntensityUpdate + intensityGraphUpdateInterval) { intensityGraph.Update(currentIntensity); targetIntensityGraph.Update(targetIntensity); lastIntensityUpdate = (float)Timing.TotalTime; } Rectangle graphRect = new Rectangle(15, y + 150, 150, 50); GUI.DrawRectangle(spriteBatch, graphRect, Color.Black * 0.5f, true); intensityGraph.Draw(spriteBatch, graphRect, 1.0f, 0.0f, Color.Lerp(Color.White, Color.Red, currentIntensity)); targetIntensityGraph.Draw(spriteBatch, graphRect, 1.0f, 0.0f, Color.Lerp(Color.White, Color.Red, targetIntensity) * 0.5f); GUI.DrawLine(spriteBatch, new Vector2(graphRect.Right, graphRect.Y + graphRect.Height * (1.0f - eventThreshold)), new Vector2(graphRect.Right + 5, graphRect.Y + graphRect.Height * (1.0f - eventThreshold)), Color.Orange, 0, 1); y = graphRect.Bottom + 20; if (eventCoolDown > 0.0f) { GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), "Event cooldown active: " + (int)eventCoolDown, Color.LightGreen * 0.8f, null, 0, GUI.SmallFont); y += 15; } else if (currentIntensity > eventThreshold) { GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), "Intensity too high for new events: " + (int)(currentIntensity * 100) + "%/" + (int)(eventThreshold * 100) + "%", Color.LightGreen * 0.8f, null, 0, GUI.SmallFont); y += 15; } foreach (ScriptedEventSet eventSet in selectedEventSets) { float distanceTraveled = MathHelper.Clamp( (Submarine.MainSub.WorldPosition.X - level.StartPosition.X) / (level.EndPosition.X - level.StartPosition.X), 0.0f, 1.0f); GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), "New event (ID " + eventSet.DebugIdentifier + ") after: ", Color.Orange * 0.8f, null, 0, GUI.SmallFont); y += 12; if ((Submarine.MainSub == null || distanceTraveled < eventSet.MinDistanceTraveled) && roundDuration < eventSet.MinMissionTime) { GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), " " + (int)(eventSet.MinDistanceTraveled * 100.0f) + "% travelled (current: " + (int)(distanceTraveled * 100.0f) + " %)", Color.Orange * 0.8f, null, 0, GUI.SmallFont); y += 12; } if (CurrentIntensity < eventSet.MinIntensity || CurrentIntensity > eventSet.MaxIntensity) { GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), " intensity between " + ((int)eventSet.MinIntensity) + " and " + ((int)eventSet.MaxIntensity), Color.Orange * 0.8f, null, 0, GUI.SmallFont); y += 12; } if (roundDuration < eventSet.MinMissionTime) { GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), " " + (int)(eventSet.MinMissionTime - roundDuration) + " s", Color.Orange * 0.8f, null, 0, GUI.SmallFont); } y += 15; } GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), "Current events: ", Color.White * 0.9f, null, 0, GUI.SmallFont); y += 12; foreach (ScriptedEvent scriptedEvent in events) { if (scriptedEvent.IsFinished) { continue; } GUI.DrawString(spriteBatch, new Vector2(graphRect.X + 5, y), scriptedEvent.ToString(), Color.White * 0.8f, null, 0, GUI.SmallFont); y += 12; } }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> public override void Update(double deltaTime) { #if RUN_PHYSICS_IN_SEPARATE_THREAD physicsTime += deltaTime; lock (updateLock) { #endif #if DEBUG && CLIENT if (GameMain.GameSession != null && !DebugConsole.IsOpen && GUI.KeyboardDispatcher.Subscriber == null) { if (GameMain.GameSession.Level != null && GameMain.GameSession.Submarine != null) { Submarine closestSub = Submarine.FindClosest(cam.WorldViewCenter) ?? GameMain.GameSession.Submarine; Vector2 targetMovement = Vector2.Zero; if (PlayerInput.KeyDown(Keys.I)) { targetMovement.Y += 1.0f; } if (PlayerInput.KeyDown(Keys.K)) { targetMovement.Y -= 1.0f; } if (PlayerInput.KeyDown(Keys.J)) { targetMovement.X -= 1.0f; } if (PlayerInput.KeyDown(Keys.L)) { targetMovement.X += 1.0f; } if (targetMovement != Vector2.Zero) { closestSub.ApplyForce(targetMovement * closestSub.SubBody.Body.Mass * 100.0f); } } } #endif #if CLIENT GameMain.LightManager?.Update((float)deltaTime); #endif GameTime += deltaTime; foreach (PhysicsBody body in PhysicsBody.List) { if (body.Enabled && body.BodyType != FarseerPhysics.BodyType.Static) { body.Update(); } } foreach (MapEntity e in MapEntity.mapEntityList) { e.IsHighlighted = false; } if (GameMain.GameSession != null) { GameMain.GameSession.Update((float)deltaTime); } #if CLIENT var sw = new System.Diagnostics.Stopwatch(); sw.Start(); GameMain.ParticleManager.Update((float)deltaTime); sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("ParticleUpdate", sw.ElapsedTicks); sw.Restart(); if (Level.Loaded != null) { Level.Loaded.Update((float)deltaTime, cam); } sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("LevelUpdate", sw.ElapsedTicks); if (Character.Controlled != null) { if (Character.Controlled.SelectedConstruction != null && Character.Controlled.CanInteractWith(Character.Controlled.SelectedConstruction)) { Character.Controlled.SelectedConstruction.UpdateHUD(cam, Character.Controlled, (float)deltaTime); } if (Character.Controlled.Inventory != null) { foreach (Item item in Character.Controlled.Inventory.AllItems) { if (Character.Controlled.HasEquippedItem(item)) { item.UpdateHUD(cam, Character.Controlled, (float)deltaTime); } } } } sw.Restart(); Character.UpdateAll((float)deltaTime, cam); #elif SERVER if (Level.Loaded != null) { Level.Loaded.Update((float)deltaTime, Camera.Instance); } Character.UpdateAll((float)deltaTime, Camera.Instance); #endif #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("CharacterUpdate", sw.ElapsedTicks); sw.Restart(); #endif StatusEffect.UpdateAll((float)deltaTime); #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("StatusEffectUpdate", sw.ElapsedTicks); sw.Restart(); if (Character.Controlled != null && Lights.LightManager.ViewTarget != null) { Vector2 targetPos = Lights.LightManager.ViewTarget.DrawPosition; if (Lights.LightManager.ViewTarget == Character.Controlled && (CharacterHealth.OpenHealthWindow != null || CrewManager.IsCommandInterfaceOpen || ConversationAction.IsDialogOpen)) { Vector2 screenTargetPos = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) * 0.5f; if (CharacterHealth.OpenHealthWindow != null) { screenTargetPos.X = GameMain.GraphicsWidth * (CharacterHealth.OpenHealthWindow.Alignment == Alignment.Left ? 0.75f : 0.25f); } else if (ConversationAction.IsDialogOpen) { screenTargetPos.Y = GameMain.GraphicsHeight * 0.4f; } Vector2 screenOffset = screenTargetPos - new Vector2(GameMain.GraphicsWidth / 2, GameMain.GraphicsHeight / 2); screenOffset.Y = -screenOffset.Y; targetPos -= screenOffset / cam.Zoom; } cam.TargetPos = targetPos; } cam.MoveCamera((float)deltaTime); #endif foreach (Submarine sub in Submarine.Loaded) { sub.SetPrevTransform(sub.Position); } foreach (PhysicsBody body in PhysicsBody.List) { if (body.Enabled && body.BodyType != FarseerPhysics.BodyType.Static) { body.SetPrevTransform(body.SimPosition, body.Rotation); } } #if CLIENT MapEntity.UpdateAll((float)deltaTime, cam); #elif SERVER MapEntity.UpdateAll((float)deltaTime, Camera.Instance); #endif #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("MapEntityUpdate", sw.ElapsedTicks); sw.Restart(); #endif Character.UpdateAnimAll((float)deltaTime); #if CLIENT Ragdoll.UpdateAll((float)deltaTime, cam); #elif SERVER Ragdoll.UpdateAll((float)deltaTime, Camera.Instance); #endif #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("AnimUpdate", sw.ElapsedTicks); sw.Restart(); #endif foreach (Submarine sub in Submarine.Loaded) { sub.Update((float)deltaTime); } #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("SubmarineUpdate", sw.ElapsedTicks); sw.Restart(); #endif #if !RUN_PHYSICS_IN_SEPARATE_THREAD try { GameMain.World.Step((float)Timing.Step); } catch (WorldLockedException e) { string errorMsg = "Attempted to modify the state of the physics simulation while a time step was running."; DebugConsole.ThrowError(errorMsg, e); GameAnalyticsManager.AddErrorEventOnce("GameScreen.Update:WorldLockedException" + e.Message, GameAnalyticsSDK.Net.EGAErrorSeverity.Critical, errorMsg); } #endif #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("Physics", sw.ElapsedTicks); #endif UpdateProjSpecific(deltaTime); #if RUN_PHYSICS_IN_SEPARATE_THREAD } #endif }
public static void UpdateEditor(Camera cam) { if (highlightedListBox != null) { highlightedListBox.UpdateManually((float)Timing.Step); } if (editingHUD != null) { if (FilteredSelectedList.Count == 0 || editingHUD.UserData != FilteredSelectedList[0]) { foreach (GUIComponent component in editingHUD.Children) { var textBox = component as GUITextBox; if (textBox == null) { continue; } textBox.Deselect(); } editingHUD = null; } } FilteredSelectedList.Clear(); if (selectedList.Count == 0) { return; } foreach (var e in selectedList) { if (e is Gap gap && gap.ConnectedDoor != null) { continue; } FilteredSelectedList.Add(e); } var first = FilteredSelectedList.FirstOrDefault(); if (first != null) { first.UpdateEditing(cam); if (first.ResizeHorizontal || first.ResizeVertical) { first.UpdateResizing(cam); } } if ((PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))) { if (PlayerInput.KeyHit(Keys.N)) { float minX = selectedList[0].WorldRect.X, maxX = selectedList[0].WorldRect.Right; for (int i = 0; i < selectedList.Count; i++) { minX = Math.Min(minX, selectedList[i].WorldRect.X); maxX = Math.Max(maxX, selectedList[i].WorldRect.Right); } float centerX = (minX + maxX) / 2.0f; foreach (MapEntity me in selectedList) { me.FlipX(false); me.Move(new Vector2((centerX - me.WorldPosition.X) * 2.0f, 0.0f)); } } else if (PlayerInput.KeyHit(Keys.M)) { float minY = selectedList[0].WorldRect.Y - selectedList[0].WorldRect.Height, maxY = selectedList[0].WorldRect.Y; for (int i = 0; i < selectedList.Count; i++) { minY = Math.Min(minY, selectedList[i].WorldRect.Y - selectedList[i].WorldRect.Height); maxY = Math.Max(maxY, selectedList[i].WorldRect.Y); } float centerY = (minY + maxY) / 2.0f; foreach (MapEntity me in selectedList) { me.FlipY(false); me.Move(new Vector2(0.0f, (centerY - me.WorldPosition.Y) * 2.0f)); } } } }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { Timing.Accumulator += gameTime.ElapsedGameTime.TotalSeconds; int updateIterations = (int)Math.Floor(Timing.Accumulator / Timing.Step); if (Timing.Accumulator > Timing.Step * 6.0) { //if the game's running too slowly then we have no choice //but to skip a bunch of steps //otherwise it snowballs and becomes unplayable Timing.Accumulator = Timing.Step; } CrossThread.ProcessTasks(); PlayerInput.UpdateVariable(); if (SoundManager != null) { if (WindowActive || !Config.MuteOnFocusLost) { SoundManager.ListenerGain = SoundManager.CompressionDynamicRangeGain; } else { SoundManager.ListenerGain = 0.0f; } } while (Timing.Accumulator >= Timing.Step) { Timing.TotalTime += Timing.Step; Stopwatch sw = new Stopwatch(); sw.Start(); fixedTime.IsRunningSlowly = gameTime.IsRunningSlowly; TimeSpan addTime = new TimeSpan(0, 0, 0, 0, 16); fixedTime.ElapsedGameTime = addTime; fixedTime.TotalGameTime.Add(addTime); base.Update(fixedTime); PlayerInput.Update(Timing.Step); if (loadingScreenOpen) { //reset accumulator if loading // -> less choppy loading screens because the screen is rendered after each update // -> no pause caused by leftover time in the accumulator when starting a new shift ResetFrameTime(); if (!TitleScreen.PlayingSplashScreen) { SoundPlayer.Update((float)Timing.Step); } if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && (!waitForKeyHit || ((PlayerInput.GetKeyboardState.GetPressedKeys().Length > 0 || PlayerInput.PrimaryMouseButtonClicked()) && WindowActive))) { loadingScreenOpen = false; } #if DEBUG if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && (Config.AutomaticQuickStartEnabled || Config.AutomaticCampaignLoadEnabled) && FirstLoad && !PlayerInput.KeyDown(Keys.LeftShift)) { loadingScreenOpen = false; FirstLoad = false; if (Config.AutomaticQuickStartEnabled) { MainMenuScreen.QuickStart(); } else if (Config.AutomaticCampaignLoadEnabled) { IEnumerable <string> saveFiles = SaveUtil.GetSaveFiles(SaveUtil.SaveType.Singleplayer); if (saveFiles.Count() > 0) { saveFiles = saveFiles.OrderBy(file => File.GetLastWriteTime(file)); try { SaveUtil.LoadGame(saveFiles.Last()); } catch (Exception e) { DebugConsole.ThrowError("Loading save \"" + saveFiles.Last() + "\" failed", e); return; } } } } #endif if (!hasLoaded && !CoroutineManager.IsCoroutineRunning(loadingCoroutine)) { throw new LoadingException(loadingCoroutine.Exception); } } else if (hasLoaded) { if (ConnectLobby != 0) { if (Client != null) { Client.Disconnect(); Client = null; GameMain.MainMenuScreen.Select(); } Steam.SteamManager.JoinLobby(ConnectLobby, true); ConnectLobby = 0; ConnectEndpoint = null; ConnectName = null; } else if (!string.IsNullOrWhiteSpace(ConnectEndpoint)) { if (Client != null) { Client.Disconnect(); Client = null; GameMain.MainMenuScreen.Select(); } UInt64 serverSteamId = SteamManager.SteamIDStringToUInt64(ConnectEndpoint); Client = new GameClient(Config.PlayerName, serverSteamId != 0 ? null : ConnectEndpoint, serverSteamId, string.IsNullOrWhiteSpace(ConnectName) ? ConnectEndpoint : ConnectName); ConnectLobby = 0; ConnectEndpoint = null; ConnectName = null; } SoundPlayer.Update((float)Timing.Step); if (PlayerInput.KeyHit(Keys.Escape) && WindowActive) { // Check if a text input is selected. if (GUI.KeyboardDispatcher.Subscriber != null) { if (GUI.KeyboardDispatcher.Subscriber is GUITextBox textBox) { textBox.Deselect(); } GUI.KeyboardDispatcher.Subscriber = null; } //if a verification prompt (are you sure you want to x) is open, close it else if (GUIMessageBox.VisibleBox as GUIMessageBox != null && GUIMessageBox.VisibleBox.UserData as string == "verificationprompt") { ((GUIMessageBox)GUIMessageBox.VisibleBox).Close(); } else if (GUIMessageBox.VisibleBox?.UserData is RoundSummary roundSummary && roundSummary.ContinueButton != null && roundSummary.ContinueButton.Visible) { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox); } else if (Tutorial.Initialized && Tutorial.ContentRunning) { (GameSession.GameMode as TutorialMode).Tutorial.CloseActiveContentGUI(); } else if (GameSession.IsTabMenuOpen) { gameSession.ToggleTabMenu(); } else if (GUI.PauseMenuOpen) { GUI.TogglePauseMenu(); } //open the pause menu if not controlling a character OR if the character has no UIs active that can be closed with ESC else if ((Character.Controlled == null || !itemHudActive()) //TODO: do we need to check Inventory.SelectedSlot? && Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null && !CrewManager.IsCommandInterfaceOpen && !(Screen.Selected is SubEditorScreen editor && !editor.WiringMode && Character.Controlled?.SelectedConstruction != null)) { // Otherwise toggle pausing, unless another window/interface is open. GUI.TogglePauseMenu(); }
public override void UpdateEditing(Camera cam) { if (editingHUD == null || editingHUD.UserData as Item != this) { editingHUD = CreateEditingHUD(Screen.Selected != GameMain.SubEditorScreen); } editingHUD.Update((float)Timing.Step); if (Screen.Selected != GameMain.SubEditorScreen) { return; } if (!Linkable) { return; } if (!PlayerInput.KeyDown(Keys.Space)) { return; } bool lClick = PlayerInput.LeftButtonClicked(); bool rClick = PlayerInput.RightButtonClicked(); if (!lClick && !rClick) { return; } Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); if (lClick) { foreach (MapEntity entity in mapEntityList) { if (entity == this || !entity.IsHighlighted) { continue; } if (linkedTo.Contains(entity)) { continue; } if (!entity.IsMouseOn(position)) { continue; } linkedTo.Add(entity); if (entity.Linkable && entity.linkedTo != null) { entity.linkedTo.Add(this); } } } else { foreach (MapEntity entity in mapEntityList) { if (entity == this || !entity.IsHighlighted) { continue; } if (!linkedTo.Contains(entity)) { continue; } if (!entity.IsMouseOn(position)) { continue; } linkedTo.Remove(entity); if (entity.linkedTo != null && entity.linkedTo.Contains(this)) { entity.linkedTo.Remove(this); } } } }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> public override void Update(double deltaTime) { #if DEBUG && CLIENT if (GameMain.GameSession != null && GameMain.GameSession.Level != null && GameMain.GameSession.Submarine != null && !DebugConsole.IsOpen && GUIComponent.KeyboardDispatcher.Subscriber == null) { var closestSub = Submarine.FindClosest(cam.WorldViewCenter); if (closestSub == null) { closestSub = GameMain.GameSession.Submarine; } Vector2 targetMovement = Vector2.Zero; if (PlayerInput.KeyDown(Keys.I)) { targetMovement.Y += 1.0f; } if (PlayerInput.KeyDown(Keys.K)) { targetMovement.Y -= 1.0f; } if (PlayerInput.KeyDown(Keys.J)) { targetMovement.X -= 1.0f; } if (PlayerInput.KeyDown(Keys.L)) { targetMovement.X += 1.0f; } if (targetMovement != Vector2.Zero) { closestSub.ApplyForce(targetMovement * closestSub.SubBody.Body.Mass * 100.0f); } } #endif foreach (MapEntity e in MapEntity.mapEntityList) { e.IsHighlighted = false; } #if CLIENT if (GameMain.GameSession != null) { GameMain.GameSession.Update((float)deltaTime); } GameMain.ParticleManager.Update((float)deltaTime); GameMain.LightManager.Update((float)deltaTime); #endif if (Level.Loaded != null) { Level.Loaded.Update((float)deltaTime, cam); } #if CLIENT if (Character.Controlled != null && Character.Controlled.SelectedConstruction != null && Character.Controlled.CanInteractWith(Character.Controlled.SelectedConstruction)) { Character.Controlled.SelectedConstruction.UpdateHUD(cam, Character.Controlled); } #endif Character.UpdateAll((float)deltaTime, cam); StatusEffect.UpdateAll((float)deltaTime); #if CLIENT if (Character.Controlled != null && Lights.LightManager.ViewTarget != null) { cam.TargetPos = Lights.LightManager.ViewTarget.WorldPosition; } #endif cam.MoveCamera((float)deltaTime); foreach (Submarine sub in Submarine.Loaded) { sub.SetPrevTransform(sub.Position); } foreach (PhysicsBody pb in PhysicsBody.List) { pb.SetPrevTransform(pb.SimPosition, pb.Rotation); } MapEntity.UpdateAll((float)deltaTime, cam); Character.UpdateAnimAll((float)deltaTime); Ragdoll.UpdateAll((float)deltaTime, cam); foreach (Submarine sub in Submarine.Loaded) { sub.Update((float)deltaTime); } GameMain.World.Step((float)deltaTime); #if CLIENT if (!PlayerInput.LeftButtonHeld()) { Inventory.draggingSlot = null; Inventory.draggingItem = null; } #endif }
public override void UpdateEditing(Camera cam) { if (editingHUD == null || editingHUD.UserData as Hull != this) { editingHUD = CreateEditingHUD(Screen.Selected != GameMain.SubEditorScreen); } if (!PlayerInput.KeyDown(Keys.Space)) { return; } bool lClick = PlayerInput.PrimaryMouseButtonClicked(); bool rClick = PlayerInput.SecondaryMouseButtonClicked(); if (!lClick && !rClick) { return; } Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); foreach (MapEntity entity in mapEntityList) { if (entity == this || !entity.IsHighlighted) { continue; } if (!entity.IsMouseOn(position)) { continue; } if (entity.linkedTo == null || !entity.Linkable) { continue; } if (entity.linkedTo.Contains(this) || linkedTo.Contains(entity) || rClick) { if (entity == this || !entity.IsHighlighted) { continue; } if (!entity.IsMouseOn(position)) { continue; } if (entity.linkedTo.Contains(this)) { entity.linkedTo.Remove(this); linkedTo.Remove(entity); } } else { if (!entity.linkedTo.Contains(this)) { entity.linkedTo.Add(this); } if (!linkedTo.Contains(this)) { linkedTo.Add(entity); } } } }
/// <summary> /// Update the selection logic in submarine editor /// </summary> public static void UpdateSelecting(Camera cam) { if (resizing) { if (selectedList.Count == 0) { resizing = false; } return; } foreach (MapEntity e in mapEntityList) { e.isHighlighted = false; } if (DisableSelect) { DisableSelect = false; return; } if (GUI.MouseOn != null || !PlayerInput.MouseInsideWindow) { if (highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn))) { UpdateHighlightedListBox(null); return; } } if (MapEntityPrefab.Selected != null) { selectionPos = Vector2.Zero; selectedList.Clear(); return; } if (PlayerInput.KeyDown(Keys.Delete)) { selectedList.ForEach(e => e.Remove()); selectedList.Clear(); } if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl)) { if (PlayerInput.GetKeyboardState.IsKeyDown(Keys.C) && PlayerInput.GetOldKeyboardState.IsKeyUp(Keys.C)) { CopyEntities(selectedList); } else if (PlayerInput.GetKeyboardState.IsKeyDown(Keys.X) && PlayerInput.GetOldKeyboardState.IsKeyUp(Keys.X)) { CopyEntities(selectedList); selectedList.ForEach(e => e.Remove()); selectedList.Clear(); } else if (copiedList.Count > 0 && PlayerInput.GetKeyboardState.IsKeyDown(Keys.V) && PlayerInput.GetOldKeyboardState.IsKeyUp(Keys.V)) { List <MapEntity> prevEntities = new List <MapEntity>(mapEntityList); Clone(copiedList); var clones = mapEntityList.Except(prevEntities).ToList(); Vector2 center = Vector2.Zero; clones.ForEach(c => center += c.WorldPosition); center = Submarine.VectorToWorldGrid(center / clones.Count); Vector2 moveAmount = Submarine.VectorToWorldGrid(cam.WorldViewCenter - center); selectedList = new List <MapEntity>(clones); foreach (MapEntity clone in selectedList) { clone.Move(moveAmount); clone.Submarine = Submarine.MainSub; } } } Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); MapEntity highLightedEntity = null; if (startMovingPos == Vector2.Zero) { List <MapEntity> highlightedEntities = new List <MapEntity>(); if (highlightedListBox != null && highlightedListBox.IsParentOf(GUI.MouseOn)) { highLightedEntity = GUI.MouseOn.UserData as MapEntity; } else { foreach (MapEntity e in mapEntityList) { if (!e.SelectableInEditor) { continue; } if (e.IsMouseOn(position)) { int i = 0; while (i < highlightedEntities.Count && e.Sprite != null && (highlightedEntities[i].Sprite == null || highlightedEntities[i].SpriteDepth < e.SpriteDepth)) { i++; } highlightedEntities.Insert(i, e); if (i == 0) { highLightedEntity = e; } } } if (PlayerInput.MouseSpeed.LengthSquared() > 10) { highlightTimer = 0.0f; } else { bool mouseNearHighlightBox = false; if (highlightedListBox != null) { Rectangle expandedRect = highlightedListBox.Rect; expandedRect.Inflate(20, 20); mouseNearHighlightBox = expandedRect.Contains(PlayerInput.MousePosition); if (!mouseNearHighlightBox) { highlightedListBox = null; } } highlightTimer += (float)Timing.Step; if (highlightTimer > 1.0f) { if (!mouseNearHighlightBox) { UpdateHighlightedListBox(highlightedEntities); highlightTimer = 0.0f; } } } } if (highLightedEntity != null) { highLightedEntity.isHighlighted = true; } } Vector2 nudgeAmount = Vector2.Zero; if (PlayerInput.KeyHit(Keys.Up)) { nudgeAmount.Y = 1f; } if (PlayerInput.KeyHit(Keys.Down)) { nudgeAmount.Y = -1f; } if (PlayerInput.KeyHit(Keys.Left)) { nudgeAmount.X = -1f; } if (PlayerInput.KeyHit(Keys.Right)) { nudgeAmount.X = 1f; } if (nudgeAmount != Vector2.Zero) { foreach (MapEntity entityToNudge in selectedList) { entityToNudge.Move(nudgeAmount); } } //started moving selected entities if (startMovingPos != Vector2.Zero) { if (PlayerInput.LeftButtonReleased()) { //mouse released -> move the entities to the new position of the mouse Vector2 moveAmount = position - startMovingPos; moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X; moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y; if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y) { moveAmount = Submarine.VectorToWorldGrid(moveAmount); //clone if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl)) { var clones = Clone(selectedList); selectedList = clones; selectedList.ForEach(c => c.Move(moveAmount)); } else // move { foreach (MapEntity e in selectedList) { e.Move(moveAmount); } } } startMovingPos = Vector2.Zero; } } //started dragging a "selection rectangle" else if (selectionPos != Vector2.Zero) { selectionSize.X = position.X - selectionPos.X; selectionSize.Y = selectionPos.Y - position.Y; List <MapEntity> newSelection = new List <MapEntity>();// FindSelectedEntities(selectionPos, selectionSize); if (Math.Abs(selectionSize.X) > Submarine.GridSize.X || Math.Abs(selectionSize.Y) > Submarine.GridSize.Y) { newSelection = FindSelectedEntities(selectionPos, selectionSize); } else { if (highLightedEntity != null) { newSelection.Add(highLightedEntity); } } if (PlayerInput.LeftButtonReleased()) { if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl)) { foreach (MapEntity e in newSelection) { if (selectedList.Contains(e)) { selectedList.Remove(e); } else { selectedList.Add(e); } } } else { selectedList = newSelection; } //select wire if both items it's connected to are selected var selectedItems = selectedList.Where(e => e is Item).Cast <Item>().ToList(); foreach (Item item in selectedItems) { if (item.Connections == null) { continue; } foreach (Connection c in item.Connections) { foreach (Wire w in c.Wires) { if (w == null || selectedList.Contains(w.Item)) { continue; } if (w.OtherConnection(c) != null && selectedList.Contains(w.OtherConnection(c).Item)) { selectedList.Add(w.Item); } } } } selectionPos = Vector2.Zero; selectionSize = Vector2.Zero; } } //default, not doing anything specific yet else { if (PlayerInput.LeftButtonHeld() && PlayerInput.KeyUp(Keys.Space) && (highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn)))) { //if clicking a selected entity, start moving it foreach (MapEntity e in selectedList) { if (e.IsMouseOn(position)) { startMovingPos = position; } } selectionPos = position; //stop camera movement to prevent accidental dragging or rect selection Screen.Selected.Cam.StopMovement(); } } }
protected override void Update(float deltaTime) { if (!Visible) { return; } if (flashTimer > 0.0f) { flashTimer -= deltaTime; } if (!Enabled) { return; } if (skipUpdate) { skipUpdate = false; return; } if (MouseRect.Contains(PlayerInput.MousePosition) && (GUI.MouseOn == null || (!(GUI.MouseOn is GUIButton) && GUI.IsMouseOn(this)))) { State = ComponentState.Hover; if (PlayerInput.PrimaryMouseButtonDown()) { mouseHeldInside = true; Select(); } else { isSelecting = PlayerInput.PrimaryMouseButtonHeld(); } if (PlayerInput.DoubleClicked()) { SelectAll(); } if (isSelecting) { if (!MathUtils.NearlyEqual(PlayerInput.MouseSpeed.X, 0)) { CaretIndex = textBlock.GetCaretIndexFromScreenPos(PlayerInput.MousePosition); CalculateCaretPos(); CalculateSelection(); } } } else { if ((PlayerInput.LeftButtonClicked() || PlayerInput.RightButtonClicked()) && selected) { if (!mouseHeldInside) { Deselect(); } mouseHeldInside = false; } isSelecting = false; State = ComponentState.None; } if (!isSelecting) { isSelecting = PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift); } if (CaretEnabled) { if (textBlock.OverflowClipActive) { if (CaretScreenPos.X < textBlock.Rect.X + textBlock.Padding.X) { textBlock.TextPos = new Vector2(textBlock.TextPos.X + ((textBlock.Rect.X + textBlock.Padding.X) - CaretScreenPos.X), textBlock.TextPos.Y); CalculateCaretPos(); } else if (CaretScreenPos.X > textBlock.Rect.Right - textBlock.Padding.Z) { textBlock.TextPos = new Vector2(textBlock.TextPos.X - (CaretScreenPos.X - (textBlock.Rect.Right - textBlock.Padding.Z)), textBlock.TextPos.Y); CalculateCaretPos(); } } caretTimer += deltaTime; caretVisible = ((caretTimer * 1000.0f) % 1000) < 500; if (caretVisible && caretPosDirty) { CalculateCaretPos(); } } if (GUI.KeyboardDispatcher.Subscriber == this) { State = ComponentState.Selected; Character.DisableControls = true; if (OnEnterPressed != null && PlayerInput.KeyHit(Keys.Enter)) { OnEnterPressed(this, Text); } } else if (Selected) { Deselect(); } textBlock.State = State; }
public void ReceiveCommandInput(char command) { if (Text == null) { Text = ""; } switch (command) { case '\b' when !Readonly: //backspace if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl)) { SetText(string.Empty, false); CaretIndex = Text.Length; } else if (selectedCharacters > 0) { RemoveSelectedText(); } else if (Text.Length > 0 && CaretIndex > 0) { CaretIndex--; SetText(Text.Remove(CaretIndex, 1)); CalculateCaretPos(); ClearSelection(); } OnTextChanged?.Invoke(this, Text); break; case (char)0x3: // ctrl-c CopySelectedText(); break; case (char)0x16 when !Readonly: // ctrl-v string text = GetCopiedText(); RemoveSelectedText(); if (SetText(Text.Insert(CaretIndex, text))) { CaretIndex = Math.Min(Text.Length, CaretIndex + text.Length); OnTextChanged?.Invoke(this, Text); } break; case (char)0x18: // ctrl-x CopySelectedText(); if (!Readonly) { RemoveSelectedText(); } break; case (char)0x1: // ctrl-a SelectAll(); break; case (char)0x1A when !Readonly: // ctrl-z text = memento.Undo(); if (text != Text) { ClearSelection(); SetText(text, false); CaretIndex = Text.Length; OnTextChanged?.Invoke(this, Text); } break; case (char)0x12 when !Readonly: // ctrl-r text = memento.Redo(); if (text != Text) { ClearSelection(); SetText(text, false); CaretIndex = Text.Length; OnTextChanged?.Invoke(this, Text); } break; } }
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) { if (allowMove && GUIComponent.KeyboardDispatcher.Subscriber == null) { if (PlayerInput.KeyDown(Keys.LeftShift)) { moveSpeed *= 3.0f; } if (PlayerInput.KeyDown(Keys.LeftControl)) { moveSpeed *= 0.5f; } if (GameMain.Config.KeyBind(InputType.Left).IsDown()) { moveCam.X -= moveSpeed; } if (GameMain.Config.KeyBind(InputType.Right).IsDown()) { moveCam.X += moveSpeed; } if (GameMain.Config.KeyBind(InputType.Down).IsDown()) { moveCam.Y -= moveSpeed; } if (GameMain.Config.KeyBind(InputType.Up).IsDown()) { moveCam.Y += moveSpeed; } } if (Screen.Selected == GameMain.GameScreen && FollowSub) { var closestSub = Submarine.FindClosest(WorldViewCenter); if (closestSub != null) { moveCam += FarseerPhysics.ConvertUnits.ToDisplayUnits(closestSub.Velocity * deltaTime); } } moveCam = moveCam * deltaTime * 60.0f; if (allowZoom) { Vector2 mouseInWorld = ScreenToWorld(PlayerInput.MousePosition); Vector2 diffViewCenter; diffViewCenter = ((mouseInWorld - Position) * Zoom); if (GUIComponent.MouseOn == null) { Zoom = MathHelper.Clamp(zoom + (PlayerInput.ScrollWheelSpeed / 1000.0f) * zoom, GameMain.DebugDraw ? 0.01f : 0.1f, 2.0f); } if (!PlayerInput.KeyDown(Keys.F)) { Position = mouseInWorld - (diffViewCenter / Zoom); } } } else { Vector2 mousePos = PlayerInput.MousePosition; Vector2 offset = mousePos - new Vector2(resolution.X / 2.0f, resolution.Y / 2.0f); offset.X = offset.X / (resolution.X * 0.4f); offset.Y = -offset.Y / (resolution.Y * 0.3f); if (offset.Length() > 1.0f) { offset.Normalize(); } offset = offset * offsetAmount; float newZoom; newZoom = (Math.Min(DefaultZoom - Math.Min(offset.Length() / resolution.Y, 1.0f), 1.0f) + ZoomModifier); Zoom += (newZoom - zoom) / ZoomSmoothness; Vector2 diff = (targetPos + offset) - position; moveCam = diff / MoveSmoothness; } shakeTargetPosition = Rand.Vector(Shake); shakePosition = Vector2.Lerp(shakePosition, shakeTargetPosition, 0.5f); Shake = MathHelper.Lerp(Shake, 0.0f, deltaTime * 2.0f); Translate(moveCam + shakePosition); }
protected override void Update(float deltaTime) { if (!Visible) { return; } if (flashTimer > 0.0f) { flashTimer -= deltaTime; } if (!Enabled) { return; } if (MouseRect.Contains(PlayerInput.MousePosition) && (GUI.MouseOn == null || GUI.IsMouseOn(this))) { state = ComponentState.Hover; if (PlayerInput.LeftButtonDown()) { Select(); } else { isSelecting = PlayerInput.LeftButtonHeld(); } if (PlayerInput.DoubleClicked()) { SelectAll(); } if (isSelecting) { if (!MathUtils.NearlyEqual(PlayerInput.MouseSpeed.X, 0)) { CaretIndex = GetCaretIndexFromScreenPos(PlayerInput.MousePosition); CalculateCaretPos(); CalculateSelection(); } } } else { isSelecting = false; state = ComponentState.None; } if (!isSelecting) { isSelecting = PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift); } if (CaretEnabled) { caretTimer += deltaTime; caretVisible = ((caretTimer * 1000.0f) % 1000) < 500; if (caretVisible && caretPosDirty) { CalculateCaretPos(); } } if (GUI.KeyboardDispatcher.Subscriber == this) { state = ComponentState.Selected; Character.DisableControls = true; if (OnEnterPressed != null && PlayerInput.KeyHit(Keys.Enter)) { OnEnterPressed(this, Text); } } else if (Selected) { Deselect(); } textBlock.State = state; }
public override void Update(double deltaTime) { base.Update(deltaTime); Widget.EnableMultiSelect = PlayerInput.KeyDown(Keys.LeftControl); spriteList.SelectMultiple = Widget.EnableMultiSelect; // Select rects with the mouse if (Widget.selectedWidgets.None() || Widget.EnableMultiSelect) { if (selectedTexture != null) { foreach (Sprite sprite in loadedSprites) { if (sprite.Texture != selectedTexture) { continue; } if (PlayerInput.LeftButtonClicked()) { var scaledRect = new Rectangle(textureRect.Location + sprite.SourceRect.Location.Multiply(zoom), sprite.SourceRect.Size.Multiply(zoom)); if (scaledRect.Contains(PlayerInput.MousePosition)) { spriteList.Select(sprite, autoScroll: false); UpdateScrollBar(spriteList); UpdateScrollBar(textureList); } } } } } if (GUI.MouseOn == null) { if (PlayerInput.ScrollWheelSpeed != 0) { zoom = MathHelper.Clamp(zoom + PlayerInput.ScrollWheelSpeed * (float)deltaTime * 0.05f * zoom, minZoom, maxZoom); zoomBar.BarScroll = GetBarScrollValue(); } widgets.Values.ForEach(w => w.Update((float)deltaTime)); if (PlayerInput.MidButtonHeld()) { // "Camera" Pan Vector2 moveSpeed = PlayerInput.MouseSpeed * (float)deltaTime * 100.0f; viewAreaOffset += moveSpeed.ToPoint(); } } if (PlayerInput.KeyHit(Keys.Left)) { foreach (var sprite in selectedSprites) { var newRect = sprite.SourceRect; newRect.X--; UpdateSourceRect(sprite, newRect); } } if (PlayerInput.KeyHit(Keys.Right)) { foreach (var sprite in selectedSprites) { var newRect = sprite.SourceRect; newRect.X++; UpdateSourceRect(sprite, newRect); } } if (PlayerInput.KeyHit(Keys.Down)) { foreach (var sprite in selectedSprites) { var newRect = sprite.SourceRect; newRect.Y++; UpdateSourceRect(sprite, newRect); } } if (PlayerInput.KeyHit(Keys.Up)) { foreach (var sprite in selectedSprites) { var newRect = sprite.SourceRect; newRect.Y--; UpdateSourceRect(sprite, newRect); } } }
public override void UpdateEditing(Camera cam, float deltaTime) { if (editingHUD == null || editingHUD.UserData != this) { editingHUD = CreateEditingHUD(); } if (IsSelected && PlayerInput.PrimaryMouseButtonClicked() && GUI.MouseOn == null) { Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); if (PlayerInput.KeyDown(Keys.Space)) { foreach (MapEntity e in mapEntityList) { if (!(e is WayPoint) || e == this || !e.IsHighlighted) { continue; } if (linkedTo.Contains(e)) { linkedTo.Remove(e); e.linkedTo.Remove(this); } else { linkedTo.Add(e); e.linkedTo.Add(this); } } } else { FindHull(); // Update gaps, ladders, and stairs UpdateLinkedEntity(position, Gap.GapList, gap => ConnectedGap = gap, gap => { if (ConnectedGap == gap) { ConnectedGap = null; } }); UpdateLinkedEntity(position, Item.ItemList, i => { var ladder = i?.GetComponent <Ladder>(); if (ladder != null) { Ladders = ladder; } }, i => { var ladder = i?.GetComponent <Ladder>(); if (ladder != null) { if (Ladders == ladder) { Ladders = null; } } }, inflate: 5); FindStairs(); // TODO: Cannot check the rectangle, since the rectangle is not rotated -> Need to use the collider. //var stairList = mapEntityList.Where(me => me is Structure s && s.StairDirection != Direction.None).Select(me => me as Structure); //UpdateLinkedEntity(position, stairList, s => //{ // Stairs = s; //}, s => //{ // if (Stairs == s) // { // Stairs = null; // } //}); } } }
public void Update(float deltaTime, GUICustomComponent mapContainer) { Rectangle rect = mapContainer.Rect; subReticlePosition = Vector2.Lerp(subReticlePosition, CurrentLocation.MapPosition, deltaTime); subReticleAnimState = 0.8f - Vector2.Distance(subReticlePosition, CurrentLocation.MapPosition) / 50.0f; subReticleAnimState = MathHelper.Clamp(subReticleAnimState + (float)Math.Sin(Timing.TotalTime * 3.5f) * 0.2f, 0.0f, 1.0f); targetReticleAnimState = SelectedLocation == null? Math.Max(targetReticleAnimState - deltaTime, 0.0f) : Math.Min(targetReticleAnimState + deltaTime, 0.6f + (float)Math.Sin(Timing.TotalTime * 2.5f) * 0.4f); #if DEBUG if (GameMain.DebugDraw) { if (editor == null) { CreateEditor(); } editor.AddToGUIUpdateList(order: 1); } #endif if (mapAnimQueue.Count > 0) { hudOpenState = Math.Max(hudOpenState - deltaTime, 0.0f); UpdateMapAnim(mapAnimQueue.Peek(), deltaTime); if (mapAnimQueue.Peek().Finished) { mapAnimQueue.Dequeue(); } return; } hudOpenState = Math.Min(hudOpenState + deltaTime, 0.75f + (float)Math.Sin(Timing.TotalTime * 3.0f) * 0.25f); Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y) + CenterOffset; float closestDist = 0.0f; highlightedLocation = null; if (GUI.MouseOn == null || GUI.MouseOn == mapContainer) { for (int i = 0; i < Locations.Count; i++) { Location location = Locations[i]; Vector2 pos = rectCenter + (location.MapPosition + drawOffset) * zoom; if (!rect.Contains(pos)) { continue; } float iconScale = MapGenerationParams.Instance.LocationIconSize / location.Type.Sprite.size.X; Rectangle drawRect = location.Type.Sprite.SourceRect; drawRect.Width = (int)(drawRect.Width * iconScale * zoom * 1.4f); drawRect.Height = (int)(drawRect.Height * iconScale * zoom * 1.4f); drawRect.X = (int)pos.X - drawRect.Width / 2; drawRect.Y = (int)pos.Y - drawRect.Width / 2; if (!drawRect.Contains(PlayerInput.MousePosition)) { continue; } float dist = Vector2.Distance(PlayerInput.MousePosition, pos); if (highlightedLocation == null || dist < closestDist) { closestDist = dist; highlightedLocation = location; } } } if (GUI.KeyboardDispatcher.Subscriber == null) { float moveSpeed = 1000.0f; Vector2 moveAmount = Vector2.Zero; if (PlayerInput.KeyDown(InputType.Left)) { moveAmount += Vector2.UnitX; } if (PlayerInput.KeyDown(InputType.Right)) { moveAmount -= Vector2.UnitX; } if (PlayerInput.KeyDown(InputType.Up)) { moveAmount += Vector2.UnitY; } if (PlayerInput.KeyDown(InputType.Down)) { moveAmount -= Vector2.UnitY; } drawOffset += moveAmount * moveSpeed / zoom * deltaTime; } if (GUI.MouseOn == mapContainer) { foreach (LocationConnection connection in connections) { if (highlightedLocation != CurrentLocation && connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(CurrentLocation)) { if (PlayerInput.PrimaryMouseButtonClicked() && SelectedLocation != highlightedLocation && highlightedLocation != null) { //clients aren't allowed to select the location without a permission if (GameMain.Client == null || GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign)) { SelectedConnection = connection; SelectedLocation = highlightedLocation; targetReticleAnimState = 0.0f; OnLocationSelected?.Invoke(SelectedLocation, SelectedConnection); GameMain.Client?.SendCampaignState(); } } } } zoom += PlayerInput.ScrollWheelSpeed / 1000.0f; zoom = MathHelper.Clamp(zoom, 1.0f, 4.0f); if (PlayerInput.MidButtonHeld() || (highlightedLocation == null && PlayerInput.PrimaryMouseButtonHeld())) { drawOffset += PlayerInput.MouseSpeed / zoom; } #if DEBUG if (PlayerInput.DoubleClicked() && highlightedLocation != null) { var passedConnection = CurrentLocation.Connections.Find(c => c.OtherLocation(CurrentLocation) == highlightedLocation); if (passedConnection != null) { passedConnection.Passed = true; } Location prevLocation = CurrentLocation; CurrentLocation = highlightedLocation; CurrentLocation.Discovered = true; OnLocationChanged?.Invoke(prevLocation, CurrentLocation); SelectLocation(-1); ProgressWorld(); } #endif } }
public void ReceiveCommandInput(char command) { if (Text == null) { Text = ""; } // Prevent alt gr from triggering any of these as that combination is often needed for special characters if (PlayerInput.IsAltDown()) { return; } switch (command) { case '\b' when !Readonly: //backspace if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl)) { SetText(string.Empty, false); CaretIndex = Text.Length; } else if (selectedCharacters > 0) { RemoveSelectedText(); } else if (Text.Length > 0 && CaretIndex > 0) { CaretIndex--; SetText(Text.Remove(CaretIndex, 1)); CalculateCaretPos(); ClearSelection(); } OnTextChanged?.Invoke(this, Text); break; case (char)0x3: // ctrl-c CopySelectedText(); break; case (char)0x16 when !Readonly: // ctrl-v string text = GetCopiedText(); RemoveSelectedText(); if (SetText(Text.Insert(CaretIndex, text))) { CaretIndex = Math.Min(Text.Length, CaretIndex + text.Length); OnTextChanged?.Invoke(this, Text); } break; case (char)0x18: // ctrl-x CopySelectedText(); if (!Readonly) { RemoveSelectedText(); } break; case (char)0x1: // ctrl-a if (PlayerInput.IsCtrlDown()) { SelectAll(); } break; case (char)0x1A when !Readonly && !SubEditorScreen.IsSubEditor(): // ctrl-z text = memento.Undo(); if (text != Text) { ClearSelection(); SetText(text, false); CaretIndex = Text.Length; OnTextChanged?.Invoke(this, Text); } break; case (char)0x12 when !Readonly && !SubEditorScreen.IsSubEditor(): // ctrl-r text = memento.Redo(); if (text != Text) { ClearSelection(); SetText(text, false); CaretIndex = Text.Length; OnTextChanged?.Invoke(this, Text); } break; } }
public static void Draw(SpriteBatch spriteBatch, Character character, Camera cam) { if (GUI.DisableHUD) { return; } character.CharacterHealth.Alignment = Alignment.Right; if (GameMain.GameSession?.CrewManager != null) { orderIndicatorCount.Clear(); foreach (Pair <Order, float> timedOrder in GameMain.GameSession.CrewManager.ActiveOrders) { DrawOrderIndicator(spriteBatch, cam, character, timedOrder.First, MathHelper.Clamp(timedOrder.Second / 10.0f, 0.2f, 1.0f)); } if (character.CurrentOrder != null) { DrawOrderIndicator(spriteBatch, cam, character, character.CurrentOrder, 1.0f); } } foreach (Character.ObjectiveEntity objectiveEntity in character.ActiveObjectiveEntities) { DrawObjectiveIndicator(spriteBatch, cam, character, objectiveEntity, 1.0f); } foreach (Item brokenItem in brokenItems) { if (brokenItem.NonInteractable) { continue; } float dist = Vector2.Distance(character.WorldPosition, brokenItem.WorldPosition); Vector2 drawPos = brokenItem.DrawPosition; float alpha = Math.Min((1000.0f - dist) / 1000.0f * 2.0f, 1.0f); if (alpha <= 0.0f) { continue; } GUI.DrawIndicator(spriteBatch, drawPos, cam, 100.0f, GUI.BrokenIcon, Color.Lerp(GUI.Style.Red, GUI.Style.Orange * 0.5f, brokenItem.Condition / brokenItem.MaxCondition) * alpha); } if (!character.IsIncapacitated && character.Stun <= 0.0f) { if (character.FocusedCharacter != null && character.FocusedCharacter.CanBeSelected) { DrawCharacterHoverTexts(spriteBatch, cam, character); } if (character.FocusedItem != null) { if (focusedItem != character.FocusedItem) { focusedItemOverlayTimer = Math.Min(1.0f, focusedItemOverlayTimer); shouldRecreateHudTexts = true; } focusedItem = character.FocusedItem; } if (focusedItem != null && focusedItemOverlayTimer > ItemOverlayDelay) { Vector2 circlePos = cam.WorldToScreen(focusedItem.DrawPosition); float circleSize = Math.Max(focusedItem.Rect.Width, focusedItem.Rect.Height) * 1.5f; circleSize = MathHelper.Clamp(circleSize, 45.0f, 100.0f) * Math.Min((focusedItemOverlayTimer - 1.0f) * 5.0f, 1.0f); if (circleSize > 0.0f) { Vector2 scale = new Vector2(circleSize / GUI.Style.FocusIndicator.FrameSize.X); GUI.Style.FocusIndicator.Draw(spriteBatch, (int)((focusedItemOverlayTimer - 1.0f) * GUI.Style.FocusIndicator.FrameCount * 3.0f), circlePos, Color.LightBlue * 0.3f, origin: GUI.Style.FocusIndicator.FrameSize.ToVector2() / 2, rotate: (float)Timing.TotalTime, scale: scale); } if (!GUI.DisableItemHighlights && !Inventory.DraggingItemToWorld) { bool shiftDown = PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift); if (shouldRecreateHudTexts || heldDownShiftWhenGotHudTexts != shiftDown) { shouldRecreateHudTexts = true; heldDownShiftWhenGotHudTexts = shiftDown; } var hudTexts = focusedItem.GetHUDTexts(character, shouldRecreateHudTexts); shouldRecreateHudTexts = false; int dir = Math.Sign(focusedItem.WorldPosition.X - character.WorldPosition.X); Vector2 textSize = GUI.Font.MeasureString(focusedItem.Name); Vector2 largeTextSize = GUI.SubHeadingFont.MeasureString(focusedItem.Name); Vector2 startPos = cam.WorldToScreen(focusedItem.DrawPosition); startPos.Y -= (hudTexts.Count + 1) * textSize.Y; if (focusedItem.Sprite != null) { startPos.X += (int)(circleSize * 0.4f * dir); startPos.Y -= (int)(circleSize * 0.4f); } Vector2 textPos = startPos; if (dir == -1) { textPos.X -= largeTextSize.X; } float alpha = MathHelper.Clamp((focusedItemOverlayTimer - ItemOverlayDelay) * 2.0f, 0.0f, 1.0f); GUI.DrawString(spriteBatch, textPos, focusedItem.Name, GUI.Style.TextColor * alpha, Color.Black * alpha * 0.7f, 2, font: GUI.SubHeadingFont); startPos.X += dir * 10.0f * GUI.Scale; textPos.X += dir * 10.0f * GUI.Scale; textPos.Y += largeTextSize.Y; foreach (ColoredText coloredText in hudTexts) { if (dir == -1) { textPos.X = (int)(startPos.X - GUI.SmallFont.MeasureString(coloredText.Text).X); } GUI.DrawString(spriteBatch, textPos, coloredText.Text, coloredText.Color * alpha, Color.Black * alpha * 0.7f, 2, GUI.SmallFont); textPos.Y += textSize.Y; } } } foreach (HUDProgressBar progressBar in character.HUDProgressBars.Values) { progressBar.Draw(spriteBatch, cam); } } if (character.SelectedConstruction != null && (character.CanInteractWith(Character.Controlled.SelectedConstruction) || Screen.Selected == GameMain.SubEditorScreen)) { character.SelectedConstruction.DrawHUD(spriteBatch, cam, Character.Controlled); } if (character.Inventory != null) { for (int i = 0; i < character.Inventory.Items.Length - 1; i++) { var item = character.Inventory.Items[i]; if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) { continue; } foreach (ItemComponent ic in item.Components) { if (ic.DrawHudWhenEquipped) { ic.DrawHUD(spriteBatch, character); } } } } bool mouseOnPortrait = false; if (character.Stun <= 0.1f && !character.IsDead) { if (CharacterHealth.OpenHealthWindow == null && character.SelectedCharacter == null) { if (character.Info != null && !character.ShouldLockHud()) { character.Info.DrawBackground(spriteBatch); character.Info.DrawJobIcon(spriteBatch, new Rectangle( (int)(HUDLayoutSettings.BottomRightInfoArea.X + HUDLayoutSettings.BottomRightInfoArea.Width * 0.05f), (int)(HUDLayoutSettings.BottomRightInfoArea.Y + HUDLayoutSettings.BottomRightInfoArea.Height * 0.1f), (int)(HUDLayoutSettings.BottomRightInfoArea.Width / 2), (int)(HUDLayoutSettings.BottomRightInfoArea.Height * 0.7f))); character.Info.DrawPortrait(spriteBatch, HUDLayoutSettings.PortraitArea.Location.ToVector2(), new Vector2(-12 * GUI.Scale, 4 * GUI.Scale), targetWidth: HUDLayoutSettings.PortraitArea.Width, true); } mouseOnPortrait = HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) && !character.ShouldLockHud(); if (mouseOnPortrait) { GUI.UIGlow.Draw(spriteBatch, HUDLayoutSettings.BottomRightInfoArea, GUI.Style.Green * 0.5f); } } if (ShouldDrawInventory(character)) { character.Inventory.Locked = LockInventory(character); character.Inventory.DrawOwn(spriteBatch); character.Inventory.CurrentLayout = CharacterHealth.OpenHealthWindow == null && character.SelectedCharacter == null ? CharacterInventory.Layout.Default : CharacterInventory.Layout.Right; } } if (!character.IsIncapacitated && character.Stun <= 0.0f) { if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null) { if (character.SelectedCharacter.CanInventoryBeAccessed) { ///character.Inventory.CurrentLayout = Alignment.Left; character.SelectedCharacter.Inventory.CurrentLayout = CharacterInventory.Layout.Left; character.SelectedCharacter.Inventory.DrawOwn(spriteBatch); } else { //character.Inventory.CurrentLayout = (CharacterHealth.OpenHealthWindow == null) ? Alignment.Center : Alignment.Left; } if (CharacterHealth.OpenHealthWindow == character.SelectedCharacter.CharacterHealth) { character.SelectedCharacter.CharacterHealth.Alignment = Alignment.Left; character.SelectedCharacter.CharacterHealth.DrawStatusHUD(spriteBatch); } } else if (character.Inventory != null) { //character.Inventory.CurrentLayout = (CharacterHealth.OpenHealthWindow == null) ? Alignment.Center : Alignment.Left; } } if (mouseOnPortrait) { GUIComponent.DrawToolTip( spriteBatch, character.Info?.Job == null ? character.DisplayName : character.DisplayName + " (" + character.Info.Job.Name + ")", HUDLayoutSettings.PortraitArea); } }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> public override void Update(double deltaTime) { #if DEBUG && CLIENT if (GameMain.GameSession != null && GameMain.GameSession.Level != null && GameMain.GameSession.Submarine != null && !DebugConsole.IsOpen && GUI.KeyboardDispatcher.Subscriber == null) { var closestSub = Submarine.FindClosest(cam.WorldViewCenter); if (closestSub == null) { closestSub = GameMain.GameSession.Submarine; } Vector2 targetMovement = Vector2.Zero; if (PlayerInput.KeyDown(Keys.I)) { targetMovement.Y += 1.0f; } if (PlayerInput.KeyDown(Keys.K)) { targetMovement.Y -= 1.0f; } if (PlayerInput.KeyDown(Keys.J)) { targetMovement.X -= 1.0f; } if (PlayerInput.KeyDown(Keys.L)) { targetMovement.X += 1.0f; } if (targetMovement != Vector2.Zero) { closestSub.ApplyForce(targetMovement * closestSub.SubBody.Body.Mass * 100.0f); } } #endif GameTime += deltaTime; foreach (PhysicsBody body in PhysicsBody.List) { body.Update((float)deltaTime); } foreach (MapEntity e in MapEntity.mapEntityList) { e.IsHighlighted = false; } if (GameMain.GameSession != null) { GameMain.GameSession.Update((float)deltaTime); } #if CLIENT var sw = new System.Diagnostics.Stopwatch(); sw.Start(); GameMain.ParticleManager.Update((float)deltaTime); sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("ParticleUpdate", sw.ElapsedTicks); sw.Restart(); GameMain.LightManager.Update((float)deltaTime); sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("LightUpdate", sw.ElapsedTicks); sw.Restart(); #endif if (Level.Loaded != null) { Level.Loaded.Update((float)deltaTime, cam); } #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("LevelUpdate", sw.ElapsedTicks); if (Character.Controlled != null && Character.Controlled.SelectedConstruction != null && Character.Controlled.CanInteractWith(Character.Controlled.SelectedConstruction)) { Character.Controlled.SelectedConstruction.UpdateHUD(cam, Character.Controlled, (float)deltaTime); } sw.Restart(); #endif Character.UpdateAll((float)deltaTime, cam); #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("CharacterUpdate", sw.ElapsedTicks); sw.Restart(); #endif StatusEffect.UpdateAll((float)deltaTime); #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("StatusEffectUpdate", sw.ElapsedTicks); sw.Restart(); if (Character.Controlled != null && Lights.LightManager.ViewTarget != null) { Vector2 targetPos = Lights.LightManager.ViewTarget.DrawPosition; if (Lights.LightManager.ViewTarget == Character.Controlled && CharacterHealth.OpenHealthWindow != null) { Vector2 screenTargetPos = CharacterHealth.OpenHealthWindow.Alignment == Alignment.Left ? new Vector2(GameMain.GraphicsWidth * 0.75f, GameMain.GraphicsHeight * 0.5f) : new Vector2(GameMain.GraphicsWidth * 0.25f, GameMain.GraphicsHeight * 0.5f); Vector2 screenOffset = screenTargetPos - new Vector2(GameMain.GraphicsWidth / 2, GameMain.GraphicsHeight / 2); screenOffset.Y = -screenOffset.Y; targetPos -= screenOffset / cam.Zoom; } cam.TargetPos = targetPos; } #endif cam.MoveCamera((float)deltaTime); foreach (Submarine sub in Submarine.Loaded) { sub.SetPrevTransform(sub.Position); } foreach (PhysicsBody pb in PhysicsBody.List) { pb.SetPrevTransform(pb.SimPosition, pb.Rotation); } MapEntity.UpdateAll((float)deltaTime, cam); #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("MapEntityUpdate", sw.ElapsedTicks); sw.Restart(); #endif Character.UpdateAnimAll((float)deltaTime); Ragdoll.UpdateAll((float)deltaTime, cam); #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("AnimUpdate", sw.ElapsedTicks); sw.Restart(); #endif foreach (Submarine sub in Submarine.Loaded) { sub.Update((float)deltaTime); } #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("SubmarineUpdate", sw.ElapsedTicks); sw.Restart(); #endif GameMain.World.Step((float)deltaTime); #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("Physics", sw.ElapsedTicks); #endif #if CLIENT if (!PlayerInput.LeftButtonHeld()) { Inventory.draggingSlot = null; Inventory.draggingItem = null; } #endif }
/// <summary> /// Update the selection logic in submarine editor /// </summary> public static void UpdateSelecting(Camera cam) { if (resizing) { if (selectedList.Count == 0) { resizing = false; } return; } foreach (MapEntity e in mapEntityList) { e.isHighlighted = false; } if (DisableSelect) { DisableSelect = false; return; } if (GUI.MouseOn != null || !PlayerInput.MouseInsideWindow) { if (highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn))) { UpdateHighlightedListBox(null, false); return; } } if (MapEntityPrefab.Selected != null) { selectionPos = Vector2.Zero; selectedList.Clear(); return; } if (GUI.KeyboardDispatcher.Subscriber == null) { if (PlayerInput.KeyHit(Keys.Delete)) { if (selectedList.Any()) { SubEditorScreen.StoreCommand(new AddOrDeleteCommand(selectedList, true)); } selectedList.ForEach(e => { if (!e.Removed) { e.Remove(); } }); selectedList.Clear(); } if (PlayerInput.IsCtrlDown()) { #if DEBUG if (PlayerInput.KeyHit(Keys.D)) { bool terminate = false; foreach (MapEntity entity in selectedList) { if (entity is Item item && item.GetComponent <Planter>() is { } planter) { planter.Update(1.0f, cam); for (var i = 0; i < planter.GrowableSeeds.Length; i++) { Growable seed = planter.GrowableSeeds[i]; PlantSlot slot = planter.PlantSlots.ContainsKey(i) ? planter.PlantSlots[i] : Planter.NullSlot; if (seed == null) { continue; } seed.CreateDebugHUD(planter, slot); terminate = true; break; } } if (terminate) { break; } } } #endif if (PlayerInput.KeyHit(Keys.C)) { Copy(selectedList); } else if (PlayerInput.KeyHit(Keys.X)) { Cut(selectedList); } else if (PlayerInput.KeyHit(Keys.V)) { Paste(cam.WorldViewCenter); } else if (PlayerInput.KeyHit(Keys.G)) { if (selectedList.Any()) { if (SelectionGroups.ContainsKey(selectedList.Last())) { // Ungroup all selected selectedList.ForEach(e => SelectionGroups.Remove(e)); } else { foreach (var entity in selectedList) { // Remove the old group, if any SelectionGroups.Remove(entity); // Create a group that can be accessed with any member SelectionGroups.Add(entity, selectedList); } } } } } } Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); MapEntity highLightedEntity = null; if (startMovingPos == Vector2.Zero) { List <MapEntity> highlightedEntities = new List <MapEntity>(); if (highlightedListBox != null && highlightedListBox.IsParentOf(GUI.MouseOn)) { highLightedEntity = GUI.MouseOn.UserData as MapEntity; } else { foreach (MapEntity e in mapEntityList) { if (!e.SelectableInEditor) { continue; } if (e.IsMouseOn(position)) { int i = 0; while (i < highlightedEntities.Count && e.Sprite != null && (highlightedEntities[i].Sprite == null || highlightedEntities[i].SpriteDepth < e.SpriteDepth)) { i++; } highlightedEntities.Insert(i, e); if (i == 0) { highLightedEntity = e; } } } UpdateHighlighting(highlightedEntities); } if (highLightedEntity != null) { highLightedEntity.isHighlighted = true; } } if (GUI.KeyboardDispatcher.Subscriber == null) { int up = PlayerInput.KeyDown(Keys.Up) ? 1 : 0, down = PlayerInput.KeyDown(Keys.Down) ? -1 : 0, left = PlayerInput.KeyDown(Keys.Left) ? -1 : 0, right = PlayerInput.KeyDown(Keys.Right) ? 1 : 0; int xKeysDown = (left + right); int yKeysDown = (up + down); if (xKeysDown != 0 || yKeysDown != 0) { keyDelay += (float)Timing.Step; } else { keyDelay = 0; } Vector2 nudgeAmount = Vector2.Zero; if (keyDelay >= 0.5f) { nudgeAmount.Y = yKeysDown; nudgeAmount.X = xKeysDown; } if (PlayerInput.KeyHit(Keys.Up)) { nudgeAmount.Y = 1f; } if (PlayerInput.KeyHit(Keys.Down)) { nudgeAmount.Y = -1f; } if (PlayerInput.KeyHit(Keys.Left)) { nudgeAmount.X = -1f; } if (PlayerInput.KeyHit(Keys.Right)) { nudgeAmount.X = 1f; } if (nudgeAmount != Vector2.Zero) { foreach (MapEntity entityToNudge in selectedList) { entityToNudge.Move(nudgeAmount); } } } else { keyDelay = 0; } bool isShiftDown = PlayerInput.IsShiftDown(); //started moving selected entities if (startMovingPos != Vector2.Zero) { Item targetContainer = GetPotentialContainer(position, selectedList); if (targetContainer != null) { targetContainer.IsHighlighted = true; } if (PlayerInput.PrimaryMouseButtonReleased()) { //mouse released -> move the entities to the new position of the mouse Vector2 moveAmount = position - startMovingPos; if (!isShiftDown) { moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X; moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y; } if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y || isShiftDown) { if (!isShiftDown) { moveAmount = Submarine.VectorToWorldGrid(moveAmount); } //clone if (PlayerInput.IsCtrlDown()) { var clones = Clone(selectedList).Where(c => c != null).ToList(); selectedList = clones; selectedList.ForEach(c => c.Move(moveAmount)); SubEditorScreen.StoreCommand(new AddOrDeleteCommand(clones, false)); } else // move { var oldRects = selectedList.Select(e => e.Rect).ToList(); List <MapEntity> deposited = new List <MapEntity>(); foreach (MapEntity e in selectedList) { e.Move(moveAmount); if (isShiftDown && e is Item item && targetContainer != null) { if (targetContainer.OwnInventory.TryPutItem(item, Character.Controlled)) { SoundPlayer.PlayUISound(GUISoundType.DropItem); deposited.Add(item); } else { SoundPlayer.PlayUISound(GUISoundType.PickItemFail); } } } SubEditorScreen.StoreCommand(new TransformCommand(new List <MapEntity>(selectedList), selectedList.Select(entity => entity.Rect).ToList(), oldRects, false)); if (deposited.Any() && deposited.Any(entity => entity is Item)) { var depositedItems = deposited.Where(entity => entity is Item).Cast <Item>().ToList(); SubEditorScreen.StoreCommand(new InventoryPlaceCommand(targetContainer.OwnInventory, depositedItems, false)); } deposited.ForEach(entity => { selectedList.Remove(entity); }); } } startMovingPos = Vector2.Zero; } } //started dragging a "selection rectangle" else if (selectionPos != Vector2.Zero) { selectionSize.X = position.X - selectionPos.X; selectionSize.Y = selectionPos.Y - position.Y; List <MapEntity> newSelection = new List <MapEntity>();// FindSelectedEntities(selectionPos, selectionSize); if (Math.Abs(selectionSize.X) > Submarine.GridSize.X || Math.Abs(selectionSize.Y) > Submarine.GridSize.Y) { newSelection = FindSelectedEntities(selectionPos, selectionSize); } else { if (highLightedEntity != null) { if (SelectionGroups.TryGetValue(highLightedEntity, out List <MapEntity> group)) { newSelection.AddRange(group); } else { newSelection.Add(highLightedEntity); } } } if (PlayerInput.PrimaryMouseButtonReleased()) { if (PlayerInput.IsCtrlDown()) { foreach (MapEntity e in newSelection) { if (selectedList.Contains(e)) { RemoveSelection(e); } else { AddSelection(e); } } } else { selectedList = new List <MapEntity>(newSelection); //selectedList.Clear(); //newSelection.ForEach(e => AddSelection(e)); foreach (var entity in newSelection) { HandleDoorGapLinks(entity, onGapFound: (door, gap) => { door.RefreshLinkedGap(); if (!selectedList.Contains(gap)) { selectedList.Add(gap); } }, onDoorFound: (door, gap) => { if (!selectedList.Contains(door.Item)) { selectedList.Add(door.Item); } }); } } //select wire if both items it's connected to are selected var selectedItems = selectedList.Where(e => e is Item).Cast <Item>().ToList(); foreach (Item item in selectedItems) { if (item.Connections == null) { continue; } foreach (Connection c in item.Connections) { foreach (Wire w in c.Wires) { if (w == null || selectedList.Contains(w.Item)) { continue; } if (w.OtherConnection(c) != null && selectedList.Contains(w.OtherConnection(c).Item)) { selectedList.Add(w.Item); } } } } selectionPos = Vector2.Zero; selectionSize = Vector2.Zero; } } //default, not doing anything specific yet else { if (PlayerInput.PrimaryMouseButtonHeld() && PlayerInput.KeyUp(Keys.Space) && (highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn)))) { //if clicking a selected entity, start moving it foreach (MapEntity e in selectedList) { if (e.IsMouseOn(position)) { startMovingPos = position; } } selectionPos = position; //stop camera movement to prevent accidental dragging or rect selection Screen.Selected.Cam.StopMovement(); } } }
/// <summary> /// Update the selection logic in submarine editor /// </summary> public static void UpdateSelecting(Camera cam) { if (resizing) { if (selectedList.Count == 0) { resizing = false; } return; } foreach (MapEntity e in mapEntityList) { e.isHighlighted = false; } if (DisableSelect) { DisableSelect = false; return; } if (GUI.MouseOn != null || !PlayerInput.MouseInsideWindow) { if (highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn))) { UpdateHighlightedListBox(null); return; } } if (MapEntityPrefab.Selected != null) { selectionPos = Vector2.Zero; selectedList.Clear(); return; } if (GUI.KeyboardDispatcher.Subscriber == null) { if (PlayerInput.KeyDown(Keys.Delete)) { selectedList.ForEach(e => e.Remove()); selectedList.Clear(); } if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl)) { if (PlayerInput.KeyHit(Keys.C)) { CopyEntities(selectedList); } else if (PlayerInput.KeyHit(Keys.X)) { CopyEntities(selectedList); selectedList.ForEach(e => e.Remove()); selectedList.Clear(); } else if (copiedList.Count > 0 && PlayerInput.KeyHit(Keys.V)) { List <MapEntity> prevEntities = new List <MapEntity>(mapEntityList); Clone(copiedList); var clones = mapEntityList.Except(prevEntities).ToList(); Vector2 center = Vector2.Zero; clones.ForEach(c => center += c.WorldPosition); center = Submarine.VectorToWorldGrid(center / clones.Count); Vector2 moveAmount = Submarine.VectorToWorldGrid(cam.WorldViewCenter - center); selectedList = new List <MapEntity>(clones); foreach (MapEntity clone in selectedList) { clone.Move(moveAmount); clone.Submarine = Submarine.MainSub; } } else if (PlayerInput.KeyHit(Keys.G)) { if (selectedList.Any()) { if (SelectionGroups.ContainsKey(selectedList.Last())) { // Ungroup all selected selectedList.ForEach(e => SelectionGroups.Remove(e)); } else { foreach (var entity in selectedList) { // Remove the old group, if any SelectionGroups.Remove(entity); // Create a group that can be accessed with any member SelectionGroups.Add(entity, selectedList); } } } } else if (PlayerInput.KeyHit(Keys.Z)) { SetPreviousRects(e => e.rectMemento.Undo()); } else if (PlayerInput.KeyHit(Keys.R)) { SetPreviousRects(e => e.rectMemento.Redo()); } void SetPreviousRects(Func <MapEntity, Rectangle> memoryMethod) { foreach (var e in SelectedList) { if (e.rectMemento != null) { Point diff = memoryMethod(e).Location - e.Rect.Location; // We have to call the move method, because there's a lot more than just storing the rect (in some cases) // We also have to reassign the rect, because the move method does not set the width and height. They might have changed too. // The Rect property is virtual and it's overridden for structs. Setting the rect via the property should automatically recreate the sections for resizable structures. e.Move(diff.ToVector2()); e.Rect = e.rectMemento.Current; } } } } } Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); MapEntity highLightedEntity = null; if (startMovingPos == Vector2.Zero) { List <MapEntity> highlightedEntities = new List <MapEntity>(); if (highlightedListBox != null && highlightedListBox.IsParentOf(GUI.MouseOn)) { highLightedEntity = GUI.MouseOn.UserData as MapEntity; } else { foreach (MapEntity e in mapEntityList) { if (!e.SelectableInEditor) { continue; } if (e.IsMouseOn(position)) { int i = 0; while (i < highlightedEntities.Count && e.Sprite != null && (highlightedEntities[i].Sprite == null || highlightedEntities[i].SpriteDepth < e.SpriteDepth)) { i++; } highlightedEntities.Insert(i, e); if (i == 0) { highLightedEntity = e; } } } if (PlayerInput.MouseSpeed.LengthSquared() > 10) { highlightTimer = 0.0f; } else { bool mouseNearHighlightBox = false; if (highlightedListBox != null) { Rectangle expandedRect = highlightedListBox.Rect; expandedRect.Inflate(20, 20); mouseNearHighlightBox = expandedRect.Contains(PlayerInput.MousePosition); if (!mouseNearHighlightBox) { highlightedListBox = null; } } highlightTimer += (float)Timing.Step; if (highlightTimer > 1.0f) { if (!mouseNearHighlightBox) { UpdateHighlightedListBox(highlightedEntities); highlightTimer = 0.0f; } } } } if (highLightedEntity != null) { highLightedEntity.isHighlighted = true; } } if (GUI.KeyboardDispatcher.Subscriber == null) { Vector2 nudgeAmount = Vector2.Zero; if (PlayerInput.KeyHit(Keys.Up)) { nudgeAmount.Y = 1f; } if (PlayerInput.KeyHit(Keys.Down)) { nudgeAmount.Y = -1f; } if (PlayerInput.KeyHit(Keys.Left)) { nudgeAmount.X = -1f; } if (PlayerInput.KeyHit(Keys.Right)) { nudgeAmount.X = 1f; } if (nudgeAmount != Vector2.Zero) { foreach (MapEntity entityToNudge in selectedList) { entityToNudge.Move(nudgeAmount); } } } //started moving selected entities if (startMovingPos != Vector2.Zero) { if (PlayerInput.LeftButtonReleased()) { //mouse released -> move the entities to the new position of the mouse Vector2 moveAmount = position - startMovingPos; moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X; moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y; if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y) { moveAmount = Submarine.VectorToWorldGrid(moveAmount); //clone if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl)) { var clones = Clone(selectedList); selectedList = clones; selectedList.ForEach(c => c.Move(moveAmount)); } else // move { foreach (MapEntity e in selectedList) { if (e.rectMemento == null) { e.rectMemento = new Memento <Rectangle>(); e.rectMemento.Store(e.Rect); } e.Move(moveAmount); e.rectMemento.Store(e.Rect); } } } startMovingPos = Vector2.Zero; } } //started dragging a "selection rectangle" else if (selectionPos != Vector2.Zero) { selectionSize.X = position.X - selectionPos.X; selectionSize.Y = selectionPos.Y - position.Y; List <MapEntity> newSelection = new List <MapEntity>();// FindSelectedEntities(selectionPos, selectionSize); if (Math.Abs(selectionSize.X) > Submarine.GridSize.X || Math.Abs(selectionSize.Y) > Submarine.GridSize.Y) { newSelection = FindSelectedEntities(selectionPos, selectionSize); } else { if (highLightedEntity != null) { if (SelectionGroups.TryGetValue(highLightedEntity, out List <MapEntity> group)) { newSelection.AddRange(group); } else { newSelection.Add(highLightedEntity); } } } if (PlayerInput.LeftButtonReleased()) { if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl)) { foreach (MapEntity e in newSelection) { if (selectedList.Contains(e)) { RemoveSelection(e); } else { AddSelection(e); } } } else { selectedList = newSelection; //selectedList.Clear(); //newSelection.ForEach(e => AddSelection(e)); foreach (var entity in newSelection) { HandleDoorGapLinks(entity, onGapFound: (door, gap) => { door.RefreshLinkedGap(); if (!selectedList.Contains(gap)) { selectedList.Add(gap); } }, onDoorFound: (door, gap) => { if (!selectedList.Contains(door.Item)) { selectedList.Add(door.Item); } }); } } //select wire if both items it's connected to are selected var selectedItems = selectedList.Where(e => e is Item).Cast <Item>().ToList(); foreach (Item item in selectedItems) { if (item.Connections == null) { continue; } foreach (Connection c in item.Connections) { foreach (Wire w in c.Wires) { if (w == null || selectedList.Contains(w.Item)) { continue; } if (w.OtherConnection(c) != null && selectedList.Contains(w.OtherConnection(c).Item)) { selectedList.Add(w.Item); } } } } selectionPos = Vector2.Zero; selectionSize = Vector2.Zero; } } //default, not doing anything specific yet else { if (PlayerInput.LeftButtonHeld() && PlayerInput.KeyUp(Keys.Space) && (highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn)))) { //if clicking a selected entity, start moving it foreach (MapEntity e in selectedList) { if (e.IsMouseOn(position)) { startMovingPos = position; } } selectionPos = position; //stop camera movement to prevent accidental dragging or rect selection Screen.Selected.Cam.StopMovement(); } } }
public void Update(float deltaTime, GUICustomComponent mapContainer) { Rectangle rect = mapContainer.Rect; if (CurrentDisplayLocation != null) { if (!CurrentDisplayLocation.Discovered) { RemoveFogOfWar(CurrentDisplayLocation); CurrentDisplayLocation.Discovered = true; if (CurrentDisplayLocation.MapPosition.X > furthestDiscoveredLocation.MapPosition.X) { furthestDiscoveredLocation = CurrentDisplayLocation; } } } currLocationIndicatorPos = Vector2.Lerp(currLocationIndicatorPos, CurrentDisplayLocation.MapPosition, deltaTime); #if DEBUG if (GameMain.DebugDraw) { if (editor == null) { CreateEditor(); } editor.AddToGUIUpdateList(order: 1); } #endif if (mapAnimQueue.Count > 0) { hudVisibility = Math.Max(hudVisibility - deltaTime, 0.0f); UpdateMapAnim(mapAnimQueue.Peek(), deltaTime); if (mapAnimQueue.Peek().Finished) { mapAnimQueue.Dequeue(); } return; } hudVisibility = Math.Min(hudVisibility + deltaTime, 0.75f + (float)Math.Sin(Timing.TotalTime * 3.0f) * 0.25f); Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y); Vector2 viewOffset = DrawOffset + drawOffsetNoise; float closestDist = 0.0f; HighlightedLocation = null; if (GUI.MouseOn == null || GUI.MouseOn == mapContainer) { for (int i = 0; i < Locations.Count; i++) { Location location = Locations[i]; if (IsInFogOfWar(location) && !(CurrentDisplayLocation?.Connections.Any(c => c.Locations.Contains(location)) ?? false) && !GameMain.DebugDraw) { continue; } Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom; if (!rect.Contains(pos)) { continue; } float iconScale = generationParams.LocationIconSize / location.Type.Sprite.size.X; if (location == CurrentDisplayLocation) { iconScale *= 1.2f; } Rectangle drawRect = location.Type.Sprite.SourceRect; drawRect.Width = (int)(drawRect.Width * iconScale * zoom * 1.4f); drawRect.Height = (int)(drawRect.Height * iconScale * zoom * 1.4f); drawRect.X = (int)pos.X - drawRect.Width / 2; drawRect.Y = (int)pos.Y - drawRect.Width / 2; if (!drawRect.Contains(PlayerInput.MousePosition)) { continue; } float dist = Vector2.Distance(PlayerInput.MousePosition, pos); if (HighlightedLocation == null || dist < closestDist) { closestDist = dist; HighlightedLocation = location; } } } if (GUI.KeyboardDispatcher.Subscriber == null) { float moveSpeed = 1000.0f; Vector2 moveAmount = Vector2.Zero; if (PlayerInput.KeyDown(InputType.Left)) { moveAmount += Vector2.UnitX; } if (PlayerInput.KeyDown(InputType.Right)) { moveAmount -= Vector2.UnitX; } if (PlayerInput.KeyDown(InputType.Up)) { moveAmount += Vector2.UnitY; } if (PlayerInput.KeyDown(InputType.Down)) { moveAmount -= Vector2.UnitY; } DrawOffset += moveAmount * moveSpeed / zoom * deltaTime; } targetZoom = MathHelper.Clamp(targetZoom, generationParams.MinZoom, generationParams.MaxZoom); zoom = MathHelper.Lerp(zoom, targetZoom, 0.1f); if (GUI.MouseOn == mapContainer) { foreach (LocationConnection connection in Connections) { if (HighlightedLocation != CurrentDisplayLocation && connection.Locations.Contains(HighlightedLocation) && connection.Locations.Contains(CurrentDisplayLocation)) { if (PlayerInput.PrimaryMouseButtonClicked() && SelectedLocation != HighlightedLocation && HighlightedLocation != null) { //clients aren't allowed to select the location without a permission if ((GameMain.GameSession?.GameMode as CampaignMode)?.AllowedToManageCampaign() ?? false) { SelectedConnection = connection; SelectedLocation = HighlightedLocation; OnLocationSelected?.Invoke(SelectedLocation, SelectedConnection); GameMain.Client?.SendCampaignState(); } } } } targetZoom += PlayerInput.ScrollWheelSpeed / 500.0f; if (PlayerInput.MidButtonHeld() || (HighlightedLocation == null && PlayerInput.PrimaryMouseButtonHeld())) { DrawOffset += PlayerInput.MouseSpeed / zoom; } if (AllowDebugTeleport) { if (PlayerInput.DoubleClicked() && HighlightedLocation != null) { var passedConnection = CurrentDisplayLocation.Connections.Find(c => c.OtherLocation(CurrentDisplayLocation) == HighlightedLocation); if (passedConnection != null) { passedConnection.Passed = true; } Location prevLocation = CurrentDisplayLocation; CurrentLocation = HighlightedLocation; Level.Loaded.DebugSetStartLocation(CurrentLocation); Level.Loaded.DebugSetEndLocation(null); CurrentLocation.Discovered = true; OnLocationChanged?.Invoke(prevLocation, CurrentLocation); SelectLocation(-1); if (GameMain.Client == null) { CurrentLocation.CreateStore(); ProgressWorld(); } else { GameMain.Client.SendCampaignState(); } } if (PlayerInput.KeyDown(Microsoft.Xna.Framework.Input.Keys.LeftShift) && PlayerInput.PrimaryMouseButtonClicked() && HighlightedLocation != null) { int distance = DistanceToClosestLocationWithOutpost(HighlightedLocation, out Location foundLocation); DebugConsole.NewMessage($"Distance to closest outpost from {HighlightedLocation.Name} to {foundLocation?.Name} is {distance}"); } if (PlayerInput.PrimaryMouseButtonClicked() && HighlightedLocation == null) { SelectLocation(-1); } } } }
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 = GetZoomAmount(offset); //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 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; }