Å spille Rust på 24 timer: erfaring med personlig utvikling

Å spille Rust på 24 timer: erfaring med personlig utvikling

I denne artikkelen vil jeg snakke om min personlige erfaring med å utvikle et lite spill i Rust. Det tok omtrent 24 timer å lage en fungerende versjon (jeg jobbet stort sett på kveldene eller i helgene). Spillet er langt fra ferdig, men jeg tror opplevelsen vil være givende. Jeg vil dele det jeg lærte og noen observasjoner jeg gjorde mens jeg bygde spillet fra bunnen av.

Skillbox anbefaler: Toårig praktisk kurs "Jeg er en PRO-nettutvikler".

Vi minner om: for alle lesere av "Habr" - en rabatt på 10 000 rubler når du melder deg på et hvilket som helst Skillbox-kurs ved å bruke kampanjekoden "Habr".

Hvorfor rust?

Jeg valgte dette språket fordi jeg har hørt mye bra om det, og jeg ser at det blir mer og mer populært innen spillutvikling. Før jeg skrev spillet, hadde jeg liten erfaring med å utvikle enkle applikasjoner i Rust. Dette var akkurat nok til å gi meg en følelse av frihet mens jeg skrev spillet.

Hvorfor spillet og hva slags spill?

Å lage spill er gøy! Jeg skulle ønske det var flere grunner, men for "hjemme"-prosjekter velger jeg temaer som ikke er for nært knyttet til mitt vanlige arbeid. Hvilket spill er dette? Jeg ønsket å lage noe som en tennissimulator som kombinerer Cities Skylines, Zoo Tycoon, Prison Architect og tennis selv. Generelt viste det seg å være et spill om et tennisakademi hvor folk kommer for å spille.

Teknisk trening

Jeg ønsket å bruke Rust, men jeg visste ikke nøyaktig hvor mye grunnarbeid det ville ta for å starte. Jeg ville ikke skrive pixel shaders og bruke dra-n-slipp, så jeg var på utkikk etter de mest fleksible løsningene.

Jeg fant nyttige ressurser som jeg deler med deg:

Jeg utforsket flere Rust-spillmotorer, og til slutt valgte jeg Piston og ggez. Jeg kom over dem mens jeg jobbet med et tidligere prosjekt. Til slutt valgte jeg ggez fordi det virket mer egnet for å implementere et lite 2D-spill. Pistons modulære struktur er for kompleks for en nybegynnerutvikler (eller noen som jobber med Rust for første gang).

Spillstruktur

Jeg brukte litt tid på å tenke på arkitekturen til prosjektet. Første steg er å lage «land», folk og tennisbaner. Folk må bevege seg rundt på banene og vente. Spillere må ha ferdigheter som forbedres over tid. I tillegg bør det være en editor som lar deg legge til nye personer og domstoler, men dette er ikke lenger gratis.

Etter å ha tenkt gjennom alt, begynte jeg å jobbe.

Oppretting av spill

Begynnelse: Sirkler og abstraksjoner

Jeg tok et eksempel fra ggez og fikk en sirkel på skjermen. Strålende! Nå noen abstraksjoner. Jeg tenkte det ville være fint å abstrahere bort fra ideen om et spillobjekt. Hvert objekt må gjengis og oppdateres som angitt her:

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

Denne kodebiten ga meg en fin liste over objekter som jeg kunne oppdatere og gjengi i en like fin loop.

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

main.rs er nødvendig fordi den inneholder alle kodelinjene. Jeg brukte litt tid på å skille filene og optimalisere katalogstrukturen. Slik så det ut etter det:
ressurser -> det er her alle eiendelene er (bilder)
src
- enheter
— game_object.rs
— sirkel.rs
— main.rs -> hovedsløyfe

Mennesker, gulv og bilder

Det neste trinnet er å lage et Person-spillobjekt og laste inn bilder. Alt skal bygges på grunnlag av 32*32 fliser.

Å spille Rust på 24 timer: erfaring med personlig utvikling

Tennisbaner

Etter å ha studert hvordan tennisbaner ser ut, bestemte jeg meg for å lage dem av 4*2 fliser. I utgangspunktet var det mulig å lage et bilde av denne størrelsen, eller å sette sammen 8 separate fliser. Men så skjønte jeg at det bare trengtes to unike fliser, og her er hvorfor.

Totalt har vi to slike fliser: 1 og 2.

Hver seksjon av banen består av flis 1 eller flis 2. De kan legges ut som normalt eller vendes 180 grader.

Å spille Rust på 24 timer: erfaring med personlig utvikling

Grunnleggende konstruksjon (montering) modus

Etter at jeg klarte å oppnå gjengivelse av nettsteder, personer og kart, innså jeg at en grunnleggende monteringsmodus også var nødvendig. Jeg implementerte det slik: når knappen trykkes, velges objektet, og klikket plasserer det på ønsket sted. Så, knapp 1 lar deg velge en bane, og knapp 2 lar deg velge en spiller.

