I wrote two projects, one of which uses native extensions. The first generates a special file with data of image transparency. The second uses it to determine if the sprite is clicked or not.
Now you can determine whether the game object clicks, even if it is of complex shape without physics!
Bundling error fixed (I forgot about custom resources)
Added zlib, now the generated files weigh even less:
Compression: 2, image from example
Size: 23,6 kb -> 799b
I made a few more optimizations, the changes are available on the github.
Please update those using large images.
Large image data takes a while to initialize. There are no lags with click detection, only with initializations.
The size of the generated data
Decreased by 30-35%
If you generate large images and generating data takes time, you can use this code and do not generate data again
It must be put into the init function once (check_click.lua), the data in the new format will appear in the new_generated_data folder.
code
local str_begin = "/generated_data/"
for k, v in pairs(init_list) do
local loaded_data = sys_load_resource(str_begin..v..".data")
if loaded_data then
loaded_data = zlib_inflate(loaded_data)
-- Should be executed once and then removed:
local file = io.open("new_generated_data/"..v..".data", "wb")
local new_data = string.gsub(loaded_data, "255", "1")
file:write(zlib.deflate(new_data))
file:close()
Optimized again. I have a lot of images in the game that I have to track when I click.
For those who do not use large images or many images, you may not need to update.
I rewrote the click tracking module into a native extension.
The main reason for the slow initialization was that the transparency data was stored in the Lua array. And adding items to it was slow. I am assuming that when elements are added, the array is re-created.
Therefore, the data is now stored and checked in a C++ module.
When initializing with data, memory of a certain size is allocated and filled with the necessary data.
Comparison of module initialization time (maps from my game): Europe:
0.659 sec -> 0.064 sec America (The map is too big):
5.2 sec -> 0.364 sec
I could not think that data is added to the lua table so slowly compared to my implementation in native code.
I hope that I don’t need to change anything here anymore.
The data format has also changed, you will need to regenerate the data again or use this code by analogy with what was above
code
local file = io.open("new_generated_data/"..v..".data", "wb")
local new_data = string.gsub(loaded_data, " ", "")
file:write(zlib.deflate(new_data))
file:close()
The data format has changed since at first it was thought that you can adjust the transparency threshold for the click detection. Now that’s either transparent or not. Data is now located as compactly as possible
In lua, an element was added to the array with each new received character. In C ++ a chunk of memory is pre-allocated and filled
lua
for val in string_gmatch(loaded_data, ".") do
if is_compression then
data_compression[v] = string_byte(val) - 48
is_compression = false
else
i = i + 1
data[v][i] = val == "0" and 0 or 255 -- It was the most demanding performance. I tried removing the conditions, it has no effect. Even data[v][i] = 1 is demanding
end
end
c++
ImageData imageData;
imageData.id = new char[strlen(id) + 1];
strncpy(imageData.id, id, strlen(id) + 1);
imageData.size = len;
imageData.data = new uint8_t[len - 1];
int compression = str[0] - '0';
for(uint32_t i = 0;i < len - 1;++i)
imageData.data[i] = str[i + 1] - '0';
I did some performance checks with the old module. It looks like the same amount of time is spent on string_gmatch and adding elements.
The simplest measurement:
0.61s with adding
0.27s without
I tried in several ways, it looks like 50/50
In any case, I have no idea how it can be faster in lua. Native extensions are awesome
from PIL import Image
file_name="file"
for number in range(5):
im = Image.open(file_name+str(number)+".png")
width, height = im.size
print(file_name+str(number)+"=vmath.vector3("+str(width)+","+str(height)+",0),")
a more advanced script: renames .png, copies to the images folder and overwrites image_data.lua. After that, all that remains is to launch the project.
from PIL import Image
import os
import shutil
directory = os.path.abspath(os.curdir)
files = os.listdir(directory)
it_path=r"PATH_TO ImageTransparencyCalculator - Check sprite on click/ImageTransparencyCalculator/"
img_path=it_path + r"images/"
name = "new name for png"
png_files=[]
code=["local t = {"]
#clear images folder
for filename in os.listdir(img_path):
file_path = os.path.join(img_path, filename)
try:
if os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path)
elif os.path.isdir(file_path):
shutil.rmtree(file_path)
except Exception as e:
print('Failed to delete %s. Reason: %s' % (file_path, e))
for i in range(len(files)):
if files[i].startswith("optional") and files[i].endswith(".png"):
png_files.append(files[i])
os.rename(directory+"/"+files[i], directory+"/"+name+str(i)+".png")
shutil.copy(directory + r"/" + name+str(i) + ".png", img_path)
for i in range(len(png_files)):
im = Image.open(name+str(i)+".png")
width, height = im.size
code.append(name+str(i)+"=vmath.vector3("+str(width)+","+str(height)+",0),")
code.append("}")
code.append("return t")
it_file = os.path.join(it_path+r"main/", 'image_data.lua')
with open(it_file, "w") as file:
file.writelines("%s\n" % line for line in code)