Rust-ով խաղի 24 ժամում: Գործողությունների անձնակազմի փորձ։

Rust-ով խաղի 24 ժամում: Գործողությունների անձնակազմի փորձ։

Այս հոդվածում ես կիսվում եմ Rust-ում փոքր խաղի մշակման իմ անձնական փորձով: Աշխատող տարբերակի ստեղծման համար անհրաժեշտ էր մոտ 24 ժամ (главно աշխատել եմ երեկոներին կամ հանգստյան օրերին): Խաղը դեռ հեռու է ավարտվելուց, բայց կարծում եմ, որ փորձը օգտակար կլինի: Ես կպատմեմ, ինչ եմ սովորել և մի շարք դիտարկումների մասին, որոնք կատարել եմ խաղը զրոյից կառուցելիս:

Skillbox խորհուրդ է տալիս: Երկամյա պրատիկ փուս «Ես՝ PRO կայքի մշակող».

Մոռացեք. Բոլոր «Հաբր» ընթերցողների համար— 10 000 ռուբլի զեղչ որևէ Skillbox դասընթացի գրանցման համար «Հաբր» промոկոդով։

pourquoi Rust?

Ես ընտրեցի այս լեզուն, քանի որ շատ լավ բաներ եմ լսել դրա մասին և տեսնում եմ, որ այն increasingly հայտնի է խաղերի մշակման ոլորտում: Խաղի գրառման նախքան ունեցել եմ փոքրիկ փորձ Rust-ում առավել պարզ ծրագրեր մշակելու մեջ: Սա բավական էր, որպեսզի առարկայական ազատություն զգայի խաղը գրելիս:

Ինչու հենց խաղ և ինչ խաղ է դա?

Խաղեր ստեղծելը ուրախ է! Ես կցանկանայի, որ պատճառները շատ լինեն, բայց «տուն» նախագծերի համար ընտրում եմ թեմաներ, որոնք ոչ այնքան սերտ կապված են իմ սովորական աշխատանքին: Որ խաղ է դա? Ես ցանկանում էի ստեղծել մի բան, ինչպիսիք են տենիսային սիմուլյատոր, որտեղ համադրվում են Cities Skylines, Zoo Tycoon, Prison Architect և իսկապես տենիս: Ընդհանուր առմամբ, ստացվեց խաղ տենիս ակադեմիայի մասին, ուր մարդիկ գալիս են խաղալու:

Տեխնիկական պատրաստություն

Ես ցանկանում էի օգտագործել Rust-ը, բայց հասկանալի չէր, թե որքան «զրոյից» պետք է սկսեմ աշխատել: Ես չէի ցանկանում գրել պիքսելային շեյդերներ և օգտագործել drag-n-drop, ուստի փնտրում էի առավել ճկուն լուծումներ:

Այնուամենայնիվ, ես գտա օգտակար ռեսուրսներ, որոնք կիսում եմ ձեզ հետ:

Ես ուսումնասիրեցի մի շարք 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 չափսի խոնավների հիմնաթող հիման վրա:

Rust-ով խաղի 24 ժամում: Գործողությունների անձնակազմի փորձ։

Tennis courts

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

Մեր հետապնդում ենք այս երկու խոնավները: 1 և 2.

Յուրաքանչյուր դատարանի հատվածը բաղկացած է 1 կամ 2 խոնավներից: Նրանք կարող են տեղակայվել սովորաբար կամ շրջվել 180 աստիճան.

Rust-ով խաղի 24 ժամում: Գործողությունների անձնակազմի փորձ։

Դպրոցական (այժմ) կառուցման ռեժիմը