Men vi må fortsatt huske hva 1 og 2 betyr, så jeg la til en wireframe for å gjøre det klart hvilket objekt som ble valgt. Slik ser det ut.

Å spille Rust på 24 timer: erfaring med personlig utvikling

Arkitektur og refaktoriseringsspørsmål

Nå har jeg flere spillobjekter: mennesker, baner og gulv. Men for at wireframes skal fungere, må hver objektenhet bli fortalt om selve objektene er i demonstrasjonsmodus, eller om en ramme ganske enkelt er tegnet. Dette er ikke veldig praktisk.

Det virket for meg som om arkitekturen måtte revurderes på en måte som avslørte noen begrensninger:

  • Å ha en enhet som gjengir og oppdaterer seg selv er et problem fordi den enheten ikke vil være i stand til å "vite" hva den skal gjengi - et bilde og en wireframe;
  • mangel på et verktøy for å utveksle egenskaper og atferd mellom individuelle enheter (for eksempel egenskapen is_build_mode eller atferdsgjengivelse). Det ville være mulig å bruke arv, selv om det ikke er noen riktig måte å implementere det i Rust. Det jeg virkelig trengte var oppsettet;
  • et verktøy for samhandling mellom enheter var nødvendig for å tildele folk til domstoler;
  • selve enhetene var en blanding av data og logikk som raskt kom ut av kontroll.

Jeg gjorde litt mer forskning og oppdaget arkitekturen ECS - Entity Component System, som ofte brukes i spill. Her er fordelene med ECS:

  • data er atskilt fra logikk;
  • sammensetning i stedet for arv;
  • datasentrisk arkitektur.

ECS er preget av tre grunnleggende konsepter:

  • enheter - typen objekt som identifikatoren refererer til (det kan være en spiller, en ball eller noe annet);
  • komponenter - enheter består av dem. Eksempel - gjengivelseskomponent, lokasjoner og annet. Dette er datavarehus;
  • systemer - de bruker både objekter og komponenter, pluss inneholder atferd og logikk som er basert på disse dataene. Et eksempel er et gjengivelsessystem som itererer gjennom alle enheter med gjengivelseskomponenter og utfører gjengivelsen.

Etter å ha studert det, ble det klart at ECS løser følgende problemer:

  • bruke layout i stedet for arv for å organisere enheter systemisk;
  • bli kvitt kodevirvar gjennom kontrollsystemer;
  • ved å bruke metoder som is_build_mode for å holde wireframe-logikken på samme sted - i gjengivelsessystemet.

Dette er hva som skjedde etter implementering av ECS.

ressurser -> det er her alle eiendelene er (bilder)
src
- komponenter
—posisjon.rs
— person.rs
— tennis_court.rs
— etasje.rs
- wireframe.rs
— mouse_tracked.rs
- ressurser
—mus.rs
- systemer
— gjengivelse.rs
— konstanter.rs
— utils.rs
— world_factory.rs -> verdens fabrikkfunksjoner
— main.rs -> hovedsløyfe

Vi tildeler folk til domstolene

ECS har gjort livet enklere. Nå hadde jeg en systematisk måte å legge til data til enheter og legge til logikk basert på disse dataene. Og dette gjorde det igjen mulig å organisere fordelingen av personer mellom domstolene.

Hva har jeg gjort:

  • lagt til data om tildelte domstoler til Person;
  • lagt til data om distribuerte personer til TennisCourt;
  • lagt til CourtChoosingSystem, som lar deg analysere mennesker og baner, oppdage tilgjengelige baner og distribuere spillere til dem;
  • lagt til et PersonMovementSystem, som ser etter personer som er tildelt domstolene, og hvis de ikke er der, sender de folk dit de skal være.

Å spille Rust på 24 timer: erfaring med personlig utvikling

Oppsummering

Jeg likte virkelig å jobbe med dette enkle spillet. Dessuten er jeg glad for at jeg brukte Rust til å skrive det, fordi:

  • Rust gir deg det du trenger;
  • den har utmerket dokumentasjon, Rust er ganske elegant;
  • konsistensen er kul;
  • du trenger ikke å ty til kloning, kopiering eller andre lignende handlinger, som jeg ofte gjorde i C++;
  • Alternativene er veldig enkle å bruke og håndterer feil veldig bra;
  • hvis prosjektet var i stand til å bli kompilert, fungerer det 99 % av tiden, og akkurat som det skal. Jeg tror kompilatorfeilmeldingene er de beste jeg har sett.

Spillutviklingen i Rust har så vidt begynt. Men det er allerede et stabilt og ganske stort fellesskap som jobber for å åpne Rust for alle. Derfor ser jeg på fremtiden til språket med optimisme, og ser frem til resultatene av vårt felles arbeid.

Skillbox anbefaler:

Kilde: www.habr.com

Legg til en kommentar