Led Shooter

Start working on new game. The main idea to emulate led display. Why led screen? Because it is looks unusually, and it is easy for me to make such art. :grinning:
Now i have working led screen, prototype game mechanic, and working animations.
I don’t know what game mechanics i will use. Now i am making vertical shmup.

13 Likes

Cute dino! Attack of dead pixels!

1 Like

Nice! How did you end up doing the “LED” display? Are they sprites?

Now i am using gui nodes. It is not best way. For screen 45 x 60 it is taking about 5ms to gameobject.guic in pc profiler. And if i make bigger screen, for example 100x100 i can’t get 60 fps.
I am think about buffer, resource.set_texture, and shader. It shoould be much better for performance.

1 Like

One way could be to just render 100x100 normal pixels with no filtering (but yeah, they will be pretty big on a bigger screen) and then just use a mask or just an image with stanced holes in it above that.

3 Likes

I am trying sheder with runtime texture from buffer,(resource.set_texture for model).
Looks like it is not fast way.

self.stream = buffer.get_stream(self.buffer, hash("rgb"))
...
--Changing stream is very slow. For example this lines in for loops for x and y
--takes about 6ms
--Looks like changing stream is slow. 

self.stream[index + 0] = color.x * 255
self.stream[index + 1] = color.y * 255
self.stream[index + 2] = color.z * 255

Is there are some others ways to fast manipulation with textures?

Have to do it with native extensions to be fast.

1 Like

How? I can send table with pixels to native extension. But how to manipulate with buffer or texture?
Or you talking about for loops? because many problem is loop?

Did you try to use render target?

1 Like

I need changing texture every frame. I don’t need render target

I would try what Andreas recommended. Basically just render a tiny pixel art game then draw a texture with holes in it over that at full resolution. You don’t need anything fancy at all, and you will have good performance.

4 Likes

Thanks, for your try. I already done shader for that, and don’t have problem with render. You can try shader, it should work fast too. led.x = width, led.y = height, led.z = width/height. I use model and runtime pixel texture. But for your example shader can be used for postprocessing.

varying mediump vec2 var_texcoord0;

uniform mediump sampler2D tex0;
uniform mediump vec4 led;

const float ledRad = 0.4; 

vec3 getColor(vec2 uv){
	float center = 0.5/led.y;
	float rad = center * ledRad * 2.0;
	vec2 newRes = vec2(led.x, led.y);

	//get color for one led
	//vec2 pixelUV = uv;
	vec2 pixelUV = floor(uv * newRes) / newRes;
	vec2 coords = pixelUV  - uv + center;
	//fixed circle aspect
	coords.x *=  led.z;
	//WTF NEED FIX IT NORMAL
	coords.x += center * 0.08;
	//coords.x -= center;
	float d = length(coords);
	vec3 color = texture2D(tex0, uv).rgb;
	return mix(color, vec3(0), smoothstep(rad *0.9 , rad, d));
} 

void main(){
	gl_FragColor = vec4(getColor(var_texcoord0.xy).rgb, 1.0);
	//gl_FragColor = vec4(color.rgb, 1.0);
}

1 Like

My problem, is that i need change texture in lua, which is very slow.
I can’t use pixel sprites. Because i need a ability to change color for every pixel in runtime. For example a brightness of pixel can describe it health. Also i need a ability to destroy every pixel of enemy.

1 Like

For screen 30x40 i spend 4-6 ms for loop in lua in android on galaxy s7. On cheap devices it will be much bigger. I am trying to move for loop in native. It should help.

local update_time = os.clock();
local stream = self.stream
local nodes = LED.NODES
local width = self.width
local index = 1
local arshift = bit.arshift
local band = bit.band
    for id = 1, self.width * self.height do
        local color = nodes[id]
        local index = id * 3 - 2
        stream[index] = arshift(band(color, 0xff0000),16)
        stream[index + 1] = arshift(band(color, 0x00FF00),8)
        stream[index + 2] = band(color, 0x0000ff)
    end
