thử thêm 2 file này vô project là ngon lành:
fastconrend.h
#pragma once
#include <cstdio>
#include <windows.h>
namespace fcr
{
enum ConsoleColor {
Black,
DarkBlue,
DarkGreen,
DarkCyan,
DarkRed,
DarkMagenta,
DarkYellow,
Gray,
DarkGray,
Blue,
Green,
Cyan,
Red,
Magenta,
Yellow,
White
};
struct Window {
HANDLE hStdOut;
CHAR_INFO* outBuf;
COORD wdSize, bufCoord;
SMALL_RECT srctWriteRect;
WORD color;
int iw, outBufSize;
~Window();
};
void init();
void settitle(const wchar_t* title);
void setsize(int w, int h);
void setfont(const wchar_t* fontName, int fontSizeX, int fontSizeY);
void gotoxy(int x, int y);
void clrscr();
int textcolor();
int backcolor();
void setcolor(int textcolor, int backcolor);
void settextcolor(int textcolor);
void setbackcolor(int backcolor);
void cursor(bool visible);
void putchar(char c);
void printf(const char* format, ...);
void putwchar(wchar_t wc);
void wprintf(const wchar_t* format, ...);
void writebuffer();
} // namespace fcr
fastconrend.cpp
#include "fastconrend.h"
#include <algorithm>
namespace fcr
{
////////////////////////////////
/// GLOBAL VARIABLE `window` ///
////////////////////////////////
Window window;
Window::~Window()
{
cursor(true);
setcolor(Gray, Black);
free(window.outBuf);
}
void makeNewBuffer(int w, int h)
{
free(window.outBuf);
window.outBufSize = w * h;
window.outBuf = (CHAR_INFO*)calloc(window.outBufSize, sizeof(CHAR_INFO));
if (!window.outBuf)
{
perror("Error allocating output buffer\n");
exit(1);
}
for (int i = 0; i < window.outBufSize; ++i)
window.outBuf[i].Attributes = window.color;
}
void init()
{
window.hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (window.hStdOut == INVALID_HANDLE_VALUE)
{
perror("Error getting stdout handle\n");
exit(1);
}
window.bufCoord.X = window.bufCoord.Y = 0;
window.srctWriteRect.Top = 0;
window.srctWriteRect.Left = 0;
window.iw = 0;
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (!GetConsoleScreenBufferInfo(window.hStdOut, &csbi))
{
perror("Error `GetConsoleScreenBufferInfo`\n");
exit(1);
}
window.outBuf = NULL;
makeNewBuffer(csbi.dwSize.X, csbi.dwSize.Y);
window.wdSize = csbi.dwSize;
window.srctWriteRect.Bottom = window.wdSize.Y - 1;
window.srctWriteRect.Right = window.wdSize.X - 1;
SetConsoleWindowInfo(window.hStdOut, true, &window.srctWriteRect);
window.color = csbi.wAttributes;
}
void settitle(const WCHAR* title)
{
SetConsoleTitleW(title);
}
void setsize(int w, int h)
{
char changeWindowSizeMsg[64];
sprintf(changeWindowSizeMsg, "mode con: cols=%d lines=%d", w, h);
system(changeWindowSizeMsg); //// system call /////
makeNewBuffer(w, h);
window.wdSize.X = w;
window.wdSize.Y = h;
window.srctWriteRect.Bottom = window.wdSize.Y - 1;
window.srctWriteRect.Right = window.wdSize.X - 1;
SetConsoleWindowInfo(window.hStdOut, true, &window.srctWriteRect);
}
void gotoxy(int x, int y)
{
window.iw = x + y * window.wdSize.X;
window.iw %= window.outBufSize; // prevent overflow
}
void clrscr()
{
for (int i = 0; i < window.outBufSize; ++i)
{
window.outBuf[i].Attributes = window.color;
window.outBuf[i].Char.AsciiChar = ' ';
}
gotoxy(0, 0);
}
int textcolor()
{
return window.color & 0xF;
}
int backcolor()
{
return (window.color >> 4) & 0xF;
}
void setcolor(int textColor, int backColor)
{
window.color = (backColor << 4) + textColor;
}
void settextcolor(int textColor)
{
setcolor(textColor, backcolor());
}
void setbackcolor(int backColor)
{
setcolor(textcolor(), backColor);
}
void cursor(bool visible)
{
CONSOLE_CURSOR_INFO cursorInfo;
GetConsoleCursorInfo(window.hStdOut, &cursorInfo);
cursorInfo.bVisible = visible; // set the cursor visibility
SetConsoleCursorInfo(window.hStdOut, &cursorInfo);
}
void putchar(char c)
{
window.outBuf[window.iw].Char.AsciiChar = c;
window.outBuf[window.iw].Attributes = window.color;
++window.iw;
window.iw %= window.outBufSize; // prevent overflow
}
void printf(const char* fmt, ...)
{
static char buff[1024];
va_list args;
va_start(args, fmt);
vsprintf(buff, fmt, args);
va_end(args);
// Write buff to outBuf
int wdX = window.wdSize.X;
for (char* ptr = buff; *ptr; ++ptr)
{
if (*ptr == '\b')
--window.iw;
else if (*ptr == '\r')
window.iw = window.iw / wdX * wdX;
else if (*ptr == '\n')
window.iw = (window.iw / wdX + 1) * wdX;
else
putchar(*ptr);
window.iw %= window.outBufSize; // prevent overflow
}
}
void putwchar(wchar_t wc)
{
window.outBuf[window.iw].Char.UnicodeChar = wc;
window.outBuf[window.iw].Attributes = window.color;
++window.iw;
window.iw %= window.outBufSize; // prevent overflow
}
void wprintf(const wchar_t* fmt, ...)
{
static wchar_t buff[1024];
va_list args;
va_start(args, fmt);
vswprintf_s(buff, 1024, fmt, args);
va_end(args);
// Write buff to outBuf
int wdX = window.wdSize.X;
for (wchar_t* ptr = buff; *ptr; ++ptr)
{
if (*ptr == L'\b')
--window.iw;
else if (*ptr == L'\r')
window.iw = window.iw / wdX * wdX;
else if (*ptr == L'\n')
window.iw = (window.iw / wdX + 1) * wdX;
else
putwchar(*ptr);
window.iw %= window.outBufSize; // prevent overflow
}
}
void writebuffer()
{
WriteConsoleOutputW(window.hStdOut, // screen buffer to write to
window.outBuf, // buffer to copy from
window.wdSize, // col-row size of chiBuffer
window.bufCoord, // top left src cell in chiBuffer
&window.srctWriteRect);
}
void setfont(const wchar_t* fontName, int fontSizeX, int fontSizeY)
{
CONSOLE_FONT_INFOEX cfi;
cfi.cbSize = sizeof cfi;
cfi.nFont = 0;
cfi.dwFontSize.X = fontSizeX;
cfi.dwFontSize.Y = fontSizeY;
cfi.FontFamily = FF_DONTCARE;
cfi.FontWeight = FW_NORMAL;
wcscpy(cfi.FaceName, fontName);
if (!SetCurrentConsoleFontEx(window.hStdOut, false, &cfi))
{
perror("Cannot set font\n");
exit(1);
}
}
} // namespace fcr
(code copy xài thoải mái license cho đại là MIT vậy :V)
file main chỉ cần chỉnh sửa chút xíu: putchar
, clrscr
, gotoxy
thêm namespace fcr::
vào, trong main
thì cần nhớ khởi tạo cho nó bằng cách gọi fcr::init();
, rồi có thể gọi fcr::cursor(false);
để ẩn dấu _ đi, fcr::setsize(80, 25);
để set kích thước màn hình cho đúng 80x25 ký tự, thậm chí đổi font cũng được: fcr::setfont(L"Consolas", 8, 16);
à quên :V vì xài 1 buffer riêng (double buffer) nên mỗi lần vẽ thật ra chỉ là chép ký tựu vào mảng 2 chiều chứ ko phải in ra màn hình, muốn in ra màn hình toàn bộ buffer phụ thì phải gọi fcr::writebuffer();
#include "fastconrend.h"
#include <conio.h>
#include <cstdio>
#include <ctime>
#include <windows.h>
struct ToaDo {
int x, y;
};
struct HinhDang {
char a[3][3];
};
struct Human {
ToaDo toado;
HinhDang hinhdang;
};
struct Xe {
ToaDo toado;
HinhDang hinhdang;
};
// khởi taọ người
void KhoiTao(Human& X, Xe& C)
{
#define hdX X.hinhdang.a
#define hdC C.hinhdang.a
X.toado.x = 40;
X.toado.y = 23;
C.toado.x = 1;
C.toado.y = 19;
hdX[0][0] = hdX[2][0] = hdX[1][2] = ' ';
hdX[1][1] = hdX[0][2] = hdX[2][2] = '|';
hdX[0][1] = hdX[2][1] = '-';
hdX[1][0] = '@';
hdC[0][0] = hdC[2][0] = hdC[0][2] = hdC[2][2] = 'O';
hdC[1][0] = hdC[1][2] = '-';
hdC[0][1] = '|';
hdC[2][1] = '>';
hdC[1][1] = ' ';
}
// hiển thị người
void HienThi(Human X, Xe C)
{
fcr::clrscr();
for (int kDong = -1; kDong <= 1; kDong++)
for (int kCot = -1; kCot <= 1; kCot++)
{
int x = kCot + C.toado.x;
int y = kDong + C.toado.y;
fcr::gotoxy(x, y);
fcr::putchar(C.hinhdang.a[kCot + 1][kDong + 1]);
}
for (int kDong = -1; kDong <= 1; kDong++)
for (int kCot = -1; kCot <= 1; kCot++)
{
int x = kCot + X.toado.x;
int y = kDong + X.toado.y;
fcr::gotoxy(x, y);
fcr::putchar(X.hinhdang.a[kCot + 1][kDong + 1]);
}
}
//điều khiển người di chuyển
void DieuKhienMan(Human& X)
{
if (_kbhit())
{
int key = _getch();
if (key == 'A' || key == 'a')
X.toado.x--;
else if (key == 'D' || key == 'd')
X.toado.x++;
else if (key == 'W' || key == 'w')
X.toado.y--;
else if (key == 'S' || key == 's')
X.toado.y++;
}
}
int main()
{
fcr::init();
fcr::cursor(false);
fcr::setsize(80, 25);
Human X;
Xe C;
KhoiTao(X, C);
while (true)
{
HienThi(X, C);
DieuKhienMan(X);
C.toado.x++;
fcr::writebuffer();
Sleep(16);
}
}
cho Sleep(16) tức là khoảng 60fps nó chạy vù vù :V :V :V

nếu tăng kích thước màn hình ~ 10k ký tự thì lâu lâu nó cũng giựt mà ít
Muốn trị hết thì qua pdcruses nó xài SDL giả lập console gì đó :V