
Այս հոդվածում ես կիսվում եմ Rust-ում փոքր խաղի մշակման իմ անձնական փորձով: Աշխատող տարբերակի ստեղծման համար անհրաժեշտ էր մոտ 24 ժամ (главно աշխատել եմ երեկոներին կամ հանգստյան օրերին): Խաղը դեռ հեռու է ավարտվելուց, բայց կարծում եմ, որ փորձը օգտակար կլինի: Ես կպատմեմ, ինչ եմ սովորել և մի շարք դիտարկումների մասին, որոնք կատարել եմ խաղը զրոյից կառուցելիս:
Skillbox խորհուրդ է տալիս: Երկամյա պրատիկ փուս .
Մոռացեք. Բոլոր «Հաբր» ընթերցողների համար— 10 000 ռուբլի զեղչ որևէ Skillbox դասընթացի գրանցման համար «Հաբր» промոկոդով։
pourquoi Rust?
Ես ընտրեցի այս լեզուն, քանի որ շատ լավ բաներ եմ լսել դրա մասին և տեսնում եմ, որ այն increasingly հայտնի է խաղերի մշակման ոլորտում: Խաղի գրառման նախքան ունեցել եմ փոքրիկ փորձ Rust-ում առավել պարզ ծրագրեր մշակելու մեջ: Սա բավական էր, որպեսզի առարկայական ազատություն զգայի խաղը գրելիս:
Ինչու հենց խաղ և ինչ խաղ է դա?
Խաղեր ստեղծելը ուրախ է! Ես կցանկանայի, որ պատճառները շատ լինեն, բայց «տուն» նախագծերի համար ընտրում եմ թեմաներ, որոնք ոչ այնքան սերտ կապված են իմ սովորական աշխատանքին: Որ խաղ է դա? Ես ցանկանում էի ստեղծել մի բան, ինչպիսիք են տենիսային սիմուլյատոր, որտեղ համադրվում են Cities Skylines, Zoo Tycoon, Prison Architect և իսկապես տենիս: Ընդհանուր առմամբ, ստացվեց խաղ տենիս ակադեմիայի մասին, ուր մարդիկ գալիս են խաղալու:
Տեխնիկական պատրաստություն
Ես ցանկանում էի օգտագործել Rust-ը, բայց հասկանալի չէր, թե որքան «զրոյից» պետք է սկսեմ աշխատել: Ես չէի ցանկանում գրել պիքսելային շեյդերներ և օգտագործել drag-n-drop, ուստի փնտրում էի առավել ճկուն լուծումներ:
Այնուամենայնիվ, ես գտա օգտակար ռեսուրսներ, որոնք կիսում եմ ձեզ հետ:
- — Rust-ում խաղերի մշակման համար անհրաժեշտ տարրերի ցուցակ;
Ես ուսումնասիրեցի մի շարք Rust խաղային շարժիչներ, վերջում ընտրելով Piston և ggez: Ես հանդիպել եմ դրանց նախորդ նախագծում աշխատելիս: Ի վերջո ընտրեցի ggez, քանի որ այն ենթադրում էր ավելի հարմարավետություն փոքր 2D խաղի իրականացման համար: Piston-ի մոդուլային կառուցվածքը շատ բարդ է սկսնակ մշակողի համար (կամ այն մարդու համար, ով առաջին անգամ Rust-ով է աշխատում):
Խաղի կառուցվածքը
Ես մի փոքր ժամանակ ծախսեցի նախագծի ճարտարապետության վրա մտածելու համար: Առաջին քայլը՝ «երկրիս», մարդկանց և տենիսային կորտերի ստեղծում: Մարդիկ պետք է շարժվեն կորտերում և սպասեն: խաղացողները պետք է ունենան հմտություններ, որոնք զարգանում են ժամանակի ընթացքում: Բացի այդ, պետք է լինի խմբագիր, որը թույլ է տալիս ավելացնել նոր մարդկանց և կորտեր, բայց դա արդեն անվճար չէ:
Պրոֆեսիոնալ ի վերջո, սկսեցի աշխատել:
Խաղ ստեղծելը
Սկիզբ: շրջաններ և աբստրակցիաներ
Ես ggez-ից օրինակը վերցրեցի և կլորություն ստացա էկրանին: Ապրեք! Հիմա մի փոքր աբստրակցիաներ: Мне показалось, что неплохо абстрагироваться от идеи игрового объекта. Каждый объект должен быть отрендерен и обновлен, как указано здесь:
// 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(())
}
}Այս կոդի հատվածը հնարավորություն տվեց ինձ ստանալ կատարյալ ցուցակ объектов статических объектов, որոնք կարող եմ թարմացնել և ներկայացնել նույնքան լավ ցիկլում:
mpl event::EventHandler համար MainState {
fn update(&mut self, context: &mut Context) -> GameResult {
// Թարմացնել բոլոր օբյեկտները
for object in self.objects.iter_mut() {
object.update(context)?;
}
Ok(())
}
fn draw(&mut self, context: &mut Context) -> GameResult {
graphics::clear(context);
// Ստանալ բոլոր օբյեկտները
for object in self.objects.iter_mut() {
object.draw(context)?;
}
graphics::present(context);
Ok(())
}
} main.rs անհրաժեշտ է, քանի որ այնտեղ - բոլոր կոդի տողերը: Ես մի քիչ ժամանակ անցկացրեցի, որպեսզի բաժանեմ ֆայլերը և օպտիմալացնեմ կատալոգի կառուցվածքը: Вот так все դարձավ այս հաջորդականությամբ:
resources -> այստեղ գտնվում են բոլոր նյութերը (նկարները)
src
— entities
— game_object.rs
— circle.rs
— main.rs -> հիմնական վճռականություն
People, platforms and images
Հաջորդ փուլը `Person` խաղի օբյեկտի ստեղծումն է և պատկերների загрузка: Ամեն ինչ պետք է լինի 32*32 չափսի խոնավների հիմնաթող հիման վրա:

Tennis courts
Տենիսային ملعبները ուսումնասիրելուց հետո, ես որոշեցի դրանք ստանալ 4*2 խոնավների հիման վրա: Առաջին հերթին, դուք կարող եք ստեղծել նկարը այդ չափով կամ միասին միացնել 8 առանձին խոնավներ: Բայց ապա ես հասկացա, որ անհրաժեշտ են միայն երկու յուրահատուկ խոնավներ և вот թե ինչու:
Մեր հետապնդում ենք այս երկու խոնավները: 1 և 2.
Յուրաքանչյուր դատարանի հատվածը բաղկացած է 1 կամ 2 խոնավներից: Նրանք կարող են տեղակայվել սովորաբար կամ շրջվել 180 աստիճան.

Դպրոցական (այժմ) կառուցման ռեժիմը
Երբ ես հասկացա, որ ստանալս ` պլատֆորմները, մարդիկ և քարտերը, ես հասկացա, որ ստիպված եղան ձեռքի հիմնական կարգավորումը: Դա իրականացրի այնպես, որ երբ կտտացնում ենք կոճակը - օբյեկտը ընտրված է, իսկ կտտացումն այն տեղն է, որտեղ այն կտեղակայվի: Այսպիսով, բանալին 1 թույլ է տալիս ընտրել դատարանը, իսկ բանալին 2 - ընտրել խաղացողը.
Բայց պետք է հիշել, թե ինչ է նշանակում 1 և 2, այդպես ես ավելացրեցի վայերֆրեյմ, որպեսզի հասկանանք, թե որն է ընտրված օբյեկտը: Вот այնպես սա выглядит.

Արվարձանների հարցեր և արձագանք
Այժմ ես ունեմ մի քանի խաղային օբյեկտներ: մարդիկ, դատարաններ և խոնավներ: Բայց որպեսզի վայերֆրեյմները աշխատեն, անհրաժեշտ է յուրաքանչյուր օբյեկտի միավորի վրա նշել, արդյօք ինքներդ օբյեկտները ցուցադրվող ռեժիմում են, թե միայն նկարագրված է շրջանակը: Սա չնչին հարմար չէ.
Ես կարծում եմ, որ պետք է նորից մտածել կառուցվածքը, որպեսզի գտնվեն որոշ սահմանափակումներ:
- նախկինության առկայություն, որը պատկերացնում և թարմացնում է իրեն - խնդիր է, քանի որ այդ առկայությունը չի կարող "ճանաչել", թե ինչ պետք է նախապատկերել - պատկեր և վայերֆրեյմ;
- հատուկ առկայությունների (օրինակ՝ is_build_mode կամ նկարված վարելու) միջև կոմպոնենքի պակասը: Կարելի է օգտագործել ժառանգություն, սակայն Ռուստում չկա նորմալ մեթոդ: Իհարկե, ինձ պետք է композիցիոն;
- օբյեկտների միջև փոխվերադարադրման գործիք պետք է, որպեսզի հատկացնենք մարդկանց դատարաններում;
- պիտի սեցինները միաձուլված են տվյալների և տրամաբանության, ինչը շատ արագ դուրս էր գալիս վերահսկողությունից։
Ես իրականացրեցի լրացուցիչ ուսումնասիրություն և հայտնաբերեցի ճարտարապետություն , որը սովորաբար օգտագործվում է խաղերում: Այստեղ են ECS-ի առավելությունները՝
- տվյալները բաժանված են տրամաբանությունից;
- կոմպոզիցիա, ոչ ժառանգություն;
- տվյալներին ուղղված ճարտարապետություն։
ECS-ի հիմնական երեք գաղափարներն են՝
- սեցիները — այն օբյեկտի տեսակը, որի վրա հղվում է նույնակը (այս կարող է լինել խաղացող, գնդակ կամ ինչ-որ մեկ այլ);
- կոմպոնենտները — սեցիների բաղադրիչներն են: Օրինակ՝ կոմպոնենտներ ռենդերինգի, դիրքի և այլնի: Դրանք տվյալների պահոցներ;
- համակարգերը — օգտագործում են ինչպես օբյեկտները, այնպես էլ կոմպոնենտները, ինչպես նաև զինված են վարքում և տրամաբանությամբ, որոնք հիմնված են այդ տվյալների վրա: Օրինակ՝ ռենդերինգի համակարգը, որը անցնում է բոլոր սեցիների միջոցով, որոնց կոմպոնենտները ռենդերինգի համար և զբաղվում է նկարահանումով։
Ուսումից հետո պարզ դարձավ, որ ECS-ին լուծում է հետևյալ խնդիրները՝
- համակարգի կազմակերպման համար կոմպոզիցիայի կիրառում, ոչ ժառանգություն;
- կոդի խառնաշփոթից ազատումը կառավարման համակարգերի օգնությամբ;
- օրինակ՝ is_build_mode մեթոդները օգտագործել տրամաբանությունը վայրֆրեյմի միևնույն տեղում՝ ռենդերինգի համակարգում։
Ահա թե ինչը ստացվել է ECS-ի ներդրումից հետո։
resources -> այստեղ գտնվում են բոլոր նյութերը (նկարները)
src
— կոմպոնենտներ
— position.rs
— person.rs
— tennis_court.rs
— floor.rs
— wireframe.rs
— mouse_tracked.rs
— ռեսուրսներ
— mouse.rs
— համակարգեր
— rendering.rs
— constants.rs
— utils.rs
— world_factory.rs -> աշխարհ հաստիքային ֆունկցիաներ
— main.rs -> հիմնական վճռականություն
Բաժանել մարդկանց կորտերին
ECS-ը հեշտացրեց կյանքը: Այժմ ես ունեի համակարգված ճանապարհ տվյալների ավելացման համար սեցիներին և տրամաբանության ավելացման համար, որը հիմնված է այդ տվյալների վրա: Դա, իր հերթին, թույլ է տվել կազմակերպել մարդկանց բաշխումը կորտերում։
Ինչ արեցի՝
- ավելացրեցի նշանակված կորտերի տվյալները Person-ում;
- ավելացրեցի բաշխված մարդկանց տվյալները TennisCourt-ում;
- ավելացրեցի CourtChoosingSystem, որը թույլ է տալիս վերլուծել մարդկանց և հարթակներ, հայտնաբերել հասանելի կորտեր և բաշխել խաղացողներին դրանց վրա;
- ավելացրեցի PersonMovementSystem համակարգ, որը փնտրում է մարդկանց, ովքեր նշանակվել են կորտերի վրա, և եթե նրանք այդտեղ չեն, առաքում է մարդկանց այնտեղ, որտեղ անհրաժեշտ է։

Ամփոփում
Շատ հիացա այս պարզ խաղի վրա աշխատելուց: ավելի ավելին, ես գոհ եմ այն բանից, որ օգտագործեցի Rust համար դրա ստեղծման, քանի որ՝
- Rust-ը տալիս է ձեզ այն, ինչ անհրաժեշտ է;
- ունի հրաշալի փաստաթղթավորում, Rust-ը շատ Էլեգանտ է;
- մշտականությունը — սա զարմանալի բան է;
- չի հարկավոր լինի դիմել քաղվածք գրելու, պատճենելու կամ նմանատոյ գործողությունների, ինչը շատ հաճախ կիրառում էի C++;
- Options շատ հեշտ է աշխատել, դրանք ևս հիանալի գործադրում են սխալները;
- եթե նախագիծը հնարավոր է հանել, 99% այն գործարկվում է, այնպես ինչպես պետք է: Ինձ թվում է, որ գործի (compiler) սխալի հաղորդագրությունները լավագույնն են, որոնք տեսել եմ։
Rust լեզվով խաղերի զարգացումը հիմա միայն սկզբվում է։ Բայց արդեն գոյություն ունի կայուն և բավականին մեծ համայնք, որը աշխատում է Rust-ը բոլորի համար հասանելի դարձնելու վրա։ Դրա համար ես հետազոտում եմ լեզվի ապագան մոտիվացված, սպասելով մեր ընդհանուր աշխատանքի արդյունքներին։
Skillbox խորհուրդ է տալիս:
- Օնլայն-курс .
- Практический курс .
- Практический годовой курс .
Ընտանիք: habr.com
