上传的文件里有3个效果:变幻Delta带影子的 变幻四面体 不同速度随机游动的点
我平常放dos启动盘里,进入dos的时候拿来做屏保啦哈哈。
#include <Conio.h>
#include <graphics.h>
#include <stdlib.h>
#define closegr closegraph
#define NDOT 4
typedef struct
{
int a,b,x,y;
} DotInf;
void initgr(void) /* BGI初始化 */
{
int gd = DETECT, gm = 0;
registerbgidriver(EGAVGA_driver);
initgraph(&gd, &gm, "");
}
void delta(DotInf dot,int c)
{
int i,j;
setcolor(c);
for (i=0;i<NDOT;i++)
for (j=i+1;j<NDOT;j++) line(dot.x,dot.y,dot.x,dot.y);
}
int main(void)
{
int i,j,whi=0;
DotInf snk,everdot;
initgr(); /* BGI初始化 */
for (i=0;i<NDOT;i++) {
snk.a=snk.b=snk.x=snk.y=200;
}
delta(snk,2);
randomize();
while (!kbhit())
{
if (whi<4) whi++; else whi=0;
for (i=0;i<600;i++) delay(10);
delta(everdot,0);
delta(snk,2);
for (i=0;i<NDOT;i++){
if ((snk.x==snk.a)&&(snk.y==snk.b)){
snk.a=rand()%600+1;
snk.b=rand()%400+20;
}
}
for (i=0;i<NDOT;i++){
everdot.x=snk.x;
everdot.y=snk.y;
if (whi>i) continue;
if (snk.x>snk.a)
snk.x--;
else if (snk.x<snk.a)
snk.x++;
else
{
if (snk.y>snk.b)
snk.y--;
else if (snk.y<snk.b)
snk.y++;
}
}
}
getch();
closegr(); /* 恢复TEXT屏幕模式 */
return 0;
}
Last edited by 523066680 on 2009-9-7 at 01:25 ]
LLM 解释
这段代码是 2000 年代初期中文 DOS 编程爱好者常用的典型实现,基于 Borland Turbo C (TC) 的 BGI (Borland Graphics Interface) 图形库。
技术实现分析
-
BGI 初始化机制:
代码中使用了 registerbgidriver(EGAVGA_driver)。在当年的 TC 环境下,BGI 驱动程序(如 EGAVGA.BGI)通常是作为独立文件存在的。如果程序运行时找不到该文件,图形初始化会失败。通过 registerbgidriver 函数,开发者可以将驱动程序静态链接到生成的可执行文件中,从而摆脱对外部 .BGI 文件的依赖,这在制作“单文件”屏保或实用工具时是标准做法。
-
动画逻辑与同步:
-
核心算法:程序定义了一个
DotInf 结构体来存储四个顶点(NDOT=4)的当前位置 (x, y) 和目标位置 (a, b)。通过 delta 函数绘制顶点间的连线,形成一个四面体(在此平面投影中为全连接图)。
-
擦除机制:程序采用了“异或擦除”或“覆盖擦除”的简化版。它保存了上一帧的状态
everdot,并在绘制新一帧之前,用背景色(颜色 0)在旧位置重绘一次图形。这在当时的显示带宽下是避免全屏闪烁(Flicker)的常用技巧,因为全屏 cleardevice() 会导致严重的视觉闪烁。
-
速度控制:代码中使用了
delay(10) 函数。需要注意的是,TC 中的 delay 函数在当时是基于硬件时钟周期的。在如今的模拟器(如 DOSBox)或现代高速 CPU 上,如果没有正确配置,这种循环延时可能会导致动画极快或极慢。
潜在的技术局限与误区
-
分步运动逻辑:
代码中的坐标更新逻辑存在一个常见的初学者偏差:
if (snk[i].x > snk[i].a) snk[i].x--;
else if (snk[i].x < snk[i].a) snk[i].x++;
else {
if (snk[i].y > snk[i].b) snk[i].y--;
else if (snk[i].y < snk[i].b) snk[i].y++;
}
这种逻辑会导致点先在 X 轴移动,待 X 坐标对齐后再在 Y 轴移动,轨迹呈直角折线而非平滑的直线。在当时的动画编程中,标准的做法是使用 Bresenham 算法 的变体或浮点数步长来计算位移,以实现任意斜率的直线运动。
-
延迟函数的副作用:
外层循环 for (i=0; i<600; i++) delay(10); 产生了一个约 6 秒的长延迟(600 * 10ms),但在延迟期间并没有检测键盘输入 kbhit()。这意味着程序在每轮移动之间会有明显的停顿,且对用户按键的响应会有滞后感。这反映了早期单线程 DOS 程序在处理实时交互与逻辑循环时的典型局限。
-
坐标范围假设:
代码硬编码了 rand()%600+1 和 rand()%400+20。这假设了显示模式为 VGA HiRes(640x480)。如果 BGI 环境被初始化为较早的 CGA 或低分辨率模式,这些坐标可能会超出绘图边界,导致 BGI 内部裁切或未定义行为。
环境兼容性提示
-
编译环境:此类代码通常需要 Turbo C 2.0 或 Borland C++ 3.1 编译。
-
图形驱动:
EGAVGA_driver 宏要求编译器能够找到对应的符号定义,通常在 graphics.h 中,并且在链接阶段需要开启图形库支持(Linker options -> Graphics library: ON)。
-
现代运行:在 DOSBox 环境下,由于模拟了 18.2Hz 的标准时钟中断,
delay 函数能相对准确地工作,但建议通过控制 CPU Cycles(如 cycles=3000)来还原当年实机的视觉速度。