创建可以连续更新变量的java方法
今年我在高中二年级时参加了AP计算机科学课程,我们主要学习循环、课程、方法、通用CS逻辑和一些数学知识。我错过了我最喜欢的编码,制作游戏。现在,我制作的每一款游戏都有某种方式来管理它,无论是使用visual basic中的计时器还是为我设置更新方法的c#XNA插件。问题是,在我的课程中,我还没有学会如何为java实现这一点。我已经读了一些关于线程和可运行的实现的书,但是我不确定我将如何使用它 第一类创建可以连续更新变量的java方法,java,swing,animation,Java,Swing,Animation,今年我在高中二年级时参加了AP计算机科学课程,我们主要学习循环、课程、方法、通用CS逻辑和一些数学知识。我错过了我最喜欢的编码,制作游戏。现在,我制作的每一款游戏都有某种方式来管理它,无论是使用visual basic中的计时器还是为我设置更新方法的c#XNA插件。问题是,在我的课程中,我还没有学会如何为java实现这一点。我已经读了一些关于线程和可运行的实现的书,但是我不确定我将如何使用它 第一类 import java.awt.FlowLayout; import javax
import java.awt.FlowLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class GFXScreen extends JFrame
{
/**
* @param screenHeigth
* @param screenHeigth
* @param The file name of the image. Make sure to include the extension type also
* @param The title at the top of the running screen
* @param The height of the screen
* @param The width of the screen
*/
public GFXScreen(String fileName, String screenTitle, int screenHeight, int screenWidth)
{
setLayout(new FlowLayout());
image1 = new ImageIcon(getClass().getResource(fileName));
label1 = new JLabel(image1);
this.add(label1);
//Set up JFrame
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
this.setTitle(screenTitle);
this.setSize(screenWidth, screenHeight);
}
/**
* @param desired amount to move picture
*/
public void updatePic(int increment)
{
//update pos
label1.setBounds(label1.bounds().x, label1.bounds().y - increment,
label1.bounds().width, label1.bounds().height);
}
private ImageIcon image1;
private JLabel label1;
}
第二类
public class MainClass implements Runnable {
public static void main(String[] args)
{
(new Thread(new MainClass())).start();
GFXScreen gfx = new GFXScreen("pixel_man.png", "pixel_Man", 1000, 1000);
}
public void run()
{
gfx.updatePic(1);
}
}
在这个例子中,我想要的是,我想要一张从顶部开始的图片,慢慢地向下平滑地移动到底部。我该怎么做呢?我一直使用的是一个无限循环,每次迭代都会调用一个更新方法,在这个方法中,您可以执行更新游戏状态或呈现GUI所需的任何操作 范例
public static void main(String[] args){
// Initialise game
while(true){
updateGame();
}
}
public static void updateGame(){
// Update things here.
}
我还要做的是创建一个名为IUpdateListener
的接口,这个接口稍微复杂一点,并且有特定的类专门用于游戏的特定元素。例如,我有一个InputListener
,一个AIListener
,每个都处理游戏更新的特定元素
public interface IUpdateListener{
public void update();
}
public class Main{
public static ArrayList<IUpdateListener> listeners = new ArrayList<IUpdateListener>();
public static void main(String[] args){
listeners.add(new InputListener());
while(true){
for(IUpdateListener listener : listeners){
listener.update();
}
}
}
}
public class InputListener implements IUpdateListener{
public void update(){
// Handle user input here etc
}
}
公共接口IUpdateListener{
公共无效更新();
}
公共班机{
公共静态ArrayList侦听器=新建ArrayList();
公共静态void main(字符串[]args){
add(newInputListener());
while(true){
for(IUpdateListener侦听器:侦听器){
update();
}
}
}
}
公共类InputListener实现IUpdateListener{
公共无效更新(){
//在此处处理用户输入等
}
}
建议:
- 同样,a也适用于简单的挥杆动画或简单的游戏循环。它可能不是复杂或严格的tame循环的最佳选择,因为它的计时不精确
- 大多数游戏循环都不是绝对精确的时间片
- 所以你的游戏模型应该考虑到这一点,应该注意绝对时间片,并在物理引擎或动画中使用这些信息
- 如果必须使用后台线程,请注意,大多数Swing调用都是在Swing事件线程上进行的。否则将导致有害的、不频繁的、难以调试的程序结束异常。欲了解更多详情,请阅读
- 我避免使用空布局,除非在设置组件动画时使用,因为这将允许我的动画引擎完全放置组件
- 在这里发布代码供我们测试时,最好避免使用本地图像的代码。让代码使用所有人都可以轻松获得的图像作为URL,或者在代码中创建自己的图像(参见下面的简单示例)
- 您的编译器应该向您抱怨您使用了不推荐的方法,例如
,更重要的是,您应该注意这些抱怨,因为它们是有原因的,并建议您使用它们时增加风险和危险。因此,不要使用这些方法,而是检查JavaAPI以寻找更好的替代方法bounds(…)
- 这只是我个人的不满——请说明你至少读过我们的评论。没有人愿意付出努力和考虑去帮助别人,结果却被忽视了。因为这个原因,我几乎没有发布这个答案
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
@SuppressWarnings("serial")
public class GfxPanel extends JPanel {
private static final int BI_WIDTH = 26;
private static final int BI_HEIGHT = BI_WIDTH;
private static final int GAP = 6;
private static final Point INITIAL_LOCATION = new Point(0, 0);
private static final int TIMER_DELAY = 40;
public static final int STEP = 1;
private ImageIcon image1;
private JLabel label1;
private Point labelLocation = INITIAL_LOCATION;
private int prefW;
private int prefH;
private Timer timer;
public GfxPanel(int width, int height) {
// the only time I use null layouts is for component animation.
setLayout(null);
this.prefW = width;
this.prefH = height;
// My program creates its image so you can run it without an image file
image1 = new ImageIcon(createMyImage());
label1 = new JLabel(image1);
label1.setSize(label1.getPreferredSize());
label1.setLocation(labelLocation);
this.add(label1);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(prefW, prefH);
}
public void startAnimation() {
if (timer != null && timer.isRunning()) {
timer.stop();
}
labelLocation = INITIAL_LOCATION;
timer = new Timer(TIMER_DELAY, new TimerListener());
timer.start();
}
// My program creates its image so you can run it without an image file
private Image createMyImage() {
BufferedImage bi = new BufferedImage(BI_WIDTH, BI_HEIGHT,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = bi.createGraphics();
g2.setColor(Color.red);
g2.fillRect(0, 0, BI_WIDTH, BI_HEIGHT);
g2.setColor(Color.blue);
int x = GAP;
int y = x;
int width = BI_WIDTH - 2 * GAP;
int height = BI_HEIGHT - 2 * GAP;
g2.fillRect(x, y, width, height);
g2.dispose();
return bi;
}
private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
int x = labelLocation.x + STEP;
int y = labelLocation.y + STEP;
labelLocation = new Point(x, y);
label1.setLocation(labelLocation);
repaint();
if (x + BI_WIDTH > getWidth() || y + BI_HEIGHT > getHeight()) {
System.out.println("Stopping Timer");
((Timer) e.getSource()).stop();
}
}
}
private static void createAndShowGui() {
final GfxPanel gfxPanel = new GfxPanel(900, 750);
JButton button = new JButton(new AbstractAction("Animate") {
@Override
public void actionPerformed(ActionEvent arg0) {
gfxPanel.startAnimation();
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(button);
JFrame frame = new JFrame("GFXScreen");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(gfxPanel);
frame.getContentPane().add(buttonPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Swing计时器可以很好地解决这个问题。此外,编译器应该向您抱怨使用了不推荐的方法,更重要的是,您应该注意这些抱怨。不要使用那些方法,而是检查Java API以寻找更好的替代方法。我刚刚学习了无限循环,我的老师告诉我们的一件事是避免它们,因为它们会导致逻辑错误!我现在明白了这是多么有用。我没有意识到这一点,因为在过去的语言中,我使用的这些inf循环甚至不会被编译,但现在,当循环在1中执行x次时,您将如何做呢sec@JGerulskis您必须将变量设置为
System.getTimeMillis()
,检查for
循环使用了多少时间,并使用Thread.sleep()
等待必要的时间。@JGerulskis:上述代码不承担Swing线程职责。再次,考虑使用Swing定时器,或者如果在后台线程中使用自己的游戏循环,则必须注意将所有Swing调用排队到Swing事件线程。我还重复了上面关于避免不推荐的方法的第二条评论(您还没有对它们发表评论)。