0

第一次使用论坛进行编码帮助,如果我把这一切都发错了,很抱歉。我有不止几个课程,我认为 screenManger 或 core 没有问题,但我将它们包括在内只是以防万一。我通过一组教程获得了大部分代码。但从某一点开始,我开始尝试自己做更多事情。

我只想在移动精灵时播放动画。

在我的 KeyTest 课程中,我正在使用线程来运行它曾经工作的动画(效果不佳),但现在一点也没有,它真的把我的电脑搞砸了。我认为这是因为线程。我是线程新手,所以我不确定我是否应该在这种情况下使用线程,或者它对我的计算机是否危险。

当我在屏幕上永远有精灵布斯时,动画效果很好。动画循环播放不停。

我认为主要问题在animationThread、Sprite 和keyTest 类之间,但它可能更深入。

如果有人可以为我指出正确的方向,以便在我按下键时使动画顺利运行并在我松开时停止运行,那将是非常重要的。

我已经看过这个 Java 一个移动动画(精灵),显然我们在做同样的教程。但我觉得我的问题略有不同。

ps 对错别字感到抱歉。

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.ImageIcon;

public class KeyTest extends Core implements KeyListener {

public static void main(String[] args){
    new KeyTest().run();
}

Sprite player1;
Image hobo;
Image background;
animation hoboRun;
animationThread t1;



//init also calls init form superclass
public void init(){
    super.init();
    loadImages();
    Window w = s.getFullScreenWindow();
    w.setFocusTraversalKeysEnabled(false);
    w.addKeyListener(this);
}

//load method will go here.
//load all pics need for animation and sprite
public void loadImages(){
    background = new ImageIcon("\\\\STUART-PC\\Users\\Stuart\\workspace\\Gaming\\yellow square.jpg").getImage();
    Image face1 = new ImageIcon("\\\\STUART-PC\\Users\\Stuart\\workspace\\Gaming\\circle.png").getImage();
    Image face2 = new ImageIcon("\\\\STUART-PC\\Users\\Stuart\\workspace\\Gaming\\one eye.png").getImage();
    hoboRun = new animation();
    hoboRun.addScene(face1, 250);
    hoboRun.addScene(face2, 250);
    player1 = new Sprite(hoboRun);
    t1 = new animationThread();
    t1.setAnimation(player1);
}


//key pressed
public void keyPressed(KeyEvent e){
    int keyCode = e.getKeyCode();
    if(keyCode == KeyEvent.VK_ESCAPE){
        stop();
    }
    if(keyCode == KeyEvent.VK_RIGHT){
        player1.setVelocityX(0.3f);
        try{
            t1.setRunning(true);
            Thread th1 = new Thread(t1);
            th1.start();
        }catch(Exception ex){System.out.println("noooo");}
    }
    if(keyCode == KeyEvent.VK_LEFT){
        player1.setVelocityX(-0.3f);
        try{
            t1.setRunning(true);
            Thread th1 = new Thread(t1);
            th1.start();
        }catch(Exception ex){System.out.println("noooo");}
    }
    if(keyCode == KeyEvent.VK_DOWN){
        player1.setVelocityY(0.3f);
        try{
            t1.setRunning(true);
            Thread th1 = new Thread(t1);
            th1.start();
        }catch(Exception ex){System.out.println("noooo");}
    }
    if(keyCode == KeyEvent.VK_UP){
        player1.setVelocityY(-0.3f);
        try{
            t1.setRunning(true);
            Thread th1 = new Thread(t1);;
            th1.start();
        }catch(Exception ex){System.out.println("noooo");}
    }else{
        e.consume();
    }
}

//keyReleased
@SuppressWarnings("static-access")
public void keyReleased(KeyEvent e){
    int keyCode = e.getKeyCode();
    if(keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_LEFT){
        player1.setVelocityX(0);
        try{
            this.t1.setRunning(false);
        }catch(Exception ex){}
    }
    if(keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN){
        player1.setVelocityY(0);
        try{
            this.t1.setRunning(false);
        }catch(Exception ex){}
    }else{
        e.consume();
    }
}

//last method from interface
public void keyTyped(KeyEvent e){
    e.consume();
}

//draw
public void draw(Graphics2D g){
    Window w = s.getFullScreenWindow();
    g.setColor(w.getBackground());
    g.fillRect(0, 0, s.getWidth(), s.getHieght());
    g.setColor(w.getForeground());
    g.drawImage(player1.getImage(), Math.round(player1.getX()), Math.round(player1.getY()), null);
}

public void update(long timePassed){
    player1.update(timePassed);
}
}


