吃豆人开/合嘴动画
Posted
技术标签:
【中文标题】吃豆人开/合嘴动画【英文标题】:Pacman open/close mouth animation 【发布时间】:2013-01-03 19:15:42 【问题描述】:我想用最简单的方法制作 pacman 的开/合嘴动画。 这是我最近的代码:问题是,什么都没有发生?
package ordner;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class PacMan implements ActionListener
private JFrame frame;
private DrawPanel panel;
private void initGui()
frame = new JFrame("Pacman");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new DrawPanel();
frame.add(panel);
panel.setBackground(Color.BLACK);
frame.setSize(300, 300);
frame.setVisible(true);
public static void main(String[] args)
PacMan pm = new PacMan();
pm.initGui();
@Override
public void actionPerformed(ActionEvent e)
panel.repaint();
这是我的绘图面板:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawPanel extends JPanel
@Override
public void paintComponent(Graphics g)
super.paintComponent(g);
g.setColor(Color.yellow);
g.fillArc(70,50,150,150,30,300);
int i = 0;
while ( i <= 60)
g.fillArc(70,50,150,150,30-i,300+i+i);
try
Thread.sleep(25);
catch (Exception e)
Thread.currentThread().interrupt();
i++;
while 循环没有任何影响,这可能是什么原因?
【问题讨论】:
请参阅here 了解如何使用动画(使用drawImage
创建图像)、游戏循环等的示例。也不要覆盖paint(..)
,而是使用JPanel
并覆盖paintComponent
我不确定您的项目的目的,但在游戏中,这种动画是通过一种称为 Blitting 的技术实现的。它基本上适用于图像文件(spritesheet),您可以在其中拥有动画的所有序列,并使用系统随着时间的推移重新计算图像的视口,从而创建动画。几乎所有游戏框架都支持。
"pacman 的开/闭嘴动画" 无论制作图形如何,我建议将它们拼接成 4 个动画(每个方向一个),将它们制作成GIF 并在运行时使用动画 GIF。
不理解这些反对意见。每个人都需要知道如何为吃豆人制作动画。
【参考方案1】:
类似的方法可能适用于 PacMan 图像。它使用基于 Java 2D 的 Shape
实例来表示表单,并使用 AffineTransform
来生成不同的方向。
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.io.*;
import javax.imageio.ImageIO;
class PacManShape
private double size;
private double rotation;
final int maxSize = 4;
static File home = new File(System.getProperty("user.home"));
static File images = new File(home, "images");
PacManShape(int size, double rotation)
this.size = size;
this.rotation = rotation;
public Area getPacManShape(double jaws)
Area area = new Area(new Ellipse2D.Double(0d, 0d, size, size));
double x1 = size / 2 + (2d * size * Math.cos(jaws / 2d));
double y1 = size / 2 + (2d * size * Math.sin(jaws / 2d));
double x2 = x1;
double y2 = size / 2 - (2d * size * Math.sin(jaws / 2d));
Polygon mouth = new Polygon();
mouth.addPoint((int) (size / 2), (int) (size / 2));
mouth.addPoint((int) x1, (int) y1);
mouth.addPoint((int) x2, (int) y2);
mouth.addPoint((int) (size / 2), (int) (size / 2));
area.subtract(new Area(mouth));
return area;
public BufferedImage getPacManImage(double angle, Color color)
BufferedImage bi = new BufferedImage(
(int) size, (int) size, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = bi.createGraphics();
g2.setColor(color);
g2.fillRect(0, 0, (int) size, (int) size);
AffineTransform rotate = AffineTransform.getRotateInstance(
rotation, size / 2, size / 2);
g2.setTransform(rotate);
Area pacMan = getPacManShape(angle);
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.YELLOW);
float[] dist = .15f, .9f;
Color[] colors = Color.YELLOW, Color.ORANGE;
Point2D center = new Point2D.Double(size / 2, size / 2);
RadialGradientPaint radial = new RadialGradientPaint(
center, (float) ((size / 2) - 2f), dist, colors);
g2.setPaint(radial);
g2.fill(pacMan);
GradientPaint gradient = new GradientPaint(
0, 0, new Color(255, 255, 225, 220),
(int) (size / 3), 0, new Color(255, 255, 255, 0));
g2.setPaint(gradient);
g2.fill(pacMan);
g2.dispose();
return bi;
public void savePacManImage(int q, int num) throws IOException
double angle = Math.PI*2 / 3d * ((double) num / (double) maxSize);
BufferedImage bi = getPacManImage(angle, Color.WHITE);
images.mkdirs();
File img = new File(images, "PacMan-" + q + "x" + num + ".gif");
ImageIO.write(bi, "gif", img);
public static void main(String[] args)
try
for (int ii = 0; ii < 4; ii++)
PacManShape pms = new PacManShape(100, (double) ii * Math.PI / 2d);
for (int jj = 0; jj <= pms.maxSize; jj++)
pms.savePacManImage(ii, jj);
Desktop.getDesktop().open(images);
catch (IOException ex)
ex.printStackTrace();
Runnable r = new Runnable()
@Override
public void run()
JPanel gui = new JPanel(new BorderLayout());
gui.add(new PacManComponent());
JOptionPane.showMessageDialog(null, gui);
;
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
class PacManComponent extends JPanel
double angle = 0d;
int preferredSize = 100;
double diff = Math.PI / 8;
boolean chomp = true;
Timer timer;
PacManComponent()
ActionListener listener = new ActionListener()
@Override
public void actionPerformed(ActionEvent e)
repaint();
;
timer = new Timer(180, listener);
timer.start();
@Override
public Dimension getPreferredSize()
return new Dimension(preferredSize, preferredSize);
@Override
public void paintComponent(Graphics g)
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
//double size = (getWidth() < getHeight() ? getWidth() : getHeight());
if (angle > 2 * Math.PI / 3)
chomp = true;
else if (angle < 0.01)
chomp = false;
if (chomp)
angle -= diff;
else
angle += diff;
PacManShape pms = new PacManShape(100, 0d);
Image image = pms.getPacManImage(angle, new Color(0, 0, 0, 0));
g2.drawImage(image, 0, 0, this);
g2.dispose();
如果您想在运行时转换和渲染图像,请尝试从这一系列使用部分透明度软化边缘的 PNG 格式图像开始。
【讨论】:
那么..这对你有用吗?也许你应该accept an answer。 在投票之前我没有详细研究这个。阅读chomp = false
时,我笑得合不拢嘴。无法真正解释原因。
@DavidWallace 很高兴我能给你带来欢乐。 :) 我这样做的通常方法是通过代码的 design (通常是“不存在”)。 ;)【参考方案2】:
对于动画,您可以使用 Swing Timer 来移动 Pacman 图形,并通过改变 fillArc
使用的参数来调整“嘴巴”张开的角度。
使用Key Bindings 可以实现与KeyEvents
的交互以进行运动控制。
另外,我会将paint
功能移动到子类JComponent
中的paintComponent
方法,以获得更好的绘制性能。
相关:Painting with Swing
编辑:
当您开始使用 Java 时,首先要完成许多任务
-
使用静态
Pacman
图形创建基于JComponent
的类。把你的绘画逻辑移到paintComponent
让 Swing Timer 功能正常工作。关注Oracle guide for Timers。
实施Key Bindings
其他功能,例如记分等。
【讨论】:
可能不需要任何JPanel
特定功能,所以我猜JComponent
应该没问题
感谢您的所有回答。我是编程初学者-> java。你能给我一些明确的例子吗?
@ScaryMary 您必须先学习许多步骤。我已经在我的更新中概述了这些。一次完成每一项任务。如果您有任何具体问题,请发布新问题。希望这会有所帮助。【参考方案3】:
二维动画: http://en.wikipedia.org/wiki/File:The_Horse_in_Motion.jpg
伪代码:
while programActive:
deltatime = get_time_since_last_call()
update_animation_frame(deltatime)
image = get_animation_frame()
draw_background()
draw(image)
enforce_framerate(24)
与 Java 相比,在 Pygame 中学习和做这类事情会很容易,但不适合大型项目
【讨论】:
以上是关于吃豆人开/合嘴动画的主要内容,如果未能解决你的问题,请参考以下文章