AffineTransformOp.filter 旋转非 0,90,180,270 度时的奇怪行为
AffineTransformOp.filter strange behavior when rotating by non 0,90,180,270 degrees
所以我正在编写一个游戏,我试图让敌人在玩家四处移动时看着玩家。我尝试使用此代码旋转图像:
public static BufferedImage rotateImage(BufferedImage image, double radians) {
//Rotate the given image by the angle
AffineTransform at = AffineTransform.getRotateInstance(radians,image.getWidth()/2,image.getHeight()/2);
AffineTransformOp atOp = new AffineTransformOp(at,AffineTransformOp.TYPE_BILINEAR);
return atOp.filter(image,null);
}
图片更新在这里:
public void rotateEnemyImage() {
double radians = Math.asin(xVel/Math.sqrt((yVel*yVel+xVel*xVel)));
if (Math.abs(currentRotation - radians) > MINIMUMROTATION) {
enemyImage = cemeteryfuntimes.Code.Shared.Utilities.rotateImage(enemyImage, radians - currentRotation);
currentRotation = radians;
}
}
(我知道计算弧度的公式不太正确我还在研究它,但是当敌人没有被正确绘制时很难修补)
然后我使用以下代码绘制图像:
public void draw(Graphics2D g) {
g.drawImage(enemyImage, Math.round(xSide+xPos), Math.round(ySide+yPos), null);
}
(xSide 和 ySide 只是游戏边界的常量)
此代码适用于改变玩家的视线方向:
public void rotatePlayerImage(int direction) {
//Rotate the image of the player
int rotationAngle = shootDirection[direction];
playerImage = cemeteryfuntimes.Code.Shared.Utilities.rotateImage(playerImage,Math.toRadians(rotationAngle - currentRotation));
currentRotation = rotationAngle;
}
(shootDirection 是一个包含 0、90、180 和 270 的静态 int 数组)
但玩家只是在水平和垂直方向上看。当我尝试传递一个不是 0,90,180 或 270 度的角度时,它似乎不会围绕其中心旋转图像。图像被截断,似乎绕着某个任意轴移动,然后程序逐渐停止。
Image of enemy after a few rotations
Original image of enemy
我不确定为什么这种旋转适用于 90 度倍数,但不适用于其他任何东西。我已经尝试将玩家旋转更改为略微偏离 0、90、180 和 270 度,然后我从中看到了同样混乱的行为。
您的代码中存在两个主要问题:
对于转换操作,您正在转换原始图像,因此 'destroying' 它。
转换操作不准确,每一步都会增加不准确性(或数据丢失)。实际上,AffineTransformOp.TYPE_BILINEAR
意味着您正在对 'calculate' 新图像进行双线性插值,这是某种 'estimation'。这就是每次迭代图像变得更多 'blurry' 的原因。
而不是对
中的同一图像进行 "increments"
enemyImage = cemeteryfuntimes.Code.Shared.Utilities.rotateImage(
enemyImage,
radians - currentRotation);
您应该保持原始图像不变,永远不要对其进行任何更改,并且对于每一步,直接从原始图像计算所需的变换:
enemyImage = cemeteryfuntimes.Code.Shared.Utilities.rotateImage(
sourceEnemyImage,
currentRotation);
图像被截断
我不完全确定为什么会发生这种情况(尽管查看 AffineTransformOp
源代码我高度怀疑是因为仿射变换变换了一些没有负坐标的角,并且由于某种原因 createCompatibleDestImage
方法选择只取积极的部分),但你可以看到其他 SO questions 的解决方案(这可能会解决你的问题,但我还没有在那里找到解释)。
截断问题的另一种解决方案是让 'enemy' 位于正方形图像的正中间,该正方形图像的长度等于(或大于)'enemy' 最大对角线。
为什么适用于直角?
如果我对负坐标的猜测是正确的,那么它不适用于直角。此外,他们似乎有 special treatment
所以我正在编写一个游戏,我试图让敌人在玩家四处移动时看着玩家。我尝试使用此代码旋转图像:
public static BufferedImage rotateImage(BufferedImage image, double radians) {
//Rotate the given image by the angle
AffineTransform at = AffineTransform.getRotateInstance(radians,image.getWidth()/2,image.getHeight()/2);
AffineTransformOp atOp = new AffineTransformOp(at,AffineTransformOp.TYPE_BILINEAR);
return atOp.filter(image,null);
}
图片更新在这里:
public void rotateEnemyImage() {
double radians = Math.asin(xVel/Math.sqrt((yVel*yVel+xVel*xVel)));
if (Math.abs(currentRotation - radians) > MINIMUMROTATION) {
enemyImage = cemeteryfuntimes.Code.Shared.Utilities.rotateImage(enemyImage, radians - currentRotation);
currentRotation = radians;
}
}
(我知道计算弧度的公式不太正确我还在研究它,但是当敌人没有被正确绘制时很难修补)
然后我使用以下代码绘制图像:
public void draw(Graphics2D g) {
g.drawImage(enemyImage, Math.round(xSide+xPos), Math.round(ySide+yPos), null);
}
(xSide 和 ySide 只是游戏边界的常量)
此代码适用于改变玩家的视线方向:
public void rotatePlayerImage(int direction) {
//Rotate the image of the player
int rotationAngle = shootDirection[direction];
playerImage = cemeteryfuntimes.Code.Shared.Utilities.rotateImage(playerImage,Math.toRadians(rotationAngle - currentRotation));
currentRotation = rotationAngle;
}
(shootDirection 是一个包含 0、90、180 和 270 的静态 int 数组)
但玩家只是在水平和垂直方向上看。当我尝试传递一个不是 0,90,180 或 270 度的角度时,它似乎不会围绕其中心旋转图像。图像被截断,似乎绕着某个任意轴移动,然后程序逐渐停止。
Image of enemy after a few rotations
Original image of enemy
我不确定为什么这种旋转适用于 90 度倍数,但不适用于其他任何东西。我已经尝试将玩家旋转更改为略微偏离 0、90、180 和 270 度,然后我从中看到了同样混乱的行为。
您的代码中存在两个主要问题:
对于转换操作,您正在转换原始图像,因此 'destroying' 它。
转换操作不准确,每一步都会增加不准确性(或数据丢失)。实际上,AffineTransformOp.TYPE_BILINEAR
意味着您正在对 'calculate' 新图像进行双线性插值,这是某种 'estimation'。这就是每次迭代图像变得更多 'blurry' 的原因。
而不是对
中的同一图像进行 "increments"enemyImage = cemeteryfuntimes.Code.Shared.Utilities.rotateImage(
enemyImage,
radians - currentRotation);
您应该保持原始图像不变,永远不要对其进行任何更改,并且对于每一步,直接从原始图像计算所需的变换:
enemyImage = cemeteryfuntimes.Code.Shared.Utilities.rotateImage(
sourceEnemyImage,
currentRotation);
图像被截断
我不完全确定为什么会发生这种情况(尽管查看 AffineTransformOp
源代码我高度怀疑是因为仿射变换变换了一些没有负坐标的角,并且由于某种原因 createCompatibleDestImage
方法选择只取积极的部分),但你可以看到其他 SO questions 的解决方案(这可能会解决你的问题,但我还没有在那里找到解释)。
截断问题的另一种解决方案是让 'enemy' 位于正方形图像的正中间,该正方形图像的长度等于(或大于)'enemy' 最大对角线。
为什么适用于直角?
如果我对负坐标的猜测是正确的,那么它不适用于直角。此外,他们似乎有 special treatment