一、题目简述
选题灵感来源于微信小程序“跳一跳”,在游戏中,一个棋子站在跳板上,用户触摸手机屏幕时棋子蓄力,松手时棋子弹跳至下一个跳板,弹力大小由触摸时长来控制,游戏至棋子跌落跳板时结束。跳得越精准(正中板心)、踩过的跳板越多,得分越高,游戏结束时可以查看本局得分以及历史最高得分。
二、题目设计思想
我们通过TFT彩屏显示游戏画面、通过蜂鸣器输出声音,并通过触摸彩屏或者按下按键实现输入。
主函数中,游戏的初始界面显示游戏名称,提示用户按下并开始游戏。同时定时器1打开,按照音乐码表填充不同的TH1、TL1值,使蜂鸣器按不同频率振动,进而播放出音乐。
用户按下后,显示设计人员姓名,延时一段时间后,主函数调用Startgame()函数,游戏进入到主界面。游戏主界面中,屏幕显示两条红色线段分别作为起点平台和目的平台,在起点平台上的黄色小方块作为棋子,初始位置位于起点平台中央。屏幕右上角显示本局得分和最高得分。
之后,进入到while循环中等待玩家按下。玩家按下后,设置标志变量pushing=1,并且打开定时器0中断,使得每过50ms,定时器0中断服务程序使timeover=1。同时,函数进入到嵌套的while(pushing==1)循环,循环中判断如果timeover==1,调用AddTime函数,以记录时间。
AddTime()函数中,当用户按下时,变量time0=time0+50,表示按下的时间增加50ms。同时,屏幕上显示进度条表示蓄力时间,蜂鸣器振动的频率也随着蓄力时间增加而升高。
当用户松开手指时,设置pushing=0,定时结束,Startgame()跳出循环,令TR0=0,关闭定时器0。
之后,Startgame()调用JUMP()函数,函数根据蓄力时间的长短,判断棋子跳跃的轨迹,使得棋子按抛物线轨迹向上跳跃,同时屏幕上的平台向左移动。通过Delay()函数,调整移动的速度。根据棋子落点的位置,分为掉落平台、命中平台和精确命中三种情况,分别对应不同的提示语、不同的提示音以及不同的得分。当棋子掉落平台时,设置标志变量fail=1。
本轮结束之后,如果没有掉落平台,程序根据玩家此轮按下的时间,屏幕显示新的平台。
如果掉落,Startgame()调用Endgame()函数,游戏结束,显示最高得分和本轮得分,等待用户按下后开始新的一局。
三、主要代码
void Endgame()
{
music_mode=3;music_bit=0;time_count=0; //切换为fail的音乐
TFT_ClearScreen(BLACK);
if(score>topscore)
topscore=score;
music_on=1;
GUI_WriteASCII(80, 100, "FAILED", RED, BLACK);
GUI_Write32CnChar(65,220, "再来一局", WHITE, BLACK);
GUI_WriteASCII(60, 170, "score:", GREEN, BLACK);
Num2Char(score);
GUI_WriteASCII(160, 170, num2char, GREEN, BLACK);
GUI_WriteASCII(11, 145, "topscore:", GREEN, BLACK);
Num2Char(topscore);
GUI_WriteASCII(160, 145, num2char, GREEN, BLACK);
while(ReadKey()==0&&ReadTouch()==0);
GUI_WriteASCII(80, 100, "FAILED", BLACK, BLACK);
GUI_Write32CnChar(65,220, "再来一局", BLACK,BLACK);
GUI_WriteASCII(60, 170, "score:", BLACK, BLACK);
Num2Char(score);
GUI_WriteASCII(160, 170, num2char, BLACK, BLACK);
GUI_WriteASCII(11, 145, "topscore:", BLACK, BLACK);
Num2Char(topscore);
GUI_WriteASCII(160, 145, num2char, BLACK, BLACK);
x1=30,x2=70;
x0=(x1+x2)/2;
Startgame();
}
void JUMP(int x0,int y0,int distance) //distance跳跃的距离
{
int i,x=x0,y=y0; //x、y点当前位置
if(x0+distance>x1+len&&x0+distance<x2+len) fail=0;
else fail=1; //判断能否跳到平台上
for(i=0;;i++)
{
GUI_Dot(x0,y,BLACK);
x++;
y=y0+(x-x0)*(x-x0-distance)/40; //抛物线轨迹
if(i<x2+1)
{
GUI_Dot(x1-i-1,200,RED);
GUI_Dot(x2-i,200,BLACK); //起点平台的移动
}
GUI_Dot(x1+len-i-1,200,RED);
GUI_Dot(x2+len-i,200,BLACK); //目的平台的移动
GUI_Dot(x0,y,YELLOW);
Delay(5); //点的移动,Delay控制移动速度
if(y==y0&&x>x0+1&&fail==0) break;
else if(y>230)
Endgame();
}
if(x1/2+x2/2+len-x0-distance<5&&x1/2+x2/2+len-x0-distance>-5)
{
music_mode=2;music_bit=0;time_count=0; //音乐切换为bravo!的音乐
score+=4;
GUI_WriteASCII(70, y-50, "bravo!", YELLOW, BLACK);
Delay(150);
GUI_WriteASCII(70, y-50, "bravo!", BLACK, BLACK);
}
else
{
music_mode=1;music_bit=0;time_count=0; //音乐切换为good的音乐
score+=2;
GUI_WriteASCII(70, y-50, "good", WHITE, BLACK);
Delay(150);
GUI_WriteASCII(70, y-50, "good", BLACK, BLACK);
}
GUI_WriteASCII(190, 40, num2char, BLACK, BLACK);
Num2Char(score);
GUI_WriteASCII(190, 40, num2char, GREEN, BLACK);
x0=x;
x1=x1+len-distance-1;
x2=x2+len-distance-1; //目的平台变成起点平台
GUI_Line(0,200,x1-2,200,BLACK); //清除前面的线
}
void AddTime() //累计时间函数
{
if(time0>100051) //防止总时间过大
{
time0=0;
}
if(ReadKey() == 1||ReadTouch()==1) //读取按键或屏幕,如果被按下
{
time0=time0+50; //定时器刚刚计时完50ms,并且此时仍然按下,那么要为总时间加50毫秒
if(time0/100<30) //防止时间过长,超过码表里的频率上限
{
frequency=time0/100; //频率随时间增高,但有上限
}
GUI_Dot(x0+time0/35,240,BLUE);
}
else
{
if(pushing == 1)
{
pushing = 0; //更新状态为松开
music_mode=4;music_bit=0;time_count=0; //音乐定时器切回到背景音乐模式
}
}
}
void Startgame()
{
music_on=0;
GUI_Line(x1,200,x2,200,RED); //起点平台
GUI_Line(x1+len,200,x2+len,200,RED); //目标平台
GUI_Dot(x0,y0,YELLOW);
GUI_WriteASCII(40, 15, "topscore:", GREEN, BLACK);
Num2Char(topscore);
GUI_WriteASCII(190, 15, num2char, GREEN, BLACK);
score=0;
GUI_WriteASCII(90, 40, "score:", GREEN, BLACK);
Num2Char(score);
GUI_WriteASCII(190, 40, num2char, GREEN, BLACK);
while(1)
{
while(ReadKey()==0&&ReadTouch()==0); //等待按键被按下
pushing=1;time0=0;frequency=0;music_mode=0;music_bit=0;time_count=0;//做好准备
Timer0Init(); //打开定时器
while(pushing == 1) //如果处于按下的状态,进入循环
{
if(timeover == 1) //定时器刚刚定时50ms
{
timeover = 0; //timeover标志变量置零
AddTime(); //调用累加时间函数
}
}
TR0=0; //关闭定时器,(不用定时器时最好关掉,不关掉会影响运行速度和声音质量)
GUI_Line(x0,240,x0+time0/20,240,BLACK);
distance=time0/15; //跳跃距离
JUMP(x0,y0,distance); //跳跃函数,x0、y0初始位置
len=time0/20; //更改下一平台的位置
if(len<50)
len+=50;
if(len>200)
len-=50;
GUI_Line(x1+len,200,x2+len,200,RED);
}
}
跳一跳界面
程序源码: