Improved Sprite System For Games

In my ninth video for the “Building a Game Development Framework” series, I focus on establishing a professional-grade Sprite System. I enhance the framework, moving from loose animation and movement logic into a structured architecture by introducing two primary classes: Decor and Actor.

To better manage a game world, the framework now separates objects based on their behavior:

  • Decor: Represents static elements that do not move or have complex logic, such as a rock or a building. These are lightweight and optimized for objects that just need to be drawn.
  • Actor: Represents dynamic, “living” entities that can move, animate, and react to logic (e.g., players, enemies, or NPCs).

The “Sprite” in this framework acts as the parent container. It ties together the separate components built in previous videos into a single, cohesive unit:

  • Movement: Handles the math of where the object is going (Keyboard, Mouse, or AI).
  • Motion: Manages which animation set to use based on the heading (4-way, 8-way, etc.).
  • Animation: Handles the actual frame-by-frame rendering.

In this video, I demonstrate how to build the Actor class to automate the character’s update loop.

  • Automated Updates: Instead of manually calling movement.update() and motion.update() in your screen’s render method, you now simply call actor.update(). The Actor class internally handles data (delta time) delegation between its movement and motion components.
  • Flexibility: Because the Actor uses the Movement and Motion interfaces, you can swap a player’s controls from “Keyboard” to “Mouse” just by changing one line of code during initialization, without changing how the character is drawn or updated.

I then integrate this with the LibGdx library by updating the Screen class logic, making the game screen significantly less cluttered. Instead of managing individual floats for X and Y or multiple animation timers, the screen simply holds a list of Sprite objects and iterates through them to call update() and draw().

By separating Decor from Actors, you optimize performance (static objects don’t need movement logic) and create a system where complex game entities are built like “Legos.” This modularity makes it easy to add features like pathfinding or new animation types later in development without breaking existing characters.

Note: Since this is part of a series, this video serves as the “bridge” that turns the experimental code from earlier videos into a structured framework ready for actual game projects.

Movement using a mouse

In my eighth installment of the “Building a Game Development Framework” series, I expand on the movement system to include mouse-based interaction and introduce visual translucency for sprites.

I have created a new Movement class that allows characters to move toward a target destination clicked by the user.

  • Goal-Oriented Logic: The class tracks a goalX and goalY. When the user clicks, the system calculates the direction from the Sprite’s current position to the click point and moves the character at a set speed.
  • Overshoot Prevention: To prevent the Sprite from going past the target, the code includes logic to check whether the next move would exceed the goal. If so, it simply sets the character’s position to the exact goal coordinates.
  • Continuous Tracking: If the mouse button is held down, the character will continuously follow the cursor.

To make the movement classes more flexible, the framework now uses a SpriteUpdate interface. This acts as a bridge (using a visitor pattern) that allows the movement logic to “get” and “set” the X and Y coordinates of any object, whether it’s a player character or an NPC, without the movement class needing to know the specific details of that object.

A significant challenge in 2D games is clicking on the screen when the camera has moved or is moving.

  • The Problem: Standard input gives “screen coordinates,” but if your camera has scrolled to the right (or any direction from center), a click at screen position (100, 100) is actually a different coordinate on the game’s screen (game world).
  • The Solution: The ScreenInput class is updated to take the camera’s position into account when returning the location of the mouse click on the world map. It offsets the raw mouse input by the camera’s current X and Y coordinates, ensuring that clicking on a world object always works regardless of where the viewport is positioned.

Additionally, I added a “translucency” property (often called Alpha, or sometimes transparency) to the animation and motion interfaces.

  • Value Range: A float from 0.0 (fully invisible) to 1.0 (fully opaque).
  • Inheritance: Setting the translucency on a Motion object automatically applies it to all underlying animations (4-way, 8-way, etc.).
  • Visual Trick for “Behind Walls”: I demonstrate a clever rendering trick for characters walking behind objects (or through objects). Instead of making the character translucent, you render the character in front of an opaque image and behind another layer, then the front layer is rendered semi-transparent. This creates a professional-looking “X-ray” effect where the character appears to be obscured but still visible.

I also point out a subtle LibGDX “gotcha”: the built-in color constants (like Color.WHITE) are actually mutable objects. If you change the alpha of Color.WHITE for one sprite, it would change it for every other sprite using that constant. To fix this, the framework now creates a new color object every time a color or translucency is set, ensuring visual isolation between sprites

