这学期的线下C语言课程,大一同学们学完旋转蛇案例后(童晶:第4章 旋转蛇(《C和C++游戏趣味编程》配套教学视频)),布置了一次错觉图片生成实验的PBL,给了大家5天时间分组完成代码、ppt报告。
这次,介绍许林苗、赵嘉仪、徐琪、刘竺同学实现的Go forward together错觉。由于同学们学习C语言刚一个月,还没有正式学习数组、函数等语法知识,因此代码可能不够完善。以下提供了分步骤的实现思路、代码,大家可以参考。
首先是同学们调研的目标效果:

最终实现效果:
知乎视频 www.zhihu.com大概原理:蓝色和黄色在黑白条纹上移动,蓝色和黄色分别有一半时间的移动是不易感知的,给我们带来交替前进的错觉。
目标效果:两个小方块,在黑白条纹背景下以相同速度前进,产生一前一后交替前进的错觉。按下空格键改变背景条纹有无的状态,有背景时,会有错觉,无背景时,很明显两小方块一起前进。
1 绘制条纹背景
黑、白色方块交替绘制,当奇数时绘制黑色长方形,偶数时绘制白色长方形,最后形成黑白条纹的背景。(for循环+if语句)

#include<stdio.h>
#include<graphics.h>
#include<conio.h>
int main()
{
int height=400;//画面高度
int width=800;//画面宽度
initgraph(width,height);//打开一个画面
setbkcolor(RGB(139,139,139));//设置背景颜色为灰色
cleardevice();//以背景色清空画面
int stripe_width=width/40;
int stripe_num;
for(stripe_num=1;stripe_num<=width/stripe_width;stripe_num++)
{
if(stripe_num%2==1)
{
setfillcolor(RGB(0,0,0));//设置填充颜色为黑色
fillrectangle(stripe_width*(stripe_num-1),0,stripe_width*stripe_num,height);//绘制方块
}
else
{
setfillcolor(RGB(255,255,255));//设置填充颜色为白色
fillrectangle(stripe_width*(stripe_num-1),0,stripe_width*stripe_num,height);//绘制方块
}
}
_getch();
closegraph();
return 0;
}
2 绘制颜色不同的两个小方块
在画面左边1/3和2/3处分别绘制一个黄色和蓝色的小方块

