#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <vector>
// 头文件
class Drawer {
private:
char** frame_;
HANDLE output, buffer;
COORD coord = { 0,0 };
DWORD bytes = 0;
int control_ = 0; // 用于切换输出区和缓冲区
int lenth_; // 绘制区域长度
int width_;// 绘制区域宽度
double fps_; // 帧数
public:
Drawer(int len = 10,int wid = 10, double fps = 10) :lenth_(len), width_(wid), fps_(1000.0 / fps) {
if(lenth_ < 0)
lenth_ = 15;
if(width_ < 0)
width_ = 15;
if(fps_ < 0)
fps_ = 20;
Init();
}
void Init();
void GetFrame(char** frame) {
frame_ = frame;
}
void Draw();
};
// 实现
void Drawer::Draw() {
for (int i = 0; i < width_; i++)
{
coord.Y = i;
if (!control_)
WriteConsoleOutputCharacterA(buffer, frame_[i], lenth_, coord, &bytes);
else
WriteConsoleOutputCharacterA(output, frame_[i], lenth_, coord, &bytes);
}
if (!control_)
SetConsoleActiveScreenBuffer(buffer);
else
SetConsoleActiveScreenBuffer(output);
Sleep(fps_);
control_ = !control_;
}
void::Drawer::Init() {
buffer = CreateConsoleScreenBuffer(
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
output = CreateConsoleScreenBuffer(
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
CONSOLE_CURSOR_INFO cci;
cci.bVisible = 0;
cci.dwSize = 1;
SetConsoleCursorInfo(output, &cci);
SetConsoleCursorInfo(buffer, &cci);
}
使用方法:
使用前要先初始化一个Drawer对象,传入三个参数,分别是绘制区域长度、绘制区域宽度以及帧率。
用GetFrame()方法传入一个char**变量,该二维char数组储存当前要绘制的帧的内容。
Draw()方法绘制当前帧。
用例一:
int main() {
Drawer a(15,15,20); // 初始化对象
char** data;
data = new char* [16];
for (int i = 0; i < 16; i++) {
data[i] = new char[16];
}
char c = 'a';
while (c <='z') {
for (int i = 0; i < 15; i++){
for (int j = 0; j < 15; j++){
data[i][j] = c;
}
}
a.GetFrame(data); // 传入帧
a.Draw(); // 绘制
c++;
}
}
用例二:
把这个类插入了上学期写的贪吃蛇里,解决了闪屏问题
#include <iostream>
#include <conio.h>
#include <Windows.h>
#include <ctime>
#include <stdio.h>
#include <stdlib.h>
#include <cstdlib>
using namespace std;
class Drawer {
private:
char** frame_;
HANDLE output, buffer;
COORD coord = { 0,0 };
DWORD bytes = 0;
int control_ = 0; // 用于切换输出区和缓冲区
int lenth_; // 绘制区域长度
int width_;// 绘制区域宽度
double fps_; // 帧数
public:
Drawer(int len = 10, int wid = 10, double fps = 10) :lenth_(len), width_(wid), fps_(1000.0 / fps) {
if (lenth_ < 0)
lenth_ = 15;
if (width_ < 0)
width_ = 15;
if (fps_ < 0)
fps_ = 20;
Init();
}
void Init();
void GetFrame(char** frame) {
frame_ = frame;
}
void Draw();
};
struct pos {//坐标点
int x;//列
int y;//行d
};
const int X = 35;
const int Y = 18;
char** screen;
Drawer D(35,18,20);
pos head{ 4,5 };//蛇头初始位置
pos foodpos{ 19, 9 }; //食物初始位置
pos body[100];//存储蛇身位置的pos数组
bool life = 1;
int score = 0;
const int speed = 1;
int moveX, moveY;//x,y坐标的增量
int lenth = 3;//蛇的初始长度
int os;//用户的输入,见get_input()函数
int get_rannum(int left, int right);
void get_input();
void hide_cursor(bool Visible);
bool food_eaten();
void update_pos();
bool is_body(int y, int x);
void fill_screen();
void draw();
int main() {
screen = new char* [Y]; // Y 是为行
for (int i = 0; i < Y; i++) {
screen[i] = new char[X]; // X是为列
}
for (int i = 0; i < lenth; i++) {
body[i] = head;
}
hide_cursor(true);
while (life) {
get_input();
update_pos();
fill_screen();
draw();
}
}
int get_rannum(int left, int right)//返回一个[left,right]内的整型数据
{
srand((unsigned)time(NULL));
return (rand() % (right - left + 1)) + left;
}
void get_input() {//获取用户输入
if (_kbhit()) os = _getch();//这一段可以直接抄
if (char(os) == 'a') {
moveX = -speed; moveY = 0;
}
if (char(os) == 'd') {
moveX = speed; moveY = 0;
}
if (char(os) == 'w') {
moveY = -speed; moveX = 0;
}
if (char(os) == 's') {
moveY = speed; moveX = 0;
}
}
void hide_cursor(bool Visible)//隐藏光标 直接抄就完事了
{
CONSOLE_CURSOR_INFO Cursor;
Cursor.bVisible = !Visible;
Cursor.dwSize = sizeof(Cursor);
HANDLE Hand = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorInfo(Hand, &Cursor);
}
bool food_eaten() {
if (head.x == foodpos.x && head.y == foodpos.y) {//若蛇头碰到了食物
return true;
}
return false;
}
void update_pos() {//蛇的身体坐标更新,食物位置更新
for (int i = 0; i < lenth - 1; i++) {//这是贪吃蛇实现中唯一一个需要动脑子的地方,注释说不清楚,自己想想吧~
body[i] = body[i + 1];
}
body[lenth - 1] = head;
head.x += moveX;
head.y += moveY;
if (food_eaten()) {
lenth++;
foodpos.x = get_rannum(5, 30);
foodpos.y = get_rannum(5, 15);
}
}
bool is_body(int y, int x) {//坐标点x,y是不是蛇的身体
for (int i = 0; i < lenth; i++) {
if (y == body[i].y && x == body[i].x) {
return true;
}
}
return false;
}
void fill_screen() {//填充屏幕矩阵
for (int y = 0; y < Y; y++) {
for (int x = 0; x < X; x++) {
if (x == head.x && y == head.y) {
screen[y][x] = 'O';
}
else if (y == 0 || y == Y - 1) {
screen[y][x] = '-';
}
else if (x == 0 || x == X - 1) {
screen[y][x] = '|';
}
else if (is_body(y, x))
{
screen[y][x] = 'o';
}
else if (y == foodpos.y && x == foodpos.x) {
screen[y][x] = '%';
}
else {
screen[y][x] = ' ';
}
}
}
D.GetFrame(screen);
}
void draw() {//绘制图案
D.Draw();
}
void Drawer::Draw() {
for (int i = 0; i < width_; i++)
{
coord.Y = i;
if (!control_)
WriteConsoleOutputCharacterA(buffer, frame_[i], lenth_, coord, &bytes);
else
WriteConsoleOutputCharacterA(output, frame_[i], lenth_, coord, &bytes);
}
if (!control_)
SetConsoleActiveScreenBuffer(buffer);
else
SetConsoleActiveScreenBuffer(output);
Sleep(fps_);
control_ = !control_;
}
void::Drawer::Init() {
buffer = CreateConsoleScreenBuffer(
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
output = CreateConsoleScreenBuffer(
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
CONSOLE_CURSOR_INFO cci;
cci.bVisible = 0;
cci.dwSize = 1;
SetConsoleCursorInfo(output, &cci);
SetConsoleCursorInfo(buffer, &cci);
}