模拟太阳系项目

这个其实是之前看视频的时候老师教的一个项目,但是也敲了,但是只能看懂代码不能自己设计出来,并且还苦于没有找到图片素材也就没有继续下去了;
今天抽了一下时间;现在网上找一些图片然后利用之前学的那皮毛都不到的ps,p了一下图,虽然依旧没有那么好但是也够用了落;
先分析一下这个面向对象设计的代码的一些特性的展示;以及自己学会了什么;
1;利用建图片工具包,给这段代码带来很好的移值性,
2;充分利用继承,很好的减少了重复编写相同代码,并且很好的联系;
3;很好的扩展性,可以扩展到银河系,因为将太阳只是作为Star的一个对象;因此还可以创造其他对象来建立其他系别;plant可以即包括行星也包括卫星,因为设置了围绕旋转的星球这个可以改变的;
4;构造方法的创建;
5;方法的创建,使代码可读性更高;
先看一下运行结果,因为是动态的,我只截了3张图来表示;
这里写图片描述
这里写图片描述
这里写图片描述
再看一下分析思路吧,设计也差不多,只是要先宏观概括更好
关于其设计;
这里写图片描述
其程序的运行步骤就是;
先创建对象,然后画出;
这里分开,背景可直接画出,
太阳在Star类中draw画出;
行星在Plant类画出,并且因为存在继承关系并且它还有画出其椭圆轨迹以及移动,
最后在showFrame方法中不断开启线程到达图片移动的效果;
因为线程的不断开启就引入了双缓冲;
至于各自的构造方法就看自己了;
第一部分;在gameUtil包中;
1;Constant类,常量类,设置了窗口的长宽,方便后期修改,提高程序的健壮性和可

扩展性;

package gameUtil;

/**
 * 设置常量类,提高程序的健壮性;
 * @author Administrator
 *
 */
public class Constant {
    /**
     * 将窗口的长宽设置为常量,已供其他类使用,也便于修改;
     */
    public static final int WIGHT = 788;//窗口的宽度
    public static final int HIGTH = 610;//窗口的高度

}

2;GamepictureUtil类;图片加载类;得到图片路径将该图片变成image对象返回;

package gameUtil;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
/**
 * 这个有点点其他知识;
 * 通过这个类的static方法实现通过输入图片路径(scr中的路径)返回图片对象;
 * @author Administrator
 *
 */
public class GamePictureUtil {
        /**
         * 设置为私有构成方法,不允许对象创建;
         */
        private  GamePictureUtil() {

        }
        /**
         * 接收图片路径返回图片对象;
         * @param path
         * @return
         */
        public static Image getImages(String path){
            URL u = GamePictureUtil.class.getClassLoader

().getResource(path);
            BufferedImage img = null;
            try {
                img = ImageIO.read(u);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            return img;

        }
}

后期的使用就是例如
Image bg = GamePictureUtil.getImages(“路径(scr中的路径)”);
就将这个路径下的地址通过这个静态方法将图片变成Image对象返回;bg为这个对象的

引用;
3;MyFrame类;继承java.awt.Frame类;这个类就实现了窗口中一些基本的设置;
例如;设置窗口的大小,位置,是否可见,以及窗口是否可以关闭,这里因为后面要加

载图片因此还需要一个内部类来启动线程,不断重画窗口,来到达窗口是不消失的,因

为在不断重画;

package gameUtil;

import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;


/*
 * 显示窗口;
 */
public class MyFrame extends Frame{

    /**
     * 显示出现窗口
     * 线程实现,动态图片。
     */
    public void showFrame(){
        setSize(Constant.WIGHT,Constant.HIGTH);//设置窗口大小,以

Eclipse的左上角为原点、
        setLocation(100, 100);//设置坐标,这里的坐标也是左上角
        setVisible(true);//设置窗口可见,默认是不可见的

        new PaintThread().start();//启动线程,反复调用paint。

        addWindowListener(new WindowAdapter() {//实现窗口关闭内部public void windowClosing(WindowEvent e) {
                    System.exit(0);
            }
        });
    }

