我使用Java和Slick2D库做了一个游戏,我有一个按钮类,它的渲染方法看起来像这样。
public void render(Graphics g, int xOffset, int yOffset){
int renderX = x+xOffset;
int renderY = y+yOffset;
if(hasFocus()){
g.setColor(HIGHLIGHTEDBUTTONCOLOR);
}else{
g.setColor(BUTTONCOLOR);
}
g.fillRect(renderX, renderY, width, height);
g.setColor(BUTTONTEXTCOLOR);
g.drawString(text, renderX+(width/2) - (g.getFont().getWidth(text)/2), renderY+(height/2) - (g.getFont().getLineHeight()/2));
}
我有一个按钮类,它的渲染方法是这样的: 这工作很好,直到我需要只渲染按钮的一部分,而另一部分在我的可滚动容器的边界之外。我试过这个方法。
Image temp = new Image(myButton.getWidth(), myButton.getHeight());
myButton.render(temp.getGraphics(),this.x, this.y);
temp.getSubImage(0, 0, int temp.getWidth(), temp.getHeight()/2);
myGraphics.drawImage(temp, myButton.getX(), myButton.getY());
但这让我的帧数从4000下降到了10.
我试过事先制作一张空白图片,然后在渲染时复制到图片上,但这并没有帮助。我试过预先渲染图片,它又以4000帧/秒的速度运行,但每当我改变按钮的文字或是否突出显示时,我不得不重新绘制图片,这导致了冻结。
我如何才能在每一帧中只渲染这个按钮的一部分,而不至于太慢.还记得我需要渲染的按钮的部分是变化的,如果我在滚动,它可能会改变每一帧。
从来没有 在一个经常被调用且对性能敏感的方法中,如render(...)或update(...),曾经绘制到图像的内部图形。
首先,这就是为什么这个
Image temp = new Image(myButton.getWidth(), myButton.getHeight());
myButton.render(temp.getGraphics(),this.x, this.y);
temp.getSubImage(0, 0, int temp.getWidth(), temp.getHeight()/2);
myGraphics.drawImage(temp, myButton.getX(), myButton.getY());
是如此之慢。
你应该避免在频繁调用的方法中使用new操作符,因为它很慢,尤其是在创建新的图像上下文时(必须创建纹理和内部缓冲区)。如果你真的要做这样的事情,可以尝试实现一些缓冲,比如在初始化时创建一个图像,然后在方法中重复使用,而不是重新创建。
getGraphics()方法 创造 为图像创建一个新的Graphics实例,并且在您的代码中每一帧都会调用这个实例。如上所述,在对性能敏感的调用中,应尽可能避免使用new操作符创建,而且在render(..)这样的方法中创建一个新的Graphics实例可能是导致应用程序中帧数大幅下降的原因。
此外,与一般人的想法相反,getSubImage(..)方法其实并不影响性能,如果有必要的话,可以在频繁调用的方法中使用,因为它基本上只是将缓冲区的信息剪辑成给定的大小(但保留了对原始图像的引用,所以如果你修改了子图像,例如:在上面画画,原始图像也会被修改!)。
为了解决你的问题,你可以手动夹住按钮,然后自己计算按钮框的边界。在你的情况下,你可以这样做(由于你没有说明你指的是哪种容器,我假设它是某种GUI元素,而且是一个简单的矩形,但这可以很容易地改变以满足你的要求)。
//some pseudo-code as a help
if (buttonX within container bounds) buttonStartX = buttonX
else if (buttonX smaller than container bounds) buttonStartX = containerMinX
if (buttonX + buttonWidth within container bounds) buttonBoxWidth = buttonWidth
else if (buttonX + buttonWidth greater than container bounds) buttonBoxWidth = containerMaxX - buttonStartX
//... and so on... (yes the horizontal logic is not complete, but I dont want you to just copy this
// without thinking but rather that you finish this yourself with the given approach :)
解决办法是为游戏容器的图形设置一个世界剪辑(可以渲染的区域)。
g.setWorldClip(this.getX()+xOffset, this.getY()+yOffset, this.getWidth(), this.getHeight());
然后在渲染组件后将其清除
g.clearWorldClip();