abstract class Core {

    private static DisplayMode modes[] = {
        new DisplayMode(1600, 900, 64, 0),
        new DisplayMode(800, 600, 32, 0),
        new DisplayMode(800, 600, 24, 0),
        new DisplayMode(800, 600, 16, 0),
        new DisplayMode(800, 480, 32, 0),
        new DisplayMode(800, 480, 24, 0),
        new DisplayMode(800, 480, 16, 0),};
    private boolean running;
    protected ScreenManager s;

    //stop method
    public void stop() {
        running = false;
    }

    public void run() {
        try {
            init();
            gameLoop();
        } finally {
            s.restoreScreen();
        }
    }

    //set to full screen
    //set current background here
    public void init() {
        s = new ScreenManager();
        DisplayMode dm = s.findFirstCompatibleMode(modes);
        s.setFullScreen(dm);

        Window w = s.getFullScreenWindow();
        w.setFont(new Font("Arial", Font.PLAIN, 20));
        w.setBackground(Color.GREEN);
        w.setForeground(Color.WHITE);
        running = true;
    }

    //main gameLoop
    public void gameLoop() {
        long startTime = System.currentTimeMillis();
        long cumTime = startTime;

        while (running) {
            long timePassed = System.currentTimeMillis() - cumTime;
            cumTime += timePassed;

            update(timePassed);

            Graphics2D g = s.getGraphics();
            draw(g);
            g.dispose();
            s.update();

            try {
                Thread.sleep(20);
            } catch (Exception ex) {
            }
        }
    }

    //update animation
    public void update(long timePassed) {
    }

    //draws to screen
    abstract void draw(Graphics2D g);
}


public class animationThread implements Runnable{

String name;
volatile boolean playing;
Sprite a;

//constructor takes input from keyboard
public animationThread(){
}

//The run method for animation
public void run() {
    long startTime = System.currentTimeMillis();
    long cumTime = startTime; 

    while(getRunning()){
        long timePassed = System.currentTimeMillis() - cumTime;
        cumTime += timePassed;
        a.startAnimation(timePassed);
    }
}

public String getName(){
    return name;
}

public void setAnimation(Sprite a){
    this.a=a;
}

public void setName(String name){
    this.name=name;
}

public synchronized void setRunning(boolean running){
    this.playing = running;
}

public synchronized boolean getRunning(){
    return playing;
}
}


class animation {

    private ArrayList scenes;
    private int sceneIndex;
    private long movieTime;
    private long totalTime;

    //constructor
    public animation() {
        scenes = new ArrayList();
        totalTime = 0;
        start();
    }

    //add scene to ArrayLisy and set time for each scene
    public synchronized void addScene(Image i, long t) {
        totalTime += t;
        scenes.add(new OneScene(i, totalTime));
    }

    public synchronized void start() {
        movieTime = 0;
        sceneIndex = 0;
    }

    //change scenes
    public synchronized void update(long timePassed) {
        if (scenes.size() > 1) {
            movieTime += timePassed;
            if (movieTime >= totalTime) {
                movieTime = 0;
                sceneIndex = 0;
            }
            while (movieTime > getScene(sceneIndex).endTime) {
                sceneIndex++;
            }
        }
    }

    //get animations current scene(aka image)
    public synchronized Image getImage() {
        if (scenes.size() == 0) {
            return null;
        } else {
            return getScene(sceneIndex).pic;
        }
    }

    //get scene
    private OneScene getScene(int x) {
        return (OneScene) scenes.get(x);
    }

    //Private Inner CLASS//////////////
    private class OneScene {

        Image pic;
        long endTime;

        public OneScene(Image pic, long endTime) {
            this.pic = pic;
            this.endTime = endTime;
        }
    }
}

class Sprite {

    private animation a;
    private float x;
    private float y;
    private float vx;
    private float vy;

