/// <summary> /// Handles the behaviour we want from this UI - to move with the mouse when it is pressed over it, and stop when released. /// Then updates the value if needs be. /// </summary> /// <param name="elapsedGameTime"></param> /// <param name="mousePosition"></param> public override void HandleInput(float elapsedGameTime, Vector2 mousePosition) { base.HandleInput(elapsedGameTime, mousePosition); DebugUtils.AssertNotNull(SliderHandle.Collider); if (SliderHandle.Collider.IsSelected) { float sliderBarHalfWidth = Size.X * 0.5f; float newX = MathHelper.Clamp(mousePosition.X - WorldPosition.X, -sliderBarHalfWidth, sliderBarHalfWidth); SliderHandle.LocalPosition = new Vector2(newX, 0); // Calculate our new value float multiplier = (newX + sliderBarHalfWidth) / (2 * sliderBarHalfWidth); Debug.Assert(multiplier >= 0 && multiplier <= 1); CurrentValue = (1 - multiplier) * MinValue + multiplier * MaxValue; // Update our value label text ValueLabel.Text = CurrentValue.ToString(); // We do asserts rather than actual clamping, because if these asserts are false the slider is behaving incorrectly Debug.Assert(CurrentValue >= MinValue); Debug.Assert(CurrentValue <= MaxValue); if (OnValueChanged != null) { OnValueChanged(this); } } }
/// <summary> /// Checks the current active state's transitions against the new behaviour state. /// Performs no checking if the new state and current ActiveState have the same ID. /// </summary> /// <param name="newBehaviourState"></param> private void HandleBehaviourChange(uint newBehaviourState) { DebugUtils.AssertNotNull(ActiveState); // If we have not changed state then just return. if (newBehaviourState == ActiveState.StateID) { return; } // Check the transitions of the current active state if (ActiveState.CheckTransitions(newBehaviourState)) { SetNewActiveState(newBehaviourState); } // Check the global states foreach (State state in GlobalStates) { if (state != ActiveState && state.StateID == newBehaviourState) { SetNewActiveState(newBehaviourState); break; } } // Check that we have indeed transitioned to our new state Debug.Assert(newBehaviourState == ActiveState.StateID); // The new state we have moved to should not be playing already Debug.Assert(ActiveState.Animation.IsPlaying == false); ActiveState.Animation.IsPlaying = true; }
/// <summary> /// A wrapper for loading xml data directly using the Intermediate Deserialiser /// Should only be used as a last resort. /// </summary> /// <typeparam name="T">The type of data to load</typeparam> /// <param name="path">The path of the object e.g. Screens\\BattleScreen</param> /// <returns>The loaded content</returns> private static T LoadDataFromDisc <T>(string path, bool createIfDoesNotExist = false) where T : BaseData { ContentManager content = ScreenManager.Instance.Content; T data = null; if (!File.Exists(content.RootDirectory + "\\" + DataPath + path)) { if (createIfDoesNotExist) { // If the file does not exist but we have specified that we should create the data file, we call the constructor of the data file data = (T)Activator.CreateInstance(typeof(T)); } else { Debug.Fail("Data file does not exist"); } } else { data = XmlDataSerializer.Deserialize <T>(content.FullRootDirectory() + "\\" + DataPath + path); } DebugUtils.AssertNotNull(data); return(data); }
/// <summary> /// Extracts the inputted child from this container, but keeps it alive for insertion into another /// </summary> /// <param name="childToExtract">The child we wish to extract from this container</param> public K ExtractChild <K>(K childToExtract) where K : T { DebugUtils.AssertNotNull(childToExtract); ObjectsToRemove.Add(childToExtract); return(childToExtract); }
/// <summary> /// Checks the current ActiveState and returns true if it has finished playing. /// Can only be checked against non-continual animations. /// </summary> /// <returns></returns> public bool CurrentAnimationFinished() { DebugUtils.AssertNotNull(ActiveState); Debug.Assert(!ActiveState.Animation.Continual); return(ActiveState.Animation.Finished); }
/// <summary> /// A utility function which wraps the extraction of this from it's current owner and the insertion into the new one. /// Should only be called if it's parent is already set - otherwise use AddChild. /// The second parameter is a flag we can pass to prevent us from calling newParent.AddChild - this is in case we do not want to call custom implementation in an AddChild function. /// This does mean that if the object is not reinserted manually elsewhere, it will be left hanging around, but not being updated. /// </summary> /// <param name="newParent"></param> public void ReparentTo(BaseObject newParent, bool moveToNewParentsChildren = true) { // Extract ourselves from our parent DebugUtils.AssertNotNull(Parent); // We are reparenting to ourselves, so no need to go through this whole process of extraction and addition again if (Parent == newParent) { return; } Parent.ExtractChild(this); // Assume this has been loaded and initialised and insert it into the new parent's Children (if not null) if (newParent != null) { if (moveToNewParentsChildren) { newParent.AddChild(this); } else { // We do not want to call add child, but rather do a shallow parent set Parent = newParent; } } }
/// <summary> /// A function to remove a child /// </summary> /// <param name="childToRemove">The child we wish to remove</param> public void RemoveChild(BaseObject childToRemove) { DebugUtils.AssertNotNull(childToRemove); // This function will set IsAlive to false so that the object gets cleaned up next Update loop Children.RemoveChild(childToRemove); }
/// <summary> /// Extracts the inputted child from this container, but keeps it alive for insertion into another /// </summary> /// <param name="childToExtract">The child we wish to extract from this container</param> public T ExtractChild <T>(T childToExtract) where T : BaseObject { DebugUtils.AssertNotNull(childToExtract); childToExtract.Parent = null; return(Children.ExtractChild(childToExtract)); }
/// <summary> /// Sets up the size to preserve the texture aspect ratio /// </summary> public override void Initialise() { // Check to see whether we should Initialise CheckShouldInitialise(); // Texture cannot be null DebugUtils.AssertNotNull(Texture); // If we are preserving aspect ratio, recalculate the size if (PreservesAspectRatio) { float aspectRatio = Texture.Bounds.Height / (float)Texture.Bounds.Width; Debug.Assert(aspectRatio > 0); if (aspectRatio < 1) { Size = new Vector2(Size.X, Size.X * aspectRatio); } else { Size = new Vector2(Size.Y / aspectRatio, Size.Y); } } base.Initialise(); }
/// <summary> /// Set the base object to the max opacity /// </summary> public override void Begin() { base.Begin(); DebugUtils.AssertNotNull(AttachedBaseObject); AttachedBaseObject.Opacity = MaxOpacity; }
/// <summary> /// Sets up all the states and transitions. /// </summary> protected virtual void SetUpAnimations() { DebugUtils.AssertNotNull(Data); CharacterData data = Data.As <CharacterData>(); DebugUtils.AssertNotNull(data); // Checks that we have declared at most the same number of enum behaviours as we have animations. // If NumAnimations is larger than data.AnimationInfo.Count, it means we have not loaded enough animations for all our behaviours. Debug.Assert(data.AnimationInfo.Count >= NumBehaviours); StateMachine = new StateMachine(this, NumBehaviours); foreach (string animationDataAsset in data.AnimationInfo) { AnimationModule animation = new AnimationModule(); animation.LoadContent(); Debug.Assert(!Animations.ContainsKey(animationDataAsset)); Animations.Add(animationDataAsset, animation); } CreateState("Idle", (uint)CharacterBehaviours.kIdle); CreateState("Death", (uint)CharacterBehaviours.kDeath); StateMachine.StartingState = (uint)CharacterBehaviours.kIdle; }
/// <summary> /// Checks each object in the inputted ObjectManager to determine whether it should be drawn this frame. /// </summary> /// <param name="objectManager"></param> /// <param name="screenSpace"></param> public static void CheckVisibility <T>(ObjectManager <T> objectManager, bool screenSpace) where T : BaseObject { Rectangle rectangleToUse = screenSpace ? ViewportRectangleScreenSpace : ViewportRectangleGameSpace; Vector2 centre = rectangleToUse.Center.ToVector2(); foreach (BaseObject baseObject in objectManager) { // If our object's visibility is driven by another object we do not need to perform visibility checks if (baseObject.ShouldDraw) { continue; } if (baseObject.UsesCollider) { DebugUtils.AssertNotNull(baseObject.Collider); baseObject.ShouldDraw = baseObject.Collider.CheckIntersects(rectangleToUse); } else { // Crude circle check, can definitely be improved upon float x = rectangleToUse.Width + baseObject.Size.X; float y = rectangleToUse.Height + baseObject.Size.Y; baseObject.ShouldDraw = (centre - baseObject.WorldPosition).LengthSquared() <= x * x + y * y; } } }
/// <summary> /// Reads the element value of the xml element the inputted reader is currently on as the inputted type. /// This method may call itself recursively for a nested list for example. /// Finally, returns the successfully deserialized object. /// Moves the nodereader past the end tag so do not need to do ReadEndElement after calling this function. /// </summary> /// <param name="nodeReader"></param> /// <param name="typeOfElement"></param> /// <returns></returns> private static object ReadElementValue(XmlReader nodeReader, Type typeOfElement) { // Set the value to the default value of the type - for value types we create an instance, for reference types we use null object value = null; try { Activator.CreateInstance(typeOfElement); } catch { } if (nodeReader.NodeType == XmlNodeType.Text) { // Read the element's content and convert it to the type of the property we are setting value = nodeReader.ReadContentAs(typeOfElement, null); } else if (nodeReader.NodeType == XmlNodeType.Element) { int startingDepth = nodeReader.Depth; // Currently only nesting Elements inside other elements is supported // This will be called if we are deserializing a list or custom data type Debug.Assert(nodeReader.NodeType == XmlNodeType.Element); if (IsListType(typeOfElement)) { value = Activator.CreateInstance(typeOfElement); // Get the add method so we can add objects to the list at runtime MethodInfo addMethod = value.GetType().GetRuntimeMethods().First(x => x.Name == "Add"); DebugUtils.AssertNotNull(addMethod); // Keep reading whilst we still have nested elements while (nodeReader.Depth >= startingDepth) { Debug.Assert(typeOfElement.GenericTypeArguments.Length == 1); Type listGenericArgumentType = typeOfElement.GenericTypeArguments[0]; object nestedValue = nodeReader.ReadElementContentAs(listGenericArgumentType, null); addMethod.Invoke(value, new object[] { nestedValue }); } } else { // We are trying to read a class value = ReadType <object>(nodeReader, typeOfElement); } } else if (nodeReader.NodeType == XmlNodeType.EndElement) { // This can happen if we have something like an empty string e.g. <String></String> // Noop } // Finally read the end tag nodeReader.ReadEndElement(); return(value); }
/// <summary> /// Returns the most recent child we added which is castable to the inputted type and satisfies the inputted condition. /// Shouldn't really be called unless we have children /// </summary> /// <returns>The most recent child we added</returns> public K LastChild <K>(Predicate <K> condition) where K : T { K lastChildOfType = ActiveObjects.FindLast(x => x is K && condition(x as K)) as K; DebugUtils.AssertNotNull(lastChildOfType); return(lastChildOfType); }
/// <summary> /// Returns the most recent child we added which is castable to the inputted type. /// Shouldn't really be called unless we have children /// </summary> /// <returns>The most recent child we added</returns> public K LastChild <K>() where K : T { K lastChildOfType = ActiveObjects.FindLast(x => x is K) as K; DebugUtils.AssertNotNull(lastChildOfType); return(lastChildOfType); }
/// <summary> /// A function to remove and kill a child /// </summary> /// <param name="childToRemove">The child we wish to remove</param> public void RemoveChild(T childToRemove) { DebugUtils.AssertNotNull(childToRemove); Debug.Assert(Exists(x => x == childToRemove)); // This function will set IsAlive to false so that the object gets cleaned up next Update loop childToRemove.Die(); }
/// <summary> /// Utility function wrapping around ReadType<> where we find the type using the assembly and typeName /// </summary> /// <param name="nodeReader"></param> /// <param name="typeName"></param> private static T ReadType <T>(XmlReader nodeReader, Assembly assembly, string typeName) { Type typeToLoad = assembly.ExportedTypes.FirstOrDefault(x => x.Name == typeName); DebugUtils.AssertNotNull(typeToLoad, "Type " + typeName + " specified for data file could not be loaded"); return(ReadType <T>(nodeReader, typeToLoad)); }
public ClickableImage(Vector2 size, Anchor anchor, int depth, string textureAsset) : base(size, anchor, depth, textureAsset) { UsesCollider = true; ClickableModule = AddModule(new ClickableObjectModule()); DebugUtils.AssertNotNull(ClickableModule); }
/// <summary> /// A function for when our direction changes. Used for flipping sprites and for re-fixing animations. /// </summary> /// <param name="newDirection"></param> public void OnDirectionChange(int oldDirection, int newDirection) { DebugUtils.AssertNotNull(StateMachine); DebugUtils.AssertNotNull(PhysicsBody); SpriteEffect = newDirection == PhysicsConstants.LeftDirection ? SpriteEffects.FlipHorizontally : SpriteEffects.None; LocalPosition += new Vector2(2 * StateMachine.ActiveState.Animation.AnimationFixup.X * newDirection, 0); }
public ClickableImage(Vector2 size, Vector2 localPosition, string textureAsset) : base(size, localPosition, textureAsset) { UsesCollider = true; ClickableModule = AddModule(new ClickableObjectModule()); DebugUtils.AssertNotNull(ClickableModule); }
/// <summary> /// Loads the effect for the lighting. /// </summary> public override void LoadContent() { CheckShouldLoad(); LightEffect = AssetManager.GetEffect(defaultLightEffect); DebugUtils.AssertNotNull(LightEffect); base.LoadContent(); }
/// <summary> /// Loads the ToolTip object /// </summary> public override void LoadContent() { CheckShouldLoad(); DebugUtils.AssertNotNull(ToolTip); ToolTip.LoadContent(); base.LoadContent(); }
/// <summary> /// Syncs our button's value with our options is full screen option /// </summary> /// <param name="baseObject"></param> private void SyncOptionsIsFullScreen(BaseObject baseObject) { Debug.Assert(baseObject is Button); Button button = baseObject as Button; DebugUtils.AssertNotNull(button); OptionsManager.IsFullScreen = !OptionsManager.IsFullScreen; button.Label.Text = OptionsManager.IsFullScreen.ToString(); }
/// <summary> /// A function which will be used to add a child and sets it's parent to this /// </summary> /// <typeparam name="K">The type of the child</typeparam> /// <param name="childToAdd">The child itself</param> /// <param name="load">A flag to indicate whether we wish to call LoadContent on the child</param> /// <param name="initialise">A flag to indicate whether we wish to call Initialise on the child</param> /// <returns></returns> public virtual K AddChild <K>(K childToAdd, bool load = false, bool initialise = false) where K : BaseObject { DebugUtils.AssertNotNull(childToAdd); DebugUtils.AssertNull(childToAdd.Parent); // Set the parent to be this childToAdd.Parent = this; return(Children.AddChild(childToAdd, load, initialise)); }
/// <summary> /// Checks to see if this object is right clicked, and if so, kills the object. /// </summary> /// <param name="elapsedGameTime"></param> /// <param name="mousePosition"></param> public override void HandleInput(float elapsedGameTime, Vector2 mousePosition) { base.HandleInput(elapsedGameTime, mousePosition); DebugUtils.AssertNotNull(Collider); if (GameMouse.Instance.IsClicked(MouseButton.kRightButton) && Collider.CheckIntersects(GameMouse.Instance.InGameWorldPosition)) { Die(); } }
public Particle(Vector2 startSize, Vector2 localPosition, AnimationData animationData, float lifeTime) : base(localPosition, "") { UsesCollider = false; LerpAmount = 0; StartColour = Colour; StartSize = startSize; DebugUtils.AssertNotNull(animationData); AnimationData = animationData; }
/// <summary> /// Fixup UI positions /// </summary> public override void Begin() { base.Begin(); DebugUtils.AssertNotNull(FullScreenLabel); DebugUtils.AssertNotNull(FullScreenLabel.Parent); float padding = 5; FullScreenLabel.LocalPosition = new Vector2(-(FullScreenLabel.Parent.Size.X + FullScreenLabel.Size.X) * 0.5f - padding, 0); }
/// <summary> /// A callback for our loading thread to load all our game's assets. /// </summary> private void LoadAllAssetsCallback() { ContentManager content = ScreenManager.Instance.Content; DebugUtils.AssertNotNull(content); DebugUtils.AssertNotNull(LoadAssets); // LoadAssets should REALLY PROBABLY not be null, unless we decide to not load ANYTHING LoadAssets(content); ScreenAfterLoading.LoadContent(); ScreenAfterLoading.Initialise(); }
/// <summary> /// Check that the texture has been loaded by doing a get call /// </summary> public override void LoadContent() { // Check to see whether we should load CheckShouldLoad(); DebugUtils.AssertNotNull(Texture); Children.LoadContent(); Modules.LoadContent(); base.LoadContent(); }
/// <summary> /// Calculates the source rectangle from the sprite sheet we should use based on the dimensions and current frame. /// </summary> private void CalculateSourceRectangle() { int currentRow = CurrentFrame / Frames.X; int currentColumn = CurrentFrame % Frames.X; Debug.Assert(currentColumn < Frames.X); Debug.Assert(currentRow < Frames.Y); DebugUtils.AssertNotNull(AttachedBaseObject); AttachedBaseObject.SourceRectangle = new Rectangle(currentColumn * FrameDimensions.X, currentRow * FrameDimensions.Y, FrameDimensions.X, FrameDimensions.Y); }