我正在研究Java中的等距2D游戏,我注意到屏幕上有一个网格线,渲染似乎在水平和垂直方向上重复像素。这是一个屏幕截图,显示我的意思:
我在Render方法中检查了循环,并将每个像素的颜色值与数组中的前一个值进行比较,以查看是否在一行中出现了两个黑色像素,并且没有找到这种情况。我不知道可能导致这种影响的原因。我该怎么做才能解决这个问题?这是相关的代码:
游戏类变量:
private BufferedImage m_imgImage = new BufferedImage( intCANVAS_WIDTH, intCANVAS_HEIGHT, BufferedImage.TYPE_INT_RGB );
private int[ ] m_aintPixels = ( ( DataBufferInt ) m_imgImage.getRaster( ).getDataBuffer( ) ).getData( );
游戏类渲染方法:
// Object to organize data on the canvas
BufferStrategy bfsBufferStrategy = getBufferStrategy( );
if( bfsBufferStrategy == null )
{
createBufferStrategy( 3 );
return;
}
for( int intY = 0; intY < intCANVAS_HEIGHT; intY += 1 )
{
for( int intX = 0; intX < intCANVAS_WIDTH; intX += 1 )
{
m_aintPixels[ intX + ( intY * intCANVAS_WIDTH ) ] = m_Screen.m_aintPixels[ intX + ( intY * m_Screen.m_intWidth ) ];
}
}
Graphics gfxGraphics = bfsBufferStrategy.getDrawGraphics( );
gfxGraphics.drawImage( m_imgImage, 0, 0, getWidth( ), getHeight( ), null );
gfxGraphics.dispose( );
bfsBufferStrategy.show( );
屏幕类渲染方法以填充像素数组:
// Render a tile with the specified tile ID
public void RenderTile( int intPositionX, int intPositionY, CSpriteSheet SpriteSheet, int intTileID )
{
int intPixelIndex = 0;
int intSheetX = 0;
int intSheetY = 0;
int intTileOffsetX = 0;
int intTileOffsetY = 0;
int intPixelColor = 0;
// Center the Tile
intPositionX -= m_intOffsetX;
intPositionY -= m_intOffsetY;
intSheetX = ( intTileID % SpriteSheet.m_intTileColumns ) * CTile.TILE_WIDTH;
intSheetY = ( intTileID / SpriteSheet.m_intTileRows ) * CTile.TILE_HEIGHT;
intPixelIndex = intPositionX + ( intPositionY * m_intWidth );
// Rows
for( int intTileRow = intSheetY; intTileRow != ( intSheetY + CTile.TILE_HEIGHT ); intTileRow += 1 )
{
// Columns
for( int intTileColumn = intSheetX; intTileColumn != ( intSheetX + CTile.TILE_WIDTH ); intTileColumn += 1 )
{
intPixelColor = SpriteSheet.m_aintPixels[ intTileColumn + ( intTileRow * m_SpriteSheet.m_intWidth ) ];
// Boundary checking
if( intPositionX + intTileOffsetX >= 0 && intPositionX + intTileOffsetX < m_intWidth &&
intPositionY + intTileOffsetY >= 0 && intPositionY + intTileOffsetY < m_intHeight &&
CColor.Transparent( intPixelColor ) == false )
{
m_aintPixels[ intPixelIndex ] = SpriteSheet.m_aintPixels[ intTileColumn + ( intTileRow * m_SpriteSheet.m_intWidth ) ];
}
// Increment
intTileOffsetX += 1;
intPixelIndex += 1;
}
// Increment
intTileOffsetY += 1;
intPixelIndex += m_intWidth - ( CTile.TILE_WIDTH );
intTileOffsetX = 0;
}
}
答案 0 :(得分:3)
这是非插值缩放的经典工件。你有:
private BufferedImage m_imgImage = new BufferedImage( intCANVAS_WIDTH, intCANVAS_HEIGHT, BufferedImage.TYPE_INT_RGB );
...
gfxGraphics.drawImage( m_imgImage, 0, 0, getWidth( ), getHeight( ), null );
您看到的效果是因为getWidth()
和getHeight()
略大于intCANVAS_WIDTH
和intCANVAS_HEIGHT
。绘制图形时,它会将其缩放得更大。它没有使用任何类型的插值进行缩放,只是从源中选取最近的像素;因此,您会定期看到重复的行或列。
检查源数据时没有看到这一点,因为源数据中没有它,这是渲染数据时输出中引入的工件。
打印图像和面板尺寸,您会看到不同之处。从我看到的重复行数(我看到10个水平和10个垂直)来判断,我猜你会发现getWidth()
比intCANVAS_WIDTH
高10倍,高度也相同。
您可以将m_imgImage
的维度传递给.drawImage()
。这将消除伪影,但由于图像小于组件,因此会在右侧和底部留下间隙。
如果您的Graphics
实际上是Graphics2D
,则可以设置KEY_INTERPOLATION
渲染提示以在缩放时使用插值(可能不遵循该提示):
Graphics2D g = (Graphics2D)gfxGraphics;
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
如果您确实想要精确绘制图像,不进行缩放,并且两侧没有间隙,则禁用主窗口上的调整大小并设置大小以匹配图像。