利用递归实现山脉效果,填充山脉以及山脉颜色渐变
递归山脉要求:
- 初始定义两个点AB
- 取AB的中点P,让中点的Y坐标在[-range,range]范围内随机取值,得到P点
- 要求每次迭代后range按比例rate缩小
- 分别取AP和PB,重复上述过程
- 递归结束,连线
—————————————————————————————————————
public void mountain(Graphics g,int x1,int y1,int x2,int y2,int range,double rate){//定义山脉方法
if(Math.abs(x2-x1)<20){ //迭代退出条件
g.drawLine(x1,y1,x2,y2); //※【迭代结束,连接当前两个点】
}else{
int x = (int)((x1+x2)/2); //P点横坐标
int y = (int)((y1+y2)/2); //P点线性纵坐标
int Rnumber = (int)(Math.random()*(2*range)-range); //从-range到range随机取值
int Nrange = (int)(range*rate); //每次迭代改变range的范围
mountain(g,x1,y1,x,y+Rnumber,Nrange,rate);
mountain(g,x,y+Rnumber,x2,y2,Nrange,rate);
}
mountain(gr,0,500,1000,500,200,0.5);
效果如下:
如何填充山脉呢?要用到fillPolygon方法,我们来看下该方法的描述:
public void fillPolygon(Polygon p)
作用是填充一个多边形,需要指定 Polygon 对象定义这个多边形。
需要用到的方法是addPoint(int x;int y);
作用是将指定的坐标追加到此 Polygon对象。
public void mountain(Graphics g,int x1,int y1,int x2,int y2,int range,double rate){
if(Math.abs(x2-x1)<20){
g.drawLine(x1,y1,x2,y2); //在连线操作结束后填充
Polygon p = new Polygon(); //创建一个Polygon()类的对象,调用addPoint方法
p.addPoint(x1, y1);
p.addPoint(x1,1000);
p.addPoint(x2, 1000);
p.addPoint(x2, y2); //这里注意坐标的追加要逆时针
g.fillPolygon(p); //填充,g是画笔对象
}else{
int x = (int)((x1+x2)/2);
int y = (int)((y1+y2)/2);
int Rnumber = (int)(Math.random()*(2*range)-range);
int Nrange = (int)(range*rate);
mountain(g,x1,y1,x,y+Rnumber,Nrange,rate);
mountain(g,x,y+Rnumber,x2,y2,Nrange,rate);
}
效果如下
由于此时还没有定义颜色,所以填充是纯黑效果
下一步我们要实现山脉的渐变,有两种方式,一是每次画完一个山脉后改变RGB的值,二是每次画完一个山脉后改变透明度A的值,我们分别试下
- 改变R、G、B三值
public void mouseClicked(MouseEvent e) { //点击方法
if ("递归山脉".equals(type)){
Color c = new Color(r,g,b); //r,g,b我定义在全局变量,初始值均为20
gr.setColor(c); //给画笔设置颜色
mountain(gr,0,500,1000,500,200,0.5);
r+=20; //迭代结束后改变r,g,b的值
g+=20;
b+=20;
}
效果如下
这种效果本质上还是纯色填充,会重叠覆盖,于是我们可以去修改透明度的值
public void mouseClicked(MouseEvent e) { //点击方法
if("递归山脉".equals(type)){
Color c = new Color(r,g,b,a); //r、g、b、a均定义在全局变量,初值均为0。r、g、b三值为0时是纯黑,a为0时全透明,为255时不透明
gr.setColor(c);
mountain(gr,0,500,1000,500,200,0.5);
a+=30;
}
效果如下
是不是有透视的感觉?
但是还有一个问题,第二种方法(改变透明度的操作)的响应速度比较慢,往往是鼠标点击后几秒,才开始“慢悠悠”绘制山脉与填充,而且填充过程也是逐渐的,像动画一样。
如何解决呢?java缓存!!!
介绍一个简易的缓存
BufferedImage类是一个带缓冲区图像类,主要作用是将一幅图片加载到内存中(BufferedImage生成的图片在内存里有一个图像缓冲区,利用这个缓冲区我们可以很方便地操作这个图片),原理是系统在尚未执行画的操作/代码前,已经把图像画在缓冲区,随时调用。
步骤:
- 创建一个BufferedImage对象
- 获取缓冲区的画笔
- 将实现画图的代码中的原画笔对象改为缓冲区画笔
- 用原画笔对象调用drawImage方法
if("递归山脉".equals(type)){
BufferedImage buffImage = new BufferedImage(1000,1000,BufferedImage.TYPE_INT_ARGB); //创建BufferedImage对象,前两个参数为窗体大小
Graphics buffG = buffImage.getGraphics(); //获取缓冲区画笔对象
Color c = new Color(r,g,b,a);
buffG.setColor(c); //将原画笔对象改为缓冲区画笔
mountain(buffG,0,500,1000,500,200,0.5); //将实现画图的代码中的原画笔对象改为缓冲区画笔
a+=30;
gr.drawImage(buffImage, 0, 0,null); //用原画笔画出缓冲区图片,中间两个int值代表画图的起始点
}
效果就不展示了,确实可以瞬间画出图片。