中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net 论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

中国DOS联盟论坛
现在时间是 2026-06-16 09:34
中国DOS联盟论坛 » DOS开发编程 & 发展交流 (开发室) » TC写的小动画效果 查看 4,385 回复 14
楼 主 TC写的小动画效果 发表于 2009-09-04 00:43 ·  中国 广东 广州 电信
银牌会员
★★★★
SuperCleaner
积分 2,362
发帖 1,133
注册 2008-02-02 21:36
UID 110072
性别 男
状态 离线
上传的文件里有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 ]
[已使用 Gemini 解答]
Gemini 解答

这段代码是 2000 年代初期中文 DOS 编程爱好者常用的典型实现,基于 Borland Turbo C (TC) 的 BGI (Borland Graphics Interface) 图形库。

技术实现分析

  1. BGI 初始化机制: 代码中使用了 registerbgidriver(EGAVGA_driver)。在当年的 TC 环境下,BGI 驱动程序(如 EGAVGA.BGI)通常是作为独立文件存在的。如果程序运行时找不到该文件,图形初始化会失败。通过 registerbgidriver 函数,开发者可以将驱动程序静态链接到生成的可执行文件中,从而摆脱对外部 .BGI 文件的依赖,这在制作“单文件”屏保或实用工具时是标准做法。

  2. 动画逻辑与同步

    • 核心算法:程序定义了一个 DotInf 结构体来存储四个顶点(NDOT=4)的当前位置 (x, y) 和目标位置 (a, b)。通过 delta 函数绘制顶点间的连线,形成一个四面体(在此平面投影中为全连接图)。
    • 擦除机制:程序采用了“异或擦除”或“覆盖擦除”的简化版。它保存了上一帧的状态 everdot,并在绘制新一帧之前,用背景色(颜色 0)在旧位置重绘一次图形。这在当时的显示带宽下是避免全屏闪烁(Flicker)的常用技巧,因为全屏 cleardevice() 会导致严重的视觉闪烁。
    • 速度控制:代码中使用了 delay(10) 函数。需要注意的是,TC 中的 delay 函数在当时是基于硬件时钟周期的。在如今的模拟器(如 DOSBox)或现代高速 CPU 上,如果没有正确配置,这种循环延时可能会导致动画极快或极慢。

潜在的技术局限与误区

  1. 分步运动逻辑: 代码中的坐标更新逻辑存在一个常见的初学者偏差:

    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 算法 的变体或浮点数步长来计算位移,以实现任意斜率的直线运动。

  2. 延迟函数的副作用: 外层循环 for (i=0; i<600; i++) delay(10); 产生了一个约 6 秒的长延迟(600 * 10ms),但在延迟期间并没有检测键盘输入 kbhit()。这意味着程序在每轮移动之间会有明显的停顿,且对用户按键的响应会有滞后感。这反映了早期单线程 DOS 程序在处理实时交互与逻辑循环时的典型局限。

  3. 坐标范围假设: 代码硬编码了 rand()%600+1rand()%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)来还原当年实机的视觉速度。
附件
TCGRAPH.rar (59.37 KiB, 下载附件所需积分 1 点, 下载次数: 132)
2 发表于 2009-09-07 01:25 ·  中国 广东 广州 电信
银牌会员
★★★★
SuperCleaner
积分 2,362
发帖 1,133
注册 2008-02-02 21:36
UID 110072
性别 男
状态 离线
3 12 发表于 2009-09-11 08:05 ·  中国 山东 青岛 阿里云
新手上路
积分 8
发帖 3
注册 2009-09-05 09:43
UID 151518
性别 男
来自 China
状态 离线
不错!
4 发表于 2009-09-12 05:35 ·  中国 河南 许昌 禹州市 电信
新手上路
积分 17
发帖 11
注册 2009-09-12 01:24
UID 151871
性别 男
来自 宇宙·······禹州
状态 离线
??????????????????
5 发表于 2009-09-12 05:41 ·  中国 广东 广州 电信
银牌会员
★★★★
SuperCleaner
积分 2,362
发帖 1,133
注册 2008-02-02 21:36
UID 110072
性别 男
状态 离线
楼上有怀疑就说,发问号很容易被当作恶意灌水并扣分的。
6 发表于 2009-09-13 01:02 ·  中国 广东 揭阳 电信
高级用户
★★
积分 774
发帖 293
注册 2003-04-16 00:00
UID 1579
性别 男
来自 湖北仙桃
状态 离线
不能在移动鼠标时退出,不能驻留内存。
下载
09年7月7日 更新
感谢网友 囧HQY 提供空间
7 发表于 2009-09-14 06:19 ·  中国 广东 梅州 电信
银牌会员
★★★★
SuperCleaner
积分 2,362
发帖 1,133
注册 2008-02-02 21:36
UID 110072
性别 男
状态 离线
学没多久,不会,多多指教啊~
什么是驻留内存
8 发表于 2010-04-20 16:22 ·  中国 四川 成都 联通
新手上路
积分 8
发帖 4
注册 2010-04-06 14:01
UID 163896
性别 男
状态 离线
这么好,看看
9 发表于 2010-04-20 22:35 ·  中国 北京 北京延庆县 联通
新手上路
积分 2
发帖 1
注册 2010-02-24 03:02
UID 161091
性别 男
状态 离线
这么好,看看
10 不错 发表于 2010-04-26 21:05 ·  中国 湖南 株洲 醴陵市 电信
新手上路
积分 2
发帖 1
注册 2010-04-20 16:06
UID 165054
性别 男
状态 离线
收下了!
11 发表于 2010-05-05 18:21 ·  中国 江苏 苏州 电信
新手上路
积分 17
发帖 8
注册 2010-01-03 14:09
UID 157870
性别 男
状态 离线
看看的哦 可惜了 不怎么会用
12 发表于 2010-10-25 11:47 ·  中国 广东 中山 电信
新手上路
积分 16
发帖 7
注册 2010-10-18 16:29
UID 176067
性别 男
状态 离线
做的不错
13 发表于 2010-11-01 20:52 ·  中国 浙江 宁波 电信
新手上路
积分 8
发帖 4
注册 2010-08-03 14:17
UID 171667
性别 男
状态 离线
不错的方法
14 发表于 2010-12-15 10:30 ·  中国 天津 电信
新手上路
积分 2
发帖 1
注册 2010-12-14 10:51
UID 179228
性别 男
状态 离线
下载来看看,还没看过呢…
15 发表于 2015-06-18 21:21 ·  中国 湖北 恩施土家族苗族自治州 电信
初级用户
积分 21
发帖 11
注册 2014-01-18 13:20
UID 181114
性别 男
状态 离线
不错!
论坛跳转: