如何在Java中聆听按键时移动图像

简介: 如何在Java中聆听按键时移动图像

如何解决如何在Java中聆听按键时移动图像?
你可以使用Swing计时器为图像设置动画:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TimerAnimation extends JLabel implements ActionListener
{

int deltaX = 2;
int deltaY = 3;
int directionX = 1;
int directionY = 1;
public TimerAnimation(
    int startX, int startY,
    int deltaX, int deltaY,
    int directionX, int directionY,
    int delay)
{
    this.deltaX = deltaX;
    this.deltaY = deltaY;
    this.directionX = directionX;
    this.directionY = directionY;
    setIcon( new ImageIcon("dukewavered.gif") );

// setIcon( new ImageIcon("copy16.gif") );

    setSize( getPreferredSize() );
    setLocation(startX, startY);
    new javax.swing.Timer(delay, this).start();
}
public void actionPerformed(ActionEvent e)
{
    Container parent = getParent();
    //  Determine next X position
    int nextX = getLocation().x + (deltaX * directionX);
    if (nextX < 0)
    {
        nextX = 0;
        directionX *= -1;
    }
    if ( nextX + getSize().width > parent.getSize().width)
    {
        nextX = parent.getSize().width - getSize().width;
        directionX *= -1;
    }
    //  Determine next Y position
    int nextY = getLocation().y + (deltaY * directionY);
    if (nextY < 0)
    {
        nextY = 0;
        directionY *= -1;
    }
    if ( nextY + getSize().height > parent.getSize().height)
    {
        nextY = parent.getSize().height - getSize().height;
        directionY *= -1;
    }
    //  Move the label
    setLocation(nextX, nextY);
}
public static void main(String[] args)
{
    JPanel panel = new JPanel();
    JFrame frame = new JFrame();
    frame.setContentPane(panel);
    frame.setDefaultCloSEOperation( JFrame.EXIT_ON_CLOSE );
    frame.getContentPane().setLayout(null);

// frame.getContentPane().add( new TimerAnimation(10, 10, 2, 3, 1, 1, 10) );

    frame.getContentPane().add( new TimerAnimation(300, 100, 3, 2, -1, 1, 20) );

// frame.getContentPane().add( new TimerAnimation(0, 000, 5, 0, 1, 1, 20) );

    frame.getContentPane().add( new TimerAnimation(0, 200, 5, 0, 1, 1, 80) );
    frame.setSize(400, 400);
    frame.setLocationRelativeto( null );
    frame.setVisible(true);

// frame.getContentPane().add( new TimerAnimation(10, 10, 2, 3, 1, 1, 10) );
// frame.getContentPane().add( new TimerAnimation(10, 10, 3, 0, 1, 1, 10) );

}

}
你可以将KeyListener添加到面板,它将独立于图像动画进行操作。

