
Bu məqalədə mən Rust-da kiçik bir oyun inkişaf etdirmək haqqında şəxsi təcrübəmi paylaşacağam. İşlək versiyanı yaratmaq üçün təxminən 24 saat vaxt sərf olunub (əsasən axşamlar və ya həftə sonları çalışdım). Oyun hələ tamamlanmayıb, amma düşünürəm ki, təcrübə faydalı olacaq. Mən nə öyrəndiyimi və oyunu sıfırdan qurarkən əldə etdiyim bəzi müşahidələri paylaşacağam.
Skillbox tövsiyə edir: İki illik praktiki kurs .
Xatırladırıq: bütün «Habr» oxucularına — «Habr» promo kodu ilə Skillbox-dakı hər hansı kursa qeydiyyat zamanı 10 000 rubl endirim.
Niyə Rust?
Bu dili seçdim, çünki onun haqqında çox şey eşitmişdim və oyun inkişaf etdirmə sahəsində getdikcə daha çox populyarlaşdığını görürəm. Oyun yazmadan əvvəl Rust-da sadə tətbiqlərin inkişafında kiçik bir təcrübəm var idi. Bu, oyunu yazarkən müəyyən bir azadlığın olduğunu hiss etmək üçün kifayət qədər idi.
Niyə məhz oyun və hansı oyun?
Oyun yaratmaq əyləncəlidir! Daha çox səbəb olsun istərdim, amma «ev» layihələri üçün mövzular seçərkən, adi işimlə çox sıx bağlı olmayanları seçirəm. Hansi oyun? Mən Cities Skylines, Zoo Tycoon, Prison Architect və tennisin birləşdiyi bir tennis simulyatorunun bir versiyasını yaratmaq istəyirdim. Yəni, nəticədə insanların oynamaq üçün gəldiyi bir tennis akademiyası haqqında bir oyun ortaya çıxdı.
Texniki hazırlıq
Rust istifadə etmək istəyirdim, amma nə qədər «sıfırdan» başlamaq lazım olduğunu dəqiq bilmirədim. Piksel şeyderləri yazmaq və drag-n-drop istifadə etmək istəmirdim, ona görə də ən çevik həlləri axtarırdım.
Sizinlə bölüşdüyüm faydalı resurslar tapdım:
- — oyun inkişafı üçün lazım olan Rust elementlərinin siyahısı;
Bir neçə Rust oyun motorunu öyrəndim, nəticədə Piston və ggez-i seçdim. Onlarla əvvəlki layihəmdə rastlaşmışdım. Nəticədə ggez-i seçdim, çünki o kiçik bir 2D oyunun həyata keçirilməsi üçün daha uyğun görünürdü. Piston-un modul strukturu yeni başlayan bir inkişafçı (və ya Rust ilə ilk dəfə işləyən biri) üçün həddən artıq mürəkkəbdir.
Oyun strukturu
Mən layihənin arxitekturası üzərində düşündüm. İlk addım «torpaq», insanlar və tennis kortlarını yaratmaqdır. İnsanlar kortlar üzrə hərəkət etməli və gözləməlidir. Oyunçuların zamanla inkişaf edən bacarıqları olmalıdır. Üstəlik, yeni insanlar və kortlar əlavə etməyə imkan verən bir redaktor olmalıdır, amma bu artıq pulsuz deyil.
Hamısı düşünüldükdən sonra, işə başladım.
Oyun yaratmaq
Başlanğıc: dairələr və abstraksiyalar
ggez-dən bir nümunə götürdüm və ekranda bir dairə meydana gətirdim. Təəccüblüdür! İndi bir az abstraxiyalar. Mən oyun obyektinin ideyasından uzaqlaşmağın yaxşı olacağını düşündüm. Hər bir obyekt burada qeyd olunduğu kimi render edilməli və yenilənməlidir:
// the game object trait
trait GameObject {
fn update(&mut self, _ctx: &mut Context) -> GameResult<()>;
fn draw(&mut self, ctx: &mut Context) -> GameResult<()>;
}
// a specific game object - Circle
struct Circle {
position: Point2,
}
impl Circle {
fn new(position: Point2) -> Circle {
Circle { position }
}
}
impl GameObject for Circle {
fn update(&mut self, _ctx: &mut Context) -> GameResult<()> {
Ok(())
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
let circle =
graphics::Mesh::new_circle(ctx, graphics::DrawMode::Fill, self.position, 100.0, 2.0)?;
graphics::draw(ctx, &circle, na::Point2::new(0.0, 0.0), 0.0)?;
Ok(())
}
}Bu kod parçası mənə yenilənə bilən və render edilən əla obyektlərin siyahısını əldə etməyə imkan verdi, eyni dərəcədə əla bir dövrədə.
mpl event::EventHandler for MainState {
fn update(&mut self, context: &mut Context) -> GameResult {
// Bütün obyektləri güncəllə
for object in self.objects.iter_mut() {
object.update(context)?;
}
Ok(())
}
fn draw(&mut self, context: &mut Context) -> GameResult {
graphics::clear(context);
// Bütün obyektləri çəkmək
for object in self.objects.iter_mut() {
object.draw(context)?;
}
graphics::present(context);
Ok(())
}
} main.rs tələb olunur, çünki burada bütün kod sətirləri var. Faylları bölməyə və direktoriyaların strukturunu optimallaşdırmağa bir az vaxt sərf etdim. Budur, prosesdən sonra hər şey necə görünür:
resources -> burada bütün resurslar (şəkillər) saxlanılır
src
— entities
— game_object.rs
— circle.rs
— main.rs -> əsas döngə
İnsanlar, məkanlar və şəkillər
Növbəti mərhələ — oyun obyekti Person yaratmaq və şəkilləri yükləmək. Hər şey 32*32 ölçülü plitələr əsasında inşa olunmalıdır.

