您的位置:首页 > 编程语言 > Java开发

模拟太阳系项目

2016-12-22 17:53 381 查看
这个其实是之前看视频的时候老师教的一个项目,但是也敲了,但是只能看懂代码不能自己设计出来,并且还苦于没有找到图片素材也就没有继续下去了;

今天抽了一下时间;现在网上找一些图片然后利用之前学的那皮毛都不到的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);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息