VC 绘图/游戏简易教程
作者:bestans
整理 : kshi ft
Page 2
前言
针对人群
职业不限,水平不限,男女不限。基本上,是从很基础的层次开始(但还是需要一
点点基础)。
基础要求
希望读者已经简单学过 C 语言。我不会从定义变量开始讲。
要有英语基础,现阶段虽不是必须,但是学学英语总没错,以后有用。
学习目标
能做简单的图形小游戏。
讲解以简单实用为主,不要指望看了这几篇文章后就能过二级考试。
目标,除了能做小游戏外,更重要的,是锻炼编程思想,以备将来做更大的程序。
学习方式
以自学为主吧,有问题就在相关课程后面跟帖就行,一起讨论。
学习要求
欲速则不达,不要指望一口气都看完,请务必每次看完后都写几个相关的程序。勤
动手才能学好编程,请务必重视。
连载次数
不确定,想到哪写到哪吧,我会把每次的文章目录发到这里。
使用平台及搭建方法
请先正确安装 Visual C++ 6.0。
请到 www.easyx.cn 首页下载最新版的 EasyX,并安装。
ps: 大家希望讲解哪些方面的内容,请到百度 easyx 吧发帖
说明
关于失联党员情况说明岗位说明总经理岗位说明书会计岗位说明书行政主管岗位说明书
。只要我会的,我都会尝
试写出来。
================================我是分割線================================
本教程由 kshift 整理發佈,希望不涉及版權,聯繫方式如下:
Gtalk & E-Mail :kshift.lv@gmail.com
Blogger: http://kshift.blogspot.com/ (墙外)
Page 3
目录
前言
1:创建新项目
2:简单绘图,学习单步执行
3:熟悉更多的绘图语句
4:结合流程控制语句来绘图
5:数学知识在绘图中的运用
6:实现简单动画
7:捕获按键,实现动画的简单控制
8:用函数简化相同图案的制作
9:绘图中的位运算
10:用鼠标控制绘图/游戏程序
11:随机函数
12:数组
13:getimage / putimage / IMAGE 的用法
14:通过位运算实现颜色的分离与处理
15:窗体句柄(Windows 编程入门)
16:设备上下文句柄(Windows 编程入门 2)
Page 4
1:创建新项目
[本期目标]
学会在 VC 里面创建项目,并写简单的程序。
VC 写程序要有项目的概念,一个项目可以有多个.cpp 文件,多个项目构成一个工作区。
记住这两个英文单词吧:
Workspace: 工作区
Project: 项目
以下是创建新项目的视频演示:
http://code.google.com/p/vcgraphics/downloads/list
下载 VC6_new_project.zip,打开看看,flash 格式的。
看明白后,自己动手建立项目试试,并输入以下代码:
#include
void main()
{
printf("Hello World!");
}
尤其是之前用 TC 的同学,请务必创建新项目试一试。
学习编程必须勤动手。
然后,输入以下代码试试(无需理解代码含义):
#include
#include
void main()
{
initgraph(640, 480);
line(200, 240, 440, 240);
line(320, 120, 320, 360);
getch();
closegraph();
}
执行后应该可以看到屏幕正中央有一个十字。
看到该十字后,本节课结束。
Page 5
2:简单绘图,学习单步执行
[本期目标]
学会简单绘图,并学会简单调试。
先看看上一课的代码,我加上了注释
#include // 绘图库头文件,绘图语句需要
#include // 控制台输入输出头文件,
getch()语句需要
void main()
{
initgraph(640, 480); // 初始化 640x480的绘图屏幕
line(200, 240, 440, 240); // 画线(200,240) - (440,240)
line(320, 120, 320, 360); // 画线(320,120) - (320,360)
getch(); // 按任意键
closegraph(); // 关闭绘图屏幕
}
解释一下:
1. 创建的绘图屏幕 640x480,
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
示横向有 640 个点,纵向有 480 个点。注意:左上角是原
点(0,0),也就是说,y 轴和数学的 y 轴是相反的。
2. getch 实现按任意键功能,按任意键后,程序继续执行。否则,程序会立刻执行 closegraph
以至于看不到绘制的内容。
[作业]
用线条画出更多的图形,要求不少于 10 条直线。
[学习单步执行]
完成作业后(务必完成),开始试着单步执行刚才的程序,由于绘图和多线程等因素的限制,
请务必按照以下步骤尝试(熟练了以后就不用了):
1. 将 VC 取消最大化,并缩小窗口,能看到代码就行。
2. 按一下 F10(单步执行),会看到屏幕上出现一个黄色的小箭头,指示将要执行的代码。
3. 当箭头指向 initgraph 语句时,按 F10,能看到窗口发生了变化。
4. 将新的绘图窗口和 VC 并排放,相互不要有覆盖。这步很重要,否则绘图内容将会被 VC
窗口覆盖。
5. F10 执行 getch 后,记得激活绘图窗口,并按任意键,否则程序不会继续执行。
6. closegraph 后,直接按 F5 执行全部剩余程序,结束。
单步执行很重要,可以让你知道程序执行到哪里是什么效果,哪条语句执行出了问题等等。
更详细的调试资料,请打开:
http://code.google.com/p/vcgraphics/downloads/list
Page 6
下载里面的 VC6_how_to_debug.zip
该文档写的调试的东西比较多,看一下大概有个了解,以后都会用到(不过以后我就不再讲
了)
[作业 2]
仍然是写一个用直线绘制的图形,并熟悉调试过程。
注:
1. 许多学校都忽略了调试部分,如果你不曾用过调试,请务必熟练该过程。
2. win-tc 不带有任何调试功能,即便你不用 vc,也请不要使用 win-tc。调试是相当相当
重要的。
Page 7
3:熟悉更多的绘图语句
[学习目标]
学会更多的绘图语句
[常用的绘图语句]
line(x1, y1, x2, y2); // 画直线 (x1,y1)-(x2,y2),都是整形
circle(x, y, r); // 画圆,圆心为(x,y),半径为 r
putpixel(x, y, c); // 画点(x,y),颜色 c
还有很多,如画椭圆、圆弧、矩形、多边形,等等,请参考绘图帮助文件(
第一课
旧约精览一百步肺炎基本知识第八章运动和力知识点六上学与问第一课时开学第一课收心教育
的绘图库
的下载里面有)
[设置颜色]
setcolor(c); // 设置绘图颜色,如 setcolor(RED)设置为红色等
常用的颜色常量可以用:
BLACK 黑 DARKGRAY 深灰
BLUE 蓝 LIGHTBLUE 亮蓝
GREEN 绿 LIGHTGREEN 亮绿
CYAN 青 LIGHTCYAN 亮青
RED 红 LIGHTRED 亮红
MAGENTA 紫 LIGHTMAGENTA 亮紫
BROWN 棕 YELLOW 黄
LIGHTGRAY 浅灰 WHITE 白
[配出更多的颜色]
颜色除了前面写的 16 种以外,还可以自由配色。格式:
RGB(r, g, b)
r / g / b 分别表示红色、绿色、蓝色,范围都是 0~255。
例如,RGB(255,0,0) 表示纯红色。
红色和绿色配成黄色,因此 RGB(255,255,0) 表示黄色。
嫌调色麻烦可以用画笔里面的调色试试,调好了以后直接将数值抄过来就行。
例如,画两条红色浓度为 200 的直线,可以写:
setcolor(RGB(200,0,0));
line(100,100, 200,100);
line(100,120, 200,120);
[用数字表示颜色]
除了用 RGB(r,g,b)方式外,还可以用 16 进制表示颜色,格式:
0xrrggbb
例如,setcolor(0xff0000) 和 setcolor(RGB(255,0,0)) 是等效的。
Page 8
[延时语句]
这个很简单 Sleep(n) 就可以表示 n 毫秒的延时。例如延时 3 秒,可以用 Sleep(3000);
[作业]
1. 简单看一下绘图库的帮助文件,了解更多的绘图语句。
2. 绘制更丰富的图形内容,不低于 20 行。
3. 将延时语句适当的插入上个作业的代码中,看看执行效果。
注:绘图语句不需要记住,用的时候翻翻手册就行。
Page 9
4:结合流程控制语句来绘图
[学习目标]
熟练使用循环、判断语句
[熟悉 for语句]
这步需要自学,看看自己手边的书,是怎样讲 for 语句的,简单看看就行。
[范例]
例如,画 10 条直线的代码:
#include
#include
void main()
{
initgraph(640, 480);
for(int y=100; y<200; y+=10)
line(100, y, 300, y);
getch();
closegraph();
}
换一下循环的范围和间隔,看看效果。
还可以用来画渐变色,例如:
#include
#include
void main()
{
initgraph(640, 480);
for(int y=0; y<256; y++)
{
setcolor(RGB(0,0,y));
line(100, y, 300, y);
}
getch();
closegraph();
}
Page 10
[熟悉 if语句]
这步需要自学,看看自己手边的书,是怎样讲 if 语句的,简单看看就行。
配合if语句,实现红色、蓝色交替画线:
#include
#include
void main()
{
initgraph(640, 480);
for(int y=100; y<200; y+=10)
{
if ( y/10 % 2 == 1) // 判断奇数行偶数行
setcolor(RGB(255,0,0));
else
setcolor(RGB(0,0,255));
line(100, y, 300, y);
}
getch();
closegraph();
}
[作业]
1. 画围棋棋盘。
2. 画中国象棋的棋盘
3. 画国际象棋的棋盘,看手册找到颜色填充语句,实现过期象棋棋盘的区块填充。
4. 自学 while 语句。
学到这里,已经可以画出很多东西了。把自己想象中的图案绘制一下吧。
Page 11
5:数学知识在绘图中的运用
[学习目标]
理解数学的重要性
1. 最简单的,来个全屏的渐变色吧,是上一课的扩展。就是需要将 0~255 的颜色和 0~479
的 y 轴对应起来;c 表示颜色,范围 0~255;y 表示 y 轴,范围 0~479
于是:
c / 255 = y / 479
c = y / 479 * 255 = y * 255 / 479 (先算乘法再算除法可以提高精度)
看代码:
#include
#include
void main()
{
initgraph(640, 480);
int c;
for(int y=0; y<480; y++)
{
c = y * 255 / 479;
setcolor(RGB(0,0,c));
line(0, y, 639, y);
}
getch();
closegraph();
}
试试效果吧。
2. 画一个圆形的渐变色
首先,我们要用到圆形的基本公式:
x*x + y*y = r*r
让弧度从 0~2*3.14,然后需要根据弧度和半径算出(x,y),
用 pi 表示圆周率
用 r 表示半径
用 a 表示弧度(小数)
用 c 表示颜色
于是:
x=r*cos(a)
y=r*sin(a)
c=a*255/(2*pi)
Page 12
看看代码:
#include
#include
#include
void main()
{
initgraph(640, 480);
int c;
double a;
int x, y, r=200;
for(a=0; a
#include
void main()
{
initgraph(640, 480);
for(int y=0; y<480; y++)
{
// 绘制绿色直线
setcolor(GREEN);
line(0, y, 639, y);
// 延时
Sleep(10);
// 绘制黑色直线(即擦掉之前画的绿线)
setcolor(BLACK);
line(0, y, 639, y);
}
closegraph();
}
Page 14
再看一个例子,实现一个圆从左往右跳动:
#include
#include
void main()
{
initgraph(640, 480);
for(int x=100; x<540; x+=20)
{
// 绘制黄线、绿色填充的圆
setcolor(YELLOW);
setfillstyle(GREEN);
fillellipse(x, 100, 20, 20);
// 演示
Sleep(500);
// 绘制黑线、黑色填充的圆
setcolor(BLACK);
setfillstyle(BLACK);
fillellipse(x, 100, 20, 20);
}
closegraph();
}
也就是说,移动的间距小、延时短,动画就会越细腻。但当画面较复杂时,会带来画面的闪
烁(怎样消除闪烁是以后的话题)。
[作业]
绘制一个沿 45 度移动的球,碰到窗口边界后反弹。
Page 15
7:捕获按键,实现动画的简单控制
最常用的一个捕获按键的函数:getch()
前几课,都把这个函数当做“按任意键继续”来用,现在我们用变量保存这个按键:
char c = getch();
然后再做判断即可。
不过程序执行到 getch() 是会阻塞的,直到用户有按键才能继续执行。可游戏中总不能因
为等待按键而停止游戏执行吧?所以,要有一个函数,判断是否有用户按键:kbhit()
这个函数返回当前是否有用户按键,如果有,再用 getch() 获取即可,这样是不会阻塞的。
即:
char c;
if (kbhit())
c = getch();
举一个简单的例子,如果有按键,就输出相关按键。否则,输出“.”。每隔 100 毫秒输出
一次。按 ESC 退出。
注:ESC 的 ASCII 码是 27。
完整代码如下:
#include
#include
#include
void main()
{
char c = 0;
while(c != 27)
{
if (kbhit())
c = getch();
else
c = '.';
printf("%c", c);
Sleep(100);
}
}
Page 16
结合上一课的简单动画,就可以做出来靠按键移动的图形了吧,看以下代码,实现 a s 控
制圆的左右移动:
#include
#include
void main()
{
initgraph(640, 480);
int x = 320;
// 画初始图形
setcolor(YELLOW);
setfillstyle(GREEN);
fillellipse(x, 240, 20, 20);
char c;
while(c != 27) // 获取按键
{
c = getch();
// 先擦掉上次显示的旧图形
setcolor(BLACK);
setfillstyle(BLACK);
fillellipse(x, 240, 20, 20);
// 根据输入,计算新的坐标
switch(c)
{
case 'a': x-=2; break;
case 'd': x+=2; break;
case 27: break;
}
// 绘制新的图形
setcolor(YELLOW);
setfillstyle(GREEN);
fillellipse(x, 240, 20, 20);
// 延时
Sleep(10);
}
closegraph();
}
Page 17
[作业]
请继续完成这个程序,实现以下功能:
1. 上下的控制;
2. 边界检测;
3. 结合 kbhit 实现惯性移动(即按一下方向键,圆就会一直向这个方向移动)
注:上下左右等按键的控制,会返回 2 个字符。由于该系列教程面向初学者,因此有兴趣
的请查看 MSDN。
Page 18
8:用函数简化相同图案的制作
总目录:http://hi.baidu.com/bestans/blog/item/341c0513efb7dd72cb80c4c6.html
(里面包括 VC 下的 graphics.h 的配置方法)
实际中有许多类似的图案,如果一一单独绘制,太麻烦。于是,我们需要一个公用的绘制过
程,就是函数。
例如,我们需要画 5 个三角形,位于不同的位置。我们可以将绘制单个三角形的过程写成函
数,函数内是一个独立的程序段,这个绘制过程很简单。
然后,在需要绘制的时候,调用这个函数即可。可以通过参数来解决细微差异(图案的坐标、
颜色等),例如:
#include
#include
// 在坐标 (x,y) 处,用颜色 c 绘制三角形
void sanjiaoxing(int x, int y, int c)
{
// 设置画线颜色
setcolor(c);
// 画三角形的三条边
line(x, y, x+50, y);
line(x, y, x, y+50);
line(x+50, y, x, y+50);
}
void main()
{
initgraph(640, 480); // 初始化图形窗口
sanjiaoxing(100, 100, RED);
sanjiaoxing(120, 160, BLUE);
sanjiaoxing(140, 220, GREEN);
sanjiaoxing(160, 120, BLUE);
sanjiaoxing(160, 160, GREEN);
sanjiaoxing(220, 140, GREEN);
getch(); // 按任意键继续
closegraph(); // 关闭图形窗口
}
Page 19
再结合循环等控制条件,就能绘制更复杂漂亮的图案了。试试运行下面程序,理解一下函数
的用处:
#include
#include
void sanjiaoxing(int x, int y, int color)
{
// 设置画线颜色
setcolor(color);
// 画三角形的三条边
line(x, y, x+10, y);
line(x, y, x, y+10);
line(x+10, y, x, y+10);
}
void main()
{
initgraph(640, 480); // 初始化图形窗口
for(int x=0; x<640; x+=10)
for(int y=0; y<480; y+= 10)
sanjiaoxing(x, y, RGB(x*255/640, y*255/480, 0));
getch(); // 按任意键继续
closegraph(); // 关闭图形窗口
}
Page 20
运行效果:
本节作业:
1. 绘制 Windows 自带游戏“扫雷”的初始界面。
Page 21
9:绘图中的位运算
教程总目录:
http://hi.baidu.com/bestans/blog/item/341c0513efb7dd72cb80c4c6.html (里面有 vc
下的 graphics.h 的下载及配置)
======================================================================
位运算和绘图有什么关系?先举个例子来个感性认识:使用 XOR 运算可以实现擦除图形后不
破坏背景,这在时钟程序中绘制表针是很有用的。稍后我们会给出这样的例子。
[位运算的运算法则]
位运算主要分 4 种:NOT、AND、OR、XOR
位运算的运算对象是二进制数(十进制要转换为二进制,计算机会自动转换)。
运算法则如下:
1. NOT
表示“取反”,将二进制位的 1 变 0、0 变 1。
C 语言用符号 ~ 表示。
如:
二进制: ~1101 = 0010
用十进制表示就是:~13 = 2
2. AND
表示“并且”,只有两数的对应二进制位都为 1,结果的二进制位才为 1;否则,结果的二
进制位为 0。
C 语言用符号 & 表示。
如:
二进制:1101 & 0110 = 0100
用十进制表示就是:13 & 6 = 4
3. OR
表示“或者”,两数的对应二进制位只要有一个是 1,结果的二进制位就是 1;否则,结果
的二进制位为 0。
C 语言用符号 | 表示。
如:
二进制:0101 | 0110 = 0111
用十进制表示就是:5 | 6 = 7
4. XOR
表示“异或”,两数的对应二进制位不同,结果的二进制位为 1;相同,结果的二进制位为
0。
C 语言用符号 ^ 表示。
Page 22
如:
二进制:0101 ^ 1110 = 1011
以上只是简单介绍一下,详细的还是请大家看课本上的讲解。
[位运算的应用]
位运算的应用很多,例如 AND 和 OR 在获取和设置标志位时经常使用。更多的,以后大家
会逐渐遇到,暂时先记下有这么回事。
这里着重说一下 XOR 运算,它有一个重要的特性:
(a ^ b) ^ b = a
也就是说,a ^ b 之后可能是某些其它数字,但是只要再 ^b 一下,就又成了 a。
一些简单的加密就用的 XOR 的这个特性。
至于绘图,假如 a 是背景图案,b 是将要绘制的图案,只要用 XOR 方式绘图,连续绘两次,
那么背景是不变的。
[演示]
我们来一个简单的绘图 XOR 运算演示:
#include
#include
void main()
{
initgraph(640, 480); // 初始化 640 x 480 的绘图窗口
setlinestyle(PS_SOLID, NULL, 10); // 设置线宽为 10,这样效果明显
rectangle(100,100,200,200); // 画一个矩形,当做背景图案
setwritemode(R2_XORPEN); // 设置 XOR 绘图模式
setcolor(RED); // 设置画线颜色
line(50,0, 200,300); // 画线
getch(); // 等待按任意键
line(50,0, 200,300); // 画线(XOR 方式重复画线会恢复背景图案)
getch(); // 等待按任意键
closegraph(); // 关闭绘图窗口
}
运行一下,看到第一次画线后,矩形与直线相交的部分,颜色变成了青色,青色就是白色和
红色 XOR 的值。当再次以红色画线时,青色部分消失了,还原为完整的白色矩形框。
Page 23
[完整的范例]
来一个相对完整的范例吧,就是钟表程序,三个表针用的都是 XOR 方式绘制,请大家运行
体会一下 XOR 的作用:
#include
#include
#include
void Draw(int hour, int minute, int second)
{
double a_hour, a_min, a_sec; // 时、分、秒针的弧度值
int x_hour, y_hour, x_min, y_min, x_sec, y_sec; // 时、分、秒针的末端位置
// 计算时、分、秒针的弧度值
a_sec = second * 2 * PI / 60;
a_min = minute * 2 * PI / 60 + a_sec / 60;
a_hour= hour * 2 * PI / 12 + a_min / 12;
// 计算时、分、秒针的末端位置
x_sec = 320 + (int)(120 * sin(a_sec));
y_sec = 240 - (int)(120 * cos(a_sec));
x_min = 320 + (int)(100 * sin(a_min));
y_min = 240 - (int)(100 * cos(a_min));
x_hour= 320 + (int)(70 * sin(a_hour));
y_hour= 240 - (int)(70 * cos(a_hour));
// 画时针
setlinestyle(PS_SOLID, NULL, 10);
setcolor(WHITE);
line(320, 240, x_hour, y_hour);
// 画分针
setlinestyle(PS_SOLID, NULL, 6);
setcolor(LIGHTGRAY);
line(320, 240, x_min, y_min);
// 画秒针
setlinestyle(PS_SOLID, NULL, 2);
setcolor(RED);
line(320, 240, x_sec, y_sec);
}
void main()
{
initgraph(640, 480); // 初始化 640 x 480 的绘图窗口
Page 24
// 绘制一个简单的表盘
circle(320, 240, 2);
circle(320, 240, 60);
circle(320, 240, 160);
outtextxy(296, 300, "BestAns");
// 设置 XOR 绘图模式
setwritemode(R2_XORPEN); // 设置 XOR 绘图模式
// 绘制表针
SYSTEMTIME ti; // 定义变量保存当前时间
while(!kbhit()) // 按任意键退出钟表程序
{
GetLocalTime(&ti); // 获取当前时间
Draw(ti.wHour, ti.wMinute, ti.wSecond); // 画表针
Sleep(1000); // 延时 1 秒
Draw(ti.wHour, ti.wMinute, ti.wSecond); // 擦表针(擦表针和
画表针的过程是一样的)
}
closegraph(); // 关闭绘图窗口
}
[作业]
最后给出的绘制时钟的例子,很不完善,有不少问题。请完善该程序。例如样式上,表盘上
没有刻度,没有数字,指针靠中心的一端应该长出来一点点,表盘太简单。还有就是尝试发
现并改进功能实现上的问题。
Page 25
10:用鼠标控制绘图 /游戏程序
教程总目录:http://hi.baidu.com/bestans/blog/item/341c0513efb7dd72cb80c4c6.html
(里面包括 VC 下的 graphics.h 的配置方法)
学习本节课前,需要熟练掌握第 7 节。详见:
http://hi.baidu.com/bestans/blog/item/487a13c0a5b3ac170ff477cf.html
======================================================================
捕获鼠标消息就像捕获按键消息一样简单。
对于按键,通常我们会先检查是否有按键,然后定义一个变量保存按键,再然后根据该按键
的值,执行相应的程序。
对于鼠标,道理是一样的。
先写个代码对比一下:
获取按键: 获取鼠标:
char c; MOUSEMSG m;
if (kbhit()) if (MouseHit())
c = getch(); m = GetMouseMsg();
很简单吧。由于鼠标消息的内容太多,不像按键那么简单,因此需要用一个结构体来保存。
通过该结构体,我们可以获取鼠标的如下信息:
struct MOUSEMSG
{
UINT uMsg; // 当前鼠标消息
bool mkCtrl; // Ctrl 键是否按下
bool mkShift; // Shift 键是否按下
bool mkLButton; // 鼠标左键是否按下
bool mkMButton; // 鼠标中键是否按下
bool mkRButton; // 鼠标右键是否按下
int x; // 当前鼠标 x 坐标
int y; // 当前鼠标 y 坐标
int wheel; // 鼠标滚轮滚动值
};
其中,“当前鼠标消息”可能是以下值:
WM_MOUSEMOVE 鼠标移动消息
WM_MOUSEWHEEL 鼠标滚轮拨动消息
Page 26
WM_LBUTTONDOWN 左键按下消息
WM_LBUTTONUP 左键弹起消息
WM_LBUTTONDBLCLK 左键双击消息
WM_MBUTTONDOWN 中键按下消息
WM_MBUTTONUP 中键弹起消息
WM_MBUTTONDBLCLK 中键双击消息
WM_RBUTTONDOWN 右键按下消息
WM_RBUTTONUP 右键弹起消息
WM_RBUTTONDBLCLK 右键双击消息
例如,判断获取的消息是否是鼠标左键按下,可以用:
if (m.uMsg == WM_LBUTTONDOWN) ...
下面举一个综合的例子(我偷点懒,直接粘贴的绘图库帮助里面的鼠标范例),该程序会用
红色的点标出鼠标移动的轨迹,按左键画一个小方块,按 Ctrl+左键画一个大方块,按右键
退出:
#include
#include
#include
void main()
{
// 初始化图形窗口
initgraph(640, 480);
MOUSEMSG m; // 定义鼠标消息
while(true)
{
// 获取一条鼠标消息
m = GetMouseMsg();
switch(m.uMsg)
{
case WM_MOUSEMOVE:
// 鼠标移动的时候画红色的小点
putpixel(m.x, m.y, RED);
break;
case WM_LBUTTONDOWN:
// 如果点左键的同时按下了 Ctrl 键
if (m.mkCtrl)
Page 27
// 画一个大方块
rectangle(m.x-10, m.y-10, m.x+10, m.y+10);
else
// 画一个小方块
rectangle(m.x-5, m.y-5, m.x+5, m.y+5);
break;
case WM_RBUTTONUP:
return; // 按鼠标右键退出程序
}
}
// 关闭图形窗口
closegraph();
}
[本节作业]
1. 画一个填充的三角形,要用鼠标点选三角形的三个顶点。提示:可以用 fillpoly 函数
画多边形。
2. 写一个“格子涂色”的游戏,要求:屏幕上有 16x8 的格子,屏幕底部有类似画笔中的选
色区(随便放上一些常用的颜色),鼠标点击选择区的颜色后,就作为当前颜色,然后再点
屏幕上的格子,就可以用刚才的颜色填涂相应格子。
Page 28
11:随机函数
教程总目录:http://hi.baidu.com/bestans/blog/item/341c0513efb7dd72cb80c4c6.html
(里面包括 VC 下的 graphics.h 的配置方法)
======================================================================
[随机函数简介]
游戏中,许多情况都是随即发生的。还有一些图案程序,例如屏保,也是随即运动的。这就
需要用随机函数。
随机函数很简单,只有一个:
rand()
该函数返回 0~32767 之间的一个整数。(不需要记住 32767 这个数字,大概知道这个范围
就行了)
该函数在头文件 中,使用前记得引用。
[简单测试]
来写个程序测试一下:
#include
#include
void main()
{
int r;
for(int i=0; i<10; i++)
{
r = rand();
printf("%d\n", r);
}
}
执行后,可以看到输出了 10 个随机数字。
[指定范围的随机函数]
实际中,我们经常要产生指定范围的随机函数,通常我们用求余数的
办法
鲁班奖评选办法下载鲁班奖评选办法下载鲁班奖评选办法下载企业年金办法下载企业年金办法下载
。例如,产生 0~
9 之间的随机数,只需要将任意产生的随机数除以 10 求余数即可。求余数的运算符号是 %,
我们可以这样做:
r = rand() % 10;
Page 29
修改前面的测试程序执行后可以看到,产生的数字都是小于 10 的。
如果是 1~6 之间的怎样求呢?
r = rand() % 6 + 1;
无论产生什么样范围的随机函数,都是通过各种运算将随机数的范围 [0, 32767] 修改为自
己需要的范围。
[随机种子]
做了多次试验,我们会发现一个问题:虽然产生的数字是随机的,但每次产生的数字序列都
一样。为了解决这个问题,我们需要用“随机种子”。
随机函数的产生原理简单来说,就是:前一个随机函数的值,决定下一个随机函数的值。
根据这个原理我们可以知道:只要第一个随机函数的值确定了,那么后面数字序列就是确定
的。如果我们想的得到不同的数字序列,我们需要确定第一个随机函数的值,对于设置第一
个随机函数的值,叫做设置“随机种子”。易知,随机种子设置一次即可。
设置随机种子的函数如下:
srand(种子);
通常,我们用当前时间来做随机种子:
srand( (unsigned)time( NULL ) );
因为使用 time 函数,所以记得引用 。
[绘图中的应用]
来一个简单的程序,在屏幕上任意位置画任意颜色的点(按任意键退出):
#include
#include
#include
#include
void main()
{
srand( (unsigned)time( NULL ) );
initgraph(640, 480);
int x, y, c;
while(!kbhit())
{
Page 30
x = rand() % 640;
y = rand() % 480;
c = RGB(rand() % 256, rand() % 256, rand() % 256);
putpixel(x, y, c);
}
closegraph();
}
[作业]
1. 回顾一下第 6 课“实现简单动画”的作业:绘制一个沿 45 度移动的球,碰到窗口边界
后反弹。
将这个球改为任意方向运动,碰到边界后任意反弹。
Page 31
12:数组
教程总目录:http://hi.baidu.com/bestans/blog/item/341c0513efb7dd72cb80c4c6.html
(里面包括 VC 下的 graphics.h 的配置方法)
======================================================================
课程要求:先复习下课本上对数组的讲解(随便一本教材都行)
[一维数组]
数组可以实现批量操作。比如,我们产生 10 个随机数,产生后先保存起来,然后输出最大
的:
int n[10];
int i;
for (i=0; i<10; i++)
n[i] = rand() % 1000;
// 按生成的顺序,逆序输出
for (i=9; i>=0; i--)
printf("%d\n", n[i]);
// 找出最大的
int max = -1;
for (i=0; i<10; i++)
{
if (n[i] > max)
max = n[i];
}
printf("最大的数字是:%d\n", max);
看明白这个程序后,我们继续。