C语言小小小项目 仿天天酷跑——Day2

开发日志

/*
2022.3.3
		1.实现玩家的奔跑
		2.实现玩家的跳跃
		3.优化帧等待
		4.实现小乌龟随机出现
		5.结构体封装
*/

今日代码

运用池的思想,需要障碍物时从池中调取

//它用于声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型,本质上是整数
//typedef enum则是用来定义一个数据类型,那么该类型的变量值只能在enum定义的范围内取
typedef enum {
	//瓜 0
	MELON,
	//华强 1
	HUAQIANG,
	//四种柱子
	//需要改变障碍物出现频率,取余
	PILLAR1,
	PILLAR2,
	PILLAR3,
	PILLAR4,
	//边界,判断有几种枚举值 6
	OBSTACLE_TYPE_COUNT
}obstacle_type;

//可变二维数组,与下面那个二维数组等价
//存放所有障碍物的各个图片
vector<vector<IMAGE>>obstacleImgs;

//内存占用较小(还不理解
// 还可以用C++的容器特性,可变数组继续优化,加头文件
//IMAGE obstacleImgs[3][12];

//暂时不理解typedef
typedef struct obstacle {
	//障碍物类型
	obstacle_type type;
	//当前时刻显示的图片的序号
	int imgIndex;
	//障碍物的坐标
	int x, y;
	//速度
	int speed;
	//杀伤力
	int power;
	//是否在窗口
	bool exist;
	//占用更多内存
	//IMAGE img[12];
}obstacle_t;

//障碍物池
obstacle_t obstacles[OBSTACLE_COUNT];

初始化

//加载人物奔跑的图片帧素材
	for (int i = 0; i < 12; i++) {
		//"res/hero1~12.png"
		sprintf(name, "res/hero%d.png", i + 1);
		loadimage(&imgPlayer[i], name);
	}

	//玩家初始位置
	//getwidth获取图片宽度函数
	playerX = WIN_WIDTH * 0.5 - imgPlayer[0].getwidth() * 0.5;
	playerY = 375 - imgPlayer[0].getheight();
	playerIndex = 0;

	//跳跃状态
	startJump = false;
	//跳跃最大高度
	jumpHeightMax = playerY - 300;
	//跳跃初速度
	jumpSpeed = -20;

	//刷新画面
	update = true;

	//加载瓜素材
	/*loadimage(&imgMelon, "res/t1.png");
	melonExist = false;
	melonY = 375 - imgMelon.getheight();*/
	IMAGE imgMelon;
	vector<IMAGE>imgMelonArray;
	for (int i = 0; i < 6; i++) {
		sprintf(name, "res/t%d.png", i + 1);
		loadimage(&imgMelon, name);
		//在数组的尾部追加
		imgMelonArray.push_back(imgMelon);
	}
	//存入二维数组
	obstacleImgs.push_back(imgMelonArray);

	//加载华强素材
	IMAGE imgHuaqiang;
	vector<IMAGE>imgHuaqiangArray;
	for (int i = 0; i < 8; i++) {
		sprintf(name, "res/p%d.png", i + 1);
		loadimage(&imgHuaqiang, name, 210, 210, true);
		imgHuaqiangArray.push_back(imgHuaqiang);
	}
	obstacleImgs.push_back(imgHuaqiangArray);

	//初始化障碍物池
	for (int i = 0; i < OBSTACLE_COUNT; i++) {
		obstacles[i].exist = false;
	}

	//加载下蹲素材
	for (int i = 0; i < 2; i++) {
		sprintf(name, "res/d%d.png", i + 1);
		loadimage(&imgPlayerDown[i], name);
	}
	startDown = false;

	//加载柱子素材
	IMAGE imgPillar;
	//vector<IMAGE>imgPillarArray;错的
	for (int i = 0; i < 4; i++) {
		//放在外面会导致柱子图片按帧动,就是二维数组按列储存了,在里面是按行
		vector<IMAGE>imgPillarArray;
		sprintf(name, "res/h%d.png", i + 1);
		//对图片进行缩放
		loadimage(&imgPillar, name, 63, 260, true);
		imgPillarArray.push_back(imgPillar);
		obstacleImgs.push_back(imgPillarArray);
	}
}