    //Constructor
    public Sprite(animation a) {
        this.a = a;
    }

    //change position
    public void update(long timePassed) {
        x += vx * timePassed;
        y += vy * timePassed;
    }

    public void startAnimation(long timePassed) {
        a.update(timePassed);
    }

    //get x position
    public float getX() {
        return x;
    }

    //get y position
    public float getY() {
        return y;
    }

    //set x
    public void setX(float x) {
        this.x = x;
    }

    //set y
    public void setY(float y) {
        this.y = y;
    }

    //get sprite width
    public int getWidth() {
        return a.getImage().getWidth(null);
    }

    //get sprite height
    public int getHeight() {
        return a.getImage().getHeight(null);
    }

    //get horizontal velocity
    public float getVelocityX() {
        return vx;
    }

    //get vertical velocity
    public float getVelocityY() {
        return vx;
    }

    //set horizontal velocity
    public void setVelocityX(float vx) {
        this.vx = vx;
    }

    //set vertical velocity
    public void setVelocityY(float vy) {
        this.vy = vy;
    }

    //get sprite / image
    public Image getImage() {
        return a.getImage();
    }
}

class ScreenManager {

    private GraphicsDevice vc;

    public ScreenManager() {
        GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
        vc = e.getDefaultScreenDevice();
    }

    //get all compatible DM
    public DisplayMode[] getCompatibleDisplayModes() {
        return vc.getDisplayModes();
    }

    //compares DM passed into vc DM and see if they match
    public DisplayMode findFirstCompatibleMode(DisplayMode modes[]) {
        DisplayMode goodModes[] = vc.getDisplayModes();
        for (int x = 0; x < modes.length; x++) {
            for (int y = 0; y < goodModes.length; y++) {
                if (displayModesMatch(modes[x], goodModes[y])) {
                    return modes[x];
                }
            }
        }
        return null;
    }

    //get current DM
    public DisplayMode getCurrentDisplayMode() {
        return vc.getDisplayMode();
    }

    //checks if two modes match each other
    public boolean displayModesMatch(DisplayMode m1, DisplayMode m2) {
        if (m1.getWidth() != m2.getWidth() || m1.getHeight() != m2.getHeight()) {
            return false;
        }
        if (m1.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI && m2.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI && m1.getBitDepth() != m2.getBitDepth()) {
            return false;
        }
        if (m1.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN && m2.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN && m1.getRefreshRate() != m2.getRefreshRate()) {
            return false;
        }
        return true;
    }

    //make frame full screen
    public void setFullScreen(DisplayMode dm) {
        JFrame f = new JFrame();
        f.setUndecorated(true);
        f.setIgnoreRepaint(true);
        f.setResizable(false);
        vc.setFullScreenWindow(f);

        if (dm != null && vc.isDisplayChangeSupported()) {
            try {
                vc.setDisplayMode(dm);
            } catch (Exception ex) {
            }
        }
        f.createBufferStrategy(2);
    }

    //sets graphics object = this return
    public Graphics2D getGraphics() {
        Window w = vc.getFullScreenWindow();
        if (w != null) {
            BufferStrategy s = w.getBufferStrategy();
            return (Graphics2D) s.getDrawGraphics();
        } else {
            return null;
        }
    }

    //updates display
    public void update() {
        Window w = vc.getFullScreenWindow();
        if (w != null) {
            BufferStrategy s = w.getBufferStrategy();
            if (!s.contentsLost()) {
                s.show();
            }
        }
    }

    //returns full screen window
    public Window getFullScreenWindow() {
        return vc.getFullScreenWindow();
    }

    //get width of window
    public int getWidth() {
        Window w = vc.getFullScreenWindow();
        if (w != null) {
            return w.getWidth();
        } else {
            return 0;
        }
    }

    //get height of window
    public int getHieght() {
        Window w = vc.getFullScreenWindow();
        if (w != null) {
            return w.getHeight();
        } else {
            return 0;
        }
    }

    //get out of full screen
    public void restoreScreen() {
        Window w = vc.getFullScreenWindow();
        if (w != null) {
            w.dispose();
        }
        vc.setFullScreenWindow(null);
    }