local header = { width=self.width, height=self.height, type=resource.TEXTURE_TYPE_2D, format=resource.TEXTURE_FORMAT_RGB, num_mip_maps=0 }
resource.set_texture(self.resource_path, header, self.buffer )
print("update time:" .. (os.clock() - update_time))
1 Like

You can also try to sample from that pixel texture in a fragment shader and render the LEDs. That may be even cheaper depending on the shader code.

1 Like

You can try rendering to an 8-bit luminance texture and do palette conversion in a shader. That way you don’t have to write as much data to the buffer. This works only if you have max 255 colors, of course.

3 Likes

Interesting, I need more colors, but I’ll keep it on mind. Also i am thinking about, setting only changed colors. But sometimes i will need changed all pixel, so i should do it as fast as possible

1 Like

Make native for changing texture.
Looks like native is 20-30% faster.

Anybody have ideas how can i increase speed more?

Test for screen 300x400.

PC

DEBUG:SCRIPT: native: 0.029
DEBUG:SCRIPT: lua:0.04
DEBUG:SCRIPT: native: 0.029
DEBUG:SCRIPT: lua:0.039
DEBUG:SCRIPT: native: 0.029
DEBUG:SCRIPT: lua:0.039
DEBUG:SCRIPT: native: 0.03
DEBUG:SCRIPT: lua:0.04
DEBUG:SCRIPT: native: 0.03
DEBUG:SCRIPT: lua:0.039
DEBUG:SCRIPT: native: 0.031
DEBUG:SCRIPT: lua:0.04
DEBUG:SCRIPT: native: 0.031
DEBUG:SCRIPT: lua:0.039

Android

native: 0.059728999999999
lua:0.077413999999999
native: 0.059455
lua:0.082948999999999
native: 0.058417
lua:0.078471
native: 0.059436
lua:0.080285
native: 0.059778999999999
lua:0.077199
native: 0.060198999999999
lua:0.081021
native: 0.059331
lua:0.082233
native: 0.0600940000000011
lua:0.079887999999999
native: 0.058405
lua:0.079704000000001
native: 0.058944
lua:0.07696
native: 0.058088
lua:0.079167999999997
native: 0.056916999999999
lua:0.079489000000002
native: 0.060658
lua:0.082440000000002
native: 0.059473000000001
lua:0.081376000000002
static int drawPixels(lua_State* L)
{	
	lua_getfield(L, 1, "width");
	lua_getfield(L, 1, "height");
	int width = luaL_checknumber(L, -2);
	int height = luaL_checknumber(L, -1);
	lua_pop(L, 1);
	lua_pop(L, 1); 
	int size = width * height;
	printf("width=%d height=%d \n",width,height);
	lua_pushstring(L,"stream");
	lua_gettable(L, -2 );
	lua_pushstring(L,"leds");
	lua_gettable(L, -3 );
	for(int i=1; i<= size;i++){
		lua_rawgeti(L,-1,i);
		int color = luaL_checknumber(L, -1);
		//printf("i=%d color=%d \n",i,color);
		lua_pop(L, 1);
		int r = color >> 16;
		int g = (color & 0x00FF00) >> 8;
		int b= color & 0x0000ff;
		
		int id = i * 3;
		lua_pushnumber(L, id - 2);
		lua_pushnumber(L, r);
		lua_settable(L, -4);
		lua_pushnumber(L, id - 1);
		lua_pushnumber(L, g);
		lua_settable(L, -4);
		lua_pushnumber(L, id);
		lua_pushnumber(L, b);
		lua_settable(L, -4);
		//lua_pop(L,1);
	}
	lua_pop(L,1);
	
	return 1;
}

Looks like setting data to stream is very expensive.
If i comment setting data to stream, i get 1 ms instead of 30. (x30 FASTER).:open_mouth:
Why buffer is so slow?

You moved from Lua to C, but you still use Lua calls extensively. You should try working with native representation of buffers directly. https://www.defold.com/ref/dmBuffer/

1 Like