前言:
烟花的实现是我自己独立实现的第一个项目。那时离除夕只剩几天,我刚学完贪吃蛇。其实个人也很喜欢烟花。所以想送给朋友一份礼物。于是觉得可以一试。构思了一会后,就直接进行了。
成品:
思路:
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;
}