Rust játék 24 óra alatt: személyes fejlődési élmény

Rust játék 24 óra alatt: személyes fejlődési élmény

Ebben a cikkben személyes tapasztalataimról fogok beszélni egy kis játék fejlesztésével kapcsolatban Rustban. Körülbelül 24 órát vett igénybe egy működő verzió elkészítése (leginkább esténként vagy hétvégén dolgoztam). A játék még korántsem ért véget, de úgy gondolom, hogy az élmény kifizetődő lesz. Megosztom, amit tanultam, és néhány észrevételt, amit a játék építése során tettem.

A Skillbox a következőket ajánlja: Két éves gyakorlati tanfolyam "PRO webfejlesztő vagyok".

Emlékeztetünk: a "Habr" minden olvasója számára - 10 000 rubel kedvezmény, ha a "Habr" promóciós kóddal bármely Skillbox tanfolyamra jelentkezik.

Miért Rust?

Azért választottam ezt a nyelvet, mert sok jót hallottam róla, és úgy látom, egyre népszerűbb a játékfejlesztésben. A játék megírása előtt kevés tapasztalatom volt egyszerű alkalmazások fejlesztésében Rustban. Ez éppen elég volt ahhoz, hogy a játék írása közben egyfajta szabadságot adjon nekem.

Miért a játék és milyen játék?

A játékok készítése szórakoztató! Bárcsak több oka lenne, de az „otthoni” projektekhez olyan témákat választok, amelyek nem kapcsolódnak túl szorosan a szokásos munkámhoz. Milyen játék ez? Valami olyan teniszszimulátort akartam készíteni, amely egyesíti a Cities Skylinest, a Zoo Tycoont, a Prison Architectet és magát a teniszt. Általában egy teniszakadémiáról szóló játéknak bizonyult, ahová az emberek játszani jönnek.

Technikai továbbképzés

A Rust-ot szerettem volna használni, de nem tudtam pontosan, mennyi alapozást igényel az indulás. Nem akartam pixel shadereket írni és drag-n-drop-ot használni, ezért a legrugalmasabb megoldásokat kerestem.

Hasznos forrásokat találtam, amelyeket megosztok veletek:

Több Rust játékmotort is felfedeztem, végül a Piston és a ggez mellett döntöttem. Egy korábbi projektem során találkoztam velük. Végül a ggez-t választottam, mert alkalmasabbnak tűnt egy kis 2D-s játék megvalósítására. A Dugattyú moduláris felépítése túl bonyolult egy kezdő fejlesztő számára (vagy valakinek, aki először dolgozik Rusttal).

A játék felépítése

Eltöltöttem egy kis időt a projekt architektúráján gondolkodva. Az első lépés a "föld", az emberek és a teniszpályák készítése. Az embereknek a bíróságokon kell mozogniuk és várniuk. A játékosoknak olyan képességekkel kell rendelkezniük, amelyek idővel fejlődnek. Ráadásul kellene egy szerkesztő, amivel új embereket és bíróságokat adhatsz hozzá, de ez már nem ingyenes.

Miután mindent átgondoltam, nekiálltam dolgozni.

Játék készítés

Kezdet: Körök és absztrakciók

Vettem egy példát a ggez-ből, és egy kört kaptam a képernyőn. Csodálatos! Most néhány absztrakció. Úgy gondoltam, jó lenne elvonatkoztatni egy játéktárgy gondolatától. Minden objektumot az itt leírtak szerint kell renderelni és frissíteni:

// 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(())
    }
}

Ez a kódrészlet egy szép listát adott azokról az objektumokról, amelyeket egy ugyanolyan szép ciklusban frissíthetek és renderelhetek.

mpl event::EventHandler for MainState {
    fn update(&mut self, context: &mut Context) -> GameResult<()> {
        // Update all objects
        for object in self.objects.iter_mut() {
            object.update(context)?;
        }
 
        Ok(())
    }
 
    fn draw(&mut self, context: &mut Context) -> GameResult<()> {
        graphics::clear(context);
 
        // Draw all objects
        for object in self.objects.iter_mut() {
            object.draw(context)?;
        }
 
        graphics::present(context);
 
        Ok(())
    }
}

A main.rs szükséges, mert az összes kódsort tartalmazza. Egy kis időt töltöttem a fájlok szétválasztásával és a könyvtárszerkezet optimalizálásával. Így nézett ki ezek után:
erőforrások -> itt van az összes eszköz (képek)
src
- entitások
— game_object.rs
— circle.rs
— main.rs -> főhurok

Emberek, padlók és képek

A következő lépés egy Személyes játékobjektum létrehozása és képek betöltése. Mindent 32*32-es csempe alapján kell építeni.

Rust játék 24 óra alatt: személyes fejlődési élmény

Teniszpálya

Miután megvizsgáltam, hogy néznek ki a teniszpályák, úgy döntöttem, hogy 4*2-es lapokból készítem őket. Kezdetben volt lehetőség ekkora képet készíteni, vagy 8 különálló csempét összerakni. De aztán rájöttem, hogy csak két egyedi lapra van szükség, és itt van miért.

Összesen két ilyen lapunk van: 1 és 2.

A pálya minden része az 1. vagy a 2. lapkából áll. Kihelyezhetők normál módon vagy 180 fokkal megfordíthatók.

Rust játék 24 óra alatt: személyes fejlődési élmény

Alapvető építési (összeszerelési) mód

