
I denne artikel vil jeg dele min personlige erfaring med at udvikle et lille spil pÄ Rust. Det tog cirka 24 timer at skabe en fungerende version (primÊrt arbejdede jeg om aftenen eller i weekenden). Spillet er stadig langt fra fÊrdigt, men jeg tror, at erfaringen vil vÊre nyttig. Jeg vil fortÊlle, hvad jeg har lÊrt, og nogle observationer, jeg har gjort under opbygningen af spillet fra bunden.
Skillbox anbefaler: ToÄrigt praktisk kursus .
Vi minder om: til alle lĂŠsere af 'Habr' â rabat pĂ„ 10.000 rubler ved tilmelding til et hvilket som helst Skillbox-kursus med rabatkoden 'Habr'.
Hvorfor Rust?
Jeg valgte dette sprog, fordi jeg havde hÞrt meget godt om det, og jeg kan se, at det bliver mere og mere populÊrt inden for spiludvikling. FÞr jeg begyndte at skrive spillet, havde jeg en smule erfaring med at udvikle simple applikationer pÄ Rust. Det var lige nok til at fÞle en vis frihed under udviklingen af spillet.
Hvorfor netop et spil, og hvad for et spil?
At skabe spil er sjovt! Jeg ville Þnske, at der var flere grunde, men til «hjemmeprojekter» vÊlger jeg emner, der ikke er for tÊt forbundet med mit sÊdvanlige arbejde. Hvad for et spil? Jeg ville gerne lave noget i stil med en tennissimulator, hvor der kombineres Cities Skylines, Zoo Tycoon, Prison Architect og selvfÞlgelig tennis. Samlet set blev det et spil om en tennisklub, hvor folk kommer for at spille.
Teknisk forberedelse
Jeg ville gerne bruge Rust, men jeg vidste ikke prĂŠcis, hvor meget jeg skulle starte âfra bundenâ. Jeg Ăžnskede ikke at skrive pixel-shaders og bruge drag-n-drop, sĂ„ jeg sĂžgte efter de mest fleksible lĂžsninger.
Jeg fandt nyttige ressourcer, som jeg vil dele med dig:
- â en liste over nĂždvendige elementer til spiludvikling i Rust;
Jeg har undersÞgt flere Rust spillemotorer og valgte til sidst Piston og ggez. Jeg stÞdte pÄ dem, da jeg arbejdede pÄ et tidligere projekt. Til sidst valgte jeg ggez, da det syntes mere passende til implementeringen af et lille 2D-spil. Den modulÊre struktur af Piston er for kompleks til en ny udvikler (eller en, der arbejder med Rust for fÞrste gang).
Spilstruktur
Jeg brugte lidt tid pĂ„ at overveje projektets arkitektur. FĂžrste skridt er at lave âjordenâ, menneskerne og tennisbanerne. Folk skal bevĂŠge sig rundt pĂ„ banerne og vente. Spillerne skal have fĂŠrdigheder, der forbedres over tid. Desuden skal der vĂŠre en editor, der tillader tilfĂžjelse af nye mennesker og baner, men det er ikke gratis.
Efter at have gennemtĂŠnkt alt, gik jeg i gang med arbejdet.
Oprettelse af spil
Begyndelse: cirkler og abstraktioner
Jeg tog et eksempel fra ggez og fik en cirkel pÄ skÊrmen. Fantastisk! Nu lidt abstraktioner. Jeg syntes, det ville vÊre godt at abstrahere fra ideen om et spilleobjekt. Hvert objekt skal rendres og opdateres som beskrevet 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 kode gjorde det muligt for mig at fÄ en fantastisk liste over objekter, som jeg kan opdatere og rendere i en lige sÄ fantastisk loop.
mpl event::EventHandler for MainState {
fn update(&mut self, context: &mut Context) -> GameResult {
// Opdater alle objekter
for object in self.objects.iter_mut() {
object.update(context)?;
}
Ok(())
}
fn draw(&mut self, context: &mut Context) -> GameResult {
graphics::clear(context);
// Tegn alle objekter
for object in self.objects.iter_mut() {
object.draw(context)?;
}
graphics::present(context);
Ok(())
}
} main.rs er nÞdvendig, fordi den indeholder alle kodelinjer. Jeg brugte lidt tid pÄ at opdele filer og optimere mappestrukturen. SÄdan sÄ alt ud efterfÞlgende:
resources -> her er alle aktiverne (billeder)
src
â entities
â game_object.rs
â circle.rs
â main.rs -> hovedlĂžkke
Personer, etager og billeder
NÊste skridt er at oprette spilleobjektet Person og indlÊse billeder. Alt skal bygges pÄ fliser, der er 32*32.

Tennisbaner
Efter at have studeret, hvordan tennisbaner ser ud, besluttede jeg at lave dem af fliser 4*2. Oprindeligt kunne man lave et billede af denne stÞrrelse eller samle 8 separate fliser. Men senere indsÄ jeg, at der kun var brug for to unikke fliser, og her er hvorfor.
Vi har i alt to sÄdanne fliser: 1 og 2.
Hver sektion af banen bestÄr af flise 1 eller flise 2. De kan vÊre normalt placeret eller vÊltet 180 grader.

