Pergunta

Como posso ter essa funcionalidade no meu jogo através do qual os jogadores podem mudar o seu penteado, aparência, estilo de roupa, etc., e por isso sempre que eles usam um item diferente de roupa seu avatar é atualizado com ele.

Devo:

  • Tenha meu designer de criar todas as combinações possíveis de armadura, penteados e caras como sprites (este poderia ser um monte de trabalho).

  • Quando os escolhe jogadores que eles devem olhar como durante a sua introdução ao jogo, o meu código seria automaticamente criar esta sprite, e todas as combinações possíveis de chapelaria / armadura com que Sprite. Em seguida, cada vez que selecionar uma armadura diferente, o sprite para essa combinação de armadura / visual é carregado.

  • É possível ter sprite de um personagem dividido em componentes, como o rosto, camisa, calça jeans, sapatos e ter as dimensões de pixel de cada uma delas. Em seguida, sempre que o jogador muda seu capacete, por exemplo, usamos as dimensões de pixel para colocar o capacete no lugar de onde sua imagem cara que normalmente seria. (Estou usando Java para construir este jogo)

  • Isto não é possível em 2D e eu deveria usar o 3D para isso?

  • Qualquer outro método?

Por favor, informe.

Foi útil?

Solução

3D não será necessário para isso, mas o algoritmo de pintor que é comum na IMHO poderio mundo 3D poupar algum trabalho:

O algoritmo pintor trabalha desenhando a maioria dos objetos distantes primeiro, depois overdrawing com objetos mais perto da câmera. No seu caso, seria boild para baixo para gerar o tampão para o sprite, puxando-o para o tampão, encontrar a próxima do sprite-parte dependente (ou seja armadura ou estante), desenho que, encontrar a próxima do sprite-parte dependente (ou seja, um especial sinal de que está na armadura), e assim por diante. Quando há partes não mais dependentes, você pintar o sprite gerado completo para a janela que o usuário vê.

As peças combinated deve ter um canal alfa (RGBA em vez de RGB), de modo que você só vai combinar partes que têm um conjunto valor alfa para um valor de sua escolha. Se você não pode fazer isso por qualquer motivo, ficar com uma combinação RGB que você vai tratar como transparente.

Usando o 3D pode fazer combinando as partes mais fácil para você, e você não iria mesmo ter que usar um buffer fora da tela ou escrever o código combinating pixel. O outro lado da moeda é que você precisa para aprender um pouco 3D se você não sabe já. :-)

Editar para comentário resposta:

A parte combinação iria funcionar mais ou menos assim (em C ++, Java será bastante similar - nota por favor que eu não executar o código abaixo através de um compilador):

// 
// @param dependant_textures is a vector of textures where 
// texture n+1 depends on texture n. 
// @param combimed_tex is the output of all textures combined
void Sprite::combineTextures (vector<Texture> const& dependant_textures, 
                              Texture& combined_tex) {
   vector< Texture >::iterator iter = dependant_textures.begin();
   combined_tex = *iter;

   if (dependant_textures.size() > 1)
     for (iter++; iter != dependant_textures.end(); iter++) {
        Texture& current_tex = *iter;

        // Go through each pixel, painting:
        for (unsigned char pixel_index = 0; 
             pixel_index < current_tex.numPixels(); pixel_index++) {
           // Assuming that Texture had a method to export the raw pixel data
           // as an array of chars - to illustrate, check Alpha value:
           int const BYTESPERPIXEL = 4; // RGBA
           if (!current_tex.getRawData()[pixel_index * BYTESPERPIXEL + 3]) 
              for (int copied_bytes = 0; copied_bytes < 3; copied_bytes++)
              {
                int index = pixel_index * BYTESPERPIXEL + copied_bytes;
                combined_tex.getRawData()[index] = 
                   current_tex.getRawData()[index];
              }               
        }
     }
}

Para responder à sua pergunta de uma solução 3D, você poderia simplesmente desenhar retângulos com as respectivas texturas (que teria um canal alfa) uns sobre os outros. Você poderia configurar o sistema para exibição em um modo ortogonal (para OpenGL: gluOrtho2D()).

Outras dicas

Um fator importante a considerar é animação. Se um personagem tem armadura com ombreiras, essas shoulderpads pode precisar se deslocar com o seu torso. Da mesma forma, se ele está vestindo botas, aqueles que seguem os mesmos ciclos como pés descalços escondidos faria.

Essencialmente, o que você precisa para seus designers é um Sprite Folha que permite que seus artistas ver todos os quadros possíveis de animação para o seu personagem base. Você então eles têm que criar penteados personalizados, botas, armaduras, etc. com base nessas folhas. Sim, é um monte de trabalho, mas na maioria dos casos, os elementos exigirá uma quantidade mínima de redesenhar; botas são a única coisa que eu podia ver realmente tomando um monte de trabalho para re-criar, uma vez que mudar vários quadros de animação. Seja rutheless com seus sprites, tentar reduzir o número necessário, tanto quanto possível.

Depois de ter acumulado uma biblioteca de elementos que você pode começar a fazer batota. Recicle o mesmo estilo de cabelo e ajustar sua cor seja no Photoshop ou diretamente no jogo com sliders em seu criador personagem.

