Java Applet:球在抛物线轨迹上移动

时间:2014-06-04 13:57:59

标签: java applet

首先,我想说我对applets很新(我不打算开发任何,但我有一个学校项目来完成它们)。在发布我的代码之前,我有几个问题:

为什么applet窗口的坐标系如此混乱?我想它应该默认显示坐标系的第一个象限,这应该意味着(0,0)在左下角和(500,500)(如果这是窗口的大小)应该在上面右上角。但是,(0,0)位于左上角,而(500,500)位于右下角。为什么会这样,并且有一个简单的解决方法吗?

在我的代码中(其中一些是由老师提供的),有一个包含以下内容的try-catch块:

Thread.currentThread().sleep(40)

它在我尝试过的任何其他计算机上都能顺利运行。除非我将数字设置为100,否则球会在屏幕上保持闪烁和闪烁,而不是平稳地运行,当我将其设置为100时,它会开始非常缓慢地移动。

现在,我必须制作一个小动画,它可以在倒置的抛物线轨迹上移动一个球,其上升时半径增大,下降时半径减小。它应该在运行期间改变颜色。

这是我的代码:

import java.awt.*;
import java.applet.*;

public class Ball extends Applet implements Runnable 
{
    private static final long serialVersionUID = 1L;
    //double x, y, xInit, wide = 100, high = 400;
    //int dx, dy, diam, sizex, sizey;
    int wide = 100, high = 400;
    int xIncrement = 1;
    int xInit = (int)(-parabolaX (0, wide, high));
    int x = xInit;
    int y = (int)(parabolaY (x, wide, high));
    int diam, sizex, sizey;
    Thread ballPlay = new Thread(this);

    public void init() 
    {
        setBackground(Color.black);
        diam = 12;
        setSize(500, 500);
        sizex = 500;
        sizey = 500;
        ballPlay.start();
    }

public void run() 
{
    while (true) 
    {
        try  { Thread.currentThread().sleep(100); }
        catch (InterruptedException e) {};
        if ((x <= -xInit) && (y >= 0)) {
            x += xIncrement;
        } else {
            xInit = (int)(-parabolaX (0, wide, high));
            x = xInit;
        }
        repaint();
    }
}

//returns y-value of parabola
int parabolaY (int x, int wideness, int highness) {
  //equation of parabola
  int y = wideness*(x*x) + highness;

  return y;
}

//returns x-value of parabola
int parabolaX (int y, int wideness, int highness) {
  //equation of parabola
  int x = (int)Math.sqrt((y - highness)/wideness);

  return x;
}

 public void paint(Graphics g) 
   {    
        g.setColor(Color.red);
        System.out.println("PAINTING... X = " + x + " Y = " + y);
        g.fillArc(x, y, diam, diam, 0, 360);
        g.drawString(String.valueOf(x), 20, sizey-40);
        g.drawString(String.valueOf(y), 20, sizey-20);
   }
}

目前,它根本不起作用。通过多种方式调整它,我已经成功地将球放在其初始位置(100,400),但没有任何动作发生。前几天我发现了这个网 - http://www.openprocessing.org/sketch/25434这正是我所需要的(没有半径和颜色变化的部分),但我仍然无法弄明白。显然,有些东西(或很可能很多东西)我做错了但几乎不知道applet是如何工作的,我似乎无法找到问题。代码是我老师提供的一些代码和网页上的代码的混搭。

我想做的是让球的动画在倒置的抛物线轨迹上移动,起始位置(100,400)。完成抛物线后,它应该返回到其初始位置并继续循环动画。但是,使用当前的代码,它甚至不能像我需要的那样接近工作。

1 个答案:

答案 0 :(得分:0)

  

但是,(0,0)位于左上角,而(500,500)位于右下角。为什么会这样,并且有一个简单的解决方法吗?

如果您考虑到它,那么在顶部有0,0是有意义的,当您调整它们时,所有现代GUI窗口都会向上和向左缩小。但是如果你在右下方有0,0点,那么编写数学代码就会非常困难,看看左边和顶部有多少空间,你应该用多少空间填充它们以使它们居中那种事。

  

除非我将数字设置为100,否则球会在屏幕上保持闪烁和闪烁,而不是平稳地运行,而当我将其设置为100时,它会开始非常缓慢地移动。

这是因为您的计算机可能没有其他计算机那么强大,因为您的计算机在下一个渲染想要进入之前没有足够快地渲染图形,或类似的东西。如果Applet的绘画方法是双重缓冲的,那么你就不会遇到这个问题。

关于速度,每次执行睡眠都会睡眠40毫秒,所以你可以想到你的应用程序运行在1000毫秒除以每个睡眠的那么多毫秒,所以100,你正在运行大约每秒更新一次。现在与游戏中的大多数动画不同,您的应用程序的移动是基于刻度的,这意味着您的图形在每次更新时移动超过一定数量的像素,因此一秒钟内更新越少,图形移动越少(更好的方法是根据自上次更新以来经过的时间更新图形的位置。

因此,为了摆脱闪烁,你必须缓冲你的绘图。升级您的课程以从JApplet而不是Applet延伸将是一个良好的开端。之后,创建另一个扩展JPanel的类,并将所有逻辑移到那里,并在applet类中覆盖paintComponent(Graphics)而不是paint(Graphics)。你仍然应该使用applet类(现在是一个JApplet),但是你应该在那里添加自定义JPanel类的子组件。您将使用的这种新的绘画方法是双缓冲的,可以消除闪烁。

// This code may not be exactly what you need but here's the general idea
public class Ball extends JApplet
{
    public void init() 
    {
        this.add(new MyCustomGraphicsPanel());
    }
}

public class MyCustomGraphicsPanel extends JPanel implements Runnable {
    private static final long serialVersionUID = 1L;
    //double x, y, xInit, wide = 100, high = 400;
    //int dx, dy, diam, sizex, sizey;
    double wide = 100, high = 400;
    int xIncrement = 1;
    double xInit = -parabolaX (0, wide, high);
    double x = xInit;
    double y;
    int diam, sizex, sizey;
    Thread ballPlay = new Thread(this);

    // Move init code into the constructor
    public MyCustomGraphicsComponent()
    {
        setBackground(Color.black);
        y = parabolaY (x, wide, high);
        diam = 12;
        setSize(500, 500);
        sizex = 500;
        sizey = 500;
        ballPlay.start();
    }

    public void run() 
    {
        while (true) 
        {
            try  { Thread.currentThread().sleep(100); }
            catch (InterruptedException e) {};
            if ((x <= -xInit) && (y >= 0)) {
                x += xIncrement;
            } else {
                xInit = -parabolaX (0, wide, high);
                x = xInit;
            }
            repaint();
        }
    }
}