跳动的小球(c++)

话不多说,放代码


#include<stdio.h>
#include<math.h>
#include<Windows.h>
#include<time.h>
#include<stdlib.h>

//界面的长和宽
#define HIGN 27 
#define WIDTH 60

//暂定球与球之间的距离≤1时视为碰撞
#define REACH 1   

#define PI 3.14159//圆周率
#define NUM 10	//球的最大数量
int COUNT = 0;

struct BALL {
	char body;//单个字符,表示球在dos控制台应有的形态
	int sel; //当前球的颜色。0表示第一种颜色,1表示第二种颜色
	int wX; //在二维数组中,球在x方向的实际显示位置(整数)
	int wY; //在二维数组中,球在y方向的实际显示位置(整数)
	double X; //球在x方向的精确位置(实数)
	double Y; //球在y方向的精确位置(实数)
	double dX; //球在x方向的速度(实数)
	double dY; //球在y方向的速度(实数)
};

void Manage(struct BALL*, int);//每一个周期进行的一次处理
void print_pos(struct BALL*, int);//一组球的输出函数
void swap(double*, double*);//double类型的交换函数
void color(const unsigned short);//设定颜色的函数

int main() {
	srand(time(NULL));

	printf("请输入球的个数:");
	int num;//球的个数
	scanf("%d", &num);
	if (num > NUM)num = NUM;
	struct BALL* ball = (struct BALL*)malloc(sizeof(struct BALL) * num);

	for (int i = 0; i < num; i++) {
		(ball + i)->sel = rand() % 15 + 1;	//颜色
		(ball + i)->X = rand() % WIDTH + 1;	//x精确坐标
		(ball + i)->Y = rand() % HIGN + 1;	//y精确坐标
		if ((ball + i)->X < 1)							//边界情况
			(ball + i)->wX = 1;
		else if ((ball + i)->X >WIDTH)					//边界情况
			(ball + i)->wX = WIDTH;
		else 
			(ball + i)->wX = (int)((ball + i)->X+0.5);	//四舍五入

		if ((ball + i)->Y < 1)							//边界情况
			(ball + i)->wY = 1;							
		else if ((ball + i)->Y > HIGN)					//边界情况
			(ball + i)->wY = HIGN;
		else
			(ball + i)->wY = (int)((ball + i)->Y+0.5);	//四舍五入

		(ball + i)->body = 'o';//球是圆的,所以直接全部设为小写字母o

		double xita = rand() % 360;
		(ball + i)->dX = cos(PI * xita / 180);
		(ball + i)->dY = sin(PI * xita / 180);

	}

	
	while (TRUE)
	{
		HANDLE hOut;
    COORD pos={0,0};
    hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOut,pos);//重设打印起点

    CONSOLE_CURSOR_INFO cci;
    GetConsoleCursorInfo(hOut, &cci);
    cci.bVisible = FALSE;
   SetConsoleCursorInfo(hOut, &cci);


		print_pos(ball, num);

		Manage(ball, num);

		Sleep(25);//休眠25毫秒


	}

	
	free(ball);			//其实这条是多余的
	return 1;			
}

//显示操作台和某球的实际位置
void print_pos(struct BALL* p, int num) {
	//上边界
	for (int i = 0; i < WIDTH + 2; i++)
		putchar('*');
	putchar('\n');

	//中间部分
	for (int i = 1; i <= HIGN; i++) {
		putchar('|');
		
		for (int j = 1; j <= WIDTH; j++) {
			short flag = 1;
			for (int k = 0; k < num; k++) {
				if ((p + k)->wX == j && (p + k)->wY == i) {
					color((p + k)->sel);
					putchar((p + k)->body);
					color(7);
					flag = 0;
					break;
				}

			}
			if (flag)
				putchar(' ');
		}

		putchar('|');
		putchar('\n');
	}
	//下边界
	for (int i = 0; i < WIDTH + 2; i++)
		putchar('*');
	putchar('\n');

}

void Manage(struct BALL* p, int num) {

	for (int i = 1; i < num; i++) 
		for(int j=0;j<num-i;j++)
			if (pow((p + i)->X - (p + j)->X, 2) + pow((p + i)->Y - (p + j)->Y, 2) <= pow(REACH,2))
			{
				swap(&(p + i)->dX, &(p + j)->dX);
				swap(&(p + i)->dY, &(p + j)->dY);
			}

	for (int i = 0; i < num; i++){

		if ((p + i)->X <= 1 || (p + i)->X >= WIDTH) {
			(p + i)->dX = -(p + i)->dX;
		}

		if ((p + i)->Y <= 1) {
			(p + i)->dY = -(p + i)->dY;
			
		}

		if ((p + i)->Y >= HIGN) {
			(p + i)->dY = -(p + i)->dY;
		}

		(p + i)->X += (p + i)->dX;
		(p + i)->Y += (p + i)->dY;
	
		
		if ((p + i)->X < 1)
			(p + i)->wX = 1;
		else if ((p + i)->X > WIDTH)
			(p + i)->wX = WIDTH;
		else
			(p + i)->wX = (int)((p + i)->X + 0.5);

		if ((p + i)->Y < 1)
			(p + i)->wY = 1;
		else if ((p + i)->Y > HIGN)
			(p + i)->wY = HIGN;
		else
			(p + i)->wY = (int)((p + i)->Y + 0.5);
	}
}


void swap(double* x, double* y) {
	double temp = *x;
	*x = *y;
	*y = temp;
}



void color(const unsigned short color1)
{       
	if (color1 >= 0 && color1 <= 15)
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color1);
	else
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}

效果

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.基本要求 能够实现如下功能: ‹ 首先用蓝色清屏 ‹ 在屏幕中央显示由字符串“-============#”组成的黄色的小球,#为, 按下方向键可以控制上述小球行方式在屏幕上行走 ‹ 在行进过程中,只能左转、右转或继续前进,不能掉转 180 度 2.鼓励实现完整的彩滚动游戏,鼓励有新的创意 3.提示 ①通过调用 INT 16H 的 0 号功能可以读取光标控制键的扩展码 光标控制键: ↑ ↓ ← → 扩展码(十进制): 72 80 75 77 ②在指定位置用指定属性显示字符的方法有两种:一是直接写显示缓冲区,二是利用 BIOS 屏显功能调用。解: 功能描述(基本上是全部功能):本程序有以下功能 共分为7关,可以手工选择关卡(带有输入异常处理)。走完一关后,如果后面还有关, 直接跳到下一关。否则,结束游戏。各个关之间的差别是速度不同。 按下方向键,能够按照题的要求在屏幕上行走。按下 ESC 键,退出游戏,按下其他键, 程序不理会。 长时间不按键,会自动前进。 能够产生随机数,作为蛋。的初始大小为 14,当大小为 20 时,此关结束。 如果运动到了边界,死亡。游戏结束。 ① 设计思路 程序开始时,由用户指定一个关卡,进入游戏。 每次用清屏加显示字符的方式重新显示和蛋。 当检测到有键子按下时,判断是什么键子,如果是 esc,退出游戏,如果是方向键,按 正确的方向走(如果方向键与运动方向相反,不理会按键),如果按下的时其它键, 不理会。 设置一个等待时间,如果超过等待时间仍没有按键,自动前行一步。否则,重新比较 时间。 每次运动或有键子被按下时,判断是否撞到了自身和边界。 如果吃到了一个蛋,更新完的位置后,将原的位置加入中。 如果的长度达到了 20(设置的的最大大小),判断后面是否还有关,没有了,就结 束程序,还有,就跳到下一关卡。 ② 算法说明 设置两个标记变量,分别记录的大小 ssize 和上次的大小 befor。设置标记变量, 分别记录蛋的横纵座标 xlabel 和 ylabel,设置标记变量,记录的位置 tailx 和 taily。设置 snake 记录各个部分的位置,设置的最大大小为 20。设置变量 TIME 为等待按键时间。 关卡的选择:程序开始时,从键盘读入一个数字,当作关卡,根据读入的数据,设置等 待时间,也就实现了对的速度的控制。 清屏和显示小球和蛋。调用 bios 中断可以实现。每次输出 1 个,下面说一下如何实现小球的手工移动(有按键输入时)。可以知道,如果把看成一个 个单元,每移动一次,它的身体的位置都等于它的前一个身体单元的上一步 的位置,因此,可以从尾部进行循环,把前一节的位置给后一节。这样循环 ssize-1 次 就更新了身体,再根据输入的按键判断如何如移动头部,如果按键是左或者右, 只需将的列加减 1,如果按键是上或者下,只需将的行加减 1。至此,完成了 对显示位置的更新,之后重新清屏、显示,可以使移动了。 在判断是否向相反方向走时,可以采用如下算法:已知按键了(以向上为例),检查 和身体第一节的行号,如果行号大,说明此时设在向下运动,按键无效。 判断撞到边界的算法如下(以向上键为例):判断此时的行号是否为 0,如果是 0, 又按下了向上键,结束游戏,输出“I AM DEAD!!!”。如果运动过程中撞到了自己, 也同撞到边界的操作。算法是这样的:取出的位置,依次和每个身体和尾巴的位置 进行比较(从开始比较),如果相等,说明撞上了,结束游戏。 如何实现的自动移动。可以用 INT 10H 的 1 号功能检测是否有按键输入,如果有,转 到手工移动模块,否则,调用 INT 1AH 中的 00 号功能,读取当前时间。与上次读的时 间相比,如果小于设定的时间,重新比较,否则,自动前移。实现前移的算法与手工 移动相似,也是将身体的某一单元的位置置成塔前一单元上一次的位置,之后判断 方向。 产生并输出蛋。相当于产生一个随机数,我已经读去了当前时间,可以利用 DX 移位(防 止溢出)以后,对 80 和 25 取余,获得位置的随机数。之后判断的大小 ssize 和 befor, 先让 ssize 为 14,befor 为 13,每产生一个随机数,befor 加 1,每吃一个蛋,ssize 加 1。比较 ssize 和 befor,如果相等,证明没有吃蛋,不用产生新的随机数,仍在 原位置输出随机数,否则,产生新的随机数。的大小的变化。每次吃到一个蛋后,ssize加1,并且将更新前的位置加入到snake, 这样下次输出就能够多输出一个,实现了大小的增加。 关卡的切换:每当吃了一个蛋以后,判断是否达到了的最大大小20,如果达到了, 继续判断是否的达到了等待时间的最小值(也就是最高的一关),如果没有达到,就更 新等待时间,进入下一关卡之前,还要将的大小 ssize 和初始大小befor 分别设为 14 和 13。将记录位置的内存 snake 的前 14 个字更新到屏幕中央。之后,就可以进入下 一关了。如果已经达到了最高关,并且通过了,就结束程序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值