恐龙快跑不能显示恐龙且与障碍碰撞

问题遇到的现象和发生背景

0基础自学java中,尝试写一个Chrome断网时的恐龙快跑
运行后不能显示恐龙,恐龙不能与障碍碰撞

问题相关代码,请勿粘贴截图

https://pan.baidu.com/s/1QNXV2N_BdRs8ClS7afnGcQ?pwd=m7ty
提取码:m7ty

package com.mr.modle;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import com.mr.service.FreshThead;
import com.mr.window.*;

public class Dinosaur {
    private final int LOWEST_Y= 120;
    private final int JUMP_HIGHT=100;
    private final int FREASH=FreshThead.FREASH;
            
    
    public int x;
    public int y;
    public BufferedImage image;
    private BufferedImage image1;
    private BufferedImage image2;
    private BufferedImage image3;
    private int stepTimer =0;
    private boolean jumpState=false;
    private int jumpValue=0;
    

    public Dinosaur(){
        x=50;
        y=0;
        try {
            Image image1=ImageIO.read(new File("images/dino/恐龙1.png"));
            Image image2=ImageIO.read(new File("images/dino/恐龙2.png"));
            Image image3=ImageIO.read(new File("images/dino/恐龙3.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void step() {
        int tmp=stepTimer/100%3;
        switch (tmp) {
        case 1: {
            image=image1;
            break;
        }
        case 2: {
            image=image2;
            break;
        }
        default:{
            image=image3;
        }
        }
        stepTimer += FREASH;
    }
    public void jump() {
        if (!jumpState) {
        }
        jumpState=true;
    }
    public void move() {
        step();
        if (jumpState) {
            if(y>=LOWEST_Y) {
                jumpValue=-4;
            }
            if(y<=LOWEST_Y-JUMP_HIGHT) {
                jumpValue=4;
            }
            y+=jumpValue;
            if(y>=LOWEST_Y) {
                jumpState=false;
            }
        }
    }
    public Rectangle getFootBound() {
        return new Rectangle(x+30,y+59,29,18);
    }
    public Rectangle getHeadBound() {
        return new Rectangle(x+66,y+25,32,22);
    }
}
package com.mr.modle;

import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;

import com.mr.window.BackgroundImage;

public class Obstactle {
    public int x;
    public int y;
    public BufferedImage image;
    BufferedImage ob;
    private int speed;
    
    public Obstactle() {
        Random random = new Random();
        int r=random.nextInt(13);
        String ra=String.valueOf(r);
        String r1="images/ob/o"+ra+".png";
        try {
            image = ImageIO.read(new File(r1));
        } catch (IOException e) {
            e.printStackTrace();
        }
        x=1200;
        y=293-image.getHeight();
        speed= BackgroundImage.SPEED;
    }


    public void move() {
        x -=speed;
    }
    public boolean isLive() {
        if(x< (-image.getWidth())) {
            return false;
        }
        return true;
        
    }
    public Rectangle getBound() {
        return (new Rectangle(x,y,34,70));
    }
}
package com.mr.service;

import java.awt.Container;

import com.mr.window.MainPanel;
import com.mr.window.ScoreDialog;
import com.mr.window.Window;

public class FreshThead extends Thread{
    public static final int FREASH=20;
    MainPanel p;
    
    public FreshThead(MainPanel p) {
        this.p=p;
    }
    public void run() {
        while (!p.isFinish()) {
            p.repaint();
            try {
                Thread.sleep(FREASH);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
                Container container=p.getParent();
                while (!(container instanceof Window)) {
                    container= container.getParent();
                }
                Window frame=(Window) container;
                new ScoreDialog(frame);
                frame.restart();
    }
}
package com.mr.service;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;


public class ScoreRecorder {

    public static final String SOURE= "soure";
    public static int[] scores =new int[3];
    
    public static void init() {
        File file=new File(SOURE);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return;
        }
        FileInputStream fileInputStream=null;
        InputStreamReader inputStreamReader=null;
        BufferedReader bufferedReader =null;
        
        try {
            fileInputStream=new FileInputStream(file);
            inputStreamReader =new InputStreamReader(fileInputStream);
            bufferedReader =new BufferedReader(inputStreamReader);
            String valueString = bufferedReader.readLine();
            if (!(valueString==null||"".equals(valueString))) {
                String vs[]= valueString.split(",");
                if (vs.length<3) {
                    Arrays.fill(scores, 0);
                    
                }else {
                    for (int i=0;i<3;i++) {
                        scores[i]=Integer.parseInt(valueString);
                    }
                }
            }
            
        } catch (FileNotFoundException e) {
            // TODO: handle exception
                e.printStackTrace();
        }catch (IOException e) {
            // TODO: handle exception
            e.printStackTrace();
        }finally {
            try {
                bufferedReader.close();
            } catch (IOException e) {
                // TODO: handle exception
                e.printStackTrace();
            }
            try {
                inputStreamReader.close();
            } catch (IOException e2) {
                // TODO: handle exception
                e2.printStackTrace();
            }
            try {
                fileInputStream.close();
            } catch (IOException e2) {
                // TODO: handle exception
                e2.printStackTrace();
            }
        }
    }
    public static void saveScore() {
        String valueString = scores[0]+","+scores[1]+","+scores[2];
        FileOutputStream fileOutputStream=null;
        OutputStreamWriter outputStreamWriter=null;
        BufferedWriter bWriter =null;
        try {
            fileOutputStream =new FileOutputStream(SOURE);
            outputStreamWriter= new OutputStreamWriter(fileOutputStream);
            bWriter=new BufferedWriter(outputStreamWriter);
            bWriter.write(valueString);
            bWriter.flush();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }catch (IOException e) {
            // TODO: handle exception
            e.printStackTrace();
        }finally {
            try {
                bWriter.close();
            } catch (IOException e2) {
                // TODO: handle exception
                e2.printStackTrace();
            }try {
                outputStreamWriter.close();
            } catch (IOException e2) {
                // TODO: handle exception
                e2.printStackTrace();
            }try {
                fileOutputStream.close();
            } catch (IOException e2) {
                // TODO: handle exception
                e2.printStackTrace();
            }
        }    
    }
    public static void addNewScore(int score) {
        int[] tmp=Arrays.copyOf(scores, 4);
        tmp[3]=score;
        Arrays.sort(tmp);
        scores=Arrays.copyOfRange(tmp, 1, 4);
    }
    public static int[] getScores() {
        return scores;
    }
}
package com.mr.window;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class BackgroundImage {
    public BufferedImage image;
    private BufferedImage image1,image2;
    private Graphics2D graphics2d;
    public int x1,x2;
    public static final int SPEED=4;
    
    public BackgroundImage() {
        
        try {
            image2 =ImageIO.read(new File("images/ground/ground2.png"));
            image1 =ImageIO.read(new File("images/ground/ground2.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        image =new BufferedImage(1200,300, BufferedImage.TYPE_INT_RGB);
        graphics2d=image.createGraphics();
        x1=0;
        x2=1200;
        graphics2d.drawImage(image1, x1, 0,null);
        
    }
    public void roll() {
        x1-=SPEED;
        x2-=SPEED;
        if (x1<=-1200) {
            x1=1200;
        }
        if (x2<=-1200) {
            x2=1200;
    }
        
        graphics2d.drawImage(image1, x1,0, null);
        graphics2d.drawImage(image2, x2,0, null);
        
    }
}
package com.mr.window;


import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
import com.mr.modle.Dinosaur;
import com.mr.modle.Obstactle;
import com.mr.service.FreshThead;
import com.mr.service.ScoreRecorder;

public class MainPanel extends JPanel implements KeyListener{
    private BufferedImage image;
    private BackgroundImage bg;
    private Dinosaur dinosaur;
    private Graphics2D graphics2d;
    
    private int addObstactleTimer = 0; 
    private boolean finish = false;
    
    private final int FREASH = FreshThead.FREASH;
    private List<Obstactle> list = new ArrayList<Obstactle>();
    int score = 0;
    int scoreTimer= 0;
    
    
    public MainPanel() {
        image = new BufferedImage(1200,300,BufferedImage.TYPE_INT_BGR);
        graphics2d = image.createGraphics();
        dinosaur =new Dinosaur();
        bg = new BackgroundImage();
        list.add(new Obstactle());
        FreshThead t=new FreshThead(this);
        t.start();
    }
    
    private void paintImage() {
        bg.roll();
        dinosaur.move();

        graphics2d.drawImage(bg.image, 0,0,this);
    
            if (addObstactleTimer ==1300) {
                if (Math.random()*100>40) {
                    list.add(new Obstactle());
                }
                addObstactleTimer =0;
            }
            for (int i=0;i<list.size();i++) {
                Obstactle obstactle=list.get(i);
                if (obstactle.isLive()) {
                    obstactle.move();
                    graphics2d.drawImage(obstactle.image, obstactle.x,obstactle.y,this);
                        if (obstactle.getBound().intersects(dinosaur.getFootBound())||obstactle.getBound().intersects(dinosaur.getHeadBound())) {
                            gameOver();
                        }
                }else {
                    list.remove(i);
                    i--;
                }
            }
        
            if (scoreTimer>= 500) {
                score += 10;
                scoreTimer =0;
            }
        graphics2d.setColor(Color.BLACK);
        graphics2d.setFont(new Font("黑体",Font.BOLD,24));
        graphics2d.drawString(String.format("%06d",score), 1100, 30);
        graphics2d.drawImage(dinosaur.image,dinosaur.x,dinosaur.y,this);
        addObstactleTimer+=FREASH;
        scoreTimer+=FREASH;    
        setVisible(true);
    }
    public void paint(Graphics g) {
        paintImage();
        g.drawImage(image,0,0,this);        
    }
    public void gameOver() {
        ScoreRecorder.addNewScore(score);
        finish=true;
    }
    public boolean isFinish() {
        return finish;
    }
    public void keyPressed(KeyEvent e) {
        int code =e.getKeyCode();
        if (code==KeyEvent.VK_SPACE) {
            dinosaur.jump();
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // TODO Auto-generated method stub
        
    }
}
package com.mr.window;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import com.mr.service.ScoreRecorder;
public class ScoreDialog extends JDialog{
public  ScoreDialog(JFrame frame) {
    super(frame,true);
    int[] score=ScoreRecorder.getScores();
    JPanel scorePanel=new JPanel(new GridLayout(4, 1));
    scorePanel.setBackground(Color.WHITE);
    JLabel titleJLabel =new JLabel("得分排行", JLabel.CENTER);
    titleJLabel.setFont(new Font("黑体",Font.BOLD,20));
    titleJLabel.setForeground(Color.RED);
    JLabel first=new JLabel("第一名"+score[2],JLabel.CENTER);
    JLabel second=new JLabel("第二名"+score[1],JLabel.CENTER);
    JLabel third=new JLabel("第三名"+score[0],JLabel.CENTER);
    JButton restart= new JButton("重新开始");
    setVisible(true);
    restart.addActionListener(new ActionListener() {
        
        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO Auto-generated method stub
            dispose();
        }
    });
    
    scorePanel.add(titleJLabel);
    scorePanel.add(first);
    scorePanel.add(second);
    scorePanel.add(third);
    
    Container container=getContentPane();
    container.setLayout(new BorderLayout());
    container.add(scorePanel,BorderLayout.CENTER);
    container.add(restart,BorderLayout.SOUTH);
    
    setTitle("游戏结束");
    int width,height;
    width=height=200;
    int x= 300;//frame.getX()+(frame.getWidth()-width)/2;
    int y= 300;//frame.getY()+(frame.getHeight()-height)/2;
    setBounds(x,y,width,height);
    setVisible(true);
    }
}

package com.mr.window;

import java.awt.Color;
import java.awt.Container;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;

import com.mr.service.ScoreRecorder;

public class Window extends JFrame{
    
    
    public Window() {
        restart();
        setBounds(340,150,1200,350);
        setTitle("恐龙快跑");
        
        addListener();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
        setBackground(Color.WHITE);
    }
    public void restart() {
        Container container=getContentPane();
        container.setBackground(Color.WHITE);
        container.removeAll();
        MainPanel panel = new MainPanel();
        container.add(panel);
        addKeyListener(panel);
        container.validate();
    }
    private void addListener() {
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                ScoreRecorder.saveScore();
            }
        });
    }
}
import com.mr.window.Window;

public class Start {
    public static void main(String[] args) {
        Window window=new Window();
    }
}
运行结果及报错内容

运行后不能显示恐龙,恐龙不能与障碍碰撞
报错如下:

javax.imageio.IIOException: Can't read input file!
    at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1310)
    at com.mr.modle.Obstactle.<init>(Obstactle.java:26)
    at com.mr.window.MainPanel.paintImage(MainPanel.java:52)
    at com.mr.window.MainPanel.paint(MainPanel.java:83)
    at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5318)
    at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedFPScales(RepaintManager.java:1720)
    at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1629)
    at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1569)
    at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1336)
    at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5266)
    at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5076)
    at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:878)
    at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:861)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:861)
    at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:834)
    at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:784)
    at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1897)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot invoke "java.awt.image.BufferedImage.getHeight()" because "this.image" is null
    at com.mr.modle.Obstactle.<init>(Obstactle.java:31)
    at com.mr.window.MainPanel.paintImage(MainPanel.java:52)
    at com.mr.window.MainPanel.paint(MainPanel.java:83)
    at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5318)
    at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedFPScales(RepaintManager.java:1720)
    at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1629)
    at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1569)
    at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1336)
    at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5266)
    at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5076)
    at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:878)
    at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:861)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:861)
    at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:834)
    at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:784)
    at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1897)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
我的解答思路和尝试过的方法

我不到啊

我想要达到的结果

运行后能正常显示恐龙,恐龙能与障碍碰撞

看控制台有没有报错,直接发代码出来。