如何实现mapMoon沿椭圆运动时隐藏在mapWorld后方的视觉效果?
解决Curses终端图形中月亮被世界地图遮挡的视觉效果方案
核心逻辑
要实现椭圆运动的月亮被世界地图遮挡的错觉,关键是按遮挡层级分阶段绘制:不再一次性绘制整个月亮,而是根据月亮当前位置与世界地图的覆盖关系,拆分月亮为「被遮挡部分」和「可见部分」,先画被遮挡的月亮片段,再画完整的世界地图,最后画可见的月亮片段。
具体修改步骤
假设你的世界地图mapWorld固定在终端某一区域(比如垂直方向占据终端下方MAP_HEIGHT行),月亮mapMoon沿椭圆轨迹穿过世界地图区域:
计算位置边界
获取月亮当前的左上角坐标(moon_x, moon_y),结合月亮尺寸MOON_WIDTH、MOON_HEIGHT算出右下角坐标(moon_x + MOON_WIDTH - 1, moon_y + MOON_HEIGHT - 1);同时确定世界地图的覆盖范围,比如世界地图的顶部行world_top_y、底部行world_bottom_y。拆分月亮绘制区域
根据垂直方向的重叠情况拆分:- 被遮挡区域:月亮中
y >= world_top_y的行(落在世界地图范围内的部分) - 可见区域:月亮中
y < world_top_y的行(在世界地图上方的部分)
- 被遮挡区域:月亮中
调整绘制顺序
把原有的「先画世界→再画月亮」改为三步绘制:- 第一步:绘制月亮的被遮挡部分。遍历月亮落在世界地图内的行,逐行绘制
mapMoon对应字符,这部分会被后续的世界地图覆盖。 - 第二步:绘制完整的
mapWorld,覆盖掉之前画的月亮被遮挡部分。 - 第三步:绘制月亮的可见部分。遍历月亮在世界地图上方的行,逐行绘制
mapMoon对应字符,这部分会显示在世界地图上层。
- 第一步:绘制月亮的被遮挡部分。遍历月亮落在世界地图内的行,逐行绘制
动态适配椭圆轨迹
因为月亮沿椭圆运动,每帧刷新都要重新计算位置和重叠区域:比如月亮完全在世界地图下方时,只执行前两步;完全在上方时,执行后两步。
代码示例片段
// 假设已获取当前月亮坐标(moon_x, moon_y),世界地图顶部行world_top_y int moon_bottom_y = moon_y + MOON_HEIGHT - 1; int world_bottom_y = world_top_y + MAP_HEIGHT - 1; // 1. 绘制月亮被遮挡的部分 if (moon_y <= world_bottom_y) { int start_row = (moon_y < world_top_y) ? world_top_y : moon_y; int end_row = (moon_bottom_y > world_bottom_y) ? world_bottom_y : moon_bottom_y; for (int y = start_row; y <= end_row; y++) { int moon_row_idx = y - moon_y; for (int x = moon_x; x < moon_x + MOON_WIDTH; x++) { int moon_col_idx = x - moon_x; if (mapMoon[moon_row_idx][moon_col_idx] != ' ') { mvaddch(y, x, mapMoon[moon_row_idx][moon_col_idx]); } } } } // 2. 绘制世界地图 for (int y = world_top_y; y <= world_bottom_y; y++) { int world_row_idx = y - world_top_y; for (int x = 0; x < MAP_WIDTH; x++) { mvaddch(y, x, mapWorld[world_row_idx][x]); } } // 3. 绘制月亮可见的部分 if (moon_bottom_y >= world_top_y) { int start_row = moon_y; int end_row = (moon_bottom_y < world_top_y) ? moon_bottom_y : world_top_y - 1; for (int y = start_row; y <= end_row; y++) { int moon_row_idx = y - moon_y; for (int x = moon_x; x < moon_x + MOON_WIDTH; x++) { int moon_col_idx = x - moon_x; if (mapMoon[moon_row_idx][moon_col_idx] != ' ') { mvaddch(y, x, mapMoon[moon_row_idx][moon_col_idx]); } } } }
额外注意事项
- 如果世界地图有镂空区域(空白处不遮挡月亮),绘制被遮挡部分时,要先检查
mapWorld对应位置是否为非空白,再决定是否绘制月亮的该字符。 - 每帧绘制前用
clear()或局部刷新清除上一帧内容,避免残影。
内容的提问来源于stack exchange,提问作者Exponecial
相关产品推荐
相关产品推荐