是的,Swing计时器和键绑定可以很好地工作。这是另一个例子(我的):)

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class AnimationWithKeyBinding {
private static void createAndShowUI() {

  AnimationPanel panel = new AnimationPanel(); // the drawing JPanel
  JFrame frame = new JFrame("Animation With Key Binding");
  frame.getContentPane().add(panel);
  frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
  frame.pack();
  frame.setLocationRelativeto(null);
  frame.setVisible(true);

}
public static void main(String[] args) {

  java.awt.EventQueue.invokelater(new Runnable() {
     public void run() {
        createAndShowUI();
     }
  });

}
}
@SuppressWarnings("serial")
class AnimationPanel extends JPanel {
public static final int SPRITE_WIDTH = 20;
public static final int PANEL_WIDTH = 400;
public static final int PANEL_HEIGHT = 400;
private static final int MAX_MSTATE = 25;
private static final int SPIN_TIMER_PERIOD = 16;
private static final int SPRITE_STEP = 3;
private int mState = 0;
private int mX = (PANEL_WIDTH - SPRITE_WIDTH) / 2;
private int mY = (PANEL_HEIGHT - SPRITE_WIDTH) / 2;
private int oldMX = mX;
private int oldMY = mY;
private boolean moved = false;
// an array of sprite images that are drawn sequentially
private BufferedImage[] spriteImages = new BufferedImage[MAX_MSTATE];
public AnimationPanel() {

  // create and start the main animation timer
  new Timer(SPIN_TIMER_PERIOD, new SpinTimerListener()).start();
  setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
  setBackground(Color.white);
  createSprites(); // create the images
  setupKeyBinding();

}
private void setupKeyBinding() {

  int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
  InputMap inMap = getInputMap(condition);
  ActionMap actMap = getActionMap();
  // this uses an enum of Direction that holds ints for the arrow keys
  for (Direction direction : Direction.values()) {
     int key = direction.getKey();
     String name = direction.name();
     // add the key bindings for arrow key and shift-arrow key
     inMap.put(Keystroke.getKeystroke(key, 0), name);
     inMap.put(Keystroke.getKeystroke(key, InputEvent.SHIFT_DOWN_MASK), name);
     actMap.put(name, new MyKeyAction(this, direction));
  }

}
// create a bunch of buffered images and place into an array,
// to be displayed sequentially
private void createSprites() {

  for (int i = 0; i < spriteImages.length; i++) {
     spriteImages[i] = new BufferedImage(SPRITE_WIDTH, SPRITE_WIDTH,
              BufferedImage.TYPE_INT_ARGB);
     Graphics2D g2 = spriteImages[i].createGraphics();
     g2.setColor(Color.red);
     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
     double theta = i * Math.PI / (2 * spriteImages.length);
     double x = SPRITE_WIDTH * Math.abs(Math.cos(theta)) / 2.0;
     double y = SPRITE_WIDTH * Math.abs(Math.sin(theta)) / 2.0;
     int x1 = (int) ((SPRITE_WIDTH / 2.0) - x);
     int y1 = (int) ((SPRITE_WIDTH / 2.0) - y);
     int x2 = (int) ((SPRITE_WIDTH / 2.0) + x);
     int y2 = (int) ((SPRITE_WIDTH / 2.0) + y);
     g2.drawLine(x1, y1, x2, y2);
     g2.drawLine(y1, x2, y2, x1);
     g2.dispose();
  }

}
@Override
protected void paintComponent(Graphics g) {

  super.paintComponent(g);
  g.drawImage(spriteImages[mState], mX, mY, null);

}
public void incrementX(boolean right) {

  oldMX = mX;
  if (right) {
     mX = Math.min(getWidth() - SPRITE_WIDTH, mX + SPRITE_STEP);
  } else {
     mX = Math.max(0, mX - SPRITE_STEP);
  }
  moved = true;

}
public void incrementY(boolean down) {

  oldMY = mY;
  if (down) {
     mY = Math.min(getHeight() - SPRITE_WIDTH, mY + SPRITE_STEP);
  } else {
     mY = Math.max(0, mY - SPRITE_STEP);
  }
  moved = true;

}
public void tick() {

  mState = (mState + 1) % MAX_MSTATE;

}
private class SpinTimerListener implements ActionListener {

  @Override
  public void actionPerformed(ActionEvent e) {
     tick();
     int delta = 20;
     int width = SPRITE_WIDTH + 2 * delta;
     int height = width;
     // make sure to erase the old image
     if (moved) {
        int x = oldMX - delta;
        int y = oldMY - delta;
        repaint(x, y, width, height);
     }
     int x = mX - delta;
     int y = mY - delta;
     // draw the new image
     repaint(x, y, width, height);
     moved = false;
  }

}
}
enum Direction {
UP(KeyEvent.VK_UP), DOWN(KeyEvent.VK_DOWN), LEFT(KeyEvent.VK_LEFT), RIGHT(KeyEvent.VK_RIGHT);
private int key;
private Direction(int key) {

  this.key = key;

}
public int getKey() {

  return key;

}
}
// Actions for the key binding
@SuppressWarnings("serial")
class MyKeyAction extends AbstractAction {
private AnimationPanel draw;
private Direction direction;
public MyKeyAction(AnimationPanel draw, Direction direction) {

  this.draw = draw;
  this.direction = direction;

}
@Override
public void actionPerformed(ActionEvent e) {

  switch (direction) {
  case UP:
     draw.incrementY(false);
     break;
  case DOWN:
     draw.incrementY(true);
     break;
  case LEFT:
     draw.incrementX(false);
     break;
  case RIGHT:
     draw.incrementX(true);
     break;
  default:
     break;
  }

}
}
这是另一个使用此精灵表的示例:

在此处输入图片说明

从本网站获得。

