Java 将微小的低分辨率应用程序扩展到更大的屏幕大小
我正在用Java创建一个复古街机游戏。游戏的屏幕分辨率是304 x 256,我想保留它以保留游戏的复古特征(视觉效果、动画、字体块状等) 但当我在一个大的桌面显示器上渲染时,它太小了,正如人们所期望的那样 我希望能够放大窗口,比如通过一个常数因子,而不必编写各种Java 将微小的低分辨率应用程序扩展到更大的屏幕大小,java,swing,awt,Java,Swing,Awt,我正在用Java创建一个复古街机游戏。游戏的屏幕分辨率是304 x 256,我想保留它以保留游戏的复古特征(视觉效果、动画、字体块状等) 但当我在一个大的桌面显示器上渲染时,它太小了,正如人们所期望的那样 我希望能够放大窗口,比如通过一个常数因子,而不必编写各种paint(Graphics)方法来了解放大的事实。也就是说,我希望渲染代码相信屏幕是304 x 256。我也不想改变我的桌面分辨率或进入全屏独占模式。只需要一个放大像素的大窗口 我会按照以下思路寻找一些东西: scale(myJFram
paint(Graphics)
方法来了解放大的事实。也就是说,我希望渲染代码相信屏幕是304 x 256。我也不想改变我的桌面分辨率或进入全屏独占模式。只需要一个放大像素的大窗口
我会按照以下思路寻找一些东西:
scale(myJFrame, 4);
并让所有内容自动放大
更新:关于输入,我的游戏恰好使用键盘输入,所以我自己不需要垃圾神描述的逆变换。我仍然可以想象其他人会需要它,所以我认为这是一个合适的建议。建议的一种方法是依靠drawImage()
来缩放内容的图像。游戏将在buffereImage
的图形上下文中呈现,而不是在paintComponent()的实现中呈现。如果游戏包含鼠标交互,则必须缩放鼠标坐标,如图所示。在下面的变体中,我给了中心
面板一个首选大小,它是比例=8的倍数
,并在边界布局的西部
添加了原始图标。默认情况下,CENTER
会忽略零部件的首选尺寸,您可能希望将其添加到具有FlowLayout
的(可能是嵌套的)面板中。调整框架大小以查看效果
f.setLayout(new FlowLayout());
f.add(new Grid(NAME));
//f.add(new JLabel(ICON), BorderLayout.WEST);
建议的一种方法是依赖图形上下文的scale()
方法,构造一个逆变换,在鼠标坐标和图像坐标之间进行转换。在下面的示例中,请注意原始图像是256 x 256,而显示的图像是按SCALE=2.0
缩放的。鼠标悬停在图像的中心;工具提示在显示中显示任意点,在原始图形中显示中心点(127127)
导入java.awt.Color;
导入java.awt.Component;
导入java.awt.Dimension;
导入java.awt.FlowLayout;
导入java.awt.Font;
导入java.awt.FontMetrics;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.Point;
导入java.awt.RenderingHints;
导入java.awt.event.MouseAdapter;
导入java.awt.event.MouseEvent;
导入java.awt.event.MouseMotionAdapter;
导入java.awt.geom.AffineTransform;
导入java.awt.geom.NoninvertibleTransformException;
导入java.awt.image.buffereImage;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
/**@见https://stackoverflow.com/a/2244285/230513 */
公共类反变换{
专用静态最终双刻度=2.0;
公共静态void main(字符串[]args){
JFrame=新JFrame(“反向测试”);
BuffereImage=getImage(256,'F');
AffineTransform at=新的AffineTransform();
比例(比例,比例);
frame.add(新的ImageView(image,at));
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
私有静态缓冲区映像getImage(整数大小,字符c){
最终字体=新字体(“衬线”,Font.BOLD,size);
BuffereImage bi=新的BuffereImage(
大小、大小、缓冲区映像。键入\ u INT \ u ARGB);
Graphics2D g2d=bi.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_抗锯齿,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(颜色:白色);
g2d.fillRect(0,0,size,size);
g2d.setPaint(颜色:蓝色);
g2d.setFont(字体);
FontMetrics fm=g2d.getFontMetrics();
intx=(size-fm.charWidth(c))/2;
int y=fm.getAscent()+fm.getDescent()/4;
g2d.抽绳(串.值(c),x,y);
g2d.setPaint(颜色:黑色);
g2d.绘制线(0,y,尺寸,y);
g2d.抽绳(x,0,x,尺寸);
g2d.椭圆形(x-3,y-3,6,6);
g2d.drawRect(0,0,大小-1,大小-1);
g2d.dispose();
返回bi;
}
私有静态类ImageView扩展了JPanel{
私有缓冲图像;
私有仿射变换at;
私有仿射变换逆;
私有图形2D画布;
专用点oldPt=新点();
私人点新港;
@凌驾
公共维度getPreferredSize(){
返回新维度(//比例的任意倍数
(int)(image.getWidth()*比例*1.25),
(int)(image.getHeight()*比例*1.25));
}
@凌驾
公共组件(图形g){
超级组件(g);
Graphics2D g2d=(Graphics2D)g;
试一试{
g2d.setRenderingHint(RenderingHints.KEY_抗锯齿,
RenderingHints.VALUE_ANTIALIAS_ON);
inverse=g2d.getTransform();
反转();
g2d.translate(this.getWidth()/2,this.getHeight()/2);
g2d.变换(at);
translate(-image.getWidth()/2,-image.getHeight()/2);
concatenate(g2d.getTransform());
g2d.drawImage(图像,0,0,this);
}捕获(不可逆转换异常){
例如printStackTrace(System.err);
}
}
图像视图(最终缓冲区图像图像、最终仿射变换){
本图为背景色(颜色:浅灰色);
这个图像=图像;
this.at=at;
T
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
/**
* @see https://stackoverflow.com/a/44373975/230513
* @see http://stackoverflow.com/questions/2900801
*/
public class Grid extends JPanel implements MouseMotionListener {
private static final String NAME = "OptionPane.informationIcon";
private static final Icon ICON = UIManager.getIcon(NAME);
private static final int SCALE = 8;
private final BufferedImage image;
private int imgW, imgH, paneW, paneH;
public Grid(String name) {
super(true);
imgW = ICON.getIconWidth();
imgH = ICON.getIconHeight();
image = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
ICON.paintIcon(null, g2d, 0, 0);
g2d.dispose();
this.addMouseMotionListener(this);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(imgW * SCALE, imgH * SCALE);
}
@Override
protected void paintComponent(Graphics g) {
paneW = this.getWidth();
paneH = this.getHeight();
g.drawImage(image, 0, 0, paneW, paneH, null);
}
@Override
public void mouseMoved(MouseEvent e) {
Point p = e.getPoint();
int x = p.x * imgW / paneW;
int y = p.y * imgH / paneH;
int c = image.getRGB(x, y);
this.setToolTipText(x + "," + y + ": "
+ String.format("%08X", c));
}
@Override
public void mouseDragged(MouseEvent e) {
}
private static void create() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new Grid(NAME));
f.add(new JLabel(ICON), BorderLayout.WEST);
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
create();
}
});
}
}
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** @see https://stackoverflow.com/a/2244285/230513 */
public class InverseTransform {
private static final double SCALE = 2.0;
public static void main(String[] args) {
JFrame frame = new JFrame("Inverse Test");
BufferedImage image = getImage(256, 'F');
AffineTransform at = new AffineTransform();
at.scale(SCALE, SCALE);
frame.add(new ImageView(image, at));
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static BufferedImage getImage(int size, char c) {
final Font font = new Font("Serif", Font.BOLD, size);
BufferedImage bi = new BufferedImage(
size, size, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(Color.white);
g2d.fillRect(0, 0, size, size);
g2d.setPaint(Color.blue);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int x = (size - fm.charWidth(c)) / 2;
int y = fm.getAscent() + fm.getDescent() / 4;
g2d.drawString(String.valueOf(c), x, y);
g2d.setPaint(Color.black);
g2d.drawLine(0, y, size, y);
g2d.drawLine(x, 0, x, size);
g2d.fillOval(x - 3, y - 3, 6, 6);
g2d.drawRect(0, 0, size - 1, size - 1);
g2d.dispose();
return bi;
}
private static class ImageView extends JPanel {
private BufferedImage image;
private AffineTransform at;
private AffineTransform inverse;
private Graphics2D canvas;
private Point oldPt = new Point();
private Point newPt;
@Override
public Dimension getPreferredSize() {
return new Dimension( // arbitrary multiple of SCALE
(int)(image.getWidth() * SCALE * 1.25),
(int)(image.getHeight() * SCALE * 1.25));
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
try {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
inverse = g2d.getTransform();
inverse.invert();
g2d.translate(this.getWidth() / 2, this.getHeight() / 2);
g2d.transform(at);
g2d.translate(-image.getWidth() / 2, -image.getHeight() / 2);
inverse.concatenate(g2d.getTransform());
g2d.drawImage(image, 0, 0, this);
} catch (NoninvertibleTransformException ex) {
ex.printStackTrace(System.err);
}
}
ImageView(final BufferedImage image, final AffineTransform at) {
this.setBackground(Color.lightGray);
this.image = image;
this.at = at;
this.canvas = image.createGraphics();
this.canvas.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
this.canvas.setColor(Color.BLACK);
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
Point m = e.getPoint();
Point i = e.getPoint();
try {
inverse.inverseTransform(m, i);
setToolTipText("<html>Mouse: " + m.x + "," + m.y
+ "<br>Inverse: " + i.x + "," + i.y + "</html>");
} catch (NoninvertibleTransformException ex) {
ex.printStackTrace();
}
}
});
}
}
}
package bb.view;
import javax.swing.JComponent;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import static bb.BBConfig.SCREEN_WIDTH_PX; // 304
import static bb.BBConfig.SCREEN_HEIGHT_PX; // 256
public class Resizer extends JPanel {
private static final int K = 3;
private static final Dimension PREF_SIZE =
new Dimension(K * SCREEN_WIDTH_PX, K * SCREEN_HEIGHT_PX);
private static final AffineTransform SCALE_XFORM =
AffineTransform.getScaleInstance(K, K);
public Resizer(JComponent component) {
setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
add(component);
}
@Override
public Dimension getPreferredSize() {
return PREF_SIZE;
}
@Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setTransform(SCALE_XFORM);
super.paint(g2);
}
}