创建可以连续更新变量的java方法

创建可以连续更新变量的java方法,java,swing,animation,Java,Swing,Animation,今年我在高中二年级时参加了AP计算机科学课程,我们主要学习循环、课程、方法、通用CS逻辑和一些数学知识。我错过了我最喜欢的编码,制作游戏。现在,我制作的每一款游戏都有某种方式来管理它,无论是使用visual basic中的计时器还是为我设置更新方法的c#XNA插件。问题是,在我的课程中,我还没有学会如何为java实现这一点。我已经读了一些关于线程和可运行的实现的书,但是我不确定我将如何使用它 第一类 import java.awt.FlowLayout; import javax

今年我在高中二年级时参加了AP计算机科学课程,我们主要学习循环、课程、方法、通用CS逻辑和一些数学知识。我错过了我最喜欢的编码,制作游戏。现在,我制作的每一款游戏都有某种方式来管理它,无论是使用visual basic中的计时器还是为我设置更新方法的c#XNA插件。问题是,在我的课程中,我还没有学会如何为java实现这一点。我已经读了一些关于线程和可运行的实现的书,但是我不确定我将如何使用它

第一类

    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,或者在代码中创建自己的图像(参见下面的简单示例)
  • 您的编译器应该向您抱怨您使用了不推荐的方法,例如
    bounds(…)
    ,更重要的是,您应该注意这些抱怨,因为它们是有原因的,并建议您使用它们时增加风险和危险。因此,不要使用这些方法,而是检查JavaAPI以寻找更好的替代方法
  • 这只是我个人的不满——请说明你至少读过我们的评论。没有人愿意付出努力和考虑去帮助别人,结果却被忽视了。因为这个原因,我几乎没有发布这个答案
例如:

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事件线程。我还重复了上面关于避免不推荐的方法的第二条评论(您还没有对它们发表评论)。