From acfee8075538818f64a3762e032dae7cbb01a974 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 17 Nov 2017 01:09:52 +0200 Subject: [PATCH] WIP particle editor, added tooltips to ParticlePrefab properties --- .../BarotraumaClient/BarotraumaClient.csproj | 1 + .../BarotraumaClient/Source/DebugConsole.cs | 9 +- .../Source/GUI/GUIDropDown.cs | 20 ++- .../BarotraumaClient/Source/GameMain.cs | 12 +- .../Source/Particles/ParticleManager.cs | 6 + .../Source/Particles/ParticlePrefab.cs | 74 ++++++---- .../Source/Screens/ParticleEditorScreen.cs | 129 ++++++++++++++++++ .../Serialization/SerializableEntityEditor.cs | 5 + 8 files changed, 218 insertions(+), 38 deletions(-) create mode 100644 Barotrauma/BarotraumaClient/Source/Screens/ParticleEditorScreen.cs diff --git a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj index b24d7da67..e2b9c47b5 100644 --- a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj +++ b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj @@ -204,6 +204,7 @@ + diff --git a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs index e180eeb9f..91ca080a3 100644 --- a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs @@ -225,13 +225,18 @@ namespace Barotrauma } GameMain.EditMapScreen.Select(); })); - + commands.Add(new Command("editcharacter", "", (string[] args) => { GameMain.EditCharacterScreen.Select(); - })); + commands.Add(new Command("editparticles", "", (string[] args) => + { + GameMain.ParticleEditorScreen.Select(); + })); + + commands.Add(new Command("control|controlcharacter", "control [character name]: Start controlling the specified character.", (string[] args) => { if (args.Length < 1) return; diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIDropDown.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIDropDown.cs index d865b5101..ce95757ca 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIDropDown.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIDropDown.cs @@ -70,7 +70,25 @@ namespace Barotrauma listBox.ToolTip = value; } } - + + + public override Rectangle Rect + { + get + { + return base.Rect; + } + + set + { + Point moveAmount = value.Location - rect.Location; + base.Rect = value; + + button.Rect = new Rectangle(button.Rect.Location + moveAmount, button.Rect.Size); + listBox.Rect = new Rectangle(listBox.Rect.Location + moveAmount, listBox.Rect.Size); + } + } + public GUIDropDown(Rectangle rect, string text, string style, GUIComponent parent = null) : this(rect, text, style, Alignment.TopLeft, parent) { diff --git a/Barotrauma/BarotraumaClient/Source/GameMain.cs b/Barotrauma/BarotraumaClient/Source/GameMain.cs index 9b58a6288..2fcd92b79 100644 --- a/Barotrauma/BarotraumaClient/Source/GameMain.cs +++ b/Barotrauma/BarotraumaClient/Source/GameMain.cs @@ -29,6 +29,7 @@ namespace Barotrauma public static EditMapScreen EditMapScreen; public static EditCharacterScreen EditCharacterScreen; + public static ParticleEditorScreen ParticleEditorScreen; public static Lights.LightManager LightManager; @@ -279,13 +280,14 @@ namespace Barotrauma TitleScreen.LoadState = 90.0f; yield return CoroutineStatus.Running; - MainMenuScreen = new MainMenuScreen(this); - LobbyScreen = new LobbyScreen(); + MainMenuScreen = new MainMenuScreen(this); + LobbyScreen = new LobbyScreen(); - ServerListScreen = new ServerListScreen(); + ServerListScreen = new ServerListScreen(); - EditMapScreen = new EditMapScreen(); - EditCharacterScreen = new EditCharacterScreen(); + EditMapScreen = new EditMapScreen(); + EditCharacterScreen = new EditCharacterScreen(); + ParticleEditorScreen = new ParticleEditorScreen(); yield return CoroutineStatus.Running; diff --git a/Barotrauma/BarotraumaClient/Source/Particles/ParticleManager.cs b/Barotrauma/BarotraumaClient/Source/Particles/ParticleManager.cs index c597ed299..882c022c0 100644 --- a/Barotrauma/BarotraumaClient/Source/Particles/ParticleManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Particles/ParticleManager.cs @@ -2,6 +2,7 @@ using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; +using System.Linq; using System.Xml.Linq; namespace Barotrauma.Particles @@ -92,6 +93,11 @@ namespace Barotrauma.Particles return particles[particleCount - 1]; } + public List GetPrefabList() + { + return prefabs.Values.ToList(); + } + public ParticlePrefab FindPrefab(string prefabName) { ParticlePrefab prefab; diff --git a/Barotrauma/BarotraumaClient/Source/Particles/ParticlePrefab.cs b/Barotrauma/BarotraumaClient/Source/Particles/ParticlePrefab.cs index afdbdd341..6d9cf98aa 100644 --- a/Barotrauma/BarotraumaClient/Source/Particles/ParticlePrefab.cs +++ b/Barotrauma/BarotraumaClient/Source/Particles/ParticlePrefab.cs @@ -5,20 +5,27 @@ using System.Xml.Linq; namespace Barotrauma.Particles { - class ParticlePrefab + class ParticlePrefab : ISerializableEntity { public enum DrawTargetType { Air = 1, Water = 2, Both = 3 } - public readonly string Name; - public readonly List Sprites; + public string Name + { + get; + private set; + } + + [Editable(0.0f, float.MaxValue, ToolTip = "How many seconds the particle remains alive."), Serialize(5.0f, false)] + public float LifeTime { get; private set; } + //movement ----------------------------------------- private float angularVelocityMin; public float AngularVelocityMinRad { get; private set; } - [Serialize(0.0f, false)] + [Editable, Serialize(0.0f, false)] public float AngularVelocityMin { get { return angularVelocityMin; } @@ -32,7 +39,7 @@ namespace Barotrauma.Particles private float angularVelocityMax; public float AngularVelocityMaxRad { get; private set; } - [Serialize(0.0f, false)] + [Editable, Serialize(0.0f, false)] public float AngularVelocityMax { get { return angularVelocityMax; } @@ -46,7 +53,7 @@ namespace Barotrauma.Particles private float startRotationMin; public float StartRotationMinRad { get; private set; } - [Serialize(0.0f, false)] + [Editable(ToolTip = "The minimum initial rotation of the particle (in degrees)."), Serialize(0.0f, false)] public float StartRotationMin { get { return startRotationMin; } @@ -60,7 +67,7 @@ namespace Barotrauma.Particles private float startRotationMax; public float StartRotationMaxRad { get; private set; } - [Serialize(0.0f, false)] + [Editable(ToolTip = "The maximum initial rotation of the particle (in degrees)."), Serialize(0.0f, false)] public float StartRotationMax { get { return startRotationMax; } @@ -71,19 +78,19 @@ namespace Barotrauma.Particles } } - [Serialize(false, false)] + [Editable(ToolTip = "Should the particle face the direction it's moving towards."), Serialize(false, false)] public bool RotateToDirection { get; private set; } - [Serialize(0.0f, false)] + [Editable(ToolTip = "Drag applied to the particle when it's moving through air."), Serialize(0.0f, false)] public float Drag { get; private set; } - [Serialize(0.0f, false)] + [Editable(ToolTip = "Drag applied to the particle when it's moving through water."), Serialize(0.0f, false)] public float WaterDrag { get; private set; } private Vector2 velocityChange; public Vector2 VelocityChangeDisplay { get; private set; } - [Serialize("0.0,0.0", false)] + [Editable(ToolTip = "How much the velocity of the particle changes per second."), Serialize("0.0,0.0", false)] public Vector2 VelocityChange { get { return velocityChange; } @@ -94,67 +101,74 @@ namespace Barotrauma.Particles } } - [Serialize(0.0f, false)] + [Editable(0.0f, 10000.0f, ToolTip = "Drag applied to the particle when it's moving through water."), Serialize(0.0f, false)] public float CollisionRadius { get; private set; } - [Serialize(false, false)] - public bool DeleteOnCollision { get; private set; } - - [Serialize(false, false)] + [Editable(ToolTip = "Does the particle collide with the walls of the submarine and the level."), Serialize(false, false)] public bool CollidesWithWalls { get; private set; } - [Serialize(0.5f, false)] + [Editable(ToolTip = "Does the particle disappear when it collides with something."), Serialize(false, false)] + public bool DeleteOnCollision { get; private set; } + + [Editable(0.0f, 1.0f, ToolTip = "The friction coefficient of the particle, i.e. how much it slows down when it's sliding against a surface."), Serialize(0.5f, false)] public float Friction { get; private set; } + [Editable(0.0f, 1.0f, ToolTip = "How much of the particle's velocity is conserved when it collides with something, i.e. the \"bounciness\" of the particle. (1.0 = the particle stops completely).")] [Serialize(0.5f, false)] public float Restitution { get; private set; } //size ----------------------------------------- - [Serialize("1.0,1.0", false)] + [Editable(ToolTip = "The minimum initial size of the particle."), Serialize("1.0,1.0", false)] public Vector2 StartSizeMin { get; private set; } - [Serialize("1.0,1.0", false)] + [Editable(ToolTip = "The maximum initial size of the particle."), Serialize("1.0,1.0", false)] public Vector2 StartSizeMax { get; private set; } + [Editable(ToolTip = "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")] [Serialize("0.0,0.0", false)] public Vector2 SizeChangeMin { get; private set; } + [Editable(ToolTip = "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")] [Serialize("0.0,0.0", false)] public Vector2 SizeChangeMax { get; private set; } + [Editable(ToolTip = "How many seconds it takes for the particle to grow to it's initial size.")] [Serialize(0.0f, false)] public float GrowTime { get; private set; } //rendering ----------------------------------------- - [Serialize("1.0,1.0,1.0,1.0", false)] + [Editable(ToolTip = "The initial color of the particle"), Serialize("1.0,1.0,1.0,1.0", false)] public Color StartColor { get; private set; } - [Serialize(1.0f, false)] + [Editable(ToolTip = "The initial alpha value of the particle"), Serialize(1.0f, false)] public float StartAlpha { get; private set; } - [Serialize("0.0,0.0,0.0,0.0", false)] + [Editable(ToolTip = "How much the color of the particle changes per second."), Serialize("0.0,0.0,0.0,0.0", false)] public Vector4 ColorChange { get; private set; } - [Serialize(DrawTargetType.Air, false)] + [Editable(ToolTip = "Should the particle be rendered in air, water or both."), Serialize(DrawTargetType.Air, false)] public DrawTargetType DrawTarget { get; private set; } - [Serialize(ParticleBlendState.AlphaBlend, false)] + [Editable(ToolTip = "The type of blending to use when rendering the particle."), Serialize(ParticleBlendState.AlphaBlend, false)] public ParticleBlendState BlendState { get; private set; } //animation ----------------------------------------- - [Serialize(1.0f, false)] + [Editable(0.0f, float.MaxValue, ToolTip = "The duration of the particle's animation cycle (if it's animated)."), Serialize(1.0f, false)] public float AnimDuration { get; private set; } - [Serialize(true, false)] + [Editable(ToolTip = "Should the sprite animation be looped, or stay at the last frame when the animation finishes."), Serialize(true, false)] public bool LoopAnim { get; private set; } - //misc ----------------------------------------- + //---------------------------------------------------- - [Serialize(5.0f, false)] - public float LifeTime { get; private set; } + public Dictionary SerializableProperties + { + get; + private set; + } //---------------------------------------------------- @@ -164,7 +178,7 @@ namespace Barotrauma.Particles Sprites = new List(); - SerializableProperty.DeserializeProperties(this, element); + SerializableProperties = SerializableProperty.DeserializeProperties(this, element); foreach (XElement subElement in element.Elements()) { diff --git a/Barotrauma/BarotraumaClient/Source/Screens/ParticleEditorScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/ParticleEditorScreen.cs new file mode 100644 index 000000000..b41c74f11 --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/Screens/ParticleEditorScreen.cs @@ -0,0 +1,129 @@ +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework; +using Barotrauma.Particles; + +namespace Barotrauma +{ + class ParticleEditorScreen : Screen + { + private GUIComponent rightPanel, leftPanel; + + private GUIListBox prefabList; + + private ParticlePrefab selectedPrefab; + + private SerializableEntityEditor particlePrefabEditor; + + private Camera cam; + + public override Camera Cam + { + get + { + return cam; + } + } + + public ParticleEditorScreen() + { + cam = new Camera(); + + leftPanel = new GUIFrame(new Rectangle(0, 0, 150, GameMain.GraphicsHeight), "GUIFrameLeft"); + leftPanel.Padding = new Vector4(10.0f, 20.0f, 10.0f, 20.0f); + + rightPanel = new GUIFrame(new Rectangle(0, 0, 450, GameMain.GraphicsHeight), null, Alignment.Right, "GUIFrameRight"); + rightPanel.Padding = new Vector4(10.0f, 20.0f, 0.0f, 20.0f); + + var listBox = new GUIListBox(new Rectangle(0,0,0,0), "", rightPanel); + + prefabList = new GUIListBox(new Rectangle(0, 50, 0, 0), "", leftPanel); + prefabList.OnSelected += (GUIComponent component, object obj) => + { + selectedPrefab = obj as ParticlePrefab; + listBox.ClearChildren(); + particlePrefabEditor = new SerializableEntityEditor(selectedPrefab, false, listBox, true); + return true; + }; + } + + public override void Select() + { + base.Select(); + RefreshPrefabList(); + } + + private void RefreshPrefabList() + { + prefabList.ClearChildren(); + + var particlePrefabs = GameMain.ParticleManager.GetPrefabList(); + foreach (ParticlePrefab particlePrefab in particlePrefabs) + { + var prefabText = new GUITextBlock(new Rectangle(0, 0, 0, 20), particlePrefab.Name, "", prefabList); + prefabText.UserData = particlePrefab; + } + } + + public override void AddToGUIUpdateList() + { + leftPanel.AddToGUIUpdateList(); + rightPanel.AddToGUIUpdateList(); + } + + public override void Update(double deltaTime) + { + cam.MoveCamera((float)deltaTime); + + leftPanel.Update((float)deltaTime); + rightPanel.Update((float)deltaTime); + + if (selectedPrefab != null) + { + GameMain.ParticleManager.CreateParticle(selectedPrefab, cam.WorldViewCenter, Vector2.UnitY * 100.0f); + } + + GameMain.ParticleManager.Update((float)deltaTime); + } + + public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch) + { + cam.UpdateTransform(); + GameMain.ParticleManager.UpdateTransforms(); + + //------------------------------------------------------- + + spriteBatch.Begin(SpriteSortMode.BackToFront, + BlendState.AlphaBlend, + null, null, null, null, + cam.Transform); + + graphics.Clear(new Color(0.051f, 0.149f, 0.271f, 1.0f)); + + GameMain.ParticleManager.Draw(spriteBatch, false, false, ParticleBlendState.AlphaBlend); + GameMain.ParticleManager.Draw(spriteBatch, true, false, ParticleBlendState.AlphaBlend); + + spriteBatch.End(); + + spriteBatch.Begin(SpriteSortMode.BackToFront, + BlendState.Additive, + null, null, null, null, + cam.Transform); + + GameMain.ParticleManager.Draw(spriteBatch, false, false, ParticleBlendState.Additive); + GameMain.ParticleManager.Draw(spriteBatch, true, false, ParticleBlendState.Additive); + + spriteBatch.End(); + + //------------------------------------------------------- + + spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, GameMain.ScissorTestEnable); + + leftPanel.Draw(spriteBatch); + rightPanel.Draw(spriteBatch); + + GUI.Draw((float)deltaTime, spriteBatch, cam); + + spriteBatch.End(); + } + } +} diff --git a/Barotrauma/BarotraumaClient/Source/Serialization/SerializableEntityEditor.cs b/Barotrauma/BarotraumaClient/Source/Serialization/SerializableEntityEditor.cs index a2d08c22b..180b77228 100644 --- a/Barotrauma/BarotraumaClient/Source/Serialization/SerializableEntityEditor.cs +++ b/Barotrauma/BarotraumaClient/Source/Serialization/SerializableEntityEditor.cs @@ -95,6 +95,11 @@ namespace Barotrauma { SetDimensions(new Point(Rect.Width, 0), false); } + + if (parent is GUIListBox) + { + ((GUIListBox)parent).UpdateScrollBarSize(); + } } public void AddCustomContent(GUIComponent component, int childIndex)