    //create image compatible with monitor
    public BufferedImage createCopatibleImage(int w, int h, int t) {
        Window win = vc.getFullScreenWindow();
        if (win != null) {
            GraphicsConfiguration gc = win.getGraphicsConfiguration();
            return gc.createCompatibleImage(w, h, t);
        }
        return null;
    }
}
4

3 回答 3

0

In your animationThread class you are accessing the field "playing". This should be done using synchronized blocks. As one option put the "synchronized" keyword before "playing". As one option put the "volatile" keyword before "playing".

Without "synchronized" one thread may not see a change of "playing" done in another thread. So the threads may run forever. (short answer only, because I am on one of those fancy mobile devices now)

EDIT:

With the "volatile" keyword the "playing" field, the field is accessed each time its value is read or written. Without it, a Thread may use a copy of it and doesn't see when the original field has changed.

You can make blocks "synchronized":

boolean setRunning(boolean running) {
    synchronized (this) {
        this.playing = running;
    }
}

You can make methods "synchronized":

synchronized boolean setRunning(boolean running) {
    this.playing = running;
}

"synchronized" ensures, that no two threads execute this code at the same time and it makes sure that a thread sees an "up to date" object. For instance if one thread changes the "playing" field and when another thread enters a synchronized block, then that other thread will see the changed value of the field.

于 2012-07-01T21:12:59.993 回答
0

我刚刚发现了一些可能需要注意的新内容:当按住右键移动精灵并更新动画时,代码正在重新执行,我通过这样做发现了

public void keyPressed(KeyEvent e){
    int keyCode = e.getKeyCode();
    if(keyCode == KeyEvent.VK_ESCAPE){
        stop();
    }
    if(keyCode == KeyEvent.VK_RIGHT){
        player1.setVelocityX(0.3f);
        try{
            t1.setRunning(true);
            Thread th1 = new Thread(t1);
            th1.start();
        }catch(Exception ex){System.out.println("noooo");}
        player1.setVelocityX(0);
    }

起初,尽管速度在最后设置为零,但如果我按住按钮足够长的时间,精灵不会移动,精灵会跳过屏幕。

这一定是问题,但不知道如何解决它

于 2012-07-02T05:29:55.457 回答
0

嘿感谢所有帮助我刚刚解决了它。

public void keyPressed(KeyEvent e){
    if(godDamn){
        godDamn=false;
        int keyCode = e.getKeyCode();
        if(keyCode == KeyEvent.VK_ESCAPE){
            stop();
        }
        if(keyCode == KeyEvent.VK_RIGHT){
            player1.setVelocityX(0.3f);
            try{
                t1.setRunning(true);
                Thread th1 = new Thread(t1);
                th1.start();
            }catch(Exception ex){System.out.println("noooo");}
        }
        if(keyCode == KeyEvent.VK_LEFT){
            player1.setVelocityX(-0.3f);
            try{
                t1.setRunning(true);
                Thread th1 = new Thread(t1);
                th1.start();
            }catch(Exception ex){System.out.println("noooo");}
        }
        if(keyCode == KeyEvent.VK_DOWN){
            player1.setVelocityY(0.3f);
            try{
                t1.setRunning(true);
                Thread th1 = new Thread(t1);
                th1.start();
            }catch(Exception ex){System.out.println("noooo");}
        }
        if(keyCode == KeyEvent.VK_UP){
            player1.setVelocityY(-0.3f);
            try{
                t1.setRunning(true);
                Thread th1 = new Thread(t1);;
                th1.start();
            }catch(Exception ex){System.out.println("noooo");}
        }else{
            e.consume();
        }

    }
}

//keyReleased
@SuppressWarnings("static-access")
public void keyReleased(KeyEvent e){
    int keyCode = e.getKeyCode();
    if(keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_LEFT){
        player1.setVelocityX(0);
        try{
            this.t1.setRunning(false);
        }catch(Exception ex){}
        godDamn=true;
    }
    if(keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN){
        player1.setVelocityY(0);
        try{
            this.t1.setRunning(false);
        }catch(Exception ex){}
    }else{
        e.consume();
    }
}

新的布尔值停止执行多个键事件。我必须微调它,但其他方面我很好。

于 2012-07-02T06:12:37.137 回答