绘制后,来自java.awt的LinearGradientPaint对象可能看起来不错,但是在某种游戏模型中绘制动画背景时,我遇到了一个问题,这需要我花很长时间来构建。
我想使用Graphics2D绘制对象在背景上绘制动画彩虹渐变,除了这样做时,我注意到重新绘制面板时有很多滞后。它应该以每秒至少30帧的速度重新绘制自身,这仅在图形对象使用的Paint对象不是彩虹渐变的情况下才有可能。
即使将其作为单独的线程运行也无法解决问题。下面是我在每一帧末尾要尝试执行的代码:
gamePanel.executor.execute(new Runnable(){
public void run()
{
while(true)
{
if (Background.selectedBackgroundIndex >= Background.SKY_HORIZON_GRADIENT_PAINT &&
Background.selectedBackgroundIndex < Background.SPACE_PAINT)
{
float displacementValue = 1.0f;
if (Background.backgroundShape.y < ((-2990.0f) + CannonShooterModel.gamePanel.getSize().height) && gamePanel.horizonGoingDown)
gamePanel.horizonGoingDown = false;
else if (Background.backgroundShape.y > (-10.0f) && !gamePanel.horizonGoingDown)
gamePanel.horizonGoingDown = true;
Point2D.Double startPoint = (Point2D.Double)(((LinearGradientPaint)Background.background).getStartPoint()),
endPoint = (Point2D.Double)(((LinearGradientPaint)Background.background).getEndPoint());
if (gamePanel.horizonGoingDown)
Background.backgroundShape.y -= displacementValue;
else
Background.backgroundShape.y += displacementValue;
startPoint.setLocation(0, Background.backgroundShape.y);
endPoint.setLocation(0, Background.horizonGradientPaintHeight + Background.backgroundShape.y);
// Should be done in another thread, particularly in arithmetic calculations.
Background.background = new LinearGradientPaint(startPoint, endPoint,
((LinearGradientPaint)Background.background).getFractions(),
((LinearGradientPaint)Background.background).getColors());
}
for (int a = 0; a < PlayerUnit.weapon.bullets.length; a++)
{
if (PlayerUnit.weapon.bullets[a] != null)
{
if (PlayerUnit.weapon instanceof Pistol &&
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x + ((Pistol)PlayerUnit.weapon).bulletWidth >= 0 &&
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x <= CannonShooterModel.gamePanel.getSize().width &&
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).y + ((Pistol)PlayerUnit.weapon).bulletWidth >= 0)
{
if (PlayerUnit.weapon.weaponAngles[a] >= 0)
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x +=
PlayerUnit.weapon.bulletSpeed * Math.cos(PlayerUnit.weapon.weaponAngles[a]);
else
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x -=
PlayerUnit.weapon.bulletSpeed * Math.cos(PlayerUnit.weapon.weaponAngles[a]);
if (PlayerUnit.weapon.weaponAngles[a] >= 0)
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).y -=
PlayerUnit.weapon.bulletSpeed * Math.sin(PlayerUnit.weapon.weaponAngles[a]);
else
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).y +=
PlayerUnit.weapon.bulletSpeed * Math.sin(PlayerUnit.weapon.weaponAngles[a]);
}
else
PlayerUnit.weapon.bullets[a] = null;
}
}
//System.out.println(Background.backgroundShape.y);
repaint();
try
{
Thread.sleep(1000 / 60);
}
catch (InterruptedException ex)
{
}
}
}
});
类Background,PlayerUnit和CannonShooterModel对我的游戏模型很重要。这是一款立式射击游戏,应该设计有各种武器和敌人。
我使用的这个彩虹渐变使用了八个不同Color对象的数组。对于通过的每一帧,我都会根据需要更改两个Point2D.Float对象的y坐标。为了使动画正常工作,我必须再次实例化LinearGradientPaint的另一个对象,该对象具有先前对象的某些先前属性,并由Paint类型的变量background对其进行引用。
问题是,LinearGradientPaint没有可在两个端点上进行转换的方法,并且get方法不会返回LinearGradientPaint对象包含的实际对象。 (我的意思是,get方法返回Point2D的新对象,该对象的值与LinearGradientPaint对象的那些值相同。)
对于传递的每一帧,我不仅要更改与渐变关联的形状的y坐标属性,还要设置再次实例化LinearGradientPaint所需的两个Point2D对象的位置。
我想重新解释一下这个简单得多的方法,因为即使这是我的主要语言,我也会对英语有所了解。如果您需要重新说明,请告诉我。
最佳答案
您可以尝试几种解决方案。
代替填充整个可绘制区域,您可以创建一个BufferedImage
,其宽度为1
像素,高度等于要填充的区域(假定垂直填充)。然后,您可以将LinearGradientPaint
应用于此BufferedImage
的Graphics2D
并填充它(完成后别忘了处置Graphics
上下文)。
然后,您只需使用Graphics#drawImage(Image, x, y, width, height, ImageObserver)
实际绘制图像。通常来说,重新缩放图像的速度似乎比用LinearGradientPaint
填充图像的速度更快,尤其是当您考虑仅在水平方向拉伸图像时。
另一个选择是生成一个已经应用了BufferedImage
的基本LinearGradientPaint
,您只需根据需要绘制此偏移量即可。这可能需要您至少绘制两次,以使其“缝制”到一起。