洗澡的时候突发奇想,2D游戏里像素是比较简单的绘画风格,但是经常除了人物外,还有一堆乱七八糟的方块比如泥土啊,墙壁啊之类的方块,这些方块如果手画,不仅不具备随机性,而且画起来也很繁琐。因此想到,能不能写一个像素方块的生成器,来生成简单的泥土,墙壁之类像素图,从而减少美工的负担呢。于是就有这篇博客了,先写一下整体思路,然后再写具体的实现。


前言:本文前部分是本人的开发流程,基本以时间顺序描述开发过程,后半部分附有效果图和程序源码,前半部分可直接跳过。部分代码受本人能力限制,显得多余累赘,别吐槽谢谢。

 

程序介绍:本程序使用java编写,是一个像素方块的生成器,可用来生成像素面,同时具有扩展性,可通过编写代码扩展本程序功能。

 

正文

       
这是一个简单的软件,首先使用java搭配天下第一swing框架开发,图形界面大概分为绘画区和参数区,绘画区负责生成图像,和提供预览功能,参数区顾名思义即输入各项参数。初步界面设计如下。



此部分的部分代码如下
public void CreateJFrame() { //声明jf窗口,设置属性 JFrame jf=new JFrame();
setLayout(null); Container c=jf.getContentPane(); JPanel DrawArea=new
JPanel(null); DrawArea.setBounds(5,0,800,600);
DrawArea.setBorder(BorderFactory.createTitledBorder("绘画区")); JPanel
PramArea=new JPanel(null); PramArea.setBounds(810,0,200,600);
PramArea.setBorder(BorderFactory.createTitledBorder("参数区")); add(DrawArea);
add(PramArea); setBounds(0,0,1040,650); setTitle("Pixel Generator::CSDN
Blog:Zhidai_"); setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); }
 

        接下来,分两部分,一是绘画区,一是参数区,两部分分开实现后再合成一体。这里先分析参数区的需求。

       
参数区需要输入参数,同时将参数传输给绘画区,因此需要一个文本框实现输入功能,一个保存按钮,保存目前输入的参数,一个清空按钮,清空目前填入的参数。输入的参数大概包括,图片大小(width,length),像素大小(pixelsize),基本颜色(R,G,B),图片存放位置,新图片名称,随机数种子。(同时基本颜色提供一个取色器,随机数种子可输入或不输入)

        后期还要排版,先用流布局随便排一下大概的顺序。代码就不贴了,简单的复制黏贴而已。



        然后还需要获取到输入框输入的数据。写个监听事件,监听鼠标点击按钮的时候,保存下当前时刻的参数。emm也很简单的东西,代码如下
JB_SavePramButton.addActionListener(new ActionListener() { @Override public
void actionPerformed(ActionEvent e) { String temp; temp=JF_width.getText();
imageWidth=StringToInt(temp); temp=JF_length.getText();
imageLength=StringToInt(temp); temp=JF_pixelsize.getText();
pixelSize=StringToInt(temp); temp=JF_color_R.getText();
color_R=StringToInt(temp); temp=JF_color_G.getText();
color_G=StringToInt(temp); temp=JF_color_B.getText();
color_B=StringToInt(temp); temp=JF_RandomNumber.getText();
randomNumber=StringToInt(temp); } });
        清空参数也是一样的,简单的代码,如下。
JB_ClearPramButton.addActionListener(new ActionListener() { @Override public
void actionPerformed(ActionEvent e) { JF_width.setText("");
JF_length.setText(""); JF_pixelsize.setText(""); JF_color_B.setText("");
JF_color_G.setText(""); JF_color_R.setText(""); JF_RandomNumber.setText(""); }
});
        到此,参数区基本上框架搭好了。

        在我试图分析绘画区的需求的时候,发现了一个严重
的问题,就是一开始绘画区是固定的,我本来希望可以在右边参数区改完立刻预览到成品,但是如果图片过大的时候可能会有问题,就是图片超出了边界,这个时候就不能很好的预览了。因此我视图通过两个窗口来解决这个问题,打开程序后,首先是参数区,填好参数之后,点击生成图片,会打开另一个窗口,展示的就是绘画区的内容,这样设计可以灵活的调整窗口的大小,但是不利于查看。

调整后的窗口发生了较大的改变,主要缩小了参数区的大小,改善了数据结构,重新写了一个类来控制绘画区的生成,同时绘画区也可以动态生成多个,方便对比。



同时将原本窗口的关闭属性修改了,这样原先关闭一个会把参数区的也关了,现在不会发生这种问题。
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
为绘画区加了个菜单栏,进行保存操作,可预见的参数区的图片名次和地址可能也会改成弹窗保存了。
public void createJFrame(Parameter para) { JFrame jf=new JFrame();
setLayout(null); Container c=jf.getContentPane(); JMenuBar JMB_menuBar=new
JMenuBar(); JMenu M_operation=new JMenu("操作"); JMenuItem MI_save=new
JMenuItem("保存图片"); M_operation.add(MI_save); JMB_menuBar.add(M_operation);
setJMenuBar(JMB_menuBar);
setBounds(200,200,para.imageWidth+50,para.imageLength+50); setTitle("Pixel
Generator::CSDN Blog:Zhidai_"); setVisible(true);
setDefaultCloseOperation(DISPOSE_ON_CLOSE); }

接下来是绘画区的绘图功能,在参数里加了一块调色板,本来还以为需要自己写,后来发现awt里有JColorChooser这个东西,而且封装的相当好,一行代码就可以解决,当然如果要更好的调色板可以自己编写,不过目前这个已经可以满足需求了。下面放修改后的参数区和绘画区。
para.color=JColorChooser.showDialog(jf,"调色板",para.color);
这个showDialog返回的是个Color类,因此声明一个Color来获取到调色板选择的颜色,三个参数分别是:父窗口,窗口标题,默认颜色 

 



接下来是写本工具的核心功能,也就是生成像素图。

像素图的生成先确定一种基本颜色,然后在基本颜色上面random出其他相近的颜色,然后组合起来变成像素图。因此需要一个随机算法来生成。
Random random=new Random(para.randomNumber); int
widcnt=para.imageWidth/para.pixelSize; int
lengcnt=para.imageLength/para.pixelSize; Color color_t; for(int
i=0;i<widcnt;i++) { for(int j=0;j<lengcnt;j++) { int color_r,color_g,color_b;
int offset=para.offset;
color_r=Math.max(Math.min(para.color_R+(random.nextInt()%offset-offset/2),255),0);
color_g=Math.max(Math.min(para.color_G+(random.nextInt()%offset-offset/2),255),0);
color_b=Math.max(Math.min(para.color_B+(random.nextInt()%offset-offset/2),255),0);
color_t=new Color(color_r,color_g,color_b); g2.setColor(color_t);
g2.fillRect(i*para.pixelSize,j*para.pixelSize,para.pixelSize,para.pixelSize); }
}

随机像素生成算法,用一个偏移量,在基本颜色上进行偏移,同时保证偏移后的数值满足RGB的要求,即属于[0,255],之后进行绘画,计算好位置和大小之后就可以画了。一个简单的随机算法。以下是不同偏移量的效果图。



 

程序到这里基本完成,剩下都是修饰工作。

总结:本博客主要是用java
swing编写一个像素方块生成器的过程,通过简单的搭建分为两个窗口,一个是参数,一个是绘画,在参数窗口写好参数后生成绘画窗口,绘画窗口是像素的预览模式,点击保存按钮可以保存图片到指定路径。下面会放本程序效果图和完整代码。

提醒:

像素大小应是图片宽度长度的公约数;

RGB可通过调色板获取;

偏移量为像素与基本颜色的偏移量,偏移量越大,像素颜色越偏离基本颜色;

随机数种子可填可不填;

图片保存地址为地址+图片命名+格式,如F:/a.jpg为保存在F盘根目录下文件名为a,格式是jpg的图片文件。


参数限制:

图片大小:整数,是像素大小的公倍数

RGB与偏移量:整数,[0,255],大于等于0,小于等于255。

随机数种子:整数

效果图如下:



 
import java.awt.*; import java.awt.event.ActionEvent; import
java.awt.event.ActionListener; import java.awt.event.MouseEvent; import
java.awt.event.MouseListener; import java.awt.image.BufferedImage; import
java.io.FileOutputStream; import java.io.IOException; import java.util.Random;
import javax.imageio.ImageIO; import javax.swing.*; public class Main { public
static class Parameter{ int imageWidth; int imageLength; int pixelSize; Color
color=new Color(0,0,0); int color_R; int color_G; int color_B; int offset; int
randomNumber; String imageFormat; String imageLocal; } public static class
createMenu extends JFrame implements MouseListener{ public Parameter para=new
Parameter(); public void CreateJFrame() { //声明jf窗口,设置属性 JFrame jf=new JFrame();
setLayout(null); Container c=jf.getContentPane(); JPanel PramArea=new
JPanel(new FlowLayout(FlowLayout.LEFT,0,0)); JPanel JP_ImageProperties=new
JPanel(new FlowLayout(FlowLayout.CENTER,10,10)); JPanel JP_ColorProperties=new
JPanel(new FlowLayout(FlowLayout.LEFT,10,10)); JPanel JP_SaveProperties=new
JPanel(new FlowLayout(FlowLayout.LEFT,10,10)); JPanel JP_Others=new JPanel(new
FlowLayout(FlowLayout.LEFT,10,10)); PramArea.setBounds(0,0,475,250);
PramArea.setBorder(BorderFactory.createTitledBorder("参数区")); JLabel
JL_width=new JLabel("图片宽度:"); JLabel JL_length=new JLabel("图片长度:"); JLabel
JL_pixelsize=new JLabel("像素大小:"); JLabel JL_color_R=new JLabel("R:"); JLabel
JL_color_G=new JLabel("G:"); JLabel JL_color_B=new JLabel("B:"); JLabel
JL_offset=new JLabel("偏移量:"); JLabel JL_ImageLocal=new JLabel("图片保存地址:");
JLabel JL_ImageFormat=new JLabel("图片格式:"); JLabel JL_RandomNumber=new
JLabel("随机数种子:"); //JCB_ImageFormat.addItem("你想要添加的格式"); 可按照右边的格式来添加其他图片格式
JComboBox JCB_ImageFormat=new JComboBox(); JCB_ImageFormat.addItem("png");
JCB_ImageFormat.addItem("jpg"); JCB_ImageFormat.addItem("bmp"); JTextField
JF_width=new JTextField(); JF_width.setText("800"); JF_width.setColumns(5);
JTextField JF_length=new JTextField(); JF_length.setText("600");
JF_length.setColumns(5); JTextField JF_pixelsize=new JTextField();
JF_pixelsize.setText("10"); JF_pixelsize.setColumns(5); JTextField
JF_color_R=new JTextField(); JF_color_R.setText("192");
JF_color_R.setColumns(3); JTextField JF_color_G=new JTextField();
JF_color_G.setText("192"); JF_color_G.setColumns(3); JTextField JF_color_B=new
JTextField(); JF_color_B.setText("192"); JF_color_B.setColumns(3); JTextField
JF_offset=new JTextField(); JF_offset.setText("10"); JF_offset.setColumns(3);
JTextField JF_ImageLocal=new JTextField(); JF_ImageLocal.setText("F:/a.jpg");
JF_ImageLocal.setColumns(10); JTextField JF_RandomNumber=new JTextField();
JF_RandomNumber.setText("1"); JF_RandomNumber.setColumns(3); JButton
JB_ClearPramButton=new JButton("清空参数");
JB_ClearPramButton.addActionListener(new ActionListener() { @Override public
void actionPerformed(ActionEvent e) { JF_width.setText("");
JF_length.setText(""); JF_pixelsize.setText(""); JF_color_B.setText("");
JF_color_G.setText(""); JF_color_R.setText(""); JF_RandomNumber.setText(""); }
}); JButton JB_CreateImageButton=new JButton("生成图片");
JB_CreateImageButton.addActionListener(new ActionListener() { @Override public
void actionPerformed(ActionEvent e) { String temp; temp=JF_length.getText();
para.imageLength=StringToInt(temp); temp=JF_width.getText();
para.imageWidth=StringToInt(temp); temp=JF_pixelsize.getText();
para.pixelSize=StringToInt(temp); temp=JF_color_R.getText();
para.color_R=StringToInt(temp); temp=JF_color_G.getText();
para.color_G=StringToInt(temp); temp=JF_color_B.getText();
para.color_B=StringToInt(temp); temp=JF_offset.getText();
para.offset=StringToInt(temp); para.imageFormat=
String.valueOf(JCB_ImageFormat.getSelectedItem());
para.imageLocal=JF_ImageLocal.getText(); para.color=new
Color(para.color_R,para.color_G,para.color_B); temp=JF_RandomNumber.getText();
para.randomNumber=StringToInt(temp); new createDrawWindow().createJFrame(para);
} }); JButton JB_GetColorButton=new JButton("调色板");
JB_GetColorButton.addActionListener(new ActionListener() { @Override public
void actionPerformed(ActionEvent e) {
para.color=JColorChooser.showDialog(jf,"调色板",para.color);
JF_color_R.setText(String.valueOf(para.color.getRed()));
JF_color_G.setText(String.valueOf(para.color.getGreen()));
JF_color_B.setText(String.valueOf(para.color.getBlue()));
para.color_R=para.color.getRed(); para.color_G=para.color.getGreen();
para.color_B=para.color.getBlue(); } }); JP_ImageProperties.add(JL_width);
JP_ImageProperties.add(JF_width); JP_ImageProperties.add(JL_length);
JP_ImageProperties.add(JF_length); JP_ImageProperties.add(JL_pixelsize);
JP_ImageProperties.add(JF_pixelsize); PramArea.add(JP_ImageProperties);
JP_ColorProperties.add(JL_color_R); JP_ColorProperties.add(JF_color_R);
JP_ColorProperties.add(JL_color_G); JP_ColorProperties.add(JF_color_G);
JP_ColorProperties.add(JL_color_B); JP_ColorProperties.add(JF_color_B);
JP_ColorProperties.add(JB_GetColorButton); JP_ColorProperties.add(JL_offset);
JP_ColorProperties.add(JF_offset); PramArea.add(JP_ColorProperties);
JP_SaveProperties.add(JL_ImageFormat); JP_SaveProperties.add(JCB_ImageFormat);
JP_SaveProperties.add(JL_ImageLocal); JP_SaveProperties.add(JF_ImageLocal);
PramArea.add(JP_SaveProperties); JP_Others.add(JL_RandomNumber);
JP_Others.add(JF_RandomNumber); JP_Others.add(JB_ClearPramButton);
JP_Others.add(JB_CreateImageButton); PramArea.add(JP_Others); add(PramArea);
setBounds(0,0,500,300); setTitle("Pixel Generator::CSDN Blog:Zhidai_");
setVisible(true); setDefaultCloseOperation(DISPOSE_ON_CLOSE); } //String转int
public int StringToInt(String t) { int n=0; for(int i=0;i<t.length();i++) {
n=n*10+t.charAt(i)-'0'; } return n; } @Override public void
mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent e)
{ } @Override public void mouseReleased(MouseEvent e) { } @Override public void
mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e)
{ } } public static class createDrawWindow extends JFrame implements
MouseListener { Parameter para; BufferedImage bi; public void
createJFrame(Parameter para_t) { para=para_t; JFrame jf=new JFrame();
setLayout(null); Container c=jf.getContentPane(); JButton SaveButton=new
JButton("<html>保存图片<br>"); SaveButton.setBounds(0,0,90,26);
SaveButton.addActionListener(new ActionListener() { @Override public void
actionPerformed(ActionEvent e) { try { ImageIO.write(bi,para.imageFormat,new
FileOutputStream(para.imageLocal)); } catch (IOException e1) {
e1.printStackTrace(); } } }); add(SaveButton);
setBounds(200,200,para.imageWidth+50,para.imageLength+100); setTitle("Pixel
Generator::CSDN Blog:Zhidai_"); setVisible(true);
setDefaultCloseOperation(DISPOSE_ON_CLOSE); } @Override public void
paint(Graphics g) { super.paint(g); bi=new
BufferedImage(para.imageWidth,para.imageLength,BufferedImage.TYPE_INT_RGB);
Graphics2D g2=(Graphics2D) bi.getGraphics(); //
-------------------------------------------- Random random=new
Random(para.randomNumber); int widcnt=para.imageWidth/para.pixelSize; int
lengcnt=para.imageLength/para.pixelSize; Color color_t; for(int
i=0;i<widcnt;i++) { for(int j=0;j<lengcnt;j++) { int color_r,color_g,color_b;
int offset=para.offset;
color_r=Math.max(Math.min(para.color_R+(random.nextInt()%offset-offset/2),255),0);
color_g=Math.max(Math.min(para.color_G+(random.nextInt()%offset-offset/2),255),0);
color_b=Math.max(Math.min(para.color_B+(random.nextInt()%offset-offset/2),255),0);
color_t=new Color(color_r,color_g,color_b); g2.setColor(color_t);
g2.fillRect(i*para.pixelSize,j*para.pixelSize,para.pixelSize,para.pixelSize); }
} // -------------------------------------------- g.drawImage(bi,30,60,this); }
@Override public void mouseClicked(MouseEvent e) { } @Override public void
mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent
e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public
void mouseExited(MouseEvent e) { } } public static void main(String[] args) {
new createMenu().CreateJFrame(); } }
 

 

 

 

 

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信