Tennis kortları
Tennis kortlarının necə göründüyünü öyrəndikdən sonra, onları 4*2 plitələrdən hazırlamağa qərar verdim. Başlanğıcda belə ölçüdə şəkil yaratmaq mümkündü ya da 8 ayrı plitəni birləşdirmək olardı. Lakin sonra anladım ki, yalnız iki unikal plitə lazımdır və səbəb budur.
Ümumilikdə bizdə iki belə plitə var: 1 və 2.
Hər kortun bölməsi ya plitə 1, ya da plitə 2-dən ibarətdir. Onlar normal şəkildə yerləşə bilər və ya 180 dərəcə çevrilə bilər.

Əsas inşaat rejimi (montaj)
Məni meydançaların, insanların və xəritələrin renderinqini əldə etdikdən sonra, əsas montaj rejiminin də olduğunu anladım. Belə həyata keçirdim: düymə basıldığında - obyekt seçilir, klik isə onu lazım olan yerdə yerləşdirir. Beləliklə, 1 düyməsi kortu seçmə imkanı verir, 2 düyməsi isə oyunçunu seçir.
Ancaq 1 və 2-nin nəyi ifadə etdiyini qeyd etmək lazım olduğu üçün seçilən obyektin hansı olduğunu anlamaq üçün bir wireframe əlavə etdim. Budur, bu necə görünür.

