我正在写一个扑克游戏,我正在尝试写一个产生特定手牌图像的课程。我最初只是通过将5张卡片中的每张卡片的图像组合在一起来制作图像。这就是结果:
然后我决定,将牌叠放在一起并展开的手牌会更好,就像拿一张牌一样。
这是迄今为止我能做到的最好的事情:
正如你所看到的,最后3张牌看起来应该是这样,但前三张牌被切断到第三张牌的左边。
这是我现在的代码(它不是最干净的,因为我一直试图让它工作,无论它需要什么)
private static final int CARD_WIDTH = 500;
private static final int CARD_HEIGHT = 726;
private static final double ROTATION = 20.0;
public void createImage(HandOfCards hand) throws IOException {
int handImageWidth = (int) (2 * (Math.sin(degreesToRadian(ROTATION)) * CARD_HEIGHT + Math.cos(degreesToRadian(ROTATION)) * CARD_WIDTH)- CARD_WIDTH);
int handImageHeight = (int) (CARD_HEIGHT + Math.sin(degreesToRadian(ROTATION)) * CARD_WIDTH);
BufferedImage handImage = new BufferedImage(handImageWidth, handImageHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = (Graphics2D) handImage.getGraphics();
int xPos = handImageWidth / 2 - CARD_WIDTH / 2;
int yPos = 0;
int xAnchor = CARD_WIDTH;
int yAnchor = CARD_HEIGHT;
double rotation = -ROTATION;
for (int i = 0; i < HandOfCards.HAND_SIZE; i++) {
if (i == 3) xAnchor = 0;
PlayingCard card = hand.getCard(i);
BufferedImage cardImage = ImageIO.read(new File("cardImages/" + card + ".png"));
AffineTransform transform = new AffineTransform();
transform.rotate(degreesToRadian(rotation), xAnchor, yAnchor);
AffineTransformOp transformOp = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
cardImage = transformOp.filter(cardImage, null);
graphics.drawImage(cardImage, xPos, yPos, null);
rotation += ROTATION / 2;
}
private double degreesToRadian(double degrees) {
return (degrees * Math.PI) / 180.0;
}
编辑
为了让事情变得更清楚,以下是仅在首次执行循环时(仅绘制第一张卡片)并且背景颜色为显示整个图像的大小的结果。
答案 0 :(得分:1)
您正在观察的行为的原因在documentation of AffineTransformOp#filter
:
getBounds2D(BufferedImage)返回的矩形坐标不一定与此方法返回的BufferedImage的坐标相同。 如果矩形的左上角坐标为负,则不绘制矩形的这部分。
当您使用类似
的声明打印每张卡片的边界时System.out.println("Bounds: "+transformOp.getBounds2D(cardImage));
你会看到边界是负面的(正如人们在将卡片向左旋转时所期望的那样)。
可以通过将AffineTransform
调整为始终生成正边界,并使用非filter
目标图片调用null
方法来避免这种情况(在你的情况下:使用包含手的图像 - 即所有卡片图像。)
(这是问题的实际答案。其余部分可能会被忽略,或被视为我有太多空闲时间的证据)
话虽如此,我想建议一个不同的解决方案,因为当前方法在不同层面存在一些问题。
在最高级别:为什么您要创建此图片根本?我想你正在实施一个纸牌游戏。在这样的游戏中,你可能有数百种不同的手#34;为什么要为每个手创建新图像?
您可以直接绘制旋转的图像,而不是为每只手创建图像。粗略地说:除了将图像绘制到新图像的Graphics
之外,您可以将它们简单地绘制到Graphics
的{{1}}中,在那里你可以用手画画。
但是考虑到差异只是你正在绘制的JPanel
对象,这可以在以后很容易地改变(如果相应地实现),也许有一个实际的原因让你创建这些图像。
在最低级别:函数Graphics
应完全替换为Math.toRadians
。
以下是一个示例,实现为MCVE。 (这意味着它不使用degreesToRadian
和HandOfCards
类。而是在PlayingCards
个对象列表上运行。这些图像实际上是在运行时从维基百科下载的。< / p>
此示例的核心是BufferedImage
。它允许您将(旋转的)卡片绘制成RotatedPlayingCardsPainter
。尝试时,这种方法的一个优点可能会变得很明显:您可以使用滑块动态更改卡之间的角度。 (想象一下你的游戏在某种奇特的动画......)
(但如果您愿意,它还包含一个Graphics2D
方法,可以让您创建一个图像,就像最初在问题中所做的那样)
当您阅读代码时,您会看到每个卡的createImage
实例是在AffineTransform
方法中创建的。在那里,我添加了一些任意的,神奇的因素来轻松地将卡片相互移动,并给他们一个更像粉丝般的&#34;出现。
比较此图片,没有神奇因素
与 一个神奇的因素:
我认为后者看起来更像现实&#34;但这可能是品味问题。
另一方面注意:直接绘制图像(与createTransform
方法相比)的缺点是图像的边框可能看起来是锯齿状的,无论过滤和抗锯齿设置如何。这是因为在图像的边界处没有任何内插。在给定的程序中,这是通过AffineTransformOp
方法规避的,它为图像添加了1像素的透明边框,以确保它看起来很漂亮,并且在旋转图像时边框看起来很平滑。
以下是代码:
addBorder