//创建障碍物
void createObstacle() {
	int i;
	//找一个没有用过的
	for (i = 0; i < OBSTACLE_COUNT; i++) {
		if (obstacles[i].exist == false){
			break;
		}
	}
	//没找到
	if (i >= OBSTACLE_COUNT) {
		return;
	}
	obstacles[i].exist = true;
	obstacles[i].imgIndex = 0;
	//type不是整型
	obstacles[i].type = (obstacle_type)(rand() % 3);
	//优化柱子出现频率,使柱子自为一类
	if (obstacles[i].type == PILLAR1) {
		//注意数据类型
		obstacles[i].type = (obstacle_type)((int)obstacles[i].type + rand() % 4);
	}
	obstacles[i].x = WIN_WIDTH;
	obstacles[i].y = 375 - obstacleImgs[obstacles[i].type][0].getheight();
	if (obstacles[i].type == MELON) {
		obstacles[i].speed = 0;
		obstacles[i].power = 5;
	}
	else if (obstacles[i].type == HUAQIANG) {
		obstacles[i].speed = 4;
		obstacles[i].power = 20;
	}
	//同类型
	else if (obstacles[i].type >= PILLAR1&& obstacles[i].type <= PILLAR4) {
		obstacles[i].speed = 0;
		obstacles[i].power = 20;
		obstacles[i].y = 0;
	}

玩家动作实现

//开关打开,实现跳跃
	if (startJump) {

		if (playerY < jumpHeightMax) {
			jumpSpeed = 0;
		}
		//仿重力
		playerY += (jumpSpeed++);
		//大于等于,不然第一次起跳会偏移
		if (playerY >= 375 - imgPlayer[0].getheight()) {
			startJump = false;
			//回归初始态
			jumpSpeed = -20;
		}
	}
	else if (startDown) {
		static int count = 0;
		int delays[2] = { 4, 10 };
		count++;
		if (count >= delays[playerIndex]) {
			count = 0;
			playerIndex++;
			if (playerIndex >= 2) {
				playerIndex = 0;
				startDown = false;
			}
		}
		
	}
	//不跳不蹲才奔跑
	else {
		//注意别写i=i++这种傻代码了!!!
		playerIndex = (++playerIndex) % 12;
	}

	//静态变量,函数调用完之后不会被销毁,下次调用值不变
	static int frameCount = 0;
	//生成障碍物频率
	static int enemyFre = 100;
	//每100帧生成一只障碍物
	frameCount++;
	if (frameCount > enemyFre) {
		//计数器清零
		frameCount = 0;
		//if (!melonExist) {
		//	melonExist = true;
		//	melonX = WIN_WIDTH;
		//	//每200~500帧生成一只 200+0...300
		//}
		enemyFre = 50 + rand() % 100;
		//用来刷障碍物,障碍物刷出来就会往左移动
		createObstacle();
	}


	//更新所有障碍物坐标
	for (int i = 0; i < OBSTACLE_COUNT; i++) {
		if (obstacles[i].exist) {
			obstacles[i].x -= (obstacles[i].speed + bgSpeed[2]);
			if (obstacles[i].x < -obstacleImgs[obstacles[i].type][0].getwidth() * 2) {
				obstacles[i].exist = false;
			}

			//图片索引
			//二维数组size()第几行有几个元素
			int len = obstacleImgs[obstacles[i].type].size();
			obstacles[i].imgIndex = (obstacles[i].imgIndex + 1) % len;
		}
	}
}

//人物奔跑与下蹲
void playerRun() {
	if (!startDown) {
		putimagePNG2(playerX,playerY,&imgPlayer[playerIndex]);
	}
	else {
		int y = 375 - imgPlayerDown[playerIndex].getheight();
			putimagePNG2(playerX, y, &imgPlayerDown[playerIndex]);
	}
//人物跳跃
void playerJumpSwitch() {
	//需要一个启动跳跃的开关,跳跃不能在一帧内完成,开关触发后,main函数循环开始跳跃
	startJump = true;
	update = true;
}

//人物下蹲
void playerDownSwitch() {
	startDown = true;
	update = true;
	playerIndex = 0;
}

用户按键输入

//处理用户按键的输入
void keyEvent() {
	//scanf会阻塞程序的执行
	char ch;
	//如果有按键按下,kbhit()返回为真
	if (_kbhit()) {
		//_getch()不需要按下回车即可直接读取
		ch=_getch();
		if (ch == 'k'){
			playerJumpSwitch();
		}
		else if (ch == 'j') {
			playerDownSwitch();
		}
	}
}

渲染障碍物

//渲染障碍物
void updateEnemy() {

	for (int i = 0; i < OBSTACLE_COUNT; i++) {
		if (obstacles[i].exist) {
			putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH, &obstacleImgs[obstacles[i].type][obstacles[i].imgIndex]);
		}
	}
}

暂无演示效果

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值