- PVSM.RU - https://www.pvsm.ru -
Здравствуйте, уважаемые читатели!
В этой статье я хотел бы поделиться необычным и вдохновляющим проектом — реализацией арканоида в текстовом VGA-режиме, написанного полностью на Rust, без использования стандартной библиотеки и даже без аллокации памяти (#![no_std] + no_alloc).
Проект работает напрямую с VGA-памятью и PS/2 клавиатурой через порт 0x60, создавая абсолютно нативную игру в стиле 80-х, но с современным вниманием к качеству кода. И всё это — с участием милого талисмана Platinum-tan.
Зачем вообще создавать игру в текстовом режиме?
Для нас, разработчиков, работающих с высокоуровневыми фреймворками и богатыми API, подобные проекты становятся отличной возможностью:
Погрузиться в низкоуровневую архитектуру x86
Попрактиковаться в чистой архитектуре и системном программировании
Понять, как можно обойтись без аллокации, без стандартных зависимостей
И просто — почувствовать дух ретро
Архитектура проекта
Проект написан на Rust с использованием #![no_std] и bootimage, что позволяет компилировать игру в виде загрузочного ядра.
|
Модуль |
Назначение |
|---|---|
|
|
Прямая работа с VGA-буфером |
|
|
Чтение клавиш напрямую с |
|
|
Игровая логика, отрисовка, физика мячика |
|
|
Точка входа, игровой цикл, обработка клавиш |
Мячик (o) отскакивает от стен, блоков и платформы
Платформа (=======) управляется клавишами A и D
Цвета блоков зависят от строки (радуга в ASCII)
Поддержка SPACE для начала и R для рестарта
Вывод очков и милых сообщений от Platinum-tan
Немного магии: как работают цвета
ColorCode::new(Color::Red, Color::Black)
Каждый символ в VGA-буфере имеет не только ASCII-байт, но и байт цвета. Мы изменяем эти цвета на лету — и получаем полноцветный «текстовый» арканоид.
Чтение клавиш без драйвера
pub unsafe fn inb(port: u16) -> u8 {
let value: u8;
core::arch::asm!("in al, dx", out("al") value, in("dx") port);
value
}
Клавиши считываются напрямую из порта 0x60 — без драйверов, без ОС, просто железо и вы.
Вывод информации в виртуальную машину кастомный и реализован через vga_buffer так как мы не можем использовать вывод с использованием no_std
...
impl Writer {
pub fn new() -> Self {
Self {
column_position: 0,
color_code: ColorCode::new(Color::Yellow, Color::Black),
buffer: unsafe { &mut *(VGA_BUFFER_ADDR as *mut Buffer) },
}
}
pub fn write_byte(&mut self, byte: u8) {
match byte {
b'n' => self.new_line(),
byte => {
if self.column_position >= BUFFER_WIDTH {
self.new_line();
}
let row = BUFFER_HEIGHT - 1;
let col = self.column_position;
self.buffer.chars[row][col].write(ScreenChar {
ascii_character: byte,
color_code: self.color_code,
});
self.column_position += 1;
}
}
}
pub fn write_string(&mut self, s: &str) {
for byte in s.bytes() {
match byte {
0x20..=0x7e | b'n' => self.write_byte(byte),
_ => self.write_byte(0xfe),
}
}
}
pub fn new_line(&mut self) {
for row in 1..BUFFER_HEIGHT {
for col in 0..BUFFER_WIDTH {
let c = self.buffer.chars[row][col].read();
self.buffer.chars[row - 1][col].write(c);
}
}
self.clear_row(BUFFER_HEIGHT - 1);
self.column_position = 0;
}
fn clear_row(&mut self, row: usize) {
let blank = ScreenChar {
ascii_character: b' ',
color_code: self.color_code,
};
for col in 0..BUFFER_WIDTH {
self.buffer.chars[row][col].write(blank);
}
}
/// Выводит строку по центру последней строки экрана
pub fn write_centered(&mut self, text: &str) {
let len = text.len().min(BUFFER_WIDTH);
let padding = (BUFFER_WIDTH - len) / 2;
self.column_position = padding;
self.write_string(text);
}
...
Как собрать и запустить
Установите Rust nightly и bootimage:
rustup install nightly
rustup component add rust-src --toolchain nightly
cargo install bootimage
Соберите ядро:
cargo +nightly bootimage -Z build-std=core,compiler_builtins --target x86_64-platinum_os.json -Z build-std-features=compiler-builtins-mem --target-dir target/x86_64-platinum_os
Запустите в QEMU:
qemu-system-x86_64 -drive format=raw,file=targetx86_64-platinum_osx86_64-platinum_osdebugbootimage-platinum_os.bin -serial stdio -no-reboot -no-shutdown
Демо: Скриншот
Вдохновение
Это не просто технический эксперимент — это способ выразить любовь к железу, к языку Rust, и к эстетике ASCII-графики. Если вы когда-нибудь мечтали создать свою игру без ОС — сейчас самое время.
Репозиторий и весь код: https://github.com/digkill/platinum-os-arkanoid [2]
Спасибо за внимание!
Автор: AlexCatLeva
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/operatsionny-e-sistemy/418823
Ссылки в тексте:
[1] main.rs: http://main.rs
[2] https://github.com/digkill/platinum-os-arkanoid: https://github.com/digkill/platinum-os-arkanoid
[3] Источник: https://habr.com/ru/articles/907162/?utm_campaign=907162&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.