3

プレイヤーが髪型、外見、服のスタイルなどを変更できる機能をゲームにどのように組み込むことができますか。また、別の服を着るたびにアバターが更新されます。

するべきか:

  • デザイナーに、鎧、髪型、顔の可能な組み合わせをすべてスプライトとして作成してもらいます (これは大変な作業になる可能性があります)。

  • プレイヤーがゲームの紹介中にどのように見えるかを選択すると、私のコードは自動的にこのスプライトを作成し、ヘッドギア/アーマーとそのスプライトのすべての可能な組み合わせを作成します。次に、別のアーマーを選択するたびに、そのアーマーと外観の組み合わせのスプライトが読み込まれます。

  • キャラクターのスプライトを顔、シャツ、ジーンズ、靴などのコンポーネントに分割し、それぞれのピクセル寸法を持つことは可能ですか? 次に、たとえば、プレイヤーがヘルメットを変更するたびに、ピクセル寸法を使用して、ヘルメットの画像を通常の顔画像の場所に配置します。(私はJavaを使用してこのゲームを構築しています)

  • これは 2D では不可能で、これには 3D を使用する必要がありますか?

  • 他の方法はありますか?

お知らせ下さい。

4

5 に答える 5

2

考慮すべき主要な要素の 1 つは、アニメーションです。キャラクターがショルダー パッド付きのアーマーを持っている場合、それらのショルダー パッドは胴体と一緒に移動する必要がある場合があります。同様に、ブーツを履いている場合は、素足を隠している場合と同じサイクルに従う必要があります。

基本的に、デザイナーに必要なのは、アーティストがベース キャラクターのアニメーションの可能なすべてのフレームを表示できるようにするスプライト シートです。次に、それらのシートに基づいてカスタム ヘアスタイル、ブーツ、アーマーなどを作成してもらいます。はい、大変な作業ですが、ほとんどの場合、要素の再描画は最小限で済みます。ブーツは、アニメーションの複数のフレームで変化するため、再作成するのに本当に多くの作業が必要であると私が見た唯一のものです. スプライトには容赦なく、必要な数をできるだけ減らすようにしてください。

要素のライブラリを集めた後、不正行為を開始できます。同じヘア スタイルをリサイクルして、Photoshop で、またはキャラクター クリエーターのスライダーを使用してゲーム内で直接その色を調整します。

ゲーム内で良好なパフォーマンスを確保するための最後のステップは、すべての異なる要素のスプライト シートを 1 つのスプライト シートにフラット化し、分割してスプライト バッファに格納することです。

于 2008-12-31T08:57:51.117 に答える
1

これには 3D は必要ありませんが、3D の世界で一般的なペインター アルゴリズムを使用すると、多少の作業を節約できる可能性があります。

ペインター アルゴリズムは、最も遠いオブジェクトを最初に描画し、次にカメラに近いオブジェクトでオーバードローすることによって機能します。あなたの場合、スプライトのバッファを生成し、それをバッファに描画し、次の依存スプライト パーツ (つまり、鎧など) を見つけ、それを描画し、次の依存スプライト パーツ (つまり、特別な鎧にあるサイン)など。依存部分がなくなったら、生成された完全なスプライトをユーザーに表示されるディスプレイにペイントします。

結合されたパーツには、選択した値に設定されたアルファ値を持つパーツのみを結合するように、アルファ チャネル (RGB ではなく RGBA) が必要です。何らかの理由でそれができない場合は、透明として扱う RGB の組み合わせを 1 つだけにしてください。

3D を使用すると、パーツの結合が容易になる可能性があり、オフスクリーン バッファーを使用したり、ピクセル結合コードを記述したりする必要さえありません。反対に、まだ知らない場合は、3D について少し学ぶ必要があります。:-)

編集してコメントに答える:

組み合わせ部分は次のように機能します (C++ では、Java はかなり似ています。以下のコードはコンパイラを介して実行していないことに注意してください)。

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

3D ソリューションに関する質問に答えるには、それぞれのテクスチャ (アルファ チャネルを持つ) を重ねて長方形を描画するだけです。直交モードで表示するようにシステムを設定します (OpenGL の場合: gluOrtho2D())。

于 2008-12-31T08:45:14.763 に答える
1

手続き型生成ソリューション (#2)を使用します。生成されるスプライトの量が制限されていない限り、生成に時間がかかりすぎます。負荷を下げるために、各アイテムを取得するときに生成を行うかもしれません。

于 2008-12-31T08:48:20.513 に答える
0

DiabloやUltimaOnlineなどの古い2Dゲームは、これを行うためにスプライト合成技術を使用しています。これらの種類の古い2Dアイソメトリックゲームからアートを検索して、それらがどのように行われたかを確認できます。

于 2009-05-02T16:00:23.930 に答える
0

コメントで 3D の方法も提供するように求められたので、かなり前に書いたコードの抜粋をいくつか示します。OpenGL と C++ です。

各スプライトは、それ自体を描画するように求められます。Adapter パターンを使用して、スプライトを結合します。つまり、(0,0) 相対位置を持つ 2 つ以上のスプライトと、それらすべての「サブ」スプライトを持つ実際の位置を持つ 1 つのスプライトを保持するスプライトが存在します。

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

tex_id_、OpenGL に使用されるテクスチャを識別する整数値です。テクスチャ マネージャの関連部分は次のとおりです。テクスチャ マネージャーは、読み取った色が純粋な白 ((ff,ff,ff) の RGB) であるかどうかを確認することにより、アルファ チャネルを実際にエミュレートします。loadFile コードは、ピクセルあたり 24 ビットの 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;          
}

これは実際には、空き時間に時々開発した小さな Jump'nRun でした。gluOrtho2D() モードも使用していました。もしあなたがあなたに連絡する手段を残してくれたら、もしよろしければソースを送ります。

于 2008-12-31T10:33:31.220 に答える