前言:
烟花的实现是我自己独立实现的第一个项目。那时离除夕只剩几天,我刚学完贪吃蛇。其实个人也很喜欢烟花。所以想送给朋友一份礼物。于是觉得可以一试。构思了一会后,就直接进行了。
成品:
思路:
1.vs2022很多特殊字符都打印不了。我首先把c语言本地化,然后复制了许多特殊字符,尝试它们在控制台能打印出来的结果,把能够打印出来的筛选字符都列出来。这样在烟花制作的过程中也许会用上。
2.烟花的画面是这样的。
下面是花筒,上面是烟花在上升时的花束和升到制高点时绽放的花体。
3.烟花如何实现
花筒直接用宽字符打印出来就可以,烟花的花束需要设置一个结构体,和贪吃蛇的蛇身一样(贪吃蛇的实现见上篇文章),只不过是单向向上移动,而且移动的速度要快许多。(睡眠的时间少很多)
烟花的花体也是一个结构体。这个结构体的构成也是一个个结点。你构建的结点个数,取决于一次绽放闪烁的火花有多少个。我尝试了一下,在9-15是最合适的,选择了12个结点。这些结点的坐标都用随机数设置。限制在上图的方体区域中。绽放一次睡眠一次。一个花筒得闪个四五次吧,在外面套上一层循环就可以了。
但是闪烁之后要消失,这个怎么处理?
借助贪吃蛇的删尾的思路,在原坐标处打印两个空格字符就可以覆盖掉。所以花体绽放之后还要写个循环来清理这些花体。
再来说花束的移动,花束升到至高点(指定坐标)后,再清理掉花束。
以上就可以完成简单的烟花播放了。(虽然是长方形的烟花)
如果要循环播放,就要在外面套个循环体。把烟花的初始化放在循环体外面。
4.代码附上
firework.h
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#pragma once
#include <stdio.h>
#include <locale.h>
#include <windows.h>
#include <stdbool.h>
#include <stdlib.h>
#define FIRE L'●'
#define ITEM L'█'
#define FLOWER L'﹡'
typedef struct firenode
{
int x;
int y;
struct firenode* next;
}firenode,*pfirenode;
typedef struct firework
{
pfirenode pf;
}firework,*pfirework;
void SetPos(int x, int y);
void Initfirework(pfirework ps);
void GameStart(pfirework ps,pfirework pflower);
void GameRun(pfirework ps,pfirework pflower);
firework.c
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include "firework.h"
void SetPos(int x, int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = { x,y };
SetConsoleCursorPosition(handle, pos);
}
void Initfirework(pfirework ps)
{
for (int i = 0; i < 3; i++)
{
pfirenode node = (pfirenode)malloc(sizeof(firenode));
if (node == NULL)
{
perror("Initfirework::(malloc)");
return;
}
if (ps->pf == NULL)
{
node->x = 59;
node->y = 31;
node->next = NULL;
ps->pf = node;
}
else
{
node->x = ps->pf->x;
node->y = ps->pf->y - 1;
node->next = ps->pf;
ps->pf = node;
}
}
}
void Initfireflower(pfirework pflower)
{
for (int i = 0; i < 12; i++)
{
pfirenode node = (pfirenode)malloc(sizeof(firenode));
if (node == NULL)
{
perror("Initfirework::(malloc)");
return;
}
pfirenode flower = pflower->pf;
if (flower == NULL)
{
node->x = 30;
node->y = 30;
node->next = NULL;
pflower->pf = node;
}
else
{
node->x = flower->x;
node->y = flower->y - 1;
node->next = flower;
pflower->pf = node;
}
}
}
void WelcomeInfo()
{
SetPos(52, 15);
printf("请查收你的礼物.");
SetPos(60, 17);
printf("制作者:真白");
}
void GameStart(pfirework ps,pfirework pflower)
{
//修改控制台大小和隐藏光标
system("mode con cols=120 lines=40");
system("title 礼物");
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO console;
GetConsoleCursorInfo(handle, &console);
console.bVisible = false;
SetConsoleCursorInfo(handle, &console);
WelcomeInfo();
SetPos(100, 36);
system("pause");
system("cls");
Initfirework(ps);
Initfirework(pflower);
}
void CreatFire(pfirework ps)
{
//打印烟花
pfirenode cur = ps->pf;
while (cur)
{
SetPos(cur->x,cur->y);
wprintf(L"%lc", FIRE);
cur = cur->next;
}
}
void FireMove(pfirework ps, pfirenode pnext)
{
pnext->next = ps->pf;
ps->pf = pnext;
//尾删
pfirenode cur = ps->pf;
while (cur->next->next)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", FIRE);
cur = cur->next;
}
SetPos(cur->next->x, cur->next->y);
printf(" ");
free(cur->next);
cur->next = NULL;
}
void CreatNextnode(pfirework ps)
{
pfirenode cur = (pfirenode)malloc(sizeof(firenode));
if (cur == NULL)
{
perror("CreatNextnode::malloc()");
return;
}
//设置下一个结点的坐标
pfirenode pnext = cur;
pnext->x = ps->pf->x;
pnext->y = ps->pf->y - 1;
pnext->next = NULL;
Sleep(50);
FireMove(ps,pnext);
}
void FireFlower(pfirework pflower)
{
Initfireflower(pflower);
pfirenode cur = pflower->pf;
while (cur)
{
cur->x = rand() % 20 + 50;
cur->y = rand() % 12 + 2;
cur = cur->next;
}
cur = pflower->pf;
while (cur->next)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", FLOWER);
cur = cur->next;
}
Sleep(200);
cur = pflower->pf;
while (cur->next)
{
SetPos(cur->x, cur->y);
printf(" ");
cur = cur->next;
}
}
test.c
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include "firework.h"
void test()
{
firework fw = { 0 };
firework Flower = { 0 };
GameStart(&fw,&Flower);
GameRun(&fw,&Flower);
}
int main()
{
setlocale(LC_ALL, "");
test();
return 0;
}