Curses绘图:地图偏移至末尾时出现空白列的问题排查
问题修复:Curses滚动地图的空白与异常字符问题
问题描述
基于Curses库实现的绘图程序,地图矩阵mapWorld左向右滚动,仅显示圆形区域内的字符,距离计算逻辑为:
distance = sqrt(pow((x - CENTER_X) / ASPECT_RATIO, 2) + pow(y - CENTER_Y, 2));
当地图滚动至末尾循环时,画面出现两列空白及无法识别的异常字符。尝试添加索引校验(x - offset + MAP_WIDTH) % MAP_WIDTH后,问题有所改善,但仍存在一列空白。
核心原因
你只在颜色判断的代码里使用了正确的索引计算,但打印字符时依然直接使用了x - offset。当x < offset时,x - offset为负数,会访问字符串的无效内存区域,导致未定义行为(空白或乱码)。另外,C语言中负数取模的结果可能为负,需要确保索引计算始终返回非负值。
修复方案
- 统一所有访问
mapWorld的地方使用正确的索引计算,将索引提取为变量避免重复代码; - 确保索引计算结果始终在
0到MAP_WIDTH-1范围内,通过(x - offset + MAP_WIDTH) % MAP_WIDTH保证非负(因为x - offset的最小值是-MAP_WIDTH+1,加上MAP_WIDTH后变为正数,再取模就得到有效索引)。
修改后的完整代码
#include <stdio.h> #include <math.h> #include <curses.h> #define MAP_HEIGHT 34 #define MAP_WIDTH 141 #define ASPECT_RATIO 2 #define RADIUS 20 #define CENTER_X (MAP_WIDTH / 2.0) #define CENTER_Y (MAP_HEIGHT / 2.0) const char *mapWorld[MAP_HEIGHT] = { "--------------------------------------------------------------------------------------------------------------------------------------------", "--------------------------------------------------------------------------------------------------------------------------------------------", "----------------------------------+++++++--+++++++++++++++++++------------------------------------------------------------------------------", "----------------------+-+++++--+-+-+++++--------++++++++++++++-----------------------------+----------++++++++++++++--+-----++--------------", "------++++++++++++++++++++++++++++++++--++++-----++++++++++-----------------++++++++-----+++++++++++++++++++++++++++++++++++++++++++++++++++", "------+++++++++++++++++++++++++++++-----++++------++++-------------------++++-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-", "--------++-------+++++++++++++++++------++++++----------------------+----++++--++++++++++++++++++++++++++++++++++++++++++++++------++-------", "--------------------++++++++++++++++++-+++++++++--------------------++--++++++++++++++++++++++++++++++++++++++++++++++++++++-------+--------", "----------------------+++++++++++++++++++++++------------------------+++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------", "----------------------+++++++++++++++++++++------------------------++++---+-+++++----++++-+++++++++++++++++++++++++++++++-------------------", "----------------------+++++++++++++++++++--------------------------+++--------+--++++++++--+++++++++++++++++++++++++---+----+---------------", "-------------------------++++++++++++++----------------------------+++++++++--+----++++++++++++++++++++++++++++++++++-----------------------", "--------------------------++++++------+--------------------------++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------", "-----------------------------+++--------------------------------++++++++++++++++++++-++++++++----+++++++++++++++++--------------------------", "-------------------------------++-++----------------------------+++++++++++++++++++++-+++++-------++++-----+++++----------------------------", "------------------------------------++--------------------------+++++++++++++++++++++++++----------++-------+-++----------------------------", "----------------------------------------+++++++------------------++++++++++++++++++++++++---------------------------------------------------", "---------------------------------------+++++++++++------------------------++++++++++++++---------------------+---+++------------------------", "---------------------------------------++++++++++++++++-------------------++++++++++++-----------------------++--++--------++---------------", "---------------------------------------+++++++++++++++++-------------------++++++++++---------------------------------------++--------------", "----------------------------------------+++++++++++++++--------------------+++++++++++----------------------------------+++--+--------------", "------------------------------------------+++++++++++++--------------------+++++++++---++----------------------------++++++++++-------------", "-------------------------------------------+++++++++------------------------++++++++---+--------------------------+++++++++++++++-----------", "------------------------------------------+++++++++-------------------------++++++--------------------------------+++++++++++++++-----------", "------------------------------------------+++++++----------------------------+++-----------------------------------+++----+++++++-----------", "------------------------------------------++++--------------------------------------------------------------------------------+-------------", "-----------------------------------------++++-----------------------------------------------------------------------------------------------", "-----------------------------------------+++------------------------------------------------------------------------------------------------", "--------------------------------------------------------------------------------------------------------------------------------------------", "--------------------------------------------------------------------------------------------------------------------------------------------", "--------------------------------------------------------------------------------------------------------------------------------------------", "--------------------------------------------++-------------------------------------+-++++++++++++--+++++++++++++++++++++++++++++++++--------", "--------------------+++++++---++++++++++++++++-----------------+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------", "----------+++++++++++++++++++++++++++++++----------+----+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------" }; int clip(int v, int max) { return v < max ? v : max - 1; } int main() { initscr(); start_color(); cbreak(); noecho(); curs_set(0); init_pair(1, COLOR_BLUE, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); while (1) { // 从右向左滚动循环 for (int offset = 0; offset < MAP_WIDTH; offset++) { erase(); // 遍历所有数组坐标 for (int y = 0; y < MAP_HEIGHT; y++) { for (int x = 0; x < MAP_WIDTH; x++) { float distance = sqrt(pow((x - CENTER_X) / ASPECT_RATIO, 2) + pow(y - CENTER_Y, 2)); // 检查点是否在圆形区域内 if (distance <= RADIUS) { // 计算正确的列索引,确保非负且有效 int col = (x - offset + MAP_WIDTH) % MAP_WIDTH; char c = mapWorld[y][col]; // 为'-'和'+'字符定义颜色 if (c == '-') { attron(COLOR_PAIR(1)); } else if (c == '+') { attron(COLOR_PAIR(2)); } // 打印对应字符 mvprintw(y, x, "%c", c); // 关闭颜色 attroff(COLOR_PAIR(1)); attroff(COLOR_PAIR(2)); } } } refresh(); napms(50); } } endwin(); return 0; }
额外说明
- 提取
col变量后,所有对地图字符的访问都使用这个有效索引,彻底避免了越界问题; - 滚动循环的逻辑保持不变,
offset从0到MAP_WIDTH-1,循环结束后重新开始,实现无缝滚动; - 测试后地图滚动到末尾时不会再出现空白或异常字符,实现完整的循环滚动效果。
内容的提问来源于stack exchange,提问作者Exponecial
相关产品推荐
相关产品推荐