同样,这是在JPanel的paintComponent方法中进行绘制并使用“键绑定”指示移动方向的示例。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.*;
@SuppressWarnings("serial")
public class Mcve3 extends JPanel {

private static final int PREF_W = 800;
private static final int PREF_H = 640;
private static final int TIMER_DELAY = 50;
private int spriteX = 400;
private int spriteY = 320;
private SpriteDirection spriteDirection = SpriteDirection.RIGHT;
private MySprite sprite = null;
private Timer timer = null;
public Mcve3() {
    try {
        sprite = new MySprite(spriteDirection, spriteX, spriteY);
    } catch (IOException e) {
        e.printstacktrace();
        System.exit(-1);
    }
    setBackground(Color.WHITE);
    setKeyBindings(SpriteDirection.LEFT, KeyEvent.VK_LEFT);
    setKeyBindings(SpriteDirection.RIGHT, KeyEvent.VK_RIGHT);
    setKeyBindings(SpriteDirection.FORWARD, KeyEvent.VK_DOWN);
    setKeyBindings(SpriteDirection.AWAY, KeyEvent.VK_UP);
    timer = new Timer(TIMER_DELAY, new TimerListener());
    timer.start();
}
private void setKeyBindings(SpriteDirection dir, int keyCode) {
    int condition = WHEN_IN_FOCUSED_WINDOW;
    InputMap inputMap = getInputMap(condition);
    ActionMap actionMap = getActionMap();
    Keystroke keypressed = Keystroke.getKeystroke(keyCode, 0, false);
    Keystroke keyreleased = Keystroke.getKeystroke(keyCode, 0, true);
    inputMap.put(keypressed, keypressed.toString());
    inputMap.put(keyreleased, keyreleased.toString());
    actionMap.put(keypressed.toString(), new MoveAction(dir, false));
    actionMap.put(keyreleased.toString(), new MoveAction(dir, true));
}
@Override
public Dimension getPreferredSize() {
    if (isPreferredSizeSet()) {
        return super.getPreferredSize();
    }
    return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    sprite.draw(g);
}
private class MoveAction extends AbstractAction {
    private SpriteDirection dir;
    private boolean released;
    public MoveAction(SpriteDirection dir, boolean released) {
        this.dir = dir;
        this.released = released;
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        if (released) {
            sprite.setMoving(false);
        } else {
            sprite.setMoving(true);
            sprite.setDirection(dir);
        }
    }
}
private class TimerListener implements ActionListener {
    @Override
        public void actionPerformed(ActionEvent e) {
            if (sprite.isMoving()) {
                sprite.tick();
            }
            repaint();
        }
}
private static void createAndShowGui() {
    Mcve3 mainPanel = new Mcve3();
    JFrame frame = new JFrame("MCVE");
    frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(mainPanel);
    frame.pack();
    frame.setLocationRelativeto(null);
    frame.setVisible(true);
}
public static void main(String[] args) {
    SwingUtilities.invokelater(() -> createAndShowGui());
}

}
class MySprite {

private static final String SPRITE_SHEET_PATH = "http://"
        + "orig12.deviantart.net/7db3/f/2010/338/3/3/"
        + "animated_sprite_sheet_32x32_by_digibody-d3479l2.gif";
private static final int MAX_MOVING_INDEX = 4;
private static final int DELTA = 4;
private SpriteDirection direction;
private Map<SpriteDirection, Image> standingImgMap = new EnumMap<>(SpriteDirection.class);
private Map<SpriteDirection, List<Image>> movingImgMap = new EnumMap<>(SpriteDirection.class);
private int x;
private int y;
private boolean moving = false;
private int movingIndex = 0;
public MySprite(SpriteDirection direction, int x, int y) throws IOException {
    this.direction = direction;
    this.x = x;
    this.y = y;
    createSprites();
}
public void draw(Graphics g) {
    Image img = null;
    if (!moving) {
        img = standingImgMap.get(direction);
    } else {
        img = movingImgMap.get(direction).get(movingIndex);
    }
    g.drawImage(img, x, y, null);
}
private void createSprites() throws IOException {
    URL spriteSheetUrl = new URL(SPRITE_SHEET_PATH);
    BufferedImage img = ImageIO.read(spriteSheetUrl);
    // get sub-images (sprites) from the sprite sheet
    // magic numbers for getting sprites from sheet, all obtained by trial and error
    int x0 = 0;
    int y0 = 64;
    int rW = 32;
    int rH = 32;
    for (int row = 0; row < 4; row++) {
        SpriteDirection dir = SpriteDirection.values()[row];
        List<Image> imgList = new ArrayList<>();
        movingImgMap.put(dir, imgList);
        int rY = y0 + row * rH;
        for (int col = 0; col < 5; coL++) {
            int rX = x0 + col * rW;
            BufferedImage subImg = img.getSubimage(rX, rY, rW, rH);
            if (col == 0) {
                // first image is standing
                standingImgMap.put(dir, subImg);
            } else {
                // all others are moving
                imgList.add(subImg);
            }
        }
    }
}
public SpriteDirection getDirection() {
    return direction;
}
public void setDirection(SpriteDirection direction) {
    if (this.direction != direction) {
        setMoving(false);
    }
    this.direction = direction;
}
public int getX() {
    return x;
}
public void setX(int x) {
    this.x = x;
}
public int getY() {
    return y;
}
public void setY(int y) {
    this.y = y;
}
public boolean isMoving() {
    return moving;
}
public void setMoving(boolean moving) {
    this.moving = moving;
    if (!moving) {
        movingIndex = 0;
    }
}
public void tick() {
    if (moving) {
        switch (direction) {
        case RIGHT:
            x += DELTA;
            break;
        case LEFT:
            x -= DELTA;
            break;
        case FORWARD:
            y += DELTA;
            break;
        case AWAY:
            y -= DELTA;
        }
        movingIndex++;
        movingIndex %= MAX_MOVING_INDEX;
    }
}
public int getMovingIndex() {
    return movingIndex;
}
public void setMovingIndex(int movingIndex) {
    this.movingIndex = movingIndex;
}

}
enum SpriteDirection {

FORWARD, LEFT, AWAY, RIGHT

}
解决方法
我开始学习Java编程,并且我认为通过游戏开发学习Java很酷。我知道如何绘制图像并听按键,然后移动该图像。但是,当窗口正在听按键时,是否可以使图像在窗口中来回移动?例如,当图像或对象(如太空飞船)在窗口中从左向右移动时,如果按空格键,激光将在屏幕底部发射(很酷的:D)。但是基本上,我只是想知道在窗口正在听按键时如何使图像左右移动。