Hovedbygningsmodellen (samlingen)
Efter at have opnÄet rendering af banerne, folkene og kortene, indsÄ jeg, at jeg ogsÄ havde brug for en grundlÊggende samlingsmode. Jeg implementerede det sÄledes: nÄr knappen er trykket pÄ - objektet er valgt, og klikker placerer det pÄ det Þnskede sted. SÄ knap 1 giver mulighed for at vÊlge banen, mens knap 2 tillader at vÊlge spilleren.
Men man skal ogsÄ huske, hvad 1 og 2 betyder, derfor tilfÞjede jeg et wireframe for at gÞre det klart, hvilket objekt der er valgt. SÄdan ser det ud.

SpÞrgsmÄl om arkitektur og refactoring
Nu har jeg flere spilelementer: mennesker, baner og etager. Men for at wireframes skal fungere, skal hver objekts entitet informeres om, hvorvidt selve objekterne er i demonstrationsmodus, eller om der blot er tegnet en ramme. Det er ikke sĂŠrlig praktisk.
Jeg syntes, det var nÞdvendigt at gentÊnke arkitekturen, sÄ nogle begrÊnsninger kunne fremhÊves:
- tilstedevĂŠrelsen af en entitet, der viser og opdaterer sig selv, er et problem, da denne entitet ikke kan 'vide', hvad den skal gengive - billede og wireframe;
- manglen pÄ et vÊrktÞj til at udveksle egenskaber og adfÊrd mellem individuelle entiteter (f.eks. egenskaben is_build_mode eller gengivelse af adfÊrd). Man kunne have brugt inheritance, selvom der ikke er nogen ordentlig mÄde at implementere det pÄ i Rust. Hvad jeg virkelig havde brug for, var sammensÊtning;
- et vĂŠrktĂžj til at interagere mellem entiteter var nĂždvendigt for at tildele mennesker til banerne;
- selve entiteterne var en blanding af data og logik, hvilket hurtigt kom ud af kontrol.
Jeg foretog en yderligere undersĂžgelse og opdagede arkitekturen , som normalt anvendes i spil. Her er fordelene ved ECS:
- data er adskilt fra logik;
- komposition i stedet for arv;
- dataorienteret arkitektur.
ECS er kendetegnet ved tre grundlĂŠggende koncepter:
- entiteter - en type objekt, som en identifikator refererer til (det kan vĂŠre en spiller, en bold eller noget andet);
- komponenter - som entiteterne bestÄr af. Eksempel - en rendering komponent, placering, og andre. Dette er datalagre;
- systemer - de bruger bÄde objekter og komponenter, plus indeholder adfÊrd og logik baseret pÄ disse data. Eksempel - et renderingssystem, der itererer over alle entiteter med komponenter til rendering og hÄndterer gengivelsen.
Efter undersÞgelsen blev det klart, at ECS lÞser sÄdanne problemer:
- anvendelsen af komposition i stedet for arv til systematisk organisering af entiteter;
- fjernelse af kodekaos ved hjĂŠlp af kontrolsystemer;
- brug af metoder som is_build_mode til at opbevare logikken for wireframe pÄ ét sted - i renderingssystemet.
Her er, hvad der kom ud af implementeringen af ECS.
resources -> her er alle aktiverne (billeder)
src
â components
â position.rs
â person.rs
â tennis_court.rs
â floor.rs
â wireframe.rs
â mouse_tracked.rs
â resources
â mouse.rs
â systems
â rendering.rs
â constants.rs
â utils.rs
â world_factory.rs -> verdens fabriksfunktioner
â main.rs -> hovedlĂžkke
Tildeler folk til banerne
ECS har gjort livet nemmere. Nu havde jeg en systematisk mÄde at tilfÞje data til enhederne og tilfÞje logik baseret pÄ disse data. Dette gjorde det muligt at organisere fordelingen af folk til banerne.
Hvad jeg har gjort:
- tilfĂžjet data om tildelte baner til Person;
- tilfĂžjet data om fordelte personer til TennisCourt;
- tilfĂžjet CourtChoosingSystem, der analyserer folk og steder, opdager ledige baner og fordeler spillere til dem;
- tilfĂžjet PersonMovementSystem, der leder efter personer, der er tildelt til banerne, og hvis de ikke er der, sender folk derhen, hvor de skal vĂŠre.

Sammenfatning
Jeg nÞd virkelig at arbejde pÄ dette enkle spil. Desuden er jeg glad for, at jeg brugte Rust til at skrive det, fordi:
- Rust giver dig det, du har brug for;
- den har fremragende dokumentation, Rust er meget elegant;
- konstanten er fantastisk;
- jeg behĂžver ikke at ty til kloning, kopiering eller lignende handlinger, som jeg ofte gjorde i C++;
- Options er meget praktiske at arbejde med, de hÄndterer ogsÄ fejl fremragende;
- hvis projektet kunne kompilere, sÄ fungerer det i 99%, og prÊcis som det skal. Kompilationsfejlmeddelelserne er efter min mening de bedste, jeg har set.
Spiludvikling pÄ Rust er kun lige begyndt. Men der er allerede et stabilt og ret stort fÊllesskab, der arbejder pÄ at gÞre Rust tilgÊngelig for alle. Derfor ser jeg optimistisk pÄ fremtiden for sproget og ser frem til resultaterne af vores fÊlles arbejde.
Skillbox anbefaler:
- Online kursus .
- Praktisk kursus .
- Praktisk Ärs kursus .
Kilde: habr.com