    /**
     * 定义一个重画窗口的内部类(线程实现);了解即可,懂得调用即可。
     * @author Administrator
     *
     */
    class PaintThread extends Thread{//通过线程,内部类

        public void run(){
            while(true){
                try {
                    repaint();
                    Thread.sleep(30);//1s等于100s,一

秒休息25次;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

4;为什么要创建一个gameUtil包,并且在里面添加这些类呢;
可移值性;因为这个包里面的类,基本上是实现游戏窗口时都需要的类因此单独成一个

包,下次则直接将这个包拷贝过去,就完成了。
第二部分;就要实现模拟太阳系的具体类了;
可分为;太阳和行星(卫星);
当然我们也是需要一个窗口类,类实现操作的。
现在分析;其实面向对象和面向过程一样,都是从main函数开始分析的;
在SolarFarame中main方法中创建了一个SolarFarame对象的时候,则此时就进行了画

图得一系列工作,再调用Frame中的showFrame方法,完成了窗口的显示,注意这里还不

断重启线程,这里就可以完成行星的移动了,只需改变其坐标即可,下次线程他就会自

动再次画出即显示在其他地方,具体的流程就是这样的;
至于Frame中的showFrame方法中,是比较简单的,就是完成一些最后窗口的显示;
细说一下创建对象时太阳系模型的显示吧?
关于其显示就是
先显示背景,就是先通过路径得到对象,引用指向之后再画出即可;
太阳,行星也是一样的,不同的是他们不同背景,他们创建了单独的类来通过构成方法

来设置参数,最后还是画出来;
大概的流程就是这样,至于细节就十分重要了,这也是体现面向对象多种好处的时候;
1;因为无论是背景还是太阳,还是行星我们都要将其画出显示在窗口上,因此我们可

以在SolarFarame类中创建一个专门显示图片的方法;paint

public void paint(Graphics g){
        g.drawImage(bg, 0, 0, null);
        sun.draw(g);
        earth.draw(g);
    }

因为太阳行星不同于背景,创建了独立的类,因此太阳和行星就调用自己的类来显示图

片,(还有一个原因是,他们要设置的参数都不同,因此单独成类创建方法画出也是很

好的;)
进一步分析显示太阳行星;
这里又有注意了,太阳和行星这间也存在相同的地方;
例如都是图片需要显示,只是行星多了需要画出运动轨迹,需要移动;
因此可以得出,行星可以继承太阳;
因此单独的对于画出图片,只需要太阳类中创建显示的方法即可;

Image img;
    double x,y;//坐标
    double width,higth;

    public void draw(Graphics g){
        g.drawImage(img, (int)x, (int)y, null);
    }
子类行星也可以这样画出,我们也看下行星是怎么画出的吧;
public void draw(Graphics g){
        super.draw(g);
        drawTrace(g);
        move();
    }

关于画出,它重写了父类的draw方法,因为行星还需要画出其运动轨迹,并且他还是移

动的,因此要不断在不同的位置显示,因此他需要重写;
接下来我们按着思路看他轨迹画出吧;椭圆的画出;
在awt中都提供了这些方法;
public abstract void drawOval(int x, int y, int width, int height);
我们所需要做的是,计算出他这些参数即可,坐标xy已经长轴短轴

public void drawTrace(Graphics g){
        double ovalX,ovalY,ovalWidth,ovalHeight;
        ovalWidth = longAxis*2;
        ovalHeight = shortAxis*2;
        ovalX = (center.x+center.width/2)-longAxis;
        ovalY = (center.y+center.higth/2)-shortAxis;

        Color c = g.getColor();
        g.setColor(Color.blue);
        g.drawOval((int)ovalX, (int)ovalY, (int)ovalWidth, (int)

ovalHeight);
        g.setColor(c);
    }

中间那个是设置颜色,注意设置颜色前要保存原颜色,之后要还原回去;注意;防止画

笔颜色出现混乱;
我们再看他的移动吧;按照其运动轨迹移动就ok了;关于行星的移动,前面也说了一点

,我们只需改变其图片的xy坐标即可,在下个线程的时候,再次画出的时候就可以表示

成移动了;

public void move(){
        x = center.x+center.width/2+longAxis*Math.cos(degree)-

img.getWidth(null)/2;
        y = center.y+center.higth/2+shortAxis*Math.sin(degree)-

img.getHeight(null)/2;

        degree += speed;//不需要再画出,在showFrame不断重启线程就可

以完成改变;
    }

关于太阳系模型的基本思路就几乎完成了,几乎,我们还缺少分享构造方法了。并且在

这里我们构造方法的设置应该是几乎接近源码那样吧?这个不多说自己看代码吧;
按照这个思路下来我们运行的结果应该是闪的,我们还少了一个东西,直接百度图片加

载时的双缓冲即可完成;因为都需要,这放到SolarFrame类即可;

Image ImageBuffer = null;  
    Graphics GraImage = null;  
    public void update(Graphics g){     //覆盖update方法,截取默认的调

用过程  
        ImageBuffer = createImage(this.getWidth(), this.getHeight()); 

  //创建图形缓冲区  
        GraImage = ImageBuffer.getGraphics();       //获取图形缓冲区的

图形 上下文  
        paint(GraImage);        //用paint方法中编写的绘图过程对图形缓冲

区绘图  
        GraImage.dispose();     //释放图形上下文资源  
        g.drawImage(ImageBuffer, 0, 0, this);   //将图形缓冲区绘制到屏

幕上  
    } 

贴一下所有代码吧;

package gameUtil;

/**
 * 设置常量类,提高程序的健壮性;
 * @author Administrator
 *
 */
public class Constant {
    /**
     * 将窗口的长宽设置为常量,已供其他类使用,也便于修改;
     */
    public static final int WIGHT = 788;//窗口的宽度
    public static final int HIGTH = 610;//窗口的高度

}
package gameUtil;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
/**
 * 这个有点点其他知识;
 * 通过这个类的static方法实现通过输入图片路径(scr中的路径)返回图片对象;
 * @author Administrator
 *
 */
public class GamePictureUtil {
        /**
         * 设置为私有构成方法,不允许对象创建;
         */
        private  GamePictureUtil() {

        }
        /**
         * 接收图片路径返回图片对象;
         * @param path
         * @return
         */
        public static Image getImages(String path){
            URL u = GamePictureUtil.class.getClassLoader().getResource(path);
            BufferedImage img = null;
            try {
                img = ImageIO.read(u);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            return img;

        }
}
package gameUtil;

import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;


/*
 * 显示窗口;
 */
public class MyFrame extends Frame{

    /**
     * 显示出现窗口
     * 线程实现,动态图片。
     */
    public void showFrame(){
        setSize(Constant.WIGHT,Constant.HIGTH);//设置窗口大小,以Eclipse的左上角为原点、
        setLocation(100, 100);//设置坐标,这里的坐标也是左上角
        setVisible(true);//设置窗口可见,默认是不可见的

        new PaintThread().start();//启动线程,反复调用paint。

        addWindowListener(new WindowAdapter() {//实现窗口关闭内部类
            public void windowClosing(WindowEvent e) {
                    System.exit(0);
            }
        });
    }

    /**
     * 定义一个重画窗口的内部类(线程实现);了解即可,懂得调用即可。
     * @author Administrator
     *
     */
    class PaintThread extends Thread{//通过线程,内部类

        public void run(){
            while(true){
                try {
                    repaint();
                    Thread.sleep(30);//1s等于100s,一秒休息25次;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

package solarFrame;

import java.awt.Graphics;
import java.awt.Image;

import gameUtil.Constant;
import gameUtil.GamePictureUtil;
import gameUtil.MyFrame;

public class SolarFrame extends MyFrame{
    Image bg  = GamePictureUtil.getImages("img/background1.png");
    Star sun = new Star("img/sun.jpg",Constant.WIGHT/2,Constant.HIGTH/2);
    Plant earth = new Plant("img/earth.jpg",300,200,0.01,sun);
    Plant mercury = new Plant("img/mercury.jpg",100,50,0.1,sun);
    Plant mras = new Plant("img/mras.jpg",150,100,0.05,sun);
    Plant moon = new Plant("img/moon.jpg",50,50,0.05,earth);

    Image ImageBuffer = null;  
    Graphics GraImage = null;  
    public void update(Graphics g){     //覆盖update方法,截取默认的调用过程  
        ImageBuffer = createImage(this.getWidth(), this.getHeight());   //创建图形缓冲区  
        GraImage = ImageBuffer.getGraphics();       //获取图形缓冲区的图形 上下文  
        paint(GraImage);        //用paint方法中编写的绘图过程对图形缓冲区绘图  
        GraImage.dispose();     //释放图形上下文资源  
        g.drawImage(ImageBuffer, 0, 0, this);   //将图形缓冲区绘制到屏幕上  
    } 

    public void paint(Graphics g){
        g.drawImage(bg, 0, 0, null);
        sun.draw(g);
        earth.draw(g);
        mercury.draw(g);
        mras.draw(g);
        moon.draw(g);
    }

    public static void main(String[] args) {
        new SolarFrame().showFrame();
    }

}
package solarFrame;

import java.awt.Graphics;
import java.awt.Image;

import gameUtil.GamePictureUtil;

public class Star {
    Image img;
    double x,y;//坐标
    double width,higth;

    public void draw(Graphics g){
        g.drawImage(img, (int)x, (int)y, null);
    }

    Star(){

    }
    Star(Image img){
        this.img = img;
        this.width = img.getWidth(null);
        this.higth = img.getHeight(null);
    }
    Star(Image img, double x, double y){
        this(img);
        this.x = x;
        this.y = y;

    }
    Star(String imgpath, double x, double y){
        this(GamePictureUtil.getImages(imgpath), x, y);
    }
}
package solarFrame;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.util.Arrays;

import gameUtil.GamePictureUtil;

public class Plant extends Star{

    double longAxis;
    double shortAxis;
    double degree;
    double speed;
    Star center;

    public void draw(Graphics g){
        super.draw(g);
        drawTrace(g);
        move();
    }

    public void drawTrace(Graphics g){
        double ovalX,ovalY,ovalWidth,ovalHeight;
        ovalWidth = longAxis*2;
        ovalHeight = shortAxis*2;
        ovalX = (center.x+center.width/2)-longAxis;
        ovalY = (center.y+center.higth/2)-shortAxis;

        Color c = g.getColor();
        g.setColor(Color.blue);
        g.drawOval((int)ovalX, (int)ovalY, (int)ovalWidth, (int)ovalHeight);
        g.setColor(c);
    }

    public void move(){
        x = center.x+center.width/2+longAxis*Math.cos(degree)-img.getWidth(null)/2;
        y = center.y+center.higth/2+shortAxis*Math.sin(degree)-img.getHeight(null)/2;

        degree += speed;//不需要再画出,在showFrame不断重启线程就可以完成改变;
    }

    public Plant(String imgpath, double longAxis, double shortAxis,double speed,
            Star center) {

        super(GamePictureUtil.getImages(imgpath));

        this.center = center;
        this.x = center.x+longAxis;
        this.y = center.y+shortAxis;
        this.img = GamePictureUtil.getImages(imgpath);

        this.longAxis = longAxis;
        this.shortAxis = shortAxis;
        this.speed = speed;
    }

    Plant(Image img, double x, double y) {
        super(img, x, y);
    }

    Plant(String imgpath, double x, double y){
        super(imgpath,x,y);
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值