VacantShade
Member
PREVIEW:
I'm implementing a custom tile system into my project, because I'd like more flexibility than what the current system allows. I've already added the system, and it works fine, but I believe it to be very inefficient. Below I'll detail some of my goals and then how my system works. It would be great to hear your ideas as to how you would go about accomplishing the same goals but with a different approach!
NOTE: All code below is pseudo code. As the features all work, I'm just interested in finding a better approach to the concept in general.
BACKGROUND:
Part of my game involves an editor which will allow players to design their own sections of the game world. When designing a section, they should be able to define a number of Palettes to use in the section. However, in the actual game, these sections are combined in a single GM Room. Transitions can be handled with a black fade out though, so it should be possible to do some data swaps between sections.
Current view resolution is [ 256 x 240 ] with [ 16 x 16 ] tile size, for a total of [ ~240 ] tiles onscreen at once. The game actually uses 3 tile layers ( Back , Mid , Front ), but what works for one should work for all of them.
GOALS:
+ This system should work on all exports ( Including HTML5 )
+ Allow Tiles to be Rotated, Mirrored, Flipped ( Just like normal )
+ Draw each individual tile with a specific Palette ( 3 Colors )
+ Let a color in a Palette be defined as Clear ( so 0 Alpha )
+ Allow for Animated tiles of varying frame length ( 4 , 6 , 8 , 10 , 12 , 16 ) ( This is flexible )
+ Allow for Animated tiles with frame offsets ( e.g. So animation starts on frame 2 )
+ Allow for tiles to use Animated Palettes of varying frame length ( 4 , 6 , 8 , 10 , 12 , 16 ) ( This is flexible )
+ Allow for tiles to use Animated Palettes with a frame offset ( e.g. So palette starts on frame 2 )
+ Allow for an Animated Tile to also have an Animated Palette
MY IMPLEMENTATION:
+ Colors are stored as HEX values
+ Drawing a single tile involves these steps
VISUALS:
Here are some GIFs of the system in action, to help you get a visual idea what all this stuff is for in the end.
FAULTS:
Profiling through the debugger shows that while non-animated tiles work relatively well, animated tiles/palettes cause major slow down. Part of this is the need to check them each step to see if they have updated. Another issue is the fact I need to "cut them out" of the surface, using a blend mode and drawing a rectangle first. Lastly, a large slowdown comes from passing the uniforms to the shader every draw.
Also, I've yet to implement it into the shader to handle a color being passed as "clear", having no Alpha. Since I'm dealing with a very small amount of colors, I could reserve a color as "clear", and have the shader do an if check for that "color".
Not a fault necessarily, but storing the palette in the tile data means I can only have a small number of palettes available per player designed "section", since indexes can only go so high. This also means that I'll need to re-setup the palette data for every "section" during fade out transitions.
SUMMARY:
There's quite a few moving parts to this machine, but it actually works and accomplishes what it set out to.
However, I'd really like to increase the efficiency, as of right now, I think I would have to limit players to about 20~ animated tiles per screen region, to prevent slowdown. I'd like to get it up to 100~.
My programming experience is still quite limited, so I imagine there are some major improvements that could be made, while maintaining the functionality, or even expanding it.
I look forward to hearing your thoughts!
I'm implementing a custom tile system into my project, because I'd like more flexibility than what the current system allows. I've already added the system, and it works fine, but I believe it to be very inefficient. Below I'll detail some of my goals and then how my system works. It would be great to hear your ideas as to how you would go about accomplishing the same goals but with a different approach!
NOTE: All code below is pseudo code. As the features all work, I'm just interested in finding a better approach to the concept in general.
BACKGROUND:
Part of my game involves an editor which will allow players to design their own sections of the game world. When designing a section, they should be able to define a number of Palettes to use in the section. However, in the actual game, these sections are combined in a single GM Room. Transitions can be handled with a black fade out though, so it should be possible to do some data swaps between sections.
Current view resolution is [ 256 x 240 ] with [ 16 x 16 ] tile size, for a total of [ ~240 ] tiles onscreen at once. The game actually uses 3 tile layers ( Back , Mid , Front ), but what works for one should work for all of them.
GOALS:
+ This system should work on all exports ( Including HTML5 )
+ Allow Tiles to be Rotated, Mirrored, Flipped ( Just like normal )
+ Draw each individual tile with a specific Palette ( 3 Colors )
+ Let a color in a Palette be defined as Clear ( so 0 Alpha )
+ Allow for Animated tiles of varying frame length ( 4 , 6 , 8 , 10 , 12 , 16 ) ( This is flexible )
+ Allow for Animated tiles with frame offsets ( e.g. So animation starts on frame 2 )
+ Allow for tiles to use Animated Palettes of varying frame length ( 4 , 6 , 8 , 10 , 12 , 16 ) ( This is flexible )
+ Allow for tiles to use Animated Palettes with a frame offset ( e.g. So palette starts on frame 2 )
+ Allow for an Animated Tile to also have an Animated Palette
MY IMPLEMENTATION:
+ Colors are stored as HEX values
- Palettes are stored in a 2d Array, like so: [ Palette 0 ] , [ Color A ] , [ Color B ] , [ Color C ]
- Animated Palettes are always a specific range of indexes, say 16-19
- Animated Palettes follow a similar system in the same Array
+ Using the default tile system, setup a monochrome tileset- Animated Palettes are always a specific range of indexes, say 16-19
- Animated Palettes follow a similar system in the same Array
Code:
// Setup Palettes
global.PALETTE[ 0 , 0 ] = ( $000000 );// Color A
global.PALETTE[ 0 , 1 ] = ( $000000 );// Color B
global.PALETTE[ 0 , 2 ] = ( $000000 );// Color C
// Setup Animated Palettes
global.PALETTE[ 16 , 0 ] = 0;// Current Frame
global.PALETTE[ 16 , 1 ] = 4;// Total Frames
global.PALETTE[ 16 , 2 ] = 100;// Speed of Animation
global.PALETTE[ 16 , 3 ] = ( $000000 );// Frame 0 - Color A
global.PALETTE[ 16 , 4 ] = ( $000000 );// Frame 0 - Color B
global.PALETTE[ 16 , 5 ] = ( $000000 );// Frame 0 - Color C
ect...
- By monochrome, there are only 3 colors. (75,75,75) (150,150,150) (225,225,225)
+ Animated Tiles use their own system. They are setup in a 2d Array ahead of time
Code:
// For a 4 Frame Animated Tile
// tile_index could be any number in the tileset
Tile_Is_Animated[ tile_index ] = 1;// Index Pointer
Tile_Is_Animated[ tile_index +1 ] = 1;// Index Pointer
Tile_Is_Animated[ tile_index +2 ] = 1;// Index Pointer
Tile_Is_Animated[ tile_index +3 ] = 1;// Index Pointer
Tile_Animation[ 1 , 0 ] = tile_index;// Base Frame Tile Index
Tile_Animation[ 1 , 1 ] = 4;// Total Frames
Tile_Animation[ 1 , 2 ] = 100;// Base Speed
- Get the tile data ( extra bits store palette index, animation speed, ect )
- Using the Palette Array, get the RGB values of each color, and pass them as uniforms to a shader
- Draw the tile using a "palette swap" shader, that recolors the initial monochrome colors
+ Have a surface the size of the view, plus small buffer
Code:
[ Bit ] [ Value ] [ Usage ]
=============================================
0 1 \
1 2 |
2 4 |
3 8 |
4 16 > Index Value
5 32 |
6 64 |
7 128 |
8 256 |
9 512 |
10 1024 /
11 2048 \
12 4096 |
13 8192 > Color Index (section relative)
14 16384 |
15 32768 /
16 65536 \
17 131072 > Palette Animation Offset
18 262144 /
19 524288 \
20 1048576 > Animation Speed
21 2097152 \
22 4194304 > Animation Offset
23 8388608 /
24 16777216 ] -- Stuff for later maybe?
25 33554432 ] -- Stuff for later maybe?
26 67108864 ] -- Stuff for later maybe?
27 134217728 ] -- Stuff for later maybe?
28 268435456 ]
29 536870912 > --- Flip
30 1073741824 > --- Mirror
31 2147483648 > --- Rotate
- Draw the tile using a "palette swap" shader, that recolors the initial monochrome colors
Code:
// Drawing a Tile
data = tilemap_get( tilemap_id , xx , yy );// Get tile data
index = ( data & TILE_INDEX_BITS );// Get tile index + rotation , mirror , flip
if( index > 0 ) // Make sure this is a legit tile
{
palette = (( data & TILE_PALETTE_BITS ) >> 11);// Get tile Palette
palette_offset = (( data & TILE_PALETTE_OFFSET_BITS ) >> 16);// Get tile Palette Animation Offset
p_colors = scr_Palette_Get_Color( palette , palette_offset );// Gets an array with the palette colors
scr_Set_Shader_Uniforms( p_colors[0] , p_colors[1] , p_colors[2] , 1.0 );// Sets the shader uniforms
draw_tile( tileset , index , 0 , draw_x , draw_y );// Draws the Tile
}
Code:
// Simple palette swap fragment shader
// NOTE: One thing I have yet to implement is allowing a color to be Clear, having 0 Alpha
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform vec3 new1;
uniform vec3 new2;
uniform vec3 new3;
uniform float alpha;
float result = 0.0;
void main()
{
gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
//Make it easier to compare (out of 255 instead of 1)
vec3 test = vec3(
gl_FragColor.r * 255.0,
gl_FragColor.g * 255.0,
gl_FragColor.b * 255.0
);
//Check if it needs to be replaced
test.r = floor( test.r + 0.5 );
if( mod( test.r , 75.0 ) < 0.5 )
{
result = (test.r / 75.0);
}
if( abs( result - 1.0 ) < 0.2 ){ test = new1; }
if( abs( result - 2.0 ) < 0.2 ){ test = new2; }
if( abs( result - 3.0 ) < 0.2 ){ test = new3; }
//return the result in the original format
gl_FragColor = vec4(
test.r / 255.0,
test.g / 255.0,
test.b / 255.0,
gl_FragColor.a * alpha
);
}
- When starting, or refocusing game window, draw every tile onto the surface
- When the view moves, copy surface onto a new surface, but offset by 1 tile, draw the new row/column of tiles
- If an Animated Tile is added, or a tile with an Animated Palette, add it to a ds_list
- Every step, run through the ds_list, and check if the tile needs updated, if so draw it to the surface
- When the view moves, copy surface onto a new surface, but offset by 1 tile, draw the new row/column of tiles
- If an Animated Tile is added, or a tile with an Animated Palette, add it to a ds_list
- Every step, run through the ds_list, and check if the tile needs updated, if so draw it to the surface
VISUALS:
Here are some GIFs of the system in action, to help you get a visual idea what all this stuff is for in the end.
FAULTS:
Profiling through the debugger shows that while non-animated tiles work relatively well, animated tiles/palettes cause major slow down. Part of this is the need to check them each step to see if they have updated. Another issue is the fact I need to "cut them out" of the surface, using a blend mode and drawing a rectangle first. Lastly, a large slowdown comes from passing the uniforms to the shader every draw.
Also, I've yet to implement it into the shader to handle a color being passed as "clear", having no Alpha. Since I'm dealing with a very small amount of colors, I could reserve a color as "clear", and have the shader do an if check for that "color".
Not a fault necessarily, but storing the palette in the tile data means I can only have a small number of palettes available per player designed "section", since indexes can only go so high. This also means that I'll need to re-setup the palette data for every "section" during fade out transitions.
SUMMARY:
There's quite a few moving parts to this machine, but it actually works and accomplishes what it set out to.
However, I'd really like to increase the efficiency, as of right now, I think I would have to limit players to about 20~ animated tiles per screen region, to prevent slowdown. I'd like to get it up to 100~.
My programming experience is still quite limited, so I imagine there are some major improvements that could be made, while maintaining the functionality, or even expanding it.
I look forward to hearing your thoughts!