Question

Comment puis-je avoir cette fonctionnalité dans mon jeu grâce à laquelle les joueurs peuvent modifier leur coiffure, leur look, leur style de vêtements, etc., et ainsi, chaque fois qu'ils portent un vêtement différent, leur avatar est mis à jour avec.

Dois-je:

  • Demandez à mon concepteur de créer toutes les combinaisons possibles d'armures, de coiffures et de faces en tant qu'images-objets (cela pourrait prendre beaucoup de travail).

  • Lorsque le joueur choisit ce à quoi il devrait ressembler lors de son introduction au jeu, mon code créera automatiquement ce sprite et toutes les combinaisons possibles de couvre-chef / armure avec ce sprite. Ensuite, chaque fois qu'ils sélectionnent une armure différente, le sprite correspondant à cette combinaison armure / apparence est chargé.

  • Est-il possible de diviser l’image-objet d’un personnage en éléments tels que le visage, la chemise, les jeans et les chaussures, et de définir les dimensions en pixels de chacun d’eux? Ensuite, chaque fois que le joueur change de casque, par exemple, nous utilisons les dimensions en pixels pour placer l’image du casque à la place de celle de son visage. (J'utilise Java pour créer ce jeu)

  • N'est-ce pas possible en 2D et je devrais utiliser la 3D pour cela?

  • Une autre méthode?

S'il vous plaît aviser.

Était-ce utile?

La solution

La 3D ne sera pas nécessaire pour cela, mais l’algorithme de peintre répandu dans le monde de la 3D pourrait vous épargner du travail:

L’algorithme de peintre dessine d’abord les objets les plus éloignés, puis les superpose avec des objets plus proches de la caméra. Dans votre cas, il s’agirait de générer le tampon pour votre sprite, de le dessiner sur le tampon, de trouver la prochaine partie dépendant de l’objet (c’est-à-dire une armure ou autre), de tirer cela, de trouver la prochaine partie dépendant de l’objet dépendant ( signe qui est sur l'armure), et ainsi de suite. Lorsqu'il n'y a plus de pièces dépendantes, vous peignez le sprite entièrement généré sur l'affichage visible par l'utilisateur.

Les parties combinées doivent avoir un canal alpha (RGBA au lieu de RGB) afin que vous ne combiniez que les parties ayant une valeur alpha définie sur une valeur de votre choix. Si vous ne pouvez pas le faire pour quelque raison que ce soit, utilisez une combinaison RVB que vous considérerez comme transparente.

L’utilisation de la 3D peut vous faciliter la tâche, car vous n’auriez même pas besoin d’utiliser un tampon hors écran ni d’écrire le code de combinaison de pixels. Le revers de la médaille est que vous devez apprendre un peu la 3D si vous ne la connaissez pas déjà. :-)

Modifier pour répondre au commentaire:

La partie combinaison fonctionnerait un peu comme ceci (en C ++, Java sera assez similaire - veuillez noter que je n'ai pas exécuté le code ci-dessous avec un compilateur):

// 
// @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];
              }               
        }
     }
}

Pour répondre à votre question concernant une solution 3D, dessinez simplement des rectangles avec leurs textures respectives (comportant un canal alpha) les uns sur les autres. Vous devez configurer le système pour qu’il affiche en mode orthogonal (pour OpenGL: gluOrtho2D () ).

Autres conseils

J'accepterais la solution de génération de procédure (n ° 2). Tant qu'il n'y a pas de limite de sprites à générer, la génération prend trop de temps. Peut-être que la génération lorsque chaque élément est acquis, pour réduire la charge.

Puisqu'on m'a demandé dans les commentaires de fournir une manière 3D ainsi, en voici quelques-uns, c'est un extrait de code que j'ai écrit il y a quelque temps. C'est OpenGL et C ++.

Chaque image-objet devrait être dessinée elle-même. En utilisant le modèle Adapter, je combinerais des images-objets, c’est-à-dire qu’il y aurait des images-objets pouvant contenir deux ou plusieurs images-objets ayant une position relative (0,0) et une image-objet ayant une position réelle contenant tous ces "sous".

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();
}

Le tex_id _ est une valeur intégrale qui identifie la texture utilisée pour OpenGL. Les parties pertinentes du gestionnaire de texture sont les suivantes. Le gestionnaire de texture émule réellement un canal alpha en vérifiant si la couleur lue est en blanc pur (RVB de (ff, ff, ff)) - le code loadFile fonctionne sur des fichiers BMP à 24 bits par pixel:

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;          
}

C’était en fait un petit Jump'nRun que je développais de temps en temps pendant mon temps libre. Il utilisait également le mode gluOrtho2D (). Si vous partez signifie de vous contacter, je vous enverrai la source si vous le souhaitez.

Les jeux 2d plus anciens tels que Diablo et Ultima Online utilisent pour cela une technique de composition par sprite. Vous pouvez rechercher des œuvres d'art dans ces jeux d'isométrie 2D plus anciens pour voir comment ils l'ont fait.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top