Rust խաղալ 24 ժամում. անձնական զարգացման փորձ

Rust խաղալ 24 ժամում. անձնական զարգացման փորձ

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

Skillbox-ը խորհուրդ է տալիս. Երկու տարվա գործնական դասընթաց «Ես PRO վեբ ծրագրավորող եմ».

Հիշեցում. «Habr»-ի բոլոր ընթերցողների համար՝ 10 ռուբլի զեղչ «Habr» գովազդային կոդով Skillbox-ի ցանկացած դասընթացին գրանցվելիս:

Ինչու՞ Ռաստ:

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

Ինչու՞ խաղ և ինչպիսի՞ խաղ:

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

Տեխնիկական ուսուցում

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

Ես գտա օգտակար ռեսուրսներ, որոնք ես կիսում եմ ձեզ հետ.

Ես ուսումնասիրեցի Rust խաղի մի քանի շարժիչներ՝ ի վերջո ընտրելով Piston-ը և ggez-ը: Ես նրանց հանդիպեցի նախորդ նախագծի վրա աշխատելիս: Ի վերջո, ես ընտրեցի ggez-ը, քանի որ այն ավելի հարմար էր թվում փոքր 2D խաղ իրականացնելու համար։ Պիստոնի մոդուլային կառուցվածքը չափազանց բարդ է սկսնակ մշակողի համար (կամ մեկի համար, ով առաջին անգամ է աշխատում 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 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-ն անհրաժեշտ է, քանի որ այն պարունակում է կոդերի բոլոր տողերը: Ես մի փոքր ժամանակ ծախսեցի ֆայլերը առանձնացնելու և գրացուցակի կառուցվածքի օպտիմալացման վրա: Ահա թե ինչ տեսք ուներ դրանից հետո.
ռեսուրսներ -> այստեղ են բոլոր ակտիվները (պատկերներ)
src
- սուբյեկտներ
— game_object.rs
- շրջան.rs
— main.rs -> հիմնական հանգույց

Մարդիկ, հատակներ և պատկերներ

Հաջորդ քայլը Անձի խաղի օբյեկտ ստեղծելն է և պատկերների բեռնումը: Ամեն ինչ պետք է կառուցվի 32*32 սալիկների հիման վրա։

Rust խաղալ 24 ժամում. անձնական զարգացման փորձ

Թենիսի կորտեր

Ուսումնասիրելով թենիսի կորտերն ինչպիսի տեսք ունեն՝ որոշեցի դրանք պատրաստել 4*2 սալիկներից։ Սկզբում հնարավոր էր այս չափի պատկեր պատրաստել, կամ 8 առանձին սալիկ հավաքել։ Բայց հետո հասկացա, որ ընդամենը երկու եզակի սալիկ է անհրաժեշտ, և ահա թե ինչու.

Ընդհանուր առմամբ մենք ունենք երկու այդպիսի սալիկներ՝ 1 և 2։

Կորտի յուրաքանչյուր հատված բաղկացած է սալիկից 1 կամ 2:

Rust խաղալ 24 ժամում. անձնական զարգացման փորձ

Հիմնական շինարարական (հավաքման) ռեժիմ

Այն բանից հետո, երբ ինձ հաջողվեց հասնել կայքերի, մարդկանց և քարտեզների մատուցման, ես հասկացա, որ անհրաժեշտ է նաև հավաքման հիմնական ռեժիմ: Ես դա իրականացրել եմ այսպես՝ երբ կոճակը սեղմվում է, օբյեկտն ընտրվում է, իսկ սեղմումը տեղադրում է այն ցանկալի տեղում։ Այսպիսով, կոճակ 1-ը թույլ է տալիս ընտրել կորտ, իսկ կոճակը 2-ը թույլ է տալիս ընտրել խաղացող:

Բայց մենք դեռ պետք է հիշենք, թե ինչ են նշանակում 1-ը և 2-ը, այնպես որ ես ավելացրեցի լարային շրջանակ, որպեսզի պարզ լինի, թե որ օբյեկտն է ընտրվել: Ահա թե ինչ տեսք ունի.

Rust խաղալ 24 ժամում. անձնական զարգացման փորձ

Ճարտարապետության և վերամշակման հարցեր

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

Ինձ թվում էր, որ ճարտարապետությունը պետք է վերաիմաստավորվի այնպես, որ բացահայտի որոշ սահմանափակումներ.

  • Ինքնարտադրող և թարմացնող կազմակերպություն ունենալը խնդիր է, քանի որ այդ կազմակերպությունը չի կարողանա «իմանալ» այն, ինչ պետք է արտաբերի՝ պատկեր և լարային շրջանակ.
  • Առանձին սուբյեկտների միջև հատկությունների և վարքագծի փոխանակման գործիքի բացակայություն (օրինակ՝ is_build_mode հատկությունը կամ վարքագծի ձևավորումը): Հնարավոր կլիներ օգտագործել ժառանգությունը, թեև Rust-ում դրա իրականացման պատշաճ ձև չկա: Ինձ իսկապես անհրաժեշտ էր դասավորությունը.
  • անհրաժեշտ էր սուբյեկտների միջև փոխգործակցության գործիք՝ մարդկանց դատարաններ նշանակելու համար.
  • սուբյեկտներն իրենք տվյալների և տրամաբանության խառնուրդ էին, որոնք արագորեն դուրս եկան վերահսկողությունից:

Ես ևս մի քանի հետազոտություն կատարեցի և բացահայտեցի ճարտարապետությունը ECS - Entity Component System, որը սովորաբար օգտագործվում է խաղերում։ Ահա ECS-ի առավելությունները.

  • տվյալները տարանջատված են տրամաբանությունից.
  • կազմը ժառանգության փոխարեն;
  • տվյալների կենտրոնացված ճարտարապետություն:

ECS-ը բնութագրվում է երեք հիմնական հասկացություններով.

  • սուբյեկտներ - օբյեկտի տեսակը, որին վերաբերում է նույնացուցիչը (դա կարող է լինել խաղացող, գնդակ կամ այլ բան);
  • բաղադրիչներ - սուբյեկտները կազմված են դրանցից: Օրինակ՝ կոմպոնենտի, տեղանքների և այլոց մատուցում: Սրանք տվյալների պահեստներ են.
  • համակարգեր - դրանք օգտագործում են և՛ առարկաներ, և՛ բաղադրիչներ, գումարած պարունակում են վարքագիծ և տրամաբանություն, որոնք հիմնված են այս տվյալների վրա: Օրինակ՝ արտապատկերման համակարգ, որը կրկնում է բոլոր սուբյեկտները, որոնք ունեն ռենդերային բաղադրիչներ և կատարում է արտապատկերումը:

Այն ուսումնասիրելուց հետո պարզ դարձավ, որ ECS-ը լուծում է հետևյալ խնդիրները.

  • սուբյեկտները համակարգված կազմակերպելու համար ժառանգության փոխարեն դասավորության օգտագործումը.
  • կոդերի խառնաշփոթից ազատվել կառավարման համակարգերի միջոցով.
  • օգտագործելով մեթոդներ, ինչպիսին է is_build_mode-ը, որպեսզի պահի wireframe տրամաբանությունը նույն տեղում՝ մատուցման համակարգում:

Ահա թե ինչ եղավ ECS-ի ներդրումից հետո։

ռեսուրսներ -> այստեղ են բոլոր ակտիվները (պատկերներ)
src
- բաղադրիչներ
— դիրքորոշում.rs
— մարդ.rs
— tennis_court.rs
— հատակ.rs
- wireframe.rs
— mouse_tracked.rs
- ռեսուրսներ
— mouse.rs
- համակարգեր
— rendering.rs
— հաստատուններ.rs
— utils.rs
— world_factory.rs -> համաշխարհային գործարանի գործառույթները
— main.rs -> հիմնական հանգույց

Մենք մարդկանց նշանակում ենք դատարաններ

ECS-ն հեշտացրել է կյանքը: Հիմա ես ունեի սուբյեկտներին տվյալներ ավելացնելու և այդ տվյալների հիման վրա տրամաբանություն ավելացնելու համակարգված միջոց: Իսկ դա իր հերթին հնարավորություն տվեց կազմակերպել մարդկանց բաշխումը դատարանների միջև։

Ինչ եմ արել.

  • Անձին ավելացրել է հանձնարարված դատարանների վերաբերյալ տվյալներ.
  • ավելացրել է տվյալներ բաշխված մարդկանց մասին TennisCourt-ին;
  • ավելացրել է CourtChoosingSystem-ը, որը թույլ է տալիս վերլուծել մարդկանց և դատարանները, հայտնաբերել հասանելի կորտերը և խաղացողներին բաժանել նրանց;
  • ավելացրել է PersonMovementSystem-ը, որը փնտրում է դատարաններում նշանակված մարդկանց, և եթե նրանք այնտեղ չեն, ապա ուղարկում է մարդկանց այնտեղ, որտեղ նրանք պետք է լինեն:

Rust խաղալ 24 ժամում. անձնական զարգացման փորձ

Ամփոփելով

Ինձ շատ դուր եկավ այս պարզ խաղի վրա աշխատելը: Ավելին, ես ուրախ եմ, որ այն գրելու համար օգտագործել եմ Rust-ը, քանի որ.

  • Ժանգը տալիս է այն, ինչ ձեզ հարկավոր է.
  • այն ունի գերազանց փաստաթղթեր, Rust-ը բավականին էլեգանտ է.
  • հետեւողականությունը թույն է;
  • դուք պետք չէ դիմել կլոնավորման, պատճենահանման կամ այլ նմանատիպ գործողությունների, որոնք ես հաճախ եմ արել C++-ում;
  • Ընտրանքները շատ հեշտ են օգտագործել և շատ լավ են վերաբերվում սխալներին.
  • եթե նախագիծը կարողացավ կազմվել, ապա 99% դեպքերում այն ​​աշխատում է, և ճիշտ այնպես, ինչպես պետք է: Կարծում եմ, որ կոմպիլյատորի սխալի հաղորդագրությունները լավագույնն են, ինչ ես տեսել եմ:

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

Skillbox-ը խորհուրդ է տալիս.

Source: www.habr.com

Добавить комментарий