#include<stdio.h>
#include<graphics.h>
#include<conio.h>
int main()
{
int height=400;//画面高度
int width=800;//画面宽度
initgraph(width,height);//打开一个画面
setbkcolor(RGB(139,139,139));//设置背景颜色为灰色
cleardevice();//以背景色清空画面
float stripe_width=width/40;//条纹宽度
float rect_length=stripe_width*4;//移动小方块长度
float rect_width=stripe_width*2;//移动小方块宽度
int stripe_num;//条纹数量
for(stripe_num=1;stripe_num<=width/stripe_width;stripe_num++)//绘制条纹背景
{
if(stripe_num%2==1)//奇数项为黑色
{
setfillcolor(RGB(0,0,0));//设置填充颜色为黑色
fillrectangle(stripe_width*(stripe_num-1),0,stripe_width*stripe_num,height);//绘制条纹
}
else//偶数项为白色
{
setfillcolor(RGB(255,255,255));//设置填充颜色为白色
fillrectangle(stripe_width*(stripe_num-1),0,stripe_width*stripe_num,height);//绘制条纹
}
}
setfillcolor(RGB(243,246,0));//设置填充颜色为黄色
setlinecolor(RGB(243,246,0));//设置圆盘线条颜色为黄色
fillrectangle(0,height/3,rect_length,rect_width+height/3);//绘制方块
setfillcolor(RGB(0,0,168));//设置填充颜色为蓝色
setlinecolor(RGB(0,0,168));//设置圆盘线条颜色为蓝色
fillrectangle(0,height/3*2,rect_length,rect_width+height/3*2);//绘制方块
_getch();
closegraph();
return 0;
}
3 让小方块匀速运动
把小方块的横坐标设置为变量,死循环,让小方块横坐标均匀增加。
知乎视频 www.zhihu.com#include<stdio.h>
#include<graphics.h>
#include<conio.h>
int main()
{
int height=400;//画面高度
int width=800;//画面宽度
initgraph(width,height);//打开一个画面
setbkcolor(RGB(139,139,139));//设置背景颜色为灰色
cleardevice();//以背景色清空画面
float x1=0,x2=0;
float stripe_width=width/40;//条纹宽度
float speed=1.2;
float rect_length=stripe_width*4;//移动小方块长度
float rect_width=stripe_width*2;//移动小方块宽度
int stripe_num;//条纹数量
BeginBatchDraw();//开始批量绘制
while(1)
{
x1+=speed;
x2+=speed;
cleardevice();//清空画面
for(stripe_num=1;stripe_num<=width/stripe_width;stripe_num++)//绘制条纹背景
{
if(stripe_num%2==1)//奇数项为黑色
{
setfillcolor(RGB(6,6,6));//设置填充颜色为黑色
setlinecolor(RGB(6,6,6));//设置圆盘线条颜色为黑色
fillrectangle(stripe_width*(stripe_num-1),0,stripe_width*stripe_num,height);//绘制条纹
}
else//偶数项为白色
{
setfillcolor(RGB(241,241,241));//设置填充颜色为白色
setlinecolor(RGB(241,241,241));//设置圆盘线条颜色为白色
fillrectangle(stripe_width*(stripe_num-1),0,stripe_width*stripe_num,height);//绘制条纹
}
}
setfillcolor(RGB(243,246,0));//设置填充颜色为黄色
setlinecolor(RGB(243,246,0));//设置圆盘线条颜色为黄色
fillrectangle(x1,height/4,x1+rect_length,rect_width+height/4);//绘制方块
setfillcolor(RGB(0,0,168));//设置填充颜色为蓝色
setlinecolor(RGB(0,0,168));//设置圆盘线条颜色为蓝色
fillrectangle(x2,height/4*3,x2+rect_length,rect_width+height/4*3);//绘制方块
FlushBatchDraw();//批量绘制
Sleep(10);
}
_getch();
closegraph();
return 0;
}
4 当小方块碰到边界时返回
当小方块到达边界时,速度反向,大小不变。
知乎视频 www.zhihu.com#include<stdio.h>
#include<graphics.h>
#include<conio.h>
int main()
{
int height=400;//画面高度
int width=800;//画面宽度
initgraph(width,height);//打开一个画面
setbkcolor(RGB(139,139,139));//设置背景颜色为灰色
cleardevice();//以背景色清空画面
float x1=0,x2=0;
float stripe_width=width/40;//条纹宽度
float speed=1.2;
float rect_length=stripe_width*4;//移动小方块长度
float rect_width=stripe_width*2;//移动小方块宽度
int stripe_num;//条纹数量
BeginBatchDraw();//开始批量绘制
while(1)
{
x1+=speed;
x2+=speed;
cleardevice();//清空画面
for(stripe_num=1;stripe_num<=width/stripe_width;stripe_num++)//绘制条纹背景
{
if(stripe_num%2==1)//奇数项为黑色
{
setfillcolor(RGB(6,6,6));//设置填充颜色为黑色
setlinecolor(RGB(6,6,6));//设置圆盘线条颜色为黑色
fillrectangle(stripe_width*(stripe_num-1),0,stripe_width*stripe_num,height);//绘制条纹
}
else//偶数项为白色
{
setfillcolor(RGB(241,241,241));//设置填充颜色为白色
setlinecolor(RGB(241,241,241));//设置圆盘线条颜色为白色
fillrectangle(stripe_width*(stripe_num-1),0,stripe_width*stripe_num,height);//绘制条纹
}
}
if(x1>=width||x1<=0)
{
Sleep(100);
speed=-speed;
}
setfillcolor(RGB(243,246,0));//设置填充颜色为黄色
setlinecolor(RGB(243,246,0));//设置圆盘线条颜色为黄色
fillrectangle(x1,height/4,x1+rect_length,rect_width+height/4);//绘制方块
setfillcolor(RGB(0,0,168));//设置填充颜色为蓝色
setlinecolor(RGB(0,0,168));//设置圆盘线条颜色为蓝色
fillrectangle(x2,height/4*3,x2+rect_length,rect_width+height/4*3);//绘制方块
FlushBatchDraw();//批量绘制
Sleep(10);
}
_getch();
closegraph();
return 0;
}
5 按下空格键改变条纹背景状态
当按下空格键时,条纹消失,再按一次,条纹背景恢复
知乎视频 www.zhihu.com#include<stdio.h>
#include<graphics.h>
#include<conio.h>
int main()
{
int height=400;//画面高度
int width=800;//画面宽度
initgraph(width,height);//打开一个画面
setbkcolor(RGB(139,139,139));//设置背景颜色为灰色
cleardevice();//以背景色清空画面
int x=1,count=0;//条纹状况
float x1=0,x2=0;//黄,蓝小方块的横坐标
float stripe_width=width/40;//条纹宽度
float speed=1.2;//小方块速度
float rect_length=stripe_width*4;//移动小方块长度
float rect_width=stripe_width*2;//移动小方块宽度
int stripe_num;//条纹数量
BeginBatchDraw();//开始批量绘制
while(1)
{
x1+=speed;//小方块横坐标匀速增加
x2+=speed;//小方块横坐标匀速增加
cleardevice();//清空画面
if(x==1)//判断是否绘制条纹背景
{
for(stripe_num=1;stripe_num<=width/stripe_width;stripe_num++)//绘制条纹背景
{
if(stripe_num%2==1)//奇数项为黑色
{
setfillcolor(RGB(6,6,6));//设置填充颜色为黑色
setlinecolor(RGB(6,6,6));//设置圆盘线条颜色为黑色
fillrectangle(stripe_width*(stripe_num-1),0,stripe_width*stripe_num,height);//绘制条纹
}
else//偶数项为白色
{
setfillcolor(RGB(241,241,241));//设置填充颜色为白色
setlinecolor(RGB(241,241,241));//设置圆盘线条颜色为白色
fillrectangle(stripe_width*(stripe_num-1),0,stripe_width*stripe_num,height);//绘制条纹
}
}
}
if(kbhit()&&count%2==0)//当按键时
{
char input=_getch();//获得输入字符
if(input=' ')//当按下空格键时
{
x=0;//改变x的值,下次按键时恢复
count++;//判断按键次数
}
}
if(kbhit()&&count%2==1)//当按键时
{
char put=_getch();//获得输入字符
if(put=' ')//当按下空格键时
{
x=1;//改变x的值,下次按键时恢复
count++;//判断按键次数
}
}
if(x1>=width||x1<=0)//当x超出边界
{
Sleep(100);//暂停100毫秒
speed=-speed;//返回
}
setfillcolor(RGB(243,246,0));//设置填充颜色为黄色
setlinecolor(RGB(243,246,0));//设置圆盘线条颜色为黄色
fillrectangle(x1,height/4,x1+rect_length,rect_width+height/4);//绘制方块
setfillcolor(RGB(0,0,168));//设置填充颜色为蓝色
setlinecolor(RGB(0,0,168));//设置圆盘线条颜色为蓝色
fillrectangle(x2,height/4*3,x2+rect_length,rect_width+height/4*3);//绘制方块
FlushBatchDraw();//批量绘制
Sleep(10);//暂停10毫秒
}
_getch();
closegraph();
return 0;
}
总结体会
通过这次小组活动,我们收获了很多。
首先,通过编写程序实现效果图不仅仅考验了我们对代码运用的熟练程度,还检验了我们逻辑思维的条理性、准确性。
其次,通过对错觉图像的呈现,我们了解到外界条件对视觉感知的影响。本组呈现的效果是通过暗色背景与亮色方块对视觉产生刺激后所形成的幻觉,而外部条件下对幻觉的形成有着重大影响。在编写程序的过程中,我们多次修改了变量,发现除去颜色外,背景黑白条纹以及移动色块的宽度也影响了视觉效果的形成。而对代码的进一步完善,又提高了我们的逻辑思维能力。
最后,便是合作。和谐的团体、明确的分工、清晰的指挥、积极的行动是本组活动顺利完成的重要因素。在团体中收获,在团体中成长,活动带给我们的不仅仅是一个作品的完成,更是加深了我们对合作共赢的认知。
以上,是本组对此次活动的总结体会。
来源:oschina
链接:https://my.oschina.net/u/4390740/blog/4704060