Skip to content

Releases: Alessio-Marchese/Am.Engine

v1.0.4

Choose a tag to compare

@Alessio-Marchese Alessio-Marchese released this 02 Dec 11:39

In this Release the following things were added:

Animation System

Let’s briefly talks about the new Models.

  • Animation, it’s a new component. It contains a dictionary of Clips (see later), the key of the Current clip, an integer FrameIndex (to keep track of the current frame of the current clip) and float Time (to keep track of the time, usefull to switch frames over time)
  • Clip, it’s a generic abstract model it contains a list of Frames (see later) and an Integer Priority (Used to understand which animation can cancel another animation, based on priority)
  • AnimationFrame, it’s a generic model, it contain a TextureHandle (the key used to obtain the texture of a specific frame) and float Duration, used inside the system to understand for how long this frame should stay.
  • LoopClip and OneShotClip, those classes extends Clip, the first one simply extend and doesn’t change anything, the second one include a new variable (string FollowUpClip, the key of the next clip that we want to play after this one is done) The idea is to implement Clips that goes on in a loop, always the same Clip.. and Clips that run once and then the animation goes back to it’s normal state, for example Run → Loop, Attack → OneShot → then i set that after attack the next Clip must be Idle.
  • Direction (Component) and FacingDirection (Enum) i created this to add the Direction behaviour to a GameObject, this behaviour is usefull for animations, if i keep track of the last direction of a specific GameObject i can Play the correct Animation based on his last Direction..
    For example after i run to the right, i expect that the next animation Idle is going to be on the right, not on the left.

Now let’s talk about the System, it gets all the game objects in a world that contains Animation and Sprite, and if the elapsed Time of the current animation is higher than the Duration of the Frames[FrameIndex], a.k.a the current frame, it means that i can swap frame and go to the next one..
Resets the time to 0, increase the FramIndex by one, and then check, if it’s the last frame, the Clip is done, then if it’s a OneShotClip i set the Animation to play the FollowUpClip, otherwise i set the FrameIndex to 0 = start again the current animation.

Here’s an example of how i implemented the system inside the Sandbox.
Inside Sandbox i extended the behaviour of the Event system by adding new Events and new Subscribers, i thought that the responsibility of which animation exists and how it’s called it’s more related to the game than to the Engine itself.
So i added, PlayerRunEvent, PlayerIdleEvent and PlayerAttackEvent. Then i added the Subscribers that subscribe for those events and Extracts the components: Animation and Direction, then based on the direction the correct animation is played on the Animation component.

Those events are published in Game1.cs, basically, inside the Update method i do these checks to understand if i need to publish any of these events:

if (k.IsKeyDown(Keys.Space))
{
    _world.Events.Publish(new PlayerAttackEvent(_player));
}
else
{
    if (movement.DirX == 1)
    {
        _world.Events.Publish(new PlayerRunEvent(_player, false));
    }
    if (movement.DirX == -1)
    {
        _world.Events.Publish(new PlayerRunEvent(_player, true));
    }
    if (movement.DirX == 0)
    {
        _world.Events.Publish(new PlayerIdleEvent(_player));
    }
}

So that’s the flow:
The Input of the user can create one of these Events → Subscriber invoked, it updates the Animation component → the System adapt to this change and start animating the new animation.

Here’s an example of how i configured the GameObject:

_player = _world.AddGameObject()
	.AddComponent(new PlayerTag()) // A tag used to recognize the player
	.AddComponent(new Collider(100, 200)) // This game object can collide with any other collider object
	.AddComponent(new Transform { X = 0, Y = 0 }) // Can have a position in the world
	.AddComponent(new Movement { Speed = 300 }) // Can move
	.AddComponent(new Sprite(playerIdleRight0, 100, 200, zIndex: 1)) // Can be rendered on the world
	.AddComponent(new Direction()) // Can have a direction (this component is used to keep track of the last direction of the game object, usefull for Animation)
	.AddComponent(new Animation("idle_right") // Can have animations + Configuration of the followings + Configuration of the default
	    .AddClip("attack_right",
	    // Add a new Clip inside the Clips Dictionary of this Animation inside this GameObj
	    // The Clip is of type OneShot (it requires to specify the follow up clip key)
	    // Can add a priority, and then i can add N frames, specifying the handle
	    // Of each frame and the Duration
	        new OneShotClip("idle_right", 2)
	            .AddFrame(playerAttackRight0, 0.15f)
	            .AddFrame(playerAttackRight1, 0.1f)
	            .AddFrame(playerAttackRight2, 0.05f)
	            .AddFrame(playerAttackRight3, 0.15f)
	    )
	    .AddClip("attack_left",
	        new OneShotClip("idle_left", 2)
	            .AddFrame(playerAttackLeft0, 0.15f)
	            .AddFrame(playerAttackLeft1, 0.1f)
	            .AddFrame(playerAttackLeft2, 0.05f)
	            .AddFrame(playerAttackLeft3, 0.15f)
	    )
	    .AddClip("idle_right",
	        new LoopClip(1)
	            .AddFrame(playerIdleRight0, 0.05f)
	            .AddFrame(playerIdleRight1, 0.05f)
	            .AddFrame(playerIdleRight2, 0.05f)
	            .AddFrame(playerIdleRight3, 0.05f)
	            .AddFrame(playerIdleRight4, 0.05f)
	            .AddFrame(playerIdleRight5, 0.05f)
	            .AddFrame(playerIdleRight6, 0.05f)
	            .AddFrame(playerIdleRight7, 0.05f)
	    ));

