今天给大家带来一个青蛙过河小游戏代码,先看看效果吧!
开始界面:
游戏界面 :
游戏中界面:
胜利界面:
死亡界面: 代码我们分了几个模块来写,这样不容易写乱,也方便后续修改
木板模块:
#include "stdafx.h"
void createBoard(BoardType board[],int channel,int interval)
{
for(int i=0;i<BOARD_AMOUNT;i++)
{
if(0==board[channel].b[i].onMap)//不在地图上
{
if(1==(channel+1)%2)//第一和第三道,从右来
{
if(0==i)//第一个
{board[channel].b[i].x=board[channel].b[BOARD_AMOUNT-1].x+BOARD_LEN+interval;}
else
{board[channel].b[i].x=board[channel].b[i-1].x+BOARD_LEN+interval;}
}
else//第二和第四道,从左来
{
if(0==i)//第一个
{board[channel].b[i].x=board[channel].b[BOARD_AMOUNT-1].x-BOARD_LEN-interval;}
else
{board[channel].b[i].x=board[channel].b[i-1].x-BOARD_LEN-interval;}
}
board[channel].b[i].onMap=1;//注册为在地图上
break;
}
}
}
void initBoard(BoardType b[])//给每个木版分配坐标
{
int ch;//河道数
int i=0;//只创建第一条船
for(ch=0;ch<CHANNEL_AMOUNT;ch++)
{
if(1==(ch+1)%2)//第一和第三道,从右来
{
b[ch].b[i].x=WINDOW_LEN+(i+1)*(BOARD_INTERVAL+BOARD_LEN);
b[ch].b[i].onMap=1;
}
else//第二和第四道
{
b[ch].b[i].x=0-((i+1)*(BOARD_INTERVAL+BOARD_LEN));
b[ch].b[i].onMap=1;
}
}
//初始化其他木板
for(ch=0;ch<CHANNEL_AMOUNT;ch++)
{
if(1==(ch+1)%2)//第一和第三道,从右来
{
for(i=1;i<BOARD_AMOUNT;i++)
{
b[ch].b[i].x=b[ch].b[i-1].x+(BOARD_INTERVAL+BOARD_LEN);
b[ch].b[i].onMap=1;
}
}
else//第二和第四道
for(i=1;i<BOARD_AMOUNT;i++)
{
b[ch].b[i].x=b[ch].b[i-1].x-(BOARD_INTERVAL+BOARD_LEN);
b[ch].b[i].onMap=1;
}
}
}
void moveBoard(BoardType board[],int speed[],FrogType *frog)//移动木板
{
if(frog->state!=DEAD){//死亡延时期间不移动木板
for(int ch=0;ch<CHANNEL_AMOUNT;ch++)
{
if(1==(ch+1)%2)
{
for(int i=0;i<BOARD_AMOUNT;i++)
{
board[ch].b[i].x-=speed[ch];//一三道
}
}
else
{
for(int i=0;i<BOARD_AMOUNT;i++)
{
board[ch].b[i].x+=speed[ch];//二四道
}
}
}
}
}
void boardOutRange(BoardType board[])//木板出界判定
{
for(int ch=0;ch<CHANNEL_AMOUNT;ch++)
{
if(1==(ch+1)%2)//一三道
{
for(int i=0;i<BOARD_AMOUNT;i++)
{
if(board[ch].b[i].x<0-BOARD_LEN)
{board[ch].b[i].onMap=0;}
}
}
else//二四道
{
for(int i=0;i<BOARD_AMOUNT;i++)
{
if(board[ch].b[i].x>WINDOW_LEN)
{board[ch].b[i].onMap=0;}
}
}
}
}
void outRangeBoardReset(BoardType board[],int interval)//重置出界的木板
{
for(int ch=0;ch<CHANNEL_AMOUNT;ch++)
{
for(int i=0;i<BOARD_AMOUNT;i++)
{
if(0==board[ch].b[i].onMap)
{
createBoard(board,ch,interval);
}
}
}
}
void drawBoard(BoardType board[],ImageType *img)//画木板
{
setfillstyle(BROWN);
int x1,y1;
for(int ch=0;ch<CHANNEL_AMOUNT;ch++)
{
for(int i=0;i<BOARD_AMOUNT;i++)
{
x1=board[ch].b[i].x;
y1=(int)(STREAM_INIT_Y+STREAM_WID-CHANNEL_WID*(ch+1)+(CHANNEL_WID-BOARD_WID)/2);
putimage(x1,y1,&(img->woodMask),SRCAND);//位与
putimage(x1,y1,&(img->wood),SRCPAINT);//位或
//背景透明\(^o^)/~
}
}
}
void excuteBoardFunc(BoardType board[],int ChannelSpeed[],FrogType *frog)
{
moveBoard(board,ChannelSpeed,frog);//移动
boardOutRange(board);//出界判定
outRangeBoardReset(board,BOARD_INTERVAL);//重置出界的木板
}
青蛙模块:
#include "stdafx.h"
#define PI 3.1415926535
#define UNIT PI/180
#include<math.h>//旋转加速度用到x平方
void initFrog(FrogType *frog)
{
frog->ch=-1;
frog->x=WINDOW_LEN/2;
frog->speed=8;
frog->life=5;
frog->passed=0;
frog->state=NORMAL;//正常
frog->coin=0;
frog->score=0;
frog->esc=0;
}
void resetFrog(FrogType *frog)
{
frog->ch=-1;
frog->x=WINDOW_LEN/2;
frog->state=NORMAL;
while(_kbhit()){_getch();}//清键盘缓存防止在死亡动画播放时按键。
}
void moveFrog(FrogType *frog,int ChannelSpeed[])
{
if(frog->state==NORMAL){//死亡则不再允许操作,也不随着河飘走
//与模板同步产生的移动
if(frog->ch>-1&&frog->ch<CHANNEL_AMOUNT)
{
if(1==((frog->ch+1)%2))
{frog->x-=ChannelSpeed[frog->ch];}
else
{frog->x+=ChannelSpeed[frog->ch];}
}
//通过键盘的移动
if(GetAsyncKeyState('A'))//获取键盘状态而非事件。
{
if(!((-1==(frog->ch))&&((frog->x)-(frog->speed)<2)))//-1道左右出界保护
{
frog->x-=frog->speed;
}
}
if(GetAsyncKeyState('D'))
{
if(!((-1==(frog->ch))&&((frog->x)+(frog->speed)>WINDOW_LEN-2)))//-1道左右出界保护
{frog->x+=frog->speed;}
}
if(GetAsyncKeyState(27))
{frog->esc=1;}
int key;
if(_kbhit())//当键盘按键事件时
{
key=_getch();
switch(key)
{
case 'w':frog->ch+=1;
break;
case 's':
{
if((frog->ch)>-1)//下出界保护
{
frog->ch-=1;
}
break;
}
}
}
}
}
void frogOutRange(FrogType *frog,BoardType board[])//青蛙出界(或死亡、过关)判定
{
int ch=frog->ch;
if((frog->x)<0||(frog->x)>WINDOW_LEN)//1234道出界
{frog->state=DEAD;}
if((ch>-1)&&(ch<CHANNEL_AMOUNT))//在河道里
{
int fall=1;//落水判定
int boardPosi;//木板左上角坐标
for(int i=0;i<BOARD_AMOUNT;i++)//落水判定
{
boardPosi=board[ch].b[i].x;
if(frog->x>boardPosi&&frog->x<boardPosi+BOARD_LEN)//在木板上
{
fall=0;
break;
}
}
if(1==fall)
{
frog->state=DEAD;
}//落水则死亡
}
if(CHANNEL_AMOUNT==ch)//上岸判定,河道数量就是河道下标+1,实际上是最后一道
{frog->state=PASSED;}//上岸
}
void excuteFrogFunc(FrogType *frog,int ChannelSpeed[],BoardType board[])//青蛙操作综合
{
moveFrog(frog,ChannelSpeed);
frogOutRange(frog,board);
}
void channelSpeedUp(int ChannelSpeed[])//河加速
{
static int channel=0;
if(4==channel){channel=0;}//重置
ChannelSpeed[channel]+=2;//2是速度提升基数
channel++;
}
void drawFrog(FrogType *frog,ImageType *img)
{
int x1=frog->x;//右上角(判定用)坐标
int y1=WINDOW_WID-(CHANNEL_WID/2)-(frog->ch+1)*CHANNEL_WID;
int x2=x1-FROG_LEN/2;
int y2=y1-FROG_WID/2;
static double radian;//旋转用的弧度
static double var=1;//变量,理解成log10x的x
static double x=0;//变量,过关的sin函数用的
static IMAGE f,fm;
if(frog->state==NORMAL){
//三元光栅,计算背景透明色
putimage(x2,y2,&(img->frog0Mask),SRCAND);//掩码和背景按位与
putimage(x2,y2,&(img->frog0),SRCPAINT);//图像与(掩码和背景按位与的结果)按位或
var=1;//变量重置
x=0;
}
else if(frog->state==DEAD){//旋转
radian=UNIT*(pow(var,2.4));//增加量扩大的系数,用的是平方图像
var+=0.2;
rotateimage(&f,&img->frog0,radian,BLACK);//黑背景
rotateimage(&fm,&img->frog0Mask,radian,WHITE);//掩码白背景
putimage(x2,y2,&fm,SRCAND);//掩码和背景按位与
putimage(x2,y2,&f,SRCPAINT);//图像与(掩码和背景按位与的结果)按位或
}
else if(frog->state==PASSED)//过关
{
radian=(PI/1.5)*sin(1.5*x);
x+=PI/30;
rotateimage(&f,&img->frog0,radian,BLACK);//黑背景
rotateimage(&fm,&img->frog0Mask,radian,WHITE);//掩码白背景
putimage(x2,y2,&fm,SRCAND);//掩码和背景按位与
putimage(x2,y2,&f,SRCPAINT);//图像与(掩码和背景按位与的结果)按位或
}
}
void excuteEvent(FrogType *frog,int ChannelSpeed[],ImageType *img)//执行过关或重置等EVENT
{
int state=frog->state;
switch(state)
{
case DEAD:
{
static int dTimer=0;//死亡时显示位置
if(DEATH_DELAY==dTimer){
resetFrog(frog);
dTimer=0;
frog->life-=1;
frog->score-=10;
int flag=1;//是否减速
for(int i=0;i<CHANNEL_AMOUNT;i++)
{
if(1==ChannelSpeed[i])
{
flag=0;//有速度是1的河道
break;
}
}
if(flag)//减速
{
for(int i=0;i<CHANNEL_AMOUNT;i++)//死亡导致河流减速
{ChannelSpeed[i]-=1;}
}
}
else
{dTimer++;}
if(0==frog->life){frog->esc=1;}//生命为0则退出
break;//switch case的break
}
case PASSED:
{
static int pTimer=0;//过关时显示位置
if(PASS_DELAY==pTimer){
pTimer=0;//计时器重置
int CSSum=0;
for(int i=0;i<CHANNEL_AMOUNT;i++)//河流速度总和
{CSSum+=ChannelSpeed[i];}
frog->passed+=1;
frog->coin+=CSSum;
frog->score+=(CSSum);
channelSpeedUp(ChannelSpeed);
resetFrog(frog);
}
else
{pTimer++;}
break;
}
}
}
定义控制台应用程序的入口点:
#include "stdafx.h"
#include "funcdef.h"//自定义的函数
int _tmain(int argc, _TCHAR* argv[])
{
//图像对象
ImageType img;
initImage(&img);//加载图像
int ChannelSpeed[CHANNEL_AMOUNT];//={2,2,2,2};//河道水流速度
BoardType board[CHANNEL_AMOUNT];//木板类型
FrogType frog;//青蛙对象
initgraph(WINDOW_LEN+STATE_BAR_LEN,WINDOW_WID);//初始化图形界面
while(initWelcome(&img))//欢迎界面
{
//开始游戏
for(int i=0;i<CHANNEL_AMOUNT;i++){
ChannelSpeed[i]=2;//河道水流速度重置
}
initBoard(board);
initFrog(&frog);
initFont();
while(!frog.esc)
{
BeginBatchDraw();//批量绘图开始
//对木板的操作
excuteBoardFunc(board,ChannelSpeed,&frog);
//对青蛙的操作
excuteFrogFunc(&frog,ChannelSpeed,board);
//状态栏
excuteStateBarFunc(&frog,ChannelSpeed);
//关卡事件
excuteEvent(&frog,ChannelSpeed,&img);
drawStream(&img);//画河
drawBackground(&img);//画背景
drawBoard(board,&img);//画船
drawFrog(&frog,&img);//画青蛙
excuteStateBarFunc(&frog,ChannelSpeed);//状态栏
FlushBatchDraw();//批量绘图输出
Sleep(TICK);
}
EndBatchDraw();
}
closegraph();
return 0;
}
void initImage(ImageType *img)//加载图片
{
loadimage(&(img->frog0),"res\\frog.jpg",FROG_LEN,FROG_WID,true);
loadimage(&(img->frog0Mask),"res\\frogMask.gif",FROG_LEN,FROG_WID,true);
loadimage(&(img->wood),"res\\wood.jpg",BOARD_LEN,int(BOARD_WID),true);
loadimage(&(img->woodMask),"res\\woodMask.gif",BOARD_LEN,int(BOARD_WID),true);
loadimage(&(img->stream),"res\\stream.jpg",WINDOW_LEN,WINDOW_WID,true);
loadimage(&(img->grass1),"res\\grass.jpg",WINDOW_LEN,STREAM_INIT_Y,true);
loadimage(&(img->grass2),"res\\grass.jpg",WINDOW_LEN,WINDOW_WID-(STREAM_INIT_Y+STREAM_WID),true);
loadimage(&(img->welcome),"res\\welcome.jpg",WINDOW_LEN+STATE_BAR_LEN,WINDOW_WID,true);
}
计分模块:
#include "stdafx.h"
#include "string.h"
#include <stdlib.h>//_itoa,整形转字符串
void printText(char str[],int value,int *line)//输出文本
{
char strValue[6];//中间变量,放数字用.
_itoa_s(value,strValue,10);//_itoa,整型转字符串
strcat_s(str,30,strValue);
outtextxy(WORD_START_X,WORD_START_Y+(*line-1)*WORD_LINE_SPACING,str);
(*line)++;
}
void drawStateBar()
{
setfillstyle(DARKGRAY);
bar(WINDOW_LEN,0,WINDOW_LEN+STATE_BAR_LEN,STATE_BAR_WID);
}
void drawBarValue(FrogType *frog,int ChannelSpeed[])
{
int line=0;//行数
setcolor(LIGHTRED);
char str[30];
strcpy_s(str,"生命值:");
printText(str,frog->life,&line);
strcpy_s(str,"金币:");
printText(str,frog->coin,&line);
strcpy_s(str,"积分:");
printText(str,frog->score,&line);
strcpy_s(str,"渡河次数:");
printText(str,frog->passed,&line);
int ch=0;
strcpy_s(str,"河道一速度:");
printText(str,ChannelSpeed[ch++],&line);
strcpy_s(str,"河道二速度:");
printText(str,ChannelSpeed[ch++],&line);
strcpy_s(str,"河道三速度:");
printText(str,ChannelSpeed[ch++],&line);
strcpy_s(str,"河道四速度:");
printText(str,ChannelSpeed[ch++],&line);
}
void excuteStateBarFunc(FrogType *frog,int ChannelSpeed[])
{
drawStateBar();
drawBarValue(frog,ChannelSpeed);
}
void initFont()
{
setbkmode(TRANSPARENT);
LOGFONT f;
getfont(&f); // 获取当前字体设置
f.lfHeight = 24; // 设置字体高度为 48(包含行距)
strcpy_s(f.lfFaceName, "华文中宋"); // 设置字体为“黑体”
f.lfQuality = ANTIALIASED_QUALITY; // 设置输出效果为抗锯齿
f.lfWeight=500; // 粗细
setfont(&f); // 设置字体样式
}
头文件:
// stdafx.cpp : 只包括标准包含文件的源文件
// Frogger2.pch 将作为预编译头
// stdafx.obj 将包含预编译类型信息
#include "stdafx.h"
// TODO: 在 STDAFX.H 中
// 引用任何所需的附加头文件,而不是在此文件中引用
游戏背景,美工模块:
#include "stdafx.h"
void drawStream(ImageType *img)//画河
{
setfillstyle(LIGHTBLUE);//填充色:蓝
int x1=0;
int y1=STREAM_INIT_Y;
putimage(x1,y1,&(img->stream));
}
void drawBackground(ImageType *img)
{
setfillstyle(LIGHTGREEN);
putimage(0,0,&(img->grass1));
putimage(0,STREAM_INIT_Y+STREAM_WID,&(img->grass2));
}
游戏开始界面:
#include "stdafx.h"
int initWelcome(ImageType *img)
{
putimage(0,0,&(img->welcome));
while(!_kbhit())
{
Sleep(TICK);
}
char key=_getch();
if(27==key){return 0;}
else{return 1;}
}
叫上你的美工好伙伴,一个精美的青蛙过河小游戏就做好啦!关注我,后续会发布更多游戏教程及源码,需要全部完整源码压缩包的小伙伴欢迎进下我们的编程学习群【881577770】领取源码,与大家一起学习哦!