Movement in Games

In this video for “Building a Game Development Framework” series, I focus on integrating LibGDX input handling into my custom 2D framework. The goal is to move away from complex, repeated logic and instead encapsulate movement and input into reusable classes.

First, I handle the coordinate system. A common issue in game development is that mouse input coordinates often start from the top-left, while OpenGL (used by LibGDX) renders from the bottom-left. I created a ScreenInput helper class to:

  • Flip the Y-axis: Automatically subtracts the input Y-position from the screen height so the “game world” Y matches the “input” Y.
  • Delta Movement: Provides methods to get the change in mouse position (DeltaX, DeltaY), which is essential for mechanics like first-person camera rotation or smooth scrolling.

Then I demonstrate the difference between the primary LibGDX input polling methods:

  • isButtonPressed vs. isButtonJustPressed: The former returns true as long as a button is held down (useful for continuous fire), while the latter fires only once per click (useful for menus).
  • Key Input: Similar logic is applied to keyboard keys using Gdx.input.isKeyPressed.
  • Multi-touch: Brief mention of how to handle specific finger indexes for mobile development.
  • Text Input: A quick look at a built-in dialog for simple user text entry.

Then I explain my Movement Interface and its implementations, which decouple “how a character moves” from “how the animation is drawn.”

  • Base Movement & Magnitudes: A base class calculates movement “magnitudes” using sine and cosine. This ensures that when a character moves diagonally, they don’t move faster than they do horizontally or vertically (maintaining a consistent speed).
  • Two-Key Movement: Encapsulates logic for moving along a single axis (e.g., Left/Right or Up/Down) using two specified keys.
  • Four-Key Movement: Handles full 2D movement. It includes a “Multi-key” mode that allows for diagonal movement (8 directions) by checking if two keys (like Up and Right) are pressed simultaneously.

I sum this up by showing how the framework simplifies the code. Instead of writing complex if statements in every character class, a developer only needs about five lines of code to:

  1. Initialize the movement type (e.g., FourKeyMovement).
  2. Update the movement with delta time.
  3. Update the animation’s direction based on the movement’s calculated heading.
  4. Update the character’s X and Y coordinates using the movement’s calculated updates.

This modularity allows for easy swapping of controls—for example, switching a character from keyboard controls to a different input method—without touching the animation logic.

Motion in Games

In my sixth video from the “Building a Game Development Framework” series, I demonstrate how to build a robust Motion System on top of the LibGDX framework. This system is designed to simplify how character animations are managed and triggered based on the movement direction.

The core of this system is the Motion interface. Similar to the Animation class from the earlier videos, the “motion” encapsulates all the possible animations for a character (e.g., walking north, south, east and west) and decides which one to play base on the character’s current heading.

To handle the movement logic, I introduce a Direction class that uses the FastMath utility class for performance. This class contains:

  • Pythagorean Theorem & Angles: It calculates the angle of movement between an origin and destination.
  • Cardinal Directions: It includes methods to snap to a precise degree (0–360) to the nearest 4-way (North, South, East, West) or 8-way cardinal directions.
  • Normalization: A helper method ensures angles always stay within the 0 to 360-degree range.

I developed classes in the framework to be used depending on how complex your character’s visuals are:

  • Single Motion: Displays the same animation regardless of direction (useful for objects like a spinning coin or a single Animation).
  • Two-Way Motion: Switches between two animations, typically for horizontal (left/right) or vertical (up/down) movement.
  • Four-Way & Eight-Way Motion: These implementations map animations to the standard cardinal and inter-cardinal directions. I show how to streamline this by creating constructors that take a single sprite sheet and automatically slice the necessary frames for each direction.

Since the Motion class contains Animations, it supports the Animation’s set color method, making it easy to change the color.

A significant addition, I added, is the LayeredAnimation class. This allows you to stack multiple animations on top of each other. This Animation class allows several Animations to be treated as a single Animation, layering them to produce a single object. The first Animation added is the bottom layer, and subsequent additions are rendered on top. Here I demonstrated with the “Magic Egg”, with a ring and egg underneath it. This allows us to color these two separately.

This modular approach allows game developers to change a character’s “Motion” type (e.g., from 4-way to 8-way) without rewriting their core game logic, making the framework highly flexible for different art styles.