Minor fix to the Camera Zoom:

The zoom wasn’t actually working properly, now it should be fine! i accidentally removed the Rendering of the Textures based on texture.Scale * camera.Zoom.

Clip of the Animation System:

Credits for the Animation: https://pixelfrog-assets.itch.io/

Sandbox4.mp4

v1.0.3

Choose a tag to compare

@Alessio-Marchese Alessio-Marchese released this 29 Nov 14:18

Release Summary 🛠️ the following things were added:

Event Driven Architecture:

I implement this architecture with the following pieces:

  • IEvent → a container that is used to incapsulate an event

  • IEventSubscriber → define the behaviour of a class that subscribe an event inside a world, it provides a Register method that takes a World as input, the class that extend this Interface should Subscribe a function connected to a specific event, for example

            public void Register(World world)
            {
               //When event Collision inside this world is published invoke OnEvent
                world.Events.Subscribe<CollisionEvent>(OnEvent);
            }
  • IEventBus → define the behavious of the EventBus, i created the interface for the sake of testing.. the EventBus is responsible for managing Subscribers and Events, it provides method to add Subscribers and publish Events (Enqueue events) and then a method that Dispatch the enqueued events and invoke the Subscribers that listen for every enqueued Event.

    A World contain an EventBus, so all the subscribers and events are linked to that specific world. The world is responsible to invoke the Dispatch method of EventBus in order to dequeue events and invoke the subscriber that listen for the enqueued event.

Collision System:

The pieces that i created for this feature are the followings:

  • Collider → a component that marks an object as collider, just like the sprite it contains Width, Height and Scale. It doesn’t necessary get those value from the Sprite itself because we might want a colliding box different than the Sprite actual size.
  • CollisionEvent → Extend IEvent, it contains GameObject A(mover), GameObject B, the two entities that are colliding
  • CollisionSystem → Get all the gameobject with Transform and Collider (we also get Transform because an object can’t collide if it doesn’t have a position in the world) then compare all the components bewteen them to understand if they’re touching, if they does it publish an event of CollisionEvent with inside the two objects that are colliding.
  • PhysicsCollisionSubscriber → Extend IEventSubscriber, when a collision event is published this subscriber catches it, calculate the direction of the mover object (A) that is colliding and blocks that direction.

Zoom camera fix:

While playing around in the project i noticed that the Zoom wasn’t working properly, so i adjusted the formula that calculate the camera position based on Zoom

General refactoring as usual:

General code and architectural cleaning, such as renaming, moving the centric Pivot logic of the rendering from MonoGameAdapter to Engine and more like those.

Video

Assets credit: https://kenney.nl/

I had to change assets because the old player asset did contain invisible spaces, this was creating problem on collision demonstration, since i wanted the collision of the player and static object to end right where the sprite ends

Sandbox3.mp4

v1.0.2

Choose a tag to compare

@Alessio-Marchese Alessio-Marchese released this 27 Nov 11:06

🔧 New Release Update

In this new Release the following things were added to the Engine:

PlayerTag component

A component that it's used to mark one GameObject as Player, it's used by the camera to adjust it's position.


CameraFollowSystem and Camera entity

Camera entity contains the X, Y pos + offset + follow speed, the system update this position based on PlayerTag position + an eventual offsett from it. It's possible to play around with the camera speed, in order to decide how fast the camera should follow the player during the delta time.. if i't high it's going to be istant.


Updated RenderingHandler

i have done 2 updated in this handler:

  1. in order to see the effect of the Camera i updated this system, so now, every sprite draw itself based on the position of the camera, this gives the illusion that the camera is moving around the sprites while instead the sprites are creating themself around based on the camera position.
  2. Sprite rendering layers.. i added inside Sprite a variable to keep track of the layer.. now the rendering is going to render all the sprites based on a Z order, so we can decide which spirte goes on top of others.. in the example i place Background with zIndex = 0 and Player with zIndex = 1.

New tests

i added new Tests for the Rendering update and also for the new Camera system.


Refactor

i refactorized some code, various improvements and cleaning, one of the most important is Tests readability, i added many comments for every test in order to make those easier to read.

Sandbox video for POC:

Sandbox2.mp4

Asset Credits
Pixel PNGs by Vecteezy

v1.0.1

Choose a tag to compare

@Alessio-Marchese Alessio-Marchese released this 26 Nov 21:35
ec450a6

Release Summary 🛠️

Even if this is the v1.0.1 it's considered the first actual version, since the v1.0.0 was just a test to try the CD Workflow.

In this Release i added the following things:

  • Abstract Rendering managment, an abstract solution to Load -> Registry -> Render the textures this pipeline is executed by the Game loop (right now it depends by the game implementation, for example right now it depends by the Sandbox project) that periodically invoke _renderSystem.Update(_world); which render everytime all the _world GameObjects that contains Transform and Sprite
  • MonoGame Rendering adapters, the implementations of the Abstract rendering, implemented with MonoGame framework.
  • Sandbox project, a simple game to test the engine also visually, by actually playing a game that runs on the ECS that i built
  • Various arious refactors to the code.
Sandbox.mp4

Asset Credits
Pixel PNGs by Vecteezy

v1.0.0

Choose a tag to compare

@Alessio-Marchese Alessio-Marchese released this 26 Nov 14:12
d473075
v.1.0.0

Add CD workflow for .NET release process