Arxitektura və refaktorizasiya ilə bağlı suallar
İndi bir neçə oyun obyekti var: insanlar, kortlar və mərtəbələr. Ancaq wireframe-lərin işləməsi üçün hər bir obyektin özünün nümayiş rejimində olduğunu ya da yalnız kontur çəkildiyini bildirmək lazımdır. Bu, çox rahatdır.
Arxitekturanı bir az yenidən düşünməyin lazım olduğu fikrinə gəldim ki, bəzi məhdudiyyətlər ortaya çıxsın:
- özünü göstərən və yeniləyə bilən obyektin olması — problem, çünki bu obyekt 'nəyi' render etməli olduğunu bilə bilməz — şəkil və wireframe;
- ayrı-ayrı obyektlər arasında mülkiyyət və davranışları bölüşmək üçün alət yoxdur (məsələn — is_build_mode xassəsi ya da render etmə davranışı). İrsdən istifadə etmək olardı, amma Rust-da bunu həyata keçirmək üçün normal bir yol yoxdur. Mənim ehtiyacım olan əslində kompozisiyadır;
- obyektlər arasında qarşılıqlı əlaqə üçün bir alət lazımdır ki, insanları kortlara təyin edə bilsin;
- varlıqlar məlumatların və məntiqin qarışığını təmsil edirdi ki, bu da çox tez kontroldan çıxırdı.
Mən əlavə öyrənmə apardım və arxitekturu kəşf etdim , adətən oyunlarda istifadə olunur. ECS-nin üstünlükləri bunlardır:
- məlumat məntiqdən ayrılır;
- təsis etmə əvəzinə tərkib;
- məlumatlara yönəldilmiş arxitektura.
ECS-nin üç əsas konsepsiyası var:
- varlıqlar - identifikatorla istinad olunan obyektin növüdür (bu oyunçu, top və ya bir şey ola bilər);
- komponentlər - varlıqları yaranan tərkib hissələridir. Məsələn - render komponenti, yerləşmə və başqaları. Bunlar məlumatların anbarlarıdır;
- sistemlər - həm obyektləri, həm də komponentləri istifadə edir, plus bu məlumatlar əsasında davranış və məntiqi ehtiva edir. Məsələn - bütün render komponentləri olan varlıqları dövr edən render sistemi və onun renderlənməsi ilə məşğuldur.
Araşdırma nəticəsində aydın oldu ki, ECS belə problemləri həll edir:
- varlıqların sistematik təşkilati sxemi üçün tərkibi istifadə etmək;
- idarəetmə sistemləri ilə kodun qarışığından xilas olmaq;
- is_build_mode kimi metodları istifadə edərək, məntiqi eyni yerdə - render sistemində saxlamaq.
ECS-i tətbiq etdikdən sonra görünən nəticə budur.
resources -> burada bütün resurslar (şəkillər) saxlanılır
src
— komponentlər
— position.rs
— person.rs
— tennis_court.rs
— floor.rs
— wireframe.rs
— mouse_tracked.rs
— resurslar
— mouse.rs
— sistemlər
— rendering.rs
— constants.rs
— utils.rs
— world_factory.rs -> dünya fabriki funksiyaları
— main.rs -> əsas döngə
İnsanları kortlara təyin edirik
ECS, həyatı asanlaşdırdı. İndi mənim varlıqlara məlumat əlavə etmək və bu məlumatlara əsaslanaraq məntiq əlavə etmək üçün sistematik bir yolum var idi. Bu da, insanların kortlara təyinatını təşkil etməyə imkan tanıdı.
Mən nə etdim:
- Təyin olunan kortlar haqqında məlumatı Person-a əlavə etdim;
- TennisCourt-da paylanmış insanlar haqqında məlumat əlavə etdim;
- İnsanları və sahələri analiz etmək, mövcud kortları aşkar etmək və oyunçuları onlara təyin etmək imkanı verən CourtChoosingSystem-i əlavə etdim;
- Kortlara təyin olunmuş insanları axtaran və olmadıqda insanları lazım olan yerə göndərən PersonMovementSystem-i əlavə etdim.

Nəticələri yekunlaşdırırıq
Bu sadə oyun üzərində işləmək mənim üçün çox xoş oldu. Üstəlik, onu yazmaq üçün Rust-dan istifadə etdiyim üçün məmnun qaldım, çünki:
- Rust sizə lazım olanı təqdim edir;
- onun əla sənədləri var, Rust olduqca zərifdir;
- davamlılıq - bu, mükəmməldir;
- klonlama, kopyalama və ya C++-da tez-tez etdiyim digər oxşar hərəkətlərə baş vurmağa ehtiyac yoxdur;
- Options işləmək üçün çox rahatdır, həmçinin xətaları mükəmməl idarə edirlər;
- əgər layihəni tərtib etmək mümkündürsə, 99% hallarda düzgün çalışır. Kompilyator xətalarının mesajları, gördüyüm ən yaxşılarıdır.
Rust dilində oyun inkişafı hələ yeni başlanır. Ancaq artıq Rust-u hər kəs üçün açmaq üçün çalışan sabit və xeyli böyük bir icma var. Buna görə də, dilin gələcəyinə optimist yanaşıram, ortaq işimizin nəticələrini səbirsizliklə gözləyirəm.
Skillbox tövsiyə edir:
- Onlayn-kurs .
- Praktik kurs .
- Praktik illik kurs .
Mənbə: habr.com
