Rust 개발 블로그: 2주 차

안녕하세요 독자 여러분! 이것은 Rust와 Bevy로 멀티플레이어 게임을 코딩한 2주차 진행 상황입니다. 이 게시물은 조금 늦었고, 어제 나왔어야 했는데 시간에 맞춰 올리지 못했습니다. 어쨌든 이번 주 내 진행 상황은 다음과 같습니다. 참고로 이것은 사이드 프로젝트일 뿐이고 장기간 작업하지 않기 때문에 진행이 느립니다.

이 게시물에서는 다음 세 가지를 다룰 것입니다.

  • 자산 로드: 내 게임의 스프라이트를 로드하고 코드 전체에서 액세스하는 방법.

  • 병력 생성: 보드에 병력을 배치하는 데 필요한 패킷을 보내는 방법은 각 클라이언트마다 약간씩 달라야 합니다.

  • 게임 아트 진행: 게임을 위한 두 개의 새로운 스프라이트.

  • 이 게시물에서는 현재 게임이 어떻게 보이는지 이미지도 보여주어 의견에 피드백을 제공하고 게임 이름을 제시할 수도 있습니다(아직 이름이 없음). 더 이상 고민하지 않고 시작합시다!

    자산 로딩



    모든 캐릭터 스프라이트를 8x 픽셀 아트 타일로 결정했습니다. 이를 처리하는 가장 좋은 방법은 모든 것을 스프라이트 시트에 넣고 Bevy의TextureAtlas 구조체를 사용하여 시스템에서 사용할 리소스(Res)에 저장하는 것입니다. 이것은 game/card.rs 파일에서 다음과 같이 수행됩니다.

    // game/card.rs
    
    pub(crate) struct CardSprites(
        pub(crate) Handle<TextureAtlas>,
        pub(crate) HashMap<String, usize>,
    );
    
    fn load_card_sprites(
        mut commands: Commands,
        asset_server: Res<AssetServer>,
        mut texture_atlases: ResMut<Assets<TextureAtlas>>,
    ) {
        let sprite_sheet = asset_server.load("sprite_sheet.png");
        let atlas: TextureAtlas = TextureAtlas::from_grid(sprite_sheet, Vec2::splat(8.), 1, 1);
    
        let atlas_handle = texture_atlases.add(atlas);
        let mut card_sprite_map = HashMap::new();
        card_sprite_map.insert("skeleton".to_string(), 0);
    
        commands.insert_resource(CardSprites(atlas_handle, card_sprite_map));
    }
    


    여기서는 자산 폴더에 있는 sprite_sheet.png 파일을 로드합니다. 우리는 Bevy에게 그것을 8x8 타일의 그리드로 파싱하도록 지시합니다. 이것은 우리에게 TextureAtlas 를 제공하고, 여기서 우리는 Handle (Bevy에 대한 일종의 참조 구조체)를 CardSprites 리소스에 저장합니다. 이 리소스에는 이름과 함께 캐릭터 텍스처의 인덱스를 가져올 수 있는 맵도 포함되어 있습니다. 이렇게 하면 나중에 더 많은 문자를 추가하는 것이 매우 간단해집니다. 이러한 스프라이트에 액세스해야 하는 다른 시스템에서는 함수 인수에 Res<CardSprites>를 추가하기만 하면 됩니다. 나중에 살펴보겠지만 매우 유용합니다.

    산란 부대



    이제 흥미로운 부분입니다. 드디어 게임 보드에 몇 가지 물건을 올릴 수 있습니다! 이렇게 하려면 먼저 서버 측으로 들어가 스폰 패킷을 클라이언트에 보내는 방법을 코딩해야 합니다.

    // net/packets.rs
    
    pub fn spawn_troop(card: &Card, x_pos: i32, y_pos: i32, flip_board: bool) -> Packet {
            let mut json: Value = serde_json::from_str(
                r#"
                {
                    "packet-type": "spawn-card"        
                }
            "#,
            )
            .unwrap();
            if let Value::Object(ref mut map) = json {
                let card_entity = CardEntity::new(
                    card,
                    if flip_board { 4 - x_pos } else { x_pos },
                    if flip_board { 8 - y_pos } else { y_pos },
                );
                map.insert(
                    "troop".to_string(),
                    serde_json::to_value(&card_entity).unwrap(),
                );
            }
            Packet { data: json }
        }
    }
    


    이것은 대부분 간단한 JSON 개체 생성입니다. 그러나 flip_board 라는 인수가 있음에 유의하십시오. true로 설정되면 이 부울은 보드에서 군대의 x 및 y 위치를 뒤집도록 만듭니다(5x9 보드이므로 4와 8이 있는 이유입니다). 이는 두 클라이언트 모두 게임에 대한 자신의 관점을 볼 수 있도록 하기 위해 필요합니다. 다음은 클라이언트 측에서 이 패킷을 처리하는 모습입니다.

    // net/packet_handler.rs
    
    "spawn-card" => {
        if !matches!(packet["troop"].clone(), Value::Null) {
            let result =
                serde_json::from_value::<CardEntity>(packet["troop"].clone());
            if result.is_ok() {
                let card_entity = result.unwrap();
                let mut sprite = TextureAtlasSprite::new(
                    card_sprites
                        .1
                        .get(&card_entity.card.get_name())
                        .unwrap()
                        .clone(),
                );
                sprite.custom_size = Some(Vec2::splat(tile_size.0 * 0.8));
    
                commands
                    .spawn_bundle(SpriteSheetBundle {
                        sprite,
                        texture_atlas: card_sprites.0.clone(),
                        transform: Transform::from_xyz(0., 0., 500.),
                        ..Default::default()
                    })
                    .insert(card_entity);
            }
        }
    }
    


    참고: 이전에 로드한 스프라이트에 액세스할 수 있도록 함수 인수에 card_sprites: Res<CardSprites>,를 추가해야 합니다.

    여기에서 패킷이 존재하는 경우 패킷에서 부대 데이터를 가져옵니다. 이것은 CardEntity를 반환합니다(이것이 무엇인지 모른다면 1주차 devlog를 확인하십시오). 새 부대를 생성하는 데 사용할 수 있습니다. 여기서는 (0, 0) 좌표에 배치됩니다. 엔터티의 위치를 ​​지정하는 또 다른 간단한 시스템이 있기 때문입니다. (0, 0)에서 스켈레톤을 스폰하면 이런 모습입니다.



    게임 아트 진행



    이번 주에 저는 다음 주까지 캐릭터 상호 작용에 사용할 두 개의 매우 간단한 스프라이트를 그렸습니다. 파란색 타일은 이동용이고 빨간색 타일은 공격용입니다.





    금주의 밈



    다시 그 시간이야!



    다시 한 번, 여기까지 오셨다면 읽어주셔서 정말 감사합니다. 의견에 의견과 제안을 남겨주세요. 나는 외출했고 다음 주에 보여줄 좋은 진전이 있기를 바랍니다!

    좋은 웹페이지 즐겨찾기