Forgotten Elixir

An enchanting engine where magic and technology intertwine

Rendering sprites

created: 2025-03-13 03:08:14 UTC
last updated: 2025-03-13 03:08:26 UTC

Screenshot 2025-03-12 at 7.43.18 PM.png 503 KB

Last night I focused some more on rendering, mostly with cleaning up some more wall rendering and taking care of rendering sprites. Rendering sprites contains a lot of similarities with rendering walls, but with a few twists. With rendering wall, we cast rays from the player's position and check against the map data. However, sprites are not in our map data and more do we want them. At least not with the current structure of the map. So, they exist in the level data. Here is a look at the updated yaml file.
player:
  x: 65 
  y: 65
  width: 10
  height: 10
map:
  rows: 10 
  columns: 10
  path: ./assets/maps/one
wall_textures:
  - id: 1
    path: "./assets/textures/redbrick.png"
  - id: 2
    path: "./assets/textures/graystone.png"
  - id: 3
    path: "./assets/textures/colorstone.png"
sprite_textures:
  - name: "armor"
    path: "./assets/textures/armor.png"
  - name: "light"
    path: "./assets/textures/light.png"
actors:
  - x: 250
    y: 250
    sprite: "light"
  - x: 300
    y: 250
    sprite: "armor"
What I have referred to as sprites are actually actors that, as of right now, consist of three pieces of data. Two of those pieces of data are components for the actor's position, an x and y coordinate. The last field is a string with the name of the sprite that we maps back to the sprite textures that is an unordered map.

As I mentioned, there are some similarities with rendering both actors and walls. Still, a calculation needs to be made for the distance from the player to the actor along with a perpendicular distance. However, some checks need to be performed since there are some obvious things we don't want. For instance, if an actor is on the other side of the wall, we don't want to render the sprite over top the wall, and that bit is important. Rendering is following the painter's algorithm. We want to render from back to front. Things in the background should be drawn first, and things in the foreground should be drawn last. This partitioning will also help to make sure that we don't paint a sprite over top the wall but going in layers, but we still need to test.

But first, the first test. A test is needed to see if a sprite is within the player's field of view. A sprite doesn't need to be rendered if it is not within's the player field of view, so there is no point in wasting the compute time on that. Such as, the actor and it's sprite are behind the player.

However the next test is to check the player's distance against the a wall that would render along that same ray path. So rays are needed for reference, then we can just compared the distance between the player and the sprite against the player and the wall that the ray would hit. If the distance to the sprite is shorter than the distance to the wall, we paint the sprite. If that is not the case, so the wall is closer than the sprite, we can forget rendering this sprite and move in to the next.

One final test is to check the pixel color. General with this kind of rendering, we get transparency by having a special color that, when we look at a sprite and see that color, it is ignored. For this, and traditionally I believe, it is a shade of purple. But it is dealer's choice, just make sure it doesn't collide with anything in the color pallets for the sprites. And since I am using the painter's algorithm, black spaces for the sprite will still fill in with the appropriate colors for the wall behind the actor and sprite.

For those not familiar with the painter's algorithm, it is simple. Render things from back to front. From farthest distance to shortest distance.
Screenshot 2025-03-12 at 7.43.01 PM.png 513 KB