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

小编典典

是的,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 standingImgMap = new EnumMap<>(SpriteDirection.class);

private Map> 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 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

}

2020-12-01

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值