我在想将一个关键侦听器添加到我的窗口,然后触发一个无限循环来移动图像。还是我需要学习有关线程的知识,以便另一个线程可以移动对象?

请指教。
声明:地推任务网所有作品(图片、文字)均由用户自行上传分享,仅供网友学习交流。

相关文章
|
26天前
|
存储 Java API
|
2月前
|
数据采集 安全 Java
Java Selenium WebDriver:代理设置与图像捕获
Java Selenium WebDriver:代理设置与图像捕获
|
3月前
|
Java 计算机视觉
图像处理之图像纹理添加效果(利用JAVA 2D纹理画笔)
图像处理之图像纹理添加效果(利用JAVA 2D纹理画笔)
34 8
|
4月前
|
数据采集 机器学习/深度学习 Java
数据猎手:使用Java和Apache HttpComponents库下载Facebook图像
本文介绍了如何使用Java和Apache HttpComponents库从Facebook获取图像数据。通过设置爬虫代理IP以避免限制,利用HttpClient发送请求,解析HTML找到图像链接,然后下载并保存图片。提供的Java代码示例展示了实现过程,包括创建代理配置、线程池,以及下载图片的逻辑。注意,实际应用需根据Facebook页面结构进行调整。
数据猎手:使用Java和Apache HttpComponents库下载Facebook图像
|
4月前
|
文字识别 Java Maven
java调用tess4j识别图像中的文字
java调用tess4j识别图像中的文字
222 3
|
4月前
|
算法 Python Java
Java每日一练(20230414) Pow(x, n) 、旋转图像、买卖股票的最佳时机 IV
Java每日一练(20230414) Pow(x, n) 、旋转图像、买卖股票的最佳时机 IV
36 0
Java每日一练(20230414) Pow(x, n) 、旋转图像、买卖股票的最佳时机 IV
|
4月前
|
Java API 容器
java和VB中按键事件处理:解析 KeyCode、KeyAscii; KeyDown/KeyUp/KeyPress 的关系区别及应用
java和VB中按键事件处理:解析 KeyCode、KeyAscii; KeyDown/KeyUp/KeyPress 的关系区别及应用
|
9月前
|
机器学习/深度学习 Java
48. 旋转图像 --力扣 --JAVA
​ 给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 ​
47 0
|
存储 算法 Java
GIF图像动态生成-JAVA后台生成
本文简要讲述了GIF图像知识,并且以JAVA技术为例,介绍了后台生成GIF的技术,并提供较详细的代码示例,希望对您有帮助。最后怀念因新冠感染去世的GIF的发明者,斯蒂芬•威尔海特。
393 0
GIF图像动态生成-JAVA后台生成
|
机器学习/深度学习 算法 Java
Java使用OpenCV进行图像操作
OpenCV是一个开源的计算机视觉库,它提供了一系列丰富的图像处理和计算机视觉算法,包括图像读取、显示、滤波、特征检测、目标跟踪等功能。
3114 2