Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regarding the creation of bounding boxes, and collision boxes. #111

Open
CharlesLindberghMcGill opened this issue Dec 31, 2019 · 4 comments

Comments

@CharlesLindberghMcGill
Copy link

CharlesLindberghMcGill commented Dec 31, 2019

The following question feels insufficiently answered as well as insufficiently documented: #80

What do we pass to the width and height as arguments provided we're talking about collision boxes?

I don't know how to get the width and height information for the object box. In Spriter Pro itself it also only provides a scale. What is the size the boxes are scaled from? Maybe I am not well informed enough about how Spriter Pro works and that's why I am so confused.

image

I do know how to get this information for textures. That is simply the actual size of the image.

The following code is how I managed to get the information from the sprites that are being drawn - as you can see I can just multiply the scale of the animation to the size of the textures - however, I don't know where to find the 'size' of the box.

 foreach (var info in Animator.DrawInfos)
            {
                var scale = info.Scale;
                var pos = new Vector2(info.Position.X, info.Position.Y);
                var size = new Vector2(info.Drawable.Width, info.Drawable.Height) * scale;
              
                var center = Vector2.Zero;// size * 0.5f;

                HitBoxes[info] = new[]
                {
                    (pos - center).RotateAround(pos, info.Rotation),
                    (pos + new Vector2(size.X, 0) - center).RotateAround(pos, info.Rotation),
                    (pos + new Vector2(size.X, size.Y) - center).RotateAround(pos, info.Rotation),
                    (pos + new Vector2(0, size.Y) - center).RotateAround(pos, info.Rotation)
                };
            }
@CharlesLindberghMcGill
Copy link
Author

CharlesLindberghMcGill commented Jan 2, 2020

Okay so I've just looked through the .scml information and it does provide an actual width and height there. How could we access this information from this library? I would then only need to apply the animator.scale to it and use the GetBoundingBox function.

<obj_info name="bathitbox" type="box" w="145.833" h="483.333" pivot_x="0" pivot_y="0"/>

image

If I could get this information the "w" and "h" as well as the "name" I could do all of this using the provided GetBoundingBox function, as opposed to the one I made myself.

Something like Survivor.Animator.FrameData.BoxData.Get("bathitbox"); would be absolutely amazing to have.

@CharlesLindberghMcGill
Copy link
Author

CharlesLindberghMcGill commented Jan 3, 2020

I'm back. I've done a little bit of digging and I've managed to retrieve the object information that I was wondering about above. The only issue is that in this information the 'id' is set to 0. So I am not sure how to (cross reference, is that the word?) the object data retrieved by name, with the information within the frame data.

            var objectData = Animator.Entity.ObjectInfos.First(d => d.Name.Equals("bathitbox"));
        
            // objectData.Id is 0 here, so the following line does not work.
            var objectFrameData = Animator.FrameData.BoxData[objectData.Id];
            var objectScaled = new Vector2(objectData.Width, objectData.Height) * Animator.Scale;
            var box = Animator.GetBoundingBox(objectFrameData, objectScaled.X, objectScaled.Y);

            var path = new[]
            {
                box.Point1,
                box.Point2,
                box.Point3,
                box.Point4
            };

         engineBatch.DrawShape(path, Color.Red);

@CharlesLindberghMcGill
Copy link
Author

CharlesLindberghMcGill commented Jan 6, 2020

Okay, so currently the hacky workaround is to add a name field to "SpriterObject"


    public class SpriterObject : SpriterSpatial
    {
        [XmlAttribute("animation")]
        public int AnimationId;

        [XmlAttribute("entity")]
        public int EntityId;

        [XmlAttribute("folder")]
        public int FolderId;

        [XmlAttribute("file")]
        public int FileId;

        [XmlAttribute("pivot_x")]
        public float PivotX;

        [XmlAttribute("pivot_y")]
        public float PivotY;

        [XmlAttribute("t")]
        public float T;

        **public string Name;**

        public SpriterObject()
        {
            PivotX = float.NaN;
            PivotY = float.NaN;
        }
    }

Then within the "AddSpatialData" function set the name.

           case SpriterObjectType.Box:
                    FrameData.BoxData[timeline.ObjectId] = info;
                    **FrameData.BoxData[timeline.ObjectId].Name = timeline.Name;**
                    break;

An example code would then be:

            if(Animator.FrameData.BoxData.Any(d => d.Value.Name.Equals("bathitbox")))
            {
                var boxData = Animator.Entity.ObjectInfos.FirstOrDefault(d => d.Name.Equals("bathitbox"));
                var frameData = Animator.FrameData.BoxData.FirstOrDefault(d => d.Value.Name.Equals("bathitbox"));

                var collision = Animator.GetBoundingBox(
                    frameData.Value,
                    boxData.Width,
                    boxData.Height
                );
                
                engineBatch.DrawShape(
                    new []{collision.Point1, collision.Point2, collision.Point3, collision.Point4}, Color.Red, 1f);
            }

I don't understand why there's no other way to cross reference the frame data with the object data. The ids are always set to zero for some reason.

@CharlesLindberghMcGill
Copy link
Author

CharlesLindberghMcGill commented Jan 11, 2020

Updated example code to map all boxes by their name.

FrameDataCalculator.cs

        protected virtual void AddSpatialData(SpriterObject info, SpriterTimeline timeline, Spriter spriter, float deltaTime)
        {
            info.TimelineName = timeline.Name;

Entity.cs

        public Dictionary<string, Box> ObjectBoxMap { get; } = new Dictionary<string, Box>();

        protected virtual void OnAnimationChanged(string animation)
        {
            ObjectInfoMap.Clear();
            ObjectBoxMap.Clear();

            foreach (var obj in Animator.CurrentAnimation.Entity.ObjectInfos)
                ObjectInfoMap[obj.Name] = obj;
        }
            var deltaTime = gameTime.ElapsedGameTime.Ticks / (float)TimeSpan.TicksPerMillisecond;
            Animator.Update(deltaTime);

            foreach (var info in Animator.FrameData.BoxData)
            {
                ObjectBoxMap[info.Value.TimelineName] = Animator.GetBoundingBox(
                    info.Value,
                    ObjectInfoMap[info.Value.TimelineName].Width,
                    ObjectInfoMap[info.Value.TimelineName].Height
                );
            }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant