Java 2D游戏中可定制的玩家头像
我怎么能在我的游戏中拥有这样的功能,玩家可以通过这些功能来改变他们的发型、外观、服装风格等,因此每当他们穿着不同的服装时,他们的头像都会随之更新 我应该:Java 2D游戏中可定制的玩家头像,java,3d,2d,Java,3d,2d,我怎么能在我的游戏中拥有这样的功能,玩家可以通过这些功能来改变他们的发型、外观、服装风格等,因此每当他们穿着不同的服装时,他们的头像都会随之更新 我应该: 让我的设计师把所有可能的盔甲、发型和脸组合成精灵(这可能需要很多工作) 当玩家在游戏介绍中选择他们应该是什么样子时,我的代码会自动创建这个精灵,以及所有可能的头盔/盔甲与该精灵的组合。然后每次他们选择不同的护甲时,就会加载该护甲/外观组合的精灵 是否可以将角色的精灵划分为多个组件,如人脸、衬衫、牛仔裤、鞋子,并具有每个组件的像素尺寸。然后,
- 让我的设计师把所有可能的盔甲、发型和脸组合成精灵(这可能需要很多工作)
- 当玩家在游戏介绍中选择他们应该是什么样子时,我的代码会自动创建这个精灵,以及所有可能的头盔/盔甲与该精灵的组合。然后每次他们选择不同的护甲时,就会加载该护甲/外观组合的精灵
- 是否可以将角色的精灵划分为多个组件,如人脸、衬衫、牛仔裤、鞋子,并具有每个组件的像素尺寸。然后,每当玩家更换头盔时,例如,我们使用像素尺寸将头盔图像放置在通常人脸图像的位置。(我正在使用Java构建这个游戏)
- 这在2D中是不可能的,我应该使用3D吗
- 还有别的方法吗
请告知 3D对此不是必需的,但3D世界中常见的画师算法可能会为您节省一些工作: 画师算法的工作原理是先绘制最远的对象,然后使用更靠近摄影机的对象进行过度绘制。在您的情况下,它可以归结为为为您的精灵生成缓冲区,将其绘制到缓冲区中,查找下一个从属精灵部分(即盔甲或诸如此类),绘制该部分,查找下一个从属精灵部分(即盔甲上的特殊标志),等等。当不再有从属零件时,将在用户看到的显示器上绘制完整生成的精灵 组合的零件应具有alpha通道(RGBA而不是RGB),以便仅组合alpha值设置为所选值的零件。如果出于任何原因,您无法做到这一点,只需坚持使用一种您将视为透明的RGB组合即可 使用3D可能会使组合部件更容易,甚至不需要使用屏幕外缓冲区或编写像素组合代码。另一方面,如果你还不知道,你需要学习一点3D技术。:-) 编辑以回答评论:
组合部分将有点像这样(C++中,java将非常相似——请注意,我没有通过编译器运行下面的代码):
//
//@param dependent_纹理是纹理向量,其中
//纹理n+1取决于纹理n。
//@param combimed_tex是所有纹理组合的输出
虚空精灵::组合纹理(向量常量和从属纹理,
纹理和组合纹理(纹理){
向量<纹理>::迭代器iter=依赖的纹理。开始();
联合_-tex=*iter;
如果(取决于纹理大小()>1)
for(iter++;iter!=依赖的_纹理。end();iter++){
纹理和电流_tex=*iter;
//通过每个像素,绘制:
对于(无符号字符像素_索引=0;
像素索引
要回答3D解决方案的问题,您只需在彼此上方绘制具有各自纹理(具有alpha通道)的矩形。您可以将系统设置为以正交模式显示(对于OpenGL:
gluOrtho2D()
)。我会选择解决方案(#2)。只要生成的精灵数量不受限制,即生成时间过长。可能在获取每个项目时生成,以降低负载一个主要的考虑因素是动画。如果角色有带垫肩的盔甲,则这些垫肩可能需要与其躯干一起移动。同样地,如果他穿着靴子,这些靴子必须遵循与赤脚相同的周期
从本质上讲,设计师需要的是一个可以让艺术家看到基础角色所有可能的动画帧的框架。然后让他们根据这些床单定制发型、靴子、盔甲等。是的,这是一个很大的工作,但在大多数情况下,元素将需要最低限度的重画;靴子是我能看到的唯一一件真正需要大量工作才能重新创建的东西,因为它们会在多个动画帧中发生变化。无情地对待你的精灵,尽量减少所需的数量
在你积累了一个元素库之后,你就可以开始作弊了。在Photoshop中或直接在游戏中使用角色创建者中的滑块,循环使用相同的发型并调整其颜色
最后一步,为了确保游戏中的良好性能,将把所有不同元素的精灵表展平为一个精灵表,然后将其拆分并存储在精灵缓冲区中。由于在评论中要求我也提供3D方式,下面是一些,这是我很久以前编写的一些代码的摘录。它是OpenGL和C++。p> 每个精灵都会被要求画自己。使用适配器模式,我将组合精灵-也就是说,将有两个或多个精灵,它们具有(0,0)相对位置,一个精灵的真实位置具有所有位置
//
// @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];
}
}
}
}
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();
}
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;
}