문제

게임에서 플레이어가 헤어 스타일, 모양, 옷 스타일 등을 바꿀 수있는 기능을 어떻게 가질 수 있습니까? 따라서 다른 옷을 입을 때마다 아바타가 업데이트됩니다.

내가해야합니까:

  • 내 디자이너가 갑옷, 헤어 스타일 및 얼굴의 가능한 모든 조합을 스프라이트로 만들도록하십시오 (이것은 많은 작업 일 수 있음).

  • 플레이어가 게임에 대한 소개 중에 어떻게 보이는지 선택하면 내 코드는이 스프라이트와 스프라이트와 헤드 기어/갑옷의 가능한 모든 조합을 자동으로 생성합니다. 그런 다음 다른 갑옷을 선택할 때마다 방어구/모양 조합의 스프라이트가로드됩니다.

  • 캐릭터의 스프라이트를 얼굴, 셔츠, 청바지, 신발과 같은 구성 요소로 나누고 각각의 픽셀 치수를 가질 수 있습니까? 예를 들어 플레이어가 헬멧을 변경할 때마다 픽셀 치수를 사용하여 헬멧 이미지를 얼굴 이미지 대신 대신에 넣습니다. (저는 Java를 사용 하여이 게임을 구축하고 있습니다)

  • 이것은 2D에서 불가능하고 이것에 3D를 사용해야합니까?

  • 다른 방법이 있습니까?

조언하십시오.

도움이 되었습니까?

해결책

이를 위해서는 3D가 필요하지 않지만 3D 세계에서 흔한 화가 알고리즘은 IMHO에 약간의 작업을 저장할 수 있습니다.

화가 알고리즘은 가장 먼 객체를 먼저 그린 다음 카메라에 가까운 물체로 오버링하여 작동합니다. 귀하의 경우, 스프라이트의 버퍼를 생성하여 버퍼에 그려서 다음 의존 스프라이트-파트 (즉, 갑옷 또는 Whatnot)를 찾아 다음 종속 스프라이트-파트 (즉, 특별한 특별한 스프라이트-파트를 찾습니다. 갑옷에 서명) 등. 더 이상 종속 부품이 없으면 전체 생성 된 스프라이트를 사용자가 보는 디스플레이에 페인트합니다.

결합 된 부품에는 알파 채널 (RGB 대신 RGBA)이 있어야하므로 알파 값이 선택한 값으로 설정된 부품 만 결합해야합니다. 어떤 이유로 든 그렇게 할 수 없다면, 투명한 것으로 취급 할 RGB 조합을 고수하십시오.

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()).

다른 팁

고려해야 할 주요 요소 중 하나는 애니메이션입니다. 캐릭터에 어깨 패드가있는 갑옷이있는 경우 어깨 패드는 몸통과 함께 움직여야 할 수도 있습니다. 마찬가지로, 그가 부츠를 입고 있다면, 그것들은 맨발과 같은주기를 따라야합니다.

본질적으로 디자이너에게 필요한 것은 a 스프라이트 시트 이를 통해 아티스트는 기본 캐릭터를위한 가능한 모든 애니메이션 프레임을 볼 수 있습니다. 그런 다음 해당 시트를 기반으로 맞춤형 헤어 스타일, 부츠, 갑옷 등을 만듭니다. 그렇습니다. 많은 작업이지만 대부분의 경우 요소는 최소한의 리 그리기가 필요합니다. 부츠는 내가 여러 프레임의 애니메이션을 바꾸기 때문에 다시 생성하기 위해 많은 작업을 수행하는 것을 볼 수있는 유일한 것입니다. 스프라이트에 대해 무자비하고 필요한 숫자를 최대한 줄이려고 노력하십시오.

요소 라이브러리를 축적 한 후에는 부정 행위를 시작할 수 있습니다. 동일한 헤어 스타일을 재활용하고 Photoshop 또는 캐릭터 제작자의 슬라이더가있는 게임에서 직접 색상을 조정하십시오.

게임 내에서 우수한 성능을 보장하는 마지막 단계는 모든 다른 요소의 스프라이트 시트를 단일 스프라이트 시트로 평평하게 한 다음 스프라이트 버퍼에 분할 및 저장되는 것입니다.

나는 함께 갈 것이다 절차 적 생성 해결책 (#2). 생성 할 스프라이트가 제한되지 않는 한, 세대가 너무 오래 걸리도록합니다. 어쩌면 각 항목이 획득 될 때 부하를 낮추기 위해 생성을 할 수 있습니다.

제가 3D 길을 제공하라는 의견을 요청 받았기 때문에 여기에 일부 코드가 발췌 한 것입니다. OpenGL과 C ++입니다.

각 스프라이트는 스스로를 그리도록 요청받을 것입니다. 어댑터 패턴을 사용하여 스프라이트를 결합합니다. 즉, (0,0) 상대 위치가있는 2 개 이상의 스프라이트와 하나의 스프라이트가있는 스프라이트가있을 것입니다.

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에 사용되는 텍스처를 식별하는 필수 값입니다. 텍스처 관리자의 관련 부분은 이것입니다. Texture Manager는 실제로 색상 읽기가 순수한 흰색인지 확인하여 실제로 알파 채널을 모방합니다 (RGB of (FF, FF, FF)) - LoadFile 코드는 픽셀 BMP 파일 당 24 비트로 작동합니다.

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

이것은 실제로 여가 시간에 가끔 발전한 작은 점프였습니다. Gluortho2d () 모드 Aswell, Btw를 사용했습니다. 당신이 연락 할 수있는 수단을 떠나면, 당신이 원한다면 소스를 보내 드리겠습니다.

Diablo 및 Ultima Online과 같은 구형 2D 게임은 스프라이트 컴포지트 기술을 사용하여이를 수행합니다. 이런 종류의 오래된 2D 아이소 메트릭 게임에서 예술을 검색하여 어떻게했는지 확인할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top