/// <summary> /// Load animation from config asset, based on animation identifier. /// </summary> /// <param name="identifier">Animation identifier.</param> /// <param name="config">Config asset to load from.</param> /// <remarks>Config must contain a section called 'anim_xxx', where xxx is this animation's unique identifier. /// Under this section, we should have the following keys: /// - repeats = true / false - does this animation loops, or remain stuck on last step after done? /// - steps_count = how many steps we have in this animation. /// - setp_x_duration[x is step index] = duration, in seconds, of this animation step. /// - setp_x_source[x is step index] = index in spritesheet file, format is: "x,y". /// For more info, check out demo_spritesheet.ini in test assets folder.</remarks> public SpriteAnimation(string identifier, ConfigAsset config) { // set identifier Identifier = identifier; // get general stuff string section = "anim_" + identifier; Repeats = config.GetBool(section, "repeats"); int steps = config.GetInt(section, "steps_count", -1); // sanity if (steps < 0) { throw new Exception($"Missing animation {identifier} section in config file, or missing 'steps_count' key!"); } // load all steps for (int i = 0; i < steps; ++i) { string prefix = "step_" + i.ToString(); float duration = config.GetFloat(section, prefix + "_duration"); PointI index = PointI.FromString(config.GetStr(section, prefix + "_source")); AddStep(new SpriteAnimationStep() { Duration = duration, Index = index }); } }
/// <summary> /// Convert direction in degrees to Point. /// </summary> public static PointI FromAngle(int directionDegrees) { var dirRads = directionDegrees * (Math.PI / 180); var ret = new PointI((int)System.Math.Cos(dirRads), (int)System.Math.Sin(dirRads)); ret.Normalize(); return(ret); }
/// <summary> /// Set a sprite's source rectangle from index in spritesheet. /// </summary> /// <param name="sprite">Sprite to set.</param> /// <param name="indexInSheet">Index in spritesheet.</param> /// <param name="sizeFactor">Set the size of the sprite to be the spritesheet's single sprite size, multiplied by this value. If set to 0, will not change sprite size.</param> public void SetSprite(Sprite sprite, PointI indexInSheet, float sizeFactor = 1.0f) { // set source rect sprite.SourceRect.Width = (int)(sprite.Image.Width * (1f / (float)SpritesCount.X)); sprite.SourceRect.Height = (int)(sprite.Image.Height * (1f / (float)SpritesCount.Y)); sprite.SourceRect.X = indexInSheet.X * sprite.SourceRect.Width; sprite.SourceRect.Y = indexInSheet.Y * sprite.SourceRect.Height; // set size if (sizeFactor != 0f) { sprite.Size.X = (int)(sprite.SourceRect.Width * sizeFactor); sprite.Size.Y = (int)(sprite.SourceRect.Height * sizeFactor); } }
/// <summary> /// Load animation from config asset, based on animation identifier. /// </summary> /// <param name="identifier">Animation identifier.</param> /// <param name="config">Config asset to load from.</param> /// <remarks>Config must contain a section called 'anim_xxx', where xxx is this animation's unique identifier. /// Under this section, we should have the following keys: /// - repeats = true / false - does this animation loops, or remain stuck on last step after done? /// - steps_count = how many steps we have in this animation. /// - setp_x_duration [x is step index] = duration, in seconds, of this animation step. /// - setp_x_source [x is step index] = index in spritesheet file, format is: "x,y". /// - step_x_tag [x is step index] = optional tag to attach to this step. /// For more info, check out demo_spritesheet.ini in test assets folder.</remarks> public SpriteAnimation(string identifier, ConfigAsset config) { // set identifier Identifier = identifier; // get general stuff string section = "anim_" + identifier; Repeats = config.GetBool(section, "repeats"); int steps = config.GetInt(section, "steps_count", -1); // sanity if (steps < 0) { throw new Exception($"Missing animation {identifier} section in config file, or missing 'steps_count' key!"); } // load all steps for (int i = 0; i < steps; ++i) { string prefix = "step_" + i.ToString(); // read duration float duration = config.GetFloat(section, prefix + "_duration", -100f); if (duration == -100f) { throw new FormatException($"Missing or invalid duration value for step {i} in animation '{identifier}'."); } // read source index PointI index = config.GetPointI(section, prefix + "_source", new PointI(-100, -100)); if (index.X == -100f) { throw new FormatException($"Missing or invalid source value for step {i} in animation '{identifier}'."); } // read optional tag and add step string tag = config.GetStr(section, prefix + "_tag", null); AddStep(new SpriteAnimationStep() { Duration = duration, Index = index, Tag = tag }); } }
/// <summary> /// Load spritesheet properties from config asset. /// Note: this will replace all existing settings. /// </summary> /// <param name="config">Config file to load from.</param> /// <remarks>Config must contain the following section: /// [general] /// - sprites_count = how many sprites there are in this spritesheet, format is: "x,y". /// - animations = list of comma-separated animations found in this spritesheet config. /// for every animation listed here, you need to also include a section with animation data. /// check out 'SpriteAnimation' constructor for more info. /// /// [bookmarks] /// - optional, contains a list of values where every key is a bookmark identifier and value is sprite index "x,y". /// later, you can use this to set sprites from spritesheet by names. for example: sheet.SetSprite(sprite, "item_sword"); /// /// For more info, check out demo_spritesheet.ini in test assets folder. /// </remarks> public void LoadFromConfig(ConfigAsset config) { // load general settings SpritesCount = PointI.FromString(config.GetStr("general", "sprites_count", "0,0")); // load bookmarks var bookmarks = config.Keys("bookmarks"); foreach (var book in bookmarks) { var value = PointI.FromString(config.GetStr("bookmarks", book, "0,0")); _bookmarks.Add(book, value); } // load animations var animations = config.GetStr("general", "animations", "").Split(','); foreach (var anim in animations) { var animationName = anim.Trim(); var spriteAnimation = new SpriteAnimation(animationName, config); _animations.Add(animationName, spriteAnimation); } }
/// <summary> /// Lerp between two points. /// </summary> /// <param name="a">From point.</param> /// <param name="b">To point.</param> /// <param name="delta">Lerp factor.</param> /// <returns>Lerped point.</returns> public static PointI Lerp(PointI a, PointI b, float delta) { return(new PointI((int)((a.X * (1f - delta) + b.X * delta)), (int)((a.Y * (1f - delta) + b.Y * delta)))); }
/// <summary> /// Get distance to another point. /// </summary> public float DistanceTo(PointI other) { return((float)Math.Sqrt(Math.Pow(X - other.X, 2) + Math.Pow(Y - other.Y, 2))); }
/// <summary> /// Substract point with a point. /// </summary> public PointI SubstractSelf(PointI other) { X -= other.X; Y -= other.Y; return(this); }
/// <summary> /// Add point with a point. /// </summary> public PointI AddSelf(PointI other) { X += other.X; Y += other.Y; return(this); }
/// <summary> /// Divide point with a point. /// </summary> public PointI DivideSelf(PointI other) { X /= other.X; Y /= other.Y; return(this); }
/// <summary> /// Substract point with a point. /// </summary> public PointI Substract(PointI other) { return(new PointI(X - other.X, Y - other.Y)); }
/// <summary> /// Add point with a point. /// </summary> public PointI Add(PointI other) { return(new PointI(X + other.X, Y + other.Y)); }
/// <summary> /// Check if contains a point. /// </summary> /// <param name="point">Point to check.</param> /// <returns>If point is within the rectangle.</returns> public bool Contains(PointI point) { return(point.X >= X && point.X <= X + Width && point.Y >= Y && point.Y <= Y + Height); }
/// <summary> /// Set a new bookmark in spritesheet. /// Can override existing keys. /// </summary> /// <param name="bookmarkId">Bookmark id to set.</param> /// <param name="spriteIndex">Bookmark index in spritesheet.</param> public void AddBookmark(string bookmarkId, PointI spriteIndex) { _bookmarks[bookmarkId] = spriteIndex; }
/// <summary> /// Multiply point with a point. /// </summary> public PointI Multiply(PointI other) { return(new PointI(X * other.X, Y * other.Y)); }
/// <summary> /// Divide point with a point. /// </summary> public PointI Divide(PointI other) { return(new PointI(X / other.X, Y / other.Y)); }
/// <summary> /// Multiply point with a point. /// </summary> public PointI MultiplySelf(PointI other) { X *= other.X; Y *= other.Y; return(this); }