A última etapa, para garantir um bom desempenho no jogo, seria para achatar folhas de sprite todos os diferentes elementos em uma única folha de sprite que é então dividido e armazenados em buffers Sprite.

Eu iria com o solução geração processual (# 2). Enquanto não existe uma quantidade limitante de sprites para ser gerado, de tal modo que a geração leva muito tempo. Talvez fazer a geração quando cada item é adquirido, para diminuir a carga.

Uma vez que me pediram em comentários para fornecer uma maneira aswell 3D, está aqui alguma, que é um trecho de algum código que eu escrevi há algum tempo atrás. É OpenGL e C ++.

Cada Sprite seria convidado a desenhar a si próprio. Usando o padrão Adapter, eu combinaria sprites - ou seja, não haveria sprites que iria realizar duas ou mais sprites que tinham um (0,0) posição relativa e um sprite com um real posição tendo todos esses sprites "sub"

void Sprite::display (void) const
{
  glBindTexture(GL_TEXTURE_2D, tex_id_);
  Display::drawTranspRect(model_->getPosition().x + draw_dimensions_[0] / 2.0f,
      model_->getPosition().y + draw_dimensions_[1] / 2.0f,
      draw_dimensions_[0] / 2.0f, draw_dimensions_[1] / 2.0f);
}

void Display::drawTranspRect (float x, float y, float x_len, float y_len)
{   
  glPushMatrix();

  glEnable(GL_BLEND);   
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  glColor4f(1.0, 1.0, 1.0, 1.0);

  glBegin(GL_QUADS);        
    glTexCoord2f(0.0f, 0.0f); glVertex3f(x - x_len, y - y_len, Z);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(x + x_len, y - y_len, Z);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(x + x_len, y + y_len, Z);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(x - x_len, y + y_len, Z);
  glEnd();

  glDisable(GL_BLEND);  
  glPopMatrix();
}

O tex_id_ é um valor inteiro que identifica quais textura é usado para OpenGL. As partes relevantes do gerente de textura são estes. O gerente textura realmente emula um canal alfa, verificando para ver se a leitura da cor é o branco puro (RGB de (ff, ff, ff)) - o código loadFile opera em 24 bits por pixel de arquivos BMP:

TextureManager::texture_id 
TextureManager::createNewTexture (Texture const& tex) {
    texture_id id;
    glGenTextures(1, &id);
    glBindTexture(GL_TEXTURE_2D, id);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);   
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);       
    glTexImage2D(GL_TEXTURE_2D, 0, 4, tex.width_, tex.height_, 0, 
        GL_BGRA_EXT, GL_UNSIGNED_BYTE, tex.texture_);

    return id;
}

void TextureManager::loadImage (FILE* f, Texture& dest) const {
  fseek(f, 18, SEEK_SET);
  signed int compression_method;
  unsigned int const HEADER_SIZE = 54;

  fread(&dest.width_, sizeof(unsigned int), 1, f);
  fread(&dest.height_, sizeof(unsigned int), 1, f);
  fseek(f, 28, SEEK_SET);
  fread(&dest.bpp_, sizeof (unsigned short), 1, f);
  fseek(f, 30, SEEK_SET);
  fread(&compression_method, sizeof(unsigned int), 1, f);

  // We add 4 channels, because we will manually set an alpha channel
  // for the color white.
  dest.size_ = dest.width_ * dest.height_ * dest.bpp_/8 * 4;
  dest.texture_ = new unsigned char[dest.size_];
  unsigned char* buffer = new unsigned char[3 * dest.size_ / 4];    

  // Slurp in whole file and replace all white colors with green
  // values and an alpha value of 0:
  fseek(f, HEADER_SIZE, SEEK_SET);      
  fread (buffer, sizeof(unsigned char), 3 * dest.size_ / 4, f); 
  for (unsigned int count = 0; count < dest.width_ * dest.height_; count++) {       
    dest.texture_[0+count*4] = buffer[0+count*3];
    dest.texture_[1+count*4] = buffer[1+count*3];
    dest.texture_[2+count*4] = buffer[2+count*3];
    dest.texture_[3+count*4] = 0xff;

    if (dest.texture_[0+count*4] == 0xff &&
        dest.texture_[1+count*4] == 0xff &&
        dest.texture_[2+count*4] == 0xff) {
      dest.texture_[0+count*4] = 0x00;
      dest.texture_[1+count*4] = 0xff;
      dest.texture_[2+count*4] = 0x00;
      dest.texture_[3+count*4] = 0x00;
      dest.uses_alpha_ = true;
    }                   
  }
  delete[] buffer;          
}

Este foi realmente um pequeno Jump'nRun que desenvolvi ocasionalmente no meu tempo livre. Ela costumava gluOrtho2D () Modo aswell, btw. Se você deixar meios para contatá-lo, vou enviar-lhe a fonte, se quiser.

mais velhos jogos 2D, como Diablo e Ultima Online usar um sprite composição técnica para fazer isso. Você poderia procurar a arte daqueles tipo de antigos jogos isométricos 2D para ver como eles fizeram isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top