第一次使用论坛编写帮助,如果我发布这个全部错误,请对不起。我有几个以上的课程,我不认为screenManger或核心存在问题,但我只是包括它们。我通过一系列教程完成了大部分代码。但是某一点开始尝试自己做更多的事情。
我想在我移动精灵时播放动画。
在我的KeyTest类中,我使用线程来运行它曾经工作过的动画(很糟糕)但是现在根本没有它真的把我的计算机搞砸了。我认为这是因为线程。我刚接触线程,所以我不确定我是否应该在这种情况下使用它或者它对我的计算机是危险的。
当我在屏幕上永远留下精灵布料时,动画工作顺利。动画循环没有停止播放。我认为主要的问题是在animationThread,Sprite和keyTest类之间,但它可能更深入。
如果有人可以指出我正确的方向让动画顺利运行,当我按下一个键并停止运行时,我放松它将会非常适应。
我已经看过这个Java a moving animation (sprite)显然我们正在做相同的教程。但我觉得我的问题略有不同。
P.S。抱歉打字错误。
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;
}
}
答案 0 :(得分:0)
在animationThread类中,您正在访问“正在播放”字段。这应该使用synchronized块完成。 作为一个选项,在“播放”之前放置“synchronized”关键字。作为一个选项,在“播放”之前放置“volatile”关键字。
如果没有“同步”,一个线程可能看不到在另一个线程中完成“播放”的更改。所以线程可能会永远运行。 (仅限简短回答,因为我现在使用其中一种移动设备)
编辑:
使用“volatile”关键字“播放”字段,每次读取或写入其值时都会访问该字段。没有它,Thread可以使用它的副本,并且不会看到原始字段何时发生变化。
您可以使块“同步”:
boolean setRunning(boolean running) {
synchronized (this) {
this.playing = running;
}
}
您可以使方法“同步”:
synchronized boolean setRunning(boolean running) {
this.playing = running;
}
“synchronized”确保没有两个线程同时执行此代码,并确保线程看到“最新”对象。例如,如果一个线程更改“正在播放”字段,而另一个线程进入同步块,则该另一个线程将看到该字段的更改值。
答案 1 :(得分: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);
}
起初,恶意没有移动,因为速度在结束时被设置为零,但是如果我按住按钮足够长的精灵跳过屏幕。
这必须是问题,但是如何解决它
答案 2 :(得分: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();
}
}
new boolean停止执行多个键事件。我必须对它进行微调,但其他方面我很好。