Miután sikerült elérni a helyek, személyek és térképek renderelését, rájöttem, hogy egy alap összeállítási módra is szükség van. Én így valósítottam meg: a gomb megnyomásakor az objektum kijelölésre kerül, és a kattintással a kívánt helyre kerül. Tehát az 1-es gombbal pályát, a 2-es gombbal pedig játékost választhat.

De még mindig emlékeznünk kell arra, hogy mit jelent az 1 és a 2, ezért hozzáadtam egy drótvázat, hogy egyértelmű legyen, melyik objektum van kiválasztva. Így néz ki.

Rust játék 24 óra alatt: személyes fejlődési élmény

Építészeti és refaktorálási kérdések

Most több játéktárgyam van: emberek, pályák és padlók. De ahhoz, hogy a drótvázak működjenek, minden objektum entitásnak meg kell mondani, hogy maguk az objektumok bemutató módban vannak-e, vagy egyszerűen megrajzolják a keretet. Ez nem túl kényelmes.

Számomra úgy tűnt, hogy az architektúrát újra kell gondolni oly módon, hogy felfedjen néhány korlátot:

  • Egy olyan entitás megléte, amely magát rendereli és frissíti, probléma, mert ez az entitás nem lesz képes „tudni”, hogy mit kell renderelnie – egy képet és egy drótvázat;
  • az egyes entitások közötti tulajdonságok és viselkedés cseréjére szolgáló eszköz hiánya (például az is_build_mode tulajdonság vagy viselkedés megjelenítése). Lehetséges lenne az öröklődést használni, bár a Rustban nincs megfelelő módja annak megvalósítására. Amire igazán szükségem volt, az az elrendezés;
  • szükség volt egy eszközre az entitások közötti interakcióhoz ahhoz, hogy embereket bíróságokhoz rendeljenek;
  • maguk az entitások adatok és logika keverékei voltak, amelyek gyorsan kikerültek az irányítás alól.

További kutatásokat végeztem, és felfedeztem az építészetet ECS – Entity Component System, amelyet általában a játékokban használnak. Íme az ECS előnyei:

  • az adatok el vannak választva a logikától;
  • öröklés helyett összetétel;
  • adatközpontú architektúra.

Az ECS-t három alapfogalom jellemzi:

  • entitások – az objektum típusa, amelyre az azonosító hivatkozik (lehet játékos, labda vagy valami más);
  • komponensek – ezekből épülnek fel az entitások. Példa - renderelő komponens, helyek és mások. Ezek adattárházak;
  • rendszerek – objektumokat és komponenseket is használnak, valamint ezeken az adatokon alapuló viselkedést és logikát tartalmaznak. Példa erre egy olyan renderelő rendszer, amely az összes renderelő komponenssel rendelkező entitáson keresztül iterál, és elvégzi a megjelenítést.

Tanulmányozása után világossá vált, hogy az ECS a következő problémákat oldja meg:

  • elrendezés használata öröklődés helyett az entitások rendszerszintű szervezéséhez;
  • a kódzavarok megszabadulása a vezérlőrendszereken keresztül;
  • olyan metódusokkal, mint az is_build_mode, hogy a drótváz logikát ugyanazon a helyen tartsa – a renderelő rendszerben.

Ez történt az ECS bevezetése után.

erőforrások -> itt van az összes eszköz (képek)
src
- alkatrészek
—pozíció.rs
— személy.rs
— tennis_court.rs
— emelet.rs
- drótváz.rs
— mouse_tracked.rs
- erőforrások
-egér.rs
- rendszerek
— rendering.rs
— állandók.rs
— utils.rs
— world_factory.rs -> világgyári funkciók
— main.rs -> főhurok

Embereket rendelünk a bíróságokhoz

Az ECS megkönnyítette az életet. Most szisztematikus módszerem volt arra, hogy adatokat adjak az entitásokhoz, és ezek alapján logikát adjak hozzá. Ez pedig lehetővé tette az emberek bíróságok közötti elosztásának megszervezését.

Mit tettem:

  • hozzáadott adatok a Személyhez rendelt bíróságokról;
  • hozzáadott adatokat az elosztott emberekről a TennisCourthoz;
  • hozzáadva a CourtChoosingSystem-et, amely lehetővé teszi az emberek és a bíróságok elemzését, az elérhető pályák észlelését és a játékosok szétosztását;
  • hozzáadott egy PersonMovementSystem-et, amely megkeresi a bíróságokhoz rendelt személyeket, és ha nincsenek ott, akkor oda küldi az embereket, ahol kell.

Rust játék 24 óra alatt: személyes fejlődési élmény

Összefoglalva

Nagyon élveztem ezen az egyszerű játékon dolgozni. Sőt, örülök, hogy Rust-ot használtam a megírásához, mert:

  • A rozsda megadja, amire szüksége van;
  • kiváló dokumentációval rendelkezik, Rust elég elegáns;
  • a konzisztencia hűvös;
  • nem kell klónozáshoz, másoláshoz vagy más hasonló műveletekhez folyamodnod, amit gyakran csináltam C++-ban;
  • Az opciók nagyon könnyen használhatók, és nagyon jól kezelik a hibákat;
  • ha a projektet sikerült lefordítani, akkor az esetek 99%-ában működik, és pontosan úgy, ahogy kell. Szerintem a fordítói hibaüzenetek a legjobbak, amiket láttam.

A Rust játékfejlesztése még csak most kezdődik. De már van egy stabil és meglehetősen nagy közösség, amely azon dolgozik, hogy mindenki számára megnyissa a Rustot. Ezért bizakodva tekintek a nyelv jövőjére, kíváncsian várom közös munkánk eredményét.

A Skillbox a következőket ajánlja:

Forrás: will.com

Hozzászólás