如何优化1D数组存储的精灵绘制到1D屏幕像素数组的代码
优化方案
核心问题梳理
当前代码主要存在几个可优化的点:
- 逐像素遍历中反复计算
tempX/tempY、屏幕地址,存在大量冗余计算 - 每个像素都要做三次边界判断,无效判断占比高
- 没有利用同行长连续内存的特性,无法用批量拷贝提升效率
具体优化建议
- 重构为按行遍历逻辑
直接外层循环遍历精灵的每一行,提前算出当前精灵行的起始地址、对应屏幕行的起始地址,完全不需要在遍历像素时计算行列偏移,大幅减少冗余运算。 - 提前做边界裁剪
提前计算精灵在屏幕上的可绘制范围:- 若精灵Y坐标超出屏幕上下边界,直接跳过绘制
- 若精灵X坐标超出左右边界,直接截取精灵行的有效绘制区间,内层循环仅遍历有效像素,无需逐像素判断边界
- 批量拷贝非透明行
如果确认某一行精灵的所有像素alpha都不为0,且该行在屏幕上的绘制区间完全在屏幕范围内,直接用memcpy拷贝整行像素,比逐像素赋值效率高3~5倍。 - 变量作用域优化
把tempX/tempY/arrayPosCheck这类临时变量改为函数内局部变量,避免全局变量的访问开销。
优化后代码示例
void PlaceSprite(uint8_t* array, Transform* trans) { // 提前计算垂直方向裁剪边界 int drawStartY = trans->posY < 0 ? 0 : trans->posY; int drawEndY = trans->posY + trans->sizeY > y ? y : trans->posY + trans->sizeY; if (drawStartY >= drawEndY) return; // 垂直方向完全超出屏幕,直接返回 // 提前计算水平方向裁剪边界 int drawStartX = trans->posX < 0 ? 0 : trans->posX; int drawEndX = trans->posX + trans->sizeX > x ? x : trans->posX + trans->sizeX; if (drawStartX >= drawEndX) return; // 水平方向完全超出屏幕,直接返回 // 计算精灵需要跳过的行列偏移 int spriteSkipY = drawStartY - trans->posY; int spriteSkipX = drawStartX - trans->posX; const int spriteRowBytes = trans->sizeX * 4; // 精灵每行的字节数 const int screenRowBytes = x * 4; // 屏幕缓冲区每行的字节数 // 逐行绘制 for (int yIdx = drawStartY; yIdx < drawEndY; yIdx++) { // 计算当前精灵行的起始地址 uint8_t* spriteRow = array + (spriteSkipY + yIdx - drawStartY) * spriteRowBytes + spriteSkipX * 4; // 计算当前屏幕行的起始地址 uint8_t* screenRow = pixData + yIdx * screenRowBytes + drawStartX * 4; // 遍历当前行的有效像素 int drawWidth = drawEndX - drawStartX; for (int xIdx = 0; xIdx < drawWidth; xIdx++) { int pxOffset = xIdx * 4; // 跳过完全透明的像素 if (spriteRow[pxOffset + 3] == 0) continue; // 直接赋值,需要支持半透明可替换为alpha混合逻辑 screenRow[pxOffset] = spriteRow[pxOffset]; screenRow[pxOffset + 1] = spriteRow[pxOffset + 1]; screenRow[pxOffset + 2] = spriteRow[pxOffset + 2]; } } }
额外优化提示
如果你的精灵大多是没有半透明的纯色块,可以提前给精灵预存每一行的透明区间信息,绘制时直接跳过全透明的行,或者直接拷贝非透明的连续区间,性能还能进一步提升。
内容的提问来源于stack exchange,提问作者Antheus
相关产品推荐
相关产品推荐

