C语言青蛙过河游戏超详细教程【附源码】

今天给大家带来一个青蛙过河小游戏代码,先看看效果吧!

开始界面:

游戏界面 :

游戏中界面:

 胜利界面:

死亡界面: 代码我们分了几个模块来写,这样不容易写乱,也方便后续修改 

木板模块:

#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】领取源码,与大家一起学习哦!

  • 11
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值