Announcement

Collapse
No announcement yet.

Spine integration with WaveEngine

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spine integration with WaveEngine

    Hi,

    I am trying to build a 2D a game using Spine as an animation tool and WaveEngine as game engine.

    Struggling to integrate spine with waveengine, can someone please provide some details around the followings ?

    - Does wave engine expose the Bounding Box of spine animation objects ? (http://esotericsoftware.com/spine-bounding-boxes)

    - What are the best practices using timers in wave engine in regards to spine animation play?

    - If I use Rigid-body2D, can I still use collider intersects to detect collision detection? It seems not working.

    Thanks in advance
    Ankan

  • #2
    Hi Ankan0004020,

    - Does wave engine expose the Bounding Box of spine animation objects ? (http://esotericsoftware.com/spine-bounding-boxes)

    WaveEngine API exposes Skeleton spine API with all spine data. So you can get it from there. For example BoundingBox attachments you can do the following:

    Code:
     this.skeleton = new Entity("Spine")
                                .AddComponent(new Transform2D() { X = 350, Y = 460, XScale = 1, YScale = 1 })
                                .AddComponent(new SkeletalData("Content/" + file + ".atlas"))
                                .AddComponent(new SkeletalAnimation("Content/" + file + ".json"))
                                .AddComponent(new SkeletalRenderer() { ActualDebugMode = SkeletalRenderer.DebugMode.None });
    
                var sa = this.skeleton.FindComponent<SkeletalAnimation>();
                var slots = sa.Skeleton.Slots;
                foreach (Spine.Slot slot in slots)
                {
                    var attachment = slot.Attachment;
                    if (attachment is Spine.RegionAttachment)
                    {
    
                    }
                    else if (attachment is Spine.MeshAttachment)
                    {
    
                    }
                    else if (attachment is Spine.SkinnedMeshAttachment)
                    {
    
                    }
                    else if (attachment is Spine.BoundingBoxAttachment)
                    {
                        var boundingbox = attachment as Spine.BoundingBoxAttachment;
                        
                    }     
                 }
    Note. You need to add a Spine-csharp.dll reference library (included with WaveEngine installation)

    - What are the best practices using timers in wave engine in regards to spine animation play?

    if you want to know when a SpineAnimation to finished. You can use EndAnimation event:

    Code:
    sa.EndAnimation += (s, o) =>
    {
        // new action
    };
    Note: sa is SkeletalAnimation instance

    On the others hand if you want to create timers on wave engine, you can use:

    Code:
    WaveServices.TimerFactory.CreateTimer(TimeSpan.FromMilliseconds(milliseconds), () =>
    {
        // new action
    }, false);
    - If I use Rigid-body2D, can I still use collider intersects to detect collision detection? It seems not working.
    If you want to detect collision between 2 physics entities, you can use the rigidBody2D events:

    Code:
    var rb2d = yourEntity.FindComponent<RigidBody2D>();
                    rb2d.OnPhysic2DCollision += (s, o) => 
                    {
                        // collision detected
                    };
    Finally I recommend you take a look at our spine sample:
    https://github.com/WaveEngine/Sample...letalAnimation

    And you can also find all the source code integration and Spine WaveEngine in:
    https://github.com/WaveEngine/Extens...veEngine.Spine


    I hope that you find it useful

    Regards!
    Jorge Cantón

    Comment


    • #3
      Hi Jorge Cantón,

      Thanks a lot for so much useful details. It really helps.

      I will try the bounding box code and spine animation event. They seem to solve a lot of issues on my end.

      In regards to Collider.Interects method, the reason I want to use them for rigidbody is I am trying to implement the Steering behaviour for obstacle avoidance:
      (Something like this)
      http://gamedevelopment.tutsplus.com/...--gamedev-7777

      That requires to determine a virtual collision detection for the object which seems to be not possible with OnPhysic2DCollision.

      Let me know if you think there is a better way to solve this problem.

      Greatly appreciate all of your help so far.

      Cheers
      Ankan

      Comment


      • #4
        Hi Ankan,

        The Steering Behavior is very interesting . In your link you can see collision code but if you want use Collider2D collision with Wave Engine you can do:

        Code:
                    // Create zombie
                    Entity zombie = new Entity()
                                    .AddComponent(new Transform2D() { Position = new Vector2(zombiePosX, zombiePosY) })
                                    .AddComponent(new CircleCollider2D()) // Or RectangleCollider2D
                                    .AddComponent(new Sprite("zombie.png"))
                                    .AddComponent(new SpriteRenderer(DefaultLayers.Alpha));
                    EntityManager.Add(zombie);
        
                    // Create random obstacles
                    for (int i = 0; i < 4; i++)
                    {
                        Entity obstacle = new Entity() { Tag = "obstacle" }
                                            .AddComponent(new Transform2D()) //{ Position = Random })
                                            .AddComponent(new CircleCollider2D()) // Or RectangleCollider2D
                                            .AddComponent(new Sprite("obstacle.png"))
                                            .AddComponent(new SpriteRenderer(DefaultLayers.Alpha));
                        EntityManager.Add(obstacle);
                    }
        
                    // Check collision between zombie and obstacles
                    var zc2d = zombie.FindComponent<CircleCollider2D>();
                    var obstacles = EntityManager.FindAllByTag("obstracle").ToList();
                    foreach (Entity e in obstacles)
                    {
                        var oc2d = e.FindComponent<CircleCollider2D>(); // Or RectangleCollider2D
                        if (zc2d.Intersects(oc2d))
                        {
                            // Collision detected
                        }
                    }
        I hope that you find it useful and you show more about your game

        Regards!
        ​Jorge Cantón

        Comment


        • #5
          Hi ​Jorge,

          Thanks again for your reply. Sorry for my late response. I will definitely share more about the game once sort out all the tricky scenarios

          In regards to collision avoidance, I think the major issue is when I add rigidbody as a component to an entity, Collider2D does not work as expected. Is that a known issue?

          I need both rigidbody and collider2D works together. I know that OnPhysics2DCollision will help but need that collider2D for a virtual collision detection in advance.

          Hope that makes sense.

          Cheers
          Ankan

          Comment


          • #6
            Hi Ankan,
            What do you mean with "Collider2D does not work as expected" ?
            Could you add some code that reproduces the issue with the current behavior and tell us what did you expect to better help you?

            Thanks!

            Comment


            • #7
              Here are some sample code: (Sorry for massive details.)

              var player= new Entity("Player")
              .AddComponent(new Transform2D()
              {
              X = position.X, Y = position.Y,
              XScale = 1f, YScale = 1f,
              Origin = Vector2.One/4,
              Rectangle = new RectangleF(0, 0, Width * 0.85f, Height * 0.85f)
              })
              .AddComponent(new SkeletalData("Content/Animations/" + file + ".atlas"))
              .AddComponent(new SkeletalAnimation("Content/Animations/" + file + ".json"))
              .AddComponent(new SkeletalRenderer() { ActualDebugMode = SkeletalRenderer.DebugMode.None })
              .AddComponent(new RectangleCollider() { DebugLineColor = Color.Red })
              .AddComponent(new RigidBody2D() { PhysicBodyType = PhysicBodyType.Dynamic, IgnoreGravity = true,
              FixedRotation = true, Damping = ImpulseDamping});

              var playerRigidBody2D = gameScene.Player.Entity.FindComponent<RigidBody2D> ();
              playerRigidBody2D.OnPhysic2DCollision += playerRigidBody2D_OnPhysic2DCollision;
              var playerCollider = gameScene.Player.Entity.FindComponent<RectangleCol lider>(true);

              var enemy = new Entity(string.Format("Enemy{0}", name)) { Tag = "Enemy" }
              .AddComponent(new Transform2D()
              {
              X = position.X, Y = position.Y,
              XScale = 1f, YScale = 1f,
              Rectangle = new RectangleF(0, 0, Width * 0.85f, Height * 0.85f)
              })
              .AddComponent(new SkeletalData("Content/Animations/" + file + ".atlas"))
              .AddComponent(new SkeletalAnimation("Content/Animations/" + file + ".json"))
              .AddComponent(new SkeletalRenderer() { ActualDebugMode = SkeletalRenderer.DebugMode.None })
              .AddComponent(new RectangleCollider() { DebugLineColor = Color.Red })
              .AddComponent(new RigidBody2D() { PhysicBodyType = PhysicBodyType.Dynamic, IgnoreGravity = true,
              FixedRotation = true, Damping = 35})
              .AddComponent(new EnemyBehavior(this));

              var enemyCollider = gameScene.Enemy.Entity.FindComponent<RectangleColl ider>(true);


              void playerRigidBody2D_OnPhysic2DCollision(object sender, Physic2DCollisionEventArgs args)
              {
              // works great!
              }



              if (playerCollider.Intersects(enemyCollider ))
              {
              // this never works
              }



              Hope this helps.

              Comment


              • #8
                To add on top of that code, what I found playerCollider.Intersects(enemyCollider )) actually works when player moves against the enemy, but if the player stands still and the enemy chases and eventually collides with player, none of the playerRigidBody2D_OnPhysic2DCollision or playerCollider.Intersects(enemyCollider ) fires, rather player keeps moving even though user is not trying to move the player.
                Not sure if I been able to explain clearly, let me know if you need more details.

                Comment


                • #9
                  I have modified the sample
                  https://github.com/WaveEngine/Sample...sionCategories

                  With this Scene:
                  Code:
                  public class MyScene : Scene
                      {
                          // Consts
                          private const string CRATEA_TEXTURE = "Content/CrateA.wpk";
                          private const string CRATEB_TEXTURE = "Content/CrateB.wpk";
                          private const string CIRCLE_TEXTURE = "Content/CircleSprite.wpk";
                          private const string GROUND_TEXTURE = "Content/GroundSprite.wpk";
                  
                          // Box Instance count
                          private long instances = 0;
                          private Entity circle;
                          private Entity crate;
                          private CircleCollider circleCollider;
                          private RectangleCollider crateCollider;
                  
                          /// <summary>
                          /// Creates the scene.
                          /// </summary>
                          /// <remarks>
                          /// This method is called before all
                          /// <see cref="T:WaveEngine.Framework.Entity" /> instances in this instance are initialized.
                          /// </remarks>
                          protected override void CreateScene()
                          {
                              // Create a 2D camera
                              var camera2D = new FixedCamera2D("Camera2D")
                              {
                                  BackgroundColor = Color.CornflowerBlue
                              };
                              EntityManager.Add(camera2D);
                  
                              // Create Border limits with "Category.All" CollisionGroup (colliding bodies no matter the body collision category)
                              this.CreateClosures();
                  
                              this.circle = this.CreateCircle(200, 200, CIRCLE_TEXTURE, Physic2DCategory.Cat2);
                              EntityManager.Add(this.circle);
                  
                              this.crate = this.CreateCrate(200, 200, CRATEB_TEXTURE, Physic2DCategory.Cat2);
                              EntityManager.Add(this.crate);
                  
                              // Mouse drag controller
                              this.AddSceneBehavior(new MouseBehavior(), SceneBehavior.Order.PostUpdate);
                          }
                  
                          /// <summary>
                          /// Allows to perform custom code when this instance is started.
                          /// </summary>
                          /// <remarks>
                          /// This base method perfoms a layout pass.
                          /// </remarks>
                          protected override void Start()
                          {
                              base.Start();
                          }
                  
                          /// <summary>
                          /// Creates a Physic Crate
                          /// </summary>
                          /// <param name="x"></param>
                          /// <param name="y"></param>
                          /// <returns></returns>
                          private Entity CreateCrate(float x, float y, string texture, Physic2DCategory category)
                          {
                              Entity crate = new Entity("Crate" + this.instances++)
                                  .AddComponent(new Transform2D() { X = x, Y = y, Origin = Vector2.Center })
                                  .AddComponent(new RectangleCollider())
                                  .AddComponent(new Sprite(texture))
                                  .AddComponent(new JointMap2D())
                                  .AddComponent(new RigidBody2D() { PhysicBodyType = PhysicBodyType.Dynamic, CollisionCategories = category, CollidesWith = category })
                                  .AddComponent(new SpriteRenderer(DefaultLayers.Opaque));
                  
                              var rigidBody = crate.FindComponent<RigidBody2D>();
                              rigidBody.OnPhysic2DCollision += rigidBody_OnPhysic2DCollision;
                  
                              this.crateCollider = crate.FindComponent<RectangleCollider>();
                              return crate;
                          }
                  
                          void rigidBody_OnPhysic2DCollision(object sender, Physic2DCollisionEventArgs args)
                          {
                  
                              if (circleCollider.Intersects(this.crateCollider))
                              {
                  
                              }
                          }
                  
                          /// <summary>
                          /// Creates a Physic Circle
                          /// </summary>
                          /// <param name="x"></param>
                          /// <param name="y"></param>
                          /// <returns></returns>
                          private Entity CreateCircle(float x, float y, string texture, Physic2DCategory category)
                          {
                              Entity box = new Entity("Circle" + this.instances++)
                                  .AddComponent(new Transform2D() { X = x, Y = y, Origin = Vector2.Center })
                                  .AddComponent(new CircleCollider())
                                  .AddComponent(new Sprite(texture))
                                  .AddComponent(new JointMap2D())
                                  .AddComponent(new RigidBody2D() { PhysicBodyType = PhysicBodyType.Dynamic, CollisionCategories = category })
                                  .AddComponent(new SpriteRenderer(DefaultLayers.Alpha));
                  
                              this.circleCollider = box.FindComponent<CircleCollider>();
                  
                              return box;
                          }
                  
                          /// <summary>
                          /// Creates Physic Borders
                          /// </summary>
                          private void CreateClosures()
                          {
                              EntityManager.Add(this.CreateGround("top1", 150, -10, 0));
                              EntityManager.Add(this.CreateGround("top2", 650, -10, 0));
                  
                              EntityManager.Add(this.CreateGround("bottom1", 150, 610, 0));
                              EntityManager.Add(this.CreateGround("bottom2", 650, 610, 0));
                  
                              EntityManager.Add(this.CreateGround("left", 0, 300, MathHelper.ToRadians(90)));
                              EntityManager.Add(this.CreateGround("right", 800, 300, MathHelper.ToRadians(90)));
                          }
                  
                          /// <summary>
                          /// Creates a Physic Ground.
                          /// </summary>
                          /// <param name="name">Entity Name.</param>
                          /// <param name="x">X Position.</param>
                          /// <param name="y">Y Position.</param>
                          /// <param name="angle">Ground Angle.</param>
                          /// <returns>Ground Entity.</returns>
                          private Entity CreateGround(string name, float x, float y, float angle)
                          {
                              Entity sprite = new Entity(name)
                                  .AddComponent(new Transform2D() { X = x, Y = y, Origin = Vector2.Center, Rotation = angle })
                                  .AddComponent(new RectangleCollider())
                                  .AddComponent(new Sprite(GROUND_TEXTURE))
                                  .AddComponent(new RigidBody2D() { PhysicBodyType = PhysicBodyType.Kinematic, Friction = 1, CollisionCategories = Physic2DCategory.All })
                                  .AddComponent(new SpriteRenderer(DefaultLayers.Alpha));
                  
                              return sprite;
                          }
                      }

                  The event is raising and the intersects method is running ok.
                  Could you try it and tell us if it is working ok for you?


                  Thanks!!

                  Comment

                  Working...
                  X