0

初めてコーディングヘルプのフォーラムを使用したので、これをすべて間違って投稿した場合は申し訳ありません。screenMangerまたはcoreが問題を抱えているとは思わないクラスがいくつかありますが、念のためにそれらを含めました。このコードのほとんどは、一連のチュートリアルを通じて機能しました。しかし、ある時点で、自分でもっと多くのことをしようとし始めました。

スプライトを動かしているときだけアニメーションを再生したい。

私のKeyTestクラスでは、スレッドを使用して、以前は機能していたアニメーションを(不十分に)実行していますが、今ではまったくプラスになりません。糸のせいだと思います。スレッドは初めてなので、この状況でスレッドを使用する必要があるのか​​、それともコンピューターにとって危険なのかはわかりません。

画面の周りにスプライトブーセを永遠に置いたとき、アニメーションはスムーズに機能しました。アニメーションループは停止せずに再生されました。

主な問題は、animationThread、Sprite、およびkeyTestクラスの間にあると思いますが、もっと深くなる可能性があります。

キーを押したときにアニメーションをスムーズに実行し、離したときに実行を停止するために、誰かが私を正しい方向に向けることができれば、それは非常に魅力的です。

私はすでにこの Javaの動くアニメーション(スプライト)を見ましたが、明らかに同じチュートリアルを行っていました。しかし、私の問題は少し違うと感じています。

タイプミスでごめんなさい。

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

右のキーを押したままスプライトを移動してアニメーションを更新すると、コードが再実行されていることがわかりました。これを実行すると、注意が必要になる可能性があります。

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);
    }

最初は速度が最後にゼロに設定されているため、スプライトは移動しませんが、バテンを十分長く保持すると、スプライトが画面を飛び越えます。

これは問題である必要がありますが、それを修正する方法をidk

于 2012-07-02T05:29:55.457 に答える
0

animationThread クラスでは、「再生中」フィールドにアクセスしています。これは、同期ブロックを使用して行う必要があります。1 つのオプションとして、「再生」の前に「同期」キーワードを置きます。1 つのオプションとして、「playing」の前に「volatile」キーワードを置きます。

「同期」がないと、あるスレッドは別のスレッドで行われた「再生」の変更を認識しない場合があります。したがって、スレッドは永遠に実行される可能性があります。(私は今、これらの派手なモバイルデバイスの1つを使用しているため、簡単な回答のみ)

編集:

「volatile」キーワードを使用すると、「playing」フィールドの値が読み書きされるたびにフィールドにアクセスされます。それがないと、スレッドはそのコピーを使用する可能性があり、元のフィールドが変更されたときに認識されません。

ブロックを「同期」させることができます:

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

メソッドを「同期」させることができます。

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

「同期」は、2 つのスレッドがこのコードを同時に実行しないことを保証し、スレッドが「最新の」オブジェクトを認識できるようにします。たとえば、あるスレッドが「playing」フィールドを変更し、別のスレッドが同期ブロックに入ると、その別のスレッドはフィールドの変更された値を確認します。

于 2012-07-01T21:12:59.993 に答える
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 に答える