Երբ ես հասկացա, որ ստանալս ` պլատֆորմները, մարդիկ և քարտերը, ես հասկացա, որ ստիպված եղան ձեռքի հիմնական կարգավորումը: Դա իրականացրի այնպես, որ երբ կտտացնում ենք կոճակը - օբյեկտը ընտրված է, իսկ կտտացումն այն տեղն է, որտեղ այն կտեղակայվի: Այսպիսով, բանալին 1 թույլ է տալիս ընտրել դատարանը, իսկ բանալին 2 - ընտրել խաղացողը.

Բայց պետք է հիշել, թե ինչ է նշանակում 1 և 2, այդպես ես ավելացրեցի վայերֆրեյմ, որպեսզի հասկանանք, թե որն է ընտրված օբյեկտը: Вот այնպես սա выглядит.

Rust-ով խաղի 24 ժամում: Գործողությունների անձնակազմի փորձ։

Արվարձանների հարցեր և արձագանք

Այժմ ես ունեմ մի քանի խաղային օբյեկտներ: մարդիկ, դատարաններ և խոնավներ: Բայց որպեսզի վայերֆրեյմները աշխատեն, անհրաժեշտ է յուրաքանչյուր օբյեկտի միավորի վրա նշել, արդյօք ինքներդ օբյեկտները ցուցադրվող ռեժիմում են, թե միայն նկարագրված է շրջանակը: Սա չնչին հարմար չէ.

Ես կարծում եմ, որ պետք է նորից մտածել կառուցվածքը, որպեսզի գտնվեն որոշ սահմանափակումներ:

  • նախկինության առկայություն, որը պատկերացնում և թարմացնում է իրեն - խնդիր է, քանի որ այդ առկայությունը չի կարող "ճանաչել", թե ինչ պետք է նախապատկերել - պատկեր և վայերֆրեյմ;
  • հատուկ առկայությունների (օրինակ՝ is_build_mode կամ նկարված վարելու) միջև կոմպոնենքի պակասը: Կարելի է օգտագործել ժառանգություն, սակայն Ռուստում չկա նորմալ մեթոդ: Իհարկե, ինձ պետք է композիցիոն;
  • օբյեկտների միջև փոխվերադարադրման գործիք պետք է, որպեսզի հատկացնենք մարդկանց դատարաններում;
  • պիտի սեցինները միաձուլված են տվյալների և տրամաբանության, ինչը շատ արագ դուրս էր գալիս վերահսկողությունից։

Ես իրականացրեցի լրացուցիչ ուսումնասիրություն և հայտնաբերեցի ճարտարապետություն ECS — Ընթացահան տարբերակների համակարգ, որը սովորաբար օգտագործվում է խաղերում: Այստեղ են 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-ով խաղի 24 ժամում: Գործողությունների անձնակազմի փորձ։

Ամփոփում

Շատ հիացա այս պարզ խաղի վրա աշխատելուց: ավելի ավելին, ես գոհ եմ այն բանից, որ օգտագործեցի Rust համար դրա ստեղծման, քանի որ՝

  • Rust-ը տալիս է ձեզ այն, ինչ անհրաժեշտ է;
  • ունի հրաշալի փաստաթղթավորում, Rust-ը շատ Էլեգանտ է;
  • մշտականությունը — սա զարմանալի բան է;
  • չի հարկավոր լինի դիմել քաղվածք գրելու, պատճենելու կամ նմանատոյ գործողությունների, ինչը շատ հաճախ կիրառում էի C++;
  • Options շատ հեշտ է աշխատել, դրանք ևս հիանալի գործադրում են սխալները;
  • եթե նախագիծը հնարավոր է հանել, 99% այն գործարկվում է, այնպես ինչպես պետք է: Ինձ թվում է, որ գործի (compiler) սխալի հաղորդագրությունները լավագույնն են, որոնք տեսել եմ։

Rust լեզվով խաղերի զարգացումը հիմա միայն սկզբվում է։ Բայց արդեն գոյություն ունի կայուն և բավականին մեծ համայնք, որը աշխատում է Rust-ը բոլորի համար հասանելի դարձնելու վրա։ Դրա համար ես հետազոտում եմ լեզվի ապագան մոտիվացված, սպասելով մեր ընդհանուր աշխատանքի արդյունքներին։

Skillbox խորհուրդ է տալիս:

Ընտանիք: habr.com

Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով 🔥 Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով | ProHoster