BestAns

路漫漫其修远兮,吾将上下而求索

VC绘图/游戏简易教程--12:数组 铜牌收录

教程总目录:https://codebus.cn/bestans/post/concise-lesson-contents(里面包括VC下的graphics.h的配置方法) 

课程要求:先复习下课本上对数组的讲解(随便一本教材都行)

一维数组

数组可以实现批量操作。比如,我们产生 10 个随机数,产生后先保存起来,然后输出最大的:

	int n[10];
	int i;
	for (i = 0; i < 10; i++)
		n[i] = rand() % 1000;

	// 按生成的顺序,逆序输出
	for (i = 9; i >= 0; i--)
		printf("%d\n", n[i]);

	// 找出最大的
	int max = -1;
	for (i = 0; i < 10; i++)
	{
		if (n[i] > max)
			max = n[i];
	}

	printf("最大的数字是:%d\n", max);

看明白这个程序后,我们继续。
下面,我们绘制一个从屏幕上边任意位置往下落的白色点:

#include <graphics.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>

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

	initgraph(640, 480);

	int x = rand() % 640;	// 点的 x 坐标
	int y = 0;		// 点的 y 坐标

	while(!_kbhit())
	{
		// 擦掉前一个点
		putpixel(x, y, BLACK);
		// 计算新坐标
		y+=3;
		if (y >= 480) break;
		// 绘制新点
		putpixel(x, y, WHITE);

		Sleep(10);
	}

	closegraph();
	return 0;
}

现在利用数组,来产生 100 个随机下落的点。并且每个点落到底部后,就回到顶部重新往下落:

#include <graphics.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>

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

	initgraph(640, 480);

	// 定义点的坐标数组
	int x[100];			// 点的 x 坐标
	int y[100];			// 点的 y 坐标
	int i;

	// 初始化点的初始坐标
	for (i = 0; i < 100; i++)
	{
		x[i] = rand() % 640;
		y[i] = rand() % 480;
	}

	while(!_kbhit())
	{
		for(i = 0; i < 100; i++)
		{
			// 擦掉前一个点
			putpixel(x[i], y[i], BLACK);
			// 计算新坐标
			y[i] += 3;
			if (y[i] >= 480) y[i] = 0;
			// 绘制新点
			putpixel(x[i], y[i], WHITE);
		}

		Sleep(10);
	}

	closegraph();
	return 0;
}

二维数组

理解了一维数组,再看二维数组甚至多维数组,就简单多了,看下面程序理解一下二维数组:

程序要求:屏幕上有 16x8 的方格,按随机顺序在将 1~128 的数字写到每个格子上。
考虑:我们需要记录这些格子,哪些写过数字,哪些没写数字。
我们用一个二维数组来记录:
bool cell[16][8];

写过数字后,我们将相应数组的值设置为 true,看程序:

#include <graphics.h>
#include <stdlib.h>
#include <conio.h>
#include <stdio.h>
#include <time.h>

int main()
{
	int x, y;
	wchar_t num[4];

	srand( (unsigned)time(NULL) );

	initgraph(640, 480);

	// 画格子
	for (x = 0; x < 480; x += 30)
		for (y = 0; y < 240; y += 30)
			rectangle(x, y, x + 28, y + 28);

	// 定义二维数组
	bool cell[16][8];
	// 初始化二维数组
	for (x = 0; x < 16; x++)
		for (y = 0; y < 8; y++)
			cell[x][y] = false;

	// 在每个格子上写数字
	for (int i = 1; i <= 128; i++)
	{
		// 找到一个没有写数字的随机格子
		do
		{
			x = rand() % 16;
			y = rand() % 8;
		}while(cell[x][y] == true);

		// 标记该格子已用
		cell[x][y] = true;

		// 在格子上写数字
		swprintf_s(num, 4, L"%d", i);
		outtextxy(x * 30 + 2, y * 30 + 6, num);
	}

	_getch();
	closegraph();
	return 0;
}

以上几个范例,无论从实用上还是美观上都很差,我只是希望大家能举一反三,写出更多漂亮的程序。

作业

  1. 回顾一下上一节课的作业,绘制一个任意反弹的球。这次,将程序修改成屏幕上有 10 个任意反弹的球。
  2. 如果反弹的不是球,而是点呢?再将某些点之间用线连起来,就可以做一个屏保“变幻线”的程序了。试试做一个。
  3. 写“涂格子(也叫点灯)”的游戏。详细规则可以试玩网上的各种版本。

以下作业,有时间就写。因为讲完这 12 节课,可以写出很多游戏了,所以可能会感觉作业一下子多了许多。
4. 写个俄罗斯方块。
5. 写贪吃蛇、扫雷。这两个稍微复杂一些,如果遇到问题,贴吧里贴出来,大家一起讨论。

后面还会有更精彩的课程,敬请期待。

评论 (8) -

  • 2.屏保  不太美

    #include<stdio.h>
    #include<graphics.h>
    #include<conio.h>
    #include<time.h>

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

        initgraph(640, 480);

        int x[10][2];
        int y[10][2] ;
        int i;
        int n;//随机数1-4

        for (i = 0; i < 10; i++)
        {
            //初始化10个点的位置
            x[i][0] = rand() % 640;
            y[i][0] = rand() % 480;
            //初始化10个点坐标变化量
            x[i][1] = rand() % 4+1;
            y[i][1] = rand() % 4+1;
        }
        while (!_kbhit())
        {
            for (i = 0; i < 10; i++)
            {
                n = rand() % 4 + 1;

                putpixel(x[i][0], y[i][0], BLACK);//删掉上一次的点
                setlinecolor(BLACK);
                line(x[i][0], y[i][0], x[9 - i][0], y[9 - i][0]);//删掉上次的线
                if (x[i][0] >= 640 || x[i][0] <= 0) //判断点是否在窗口内,使点碰到窗口后反向
                    x[i][1] = x[i][1] > 0 ? (-n) : n;
                if (y[i][0] >= 480 || y[i][0] <=0)
                    y[i][1] = y[i][1] > 0 ? (-n) : n;
                x[i][0] += x[i][1];
                y[i][0] += y[i][1];
                putpixel(x[i][0], y[i][0], WHITE);//画点
                setlinecolor(WHITE);
                line(x[i][0], y[i][0], x[9 - i][0], y[9 - i][0]);//画线
             }
            Sleep(10);
        }
        closegraph();

        return  0;
    }
  • D:\编程\easy X practice\demo.cpp(42) : error C2065: 'swprintf_s' : undeclared identifier
    D:\编程\easy X practice\demo.cpp(43) : error C2665: 'outtextxy' : none of the 2 overloads can convert parameter 3 from type 'unsigned short [4]'
    执行 cl.exe 时出错.

    这是啥意思啊…………
    • 不用宽字符
      wchar_t num[4];                              -> char num[4];
      swprintf_s(num, 4, L"%d", i);           -> sprintf_s(num, 4, "%d", i);
      • 改了还是显示’sprintf_s‘:undeclared identifier
        • VC6没有sprintf之类的函数,可以用char num[20]; itoa(i,num,10);。他们估计没用VC6,你说了没用。
  • 你好:sprintf似乎不安全;系统让改为sprintf_s
    • 谢谢提醒!由于该系列教程最早针对 vc6,所以很多内容有点旧,目前正在逐步调整。

添加评论