Swing实现五子棋

来源:互联网 发布:淘宝详情上传 编辑:程序博客网 时间:2024/06/07 02:02

根据http://blog.csdn.net/cnlht/article/details/8176130衍生。增加了悔棋只可毁一次。

五子棋运行界面


一、先设计棋子类

棋子类要包括下的位置和棋子的颜色,即x、y坐标与Color。另外,还要设置好棋子的大小,即直径。

import java.awt.Color;public class Point {private int x;private int y;private Color color;public static final int DIAMETER = 30; //直径public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public Color getColor() {return color;}public void setColor(Color color) {this.color = color;}public Point(int x, int y, Color color) {this.x = x;this.y = y;this.color = color;}}

二、设计棋盘类

继承自JPanel,接口MouseListener来监听鼠标事件。

JPanel 是 Java图形用户界面(GUI)工具包swing中的面板容器类,包含在javax.swing 包中,是一种轻量级容器,可以加入到JFrame窗体中。JPanel默认的布局管理器是FlowLayout((从左到右诸行排列)),其自身可以嵌套组合,在不同子容器中可包含其他组件(component),如JButton、JTextArea、JTextField 等,功能是对对窗体上的这些控件进行组合。

1、全局变量

public static final int MARGIN = 20;  //边距public static final int GRID_SPAN = 35;  //网络间隔public static final int ROWS = 15;  //棋盘行数public static final int COLS = 15;  //棋盘列数public static final Color DEFAULT_COLOR = Color.RED;  //无悔棋默认为红色private Point[] chessList = new Point[(ROWS + 1) * (COLS + 1)];  //初始化每个数组元素为nullprivate boolean isBlack = true;  //默认执黑先行private boolean gameOver = false;  //游戏是否结束private Color regretColor= DEFAULT_COLOR;  //悔棋时候的棋子色,无悔棋默认为红色private int chessCount;  //当前棋盘棋子的个数private int xIndex, yIndex;  //当前落子的索引



2、构造函数

public ChessBoard() {setBackground(Color.orange);  //设置背景色为桔黄色addMouseListener(this);addMouseMotionListener(new MouseMotionListener() {@Overridepublic void mouseDragged(MouseEvent e) {}@Overridepublic void mouseMoved(MouseEvent e) {//将鼠标点击的坐标转成网络索引int x1 = (e.getX() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;int y1 = (e.getY() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;//游戏结束不能下;落在棋盘外不能下;位置上已有棋子不能下if (x1 < 0 || x1 > ROWS || y1 < 0 || y1 > COLS || gameOver ||findChess(x1, y1)) {setCursor(new Cursor(Cursor.DEFAULT_CURSOR));  //光标为默认的指针} else {setCursor(new Cursor(Cursor.HAND_CURSOR));  //光标为手掌}}});}


3、绘制棋盘与棋子paintComponent

super.paintComponent(g)是父类JPanel里的方法,会把整个面板用背景色重画一遍,起到清屏的作用。在swing控件中,paint方法会依次调用paintcomponent, paintborder, paintchildren三个方法,后两者一般默认即可,所以swing编程时,如果继承jcomponent或者其子类,要覆盖paintcomponent而不是paint方法。

paint :绘制容器。 
paintComponents : 绘制此容器中的每个组件。 
由此不难看出,二者就是房子与家具的关系。

 在java里设置组件的属性后会导致重绘,只不过由于这个重绘事件被放在事件派发线程里,因此随后调用的堵塞动作会导致事件派发线程被Idle,要避免这种情况,应该将这个堵塞动作放到另外的线程里面完成。 
repaint()是触发重绘动作,当调用repaint()后,会通知repaintManager增加一个重绘区域,repaintManager在一定条件下会合并一些重绘区域,然后派发一个绘制动作到事件派发线程(EventQueue)。事件派发线程执行到这个绘制事件时,就会调用组件的paint(),在paint()方法里会先调用update来将重绘区域清空(默认情况下是填充白色),然后再调用paintcomponent()来绘制自身,最后调用paintChildren来绘制所有的子。具体流程可以参考JComponent里的paint()方法

如果super,会先调用了super.paintComponent进行界面重绘,再继续绘制自写函数里的东西。如果不调用父类的方法,则直接用重写函数里的内容进行重绘。

/** * 绘制 */public void paintComponent(Graphics graphics) {super.paintComponent(graphics);  //画棋盘/*//获得窗口的宽度与高度int FWidth = getWidth();int FHeight = getHeight();*///画网格线for (int i = 0;i <= ROWS; i++) {graphics.drawLine(MARGIN, MARGIN + i * GRID_SPAN, MARGIN + COLS * GRID_SPAN, MARGIN + i * GRID_SPAN);}for (int j = 0;j <= COLS; j++) {graphics.drawLine(MARGIN + j * GRID_SPAN, MARGIN, MARGIN + j * GRID_SPAN, MARGIN + ROWS * GRID_SPAN);}//画棋子for (int i = 0;i < chessCount; i++) {//网格交叉点坐标int xPos = (int) (chessList[i].getX() * GRID_SPAN + MARGIN);int yPos = (int) (chessList[i].getY() * GRID_SPAN + MARGIN);Color colorTemp = chessList[i].getColor();graphics.setColor(colorTemp);  //设置颜色RadialGradientPaint paint;if (colorTemp == Color.black) {//前两个参数为圆心,第三个为半径paint = new RadialGradientPaint(xPos-Point.DIAMETER / 2 + 25,yPos - Point.DIAMETER / 2 + 10, 20, new float[]{0f, 1f},new Color[]{Color.WHITE, Color.BLACK});} else {paint = new RadialGradientPaint(xPos-Point.DIAMETER / 2 + 25,yPos - Point.DIAMETER / 2 + 10, 70, new float[]{0f, 1f},new Color[]{Color.WHITE, Color.BLACK});}((Graphics2D) graphics).setPaint(paint);((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);Ellipse2D ellipse = new Ellipse2D.Float(xPos - Point.DIAMETER / 2,yPos - Point.DIAMETER / 2, 34, 35);((Graphics2D) graphics).fill(ellipse);//标记最后一个棋子的红矩形框if (i == chessCount - 1) {graphics.setColor(Color.red);graphics.drawRect(xPos - Point.DIAMETER / 2, yPos - Point.DIAMETER / 2, 34, 35);}}}


4、下棋时的逻辑操作

@Overridepublic void mousePressed(MouseEvent e) {//游戏结束时,不能再下if (gameOver) {return ;}String colorName = isBlack ? "黑棋" : "白棋";//将鼠标点击的坐标位置转换成网络索引xIndex = (e.getX() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;yIndex = (e.getY() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;//若落在棋盘外或位置上以后棋子,不能下if (xIndex < 0 || xIndex > ROWS || yIndex < 0 || yIndex > COLS || findChess(xIndex, yIndex)){return ;}//可下时的处理Point chess = new Point(xIndex, yIndex, isBlack ? Color.BLACK : Color.WHITE);chessList[chessCount ++] = chess;repaint();  //通知系统重绘//如果为毁过棋,则标记为可悔棋if(chess.getColor() != regretColor) {regretColor = DEFAULT_COLOR;}//如果胜出则给出提示,不能继续下棋if (isWin()) {String msg = String.format("恭喜,%s赢了!", colorName);JOptionPane.showMessageDialog(this, msg);gameOver = true;}isBlack = !isBlack;}


5、清除棋子

public void restartGame() {//清除棋子for (int i = 0;i < chessList.length; i++) {chessList[i] = null;}//恢复游戏相关的变量值isBlack = true;gameOver = false;  //游戏重新开始chessCount = 0;  //当前棋盘棋子个数repaint();}

</pre><pre>
6、悔棋

</pre><pre>
/** * 悔棋 */public void goback() {if (chessCount == 0) {return ;}//只有当前下棋那个人下完后可以悔棋一次if (regretColor != DEFAULT_COLOR) {return ;}regretColor = isBlack ? Color.BLACK : Color.WHITE;chessList[chessCount -1] = null;chessCount --;if (chessCount > 0) {xIndex = chessList[chessCount - 1].getX();yIndex = chessList[chessCount - 1].getY();}isBlack = !isBlack;repaint();}

三、五子棋主框架StartChessJFrame类

1、全局控件变量

private ChessBoard chessBoard;private JPanel toolbar;private JButton startButton, exitButton, backButton;private JMenuBar menuBar;private JMenu sysMenu;private JMenuItem startMenuItem, exitMenuItem, backMenuItem;

</pre><pre>
2、初始化控件

public StartChessJFrame() {setTitle("单机版五子棋");chessBoard = new ChessBoard();initComponents();}private void initComponents() {Container contentPane = getContentPane();contentPane.add(chessBoard);chessBoard.setOpaque(true);//创建和添加菜单menuBar = new JMenuBar();  //初始化菜单栏sysMenu = new JMenu("系统");  //初始化菜单//初始化菜单项startMenuItem = new JMenuItem("重新开始");exitMenuItem = new JMenuItem("退出");backMenuItem = new JMenuItem("悔棋");//将三个菜单项添加到菜单上sysMenu.add(startMenuItem);sysMenu.add(exitMenuItem);sysMenu.add(backMenuItem);//初始化按钮事件监听器内部类MyItemListener listener = new MyItemListener();//将三个菜单注册到事件监听器上this.startMenuItem.addActionListener(listener);backMenuItem.addActionListener(listener);exitMenuItem.addActionListener(listener);menuBar.add(sysMenu);  //将系统菜单添加到菜单栏上setJMenuBar(menuBar);  //将menuBar设置为菜单栏toolbar = new JPanel();  //工具面板实例化//三个按钮初始化startButton = new JButton("重新开始");exitButton = new JButton("退出");backButton = new JButton("悔棋");//将工具面板按钮用FlowLayout布局toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));//将三个按钮添加到工具面板toolbar.add(startButton);toolbar.add(exitButton);toolbar.add(backButton);//将三个按钮注册监听事件startButton.addActionListener(listener);exitButton.addActionListener(listener);backButton.addActionListener(listener);//将工具面板布局到界面下方add(toolbar, BorderLayout.SOUTH);//将面板对象添加到窗体上add(chessBoard);//设置界面关闭事件setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//自适应大小pack();}

</pre><pre>
3、点击Item的事件监听

private class MyItemListener implements ActionListener {@Overridepublic void actionPerformed(ActionEvent e) {//获得事件源Object obj = e.getSource();if (obj == StartChessJFrame.this.startMenuItem || obj == startButton) {//重新开始//JFiveFrame.this内部类引用外部类System.out.println("重新开始");chessBoard.restartGame();} else if (obj == exitMenuItem || obj == exitButton) {System.exit(0);} else if (obj == backMenuItem || obj == backButton) {System.out.println("悔棋");chessBoard.goback();}}}


4、创建

public static void main(String args[]) {StartChessJFrame frame = new StartChessJFrame();  //创建主框架frame.setVisible(true);}


完整代码:

棋子类

import java.awt.Color;public class Point {private int x;private int y;private Color color;public static final int DIAMETER = 30; //直径public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public Color getColor() {return color;}public void setColor(Color color) {this.color = color;}public Point(int x, int y, Color color) {this.x = x;this.y = y;this.color = color;}}

棋盘类

import java.awt.Color;import java.awt.Cursor;import java.awt.Dimension;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Image;import java.awt.RadialGradientPaint;import java.awt.RenderingHints;import java.awt.Toolkit;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.awt.event.MouseMotionListener;import java.awt.geom.Ellipse2D;import javax.swing.JOptionPane;import javax.swing.JPanel;/** * 五子棋棋盘 * @author shenjingyi * */public class ChessBoard extends JPanel implements MouseListener {public static final int MARGIN = 20;  //边距public static final int GRID_SPAN = 35;  //网络间隔public static final int ROWS = 15;  //棋盘行数public static final int COLS = 15;  //棋盘列数public static final Color DEFAULT_COLOR = Color.RED;  //无悔棋默认为红色private Point[] chessList = new Point[(ROWS + 1) * (COLS + 1)];  //初始化每个数组元素为nullprivate boolean isBlack = true;  //默认执黑先行private boolean gameOver = false;  //游戏是否结束private Color regretColor= DEFAULT_COLOR;  //悔棋时候的棋子色,无悔棋默认为红色private int chessCount;  //当前棋盘棋子的个数private int xIndex, yIndex;  //当前落子的索引public ChessBoard() {setBackground(Color.orange);  //设置背景色为桔黄色addMouseListener(this);addMouseMotionListener(new MouseMotionListener() {@Overridepublic void mouseDragged(MouseEvent e) {}@Overridepublic void mouseMoved(MouseEvent e) {//将鼠标点击的坐标转成网络索引int x1 = (e.getX() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;int y1 = (e.getY() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;//游戏结束不能下;落在棋盘外不能下;位置上已有棋子不能下if (x1 < 0 || x1 > ROWS || y1 < 0 || y1 > COLS || gameOver ||findChess(x1, y1)) {setCursor(new Cursor(Cursor.DEFAULT_CURSOR));  //光标为默认的指针} else {setCursor(new Cursor(Cursor.HAND_CURSOR));  //光标为手掌}}});}/** * 绘制 */public void paintComponent(Graphics graphics) {super.paintComponent(graphics);  //画棋盘/*//获得窗口的宽度与高度int FWidth = getWidth();int FHeight = getHeight();*///画网格线for (int i = 0;i <= ROWS; i++) {graphics.drawLine(MARGIN, MARGIN + i * GRID_SPAN, MARGIN + COLS * GRID_SPAN, MARGIN + i * GRID_SPAN);}for (int j = 0;j <= COLS; j++) {graphics.drawLine(MARGIN + j * GRID_SPAN, MARGIN, MARGIN + j * GRID_SPAN, MARGIN + ROWS * GRID_SPAN);}//画棋子for (int i = 0;i < chessCount; i++) {//网格交叉点坐标int xPos = (int) (chessList[i].getX() * GRID_SPAN + MARGIN);int yPos = (int) (chessList[i].getY() * GRID_SPAN + MARGIN);Color colorTemp = chessList[i].getColor();graphics.setColor(colorTemp);  //设置颜色RadialGradientPaint paint;if (colorTemp == Color.black) {//前两个参数为圆心,第三个为半径paint = new RadialGradientPaint(xPos-Point.DIAMETER / 2 + 25,yPos - Point.DIAMETER / 2 + 10, 20, new float[]{0f, 1f},new Color[]{Color.WHITE, Color.BLACK});} else {paint = new RadialGradientPaint(xPos-Point.DIAMETER / 2 + 25,yPos - Point.DIAMETER / 2 + 10, 70, new float[]{0f, 1f},new Color[]{Color.WHITE, Color.BLACK});}((Graphics2D) graphics).setPaint(paint);((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);Ellipse2D ellipse = new Ellipse2D.Float(xPos - Point.DIAMETER / 2,yPos - Point.DIAMETER / 2, 34, 35);((Graphics2D) graphics).fill(ellipse);//标记最后一个棋子的红矩形框if (i == chessCount - 1) {graphics.setColor(Color.red);graphics.drawRect(xPos - Point.DIAMETER / 2, yPos - Point.DIAMETER / 2, 34, 35);}}}protected boolean findChess(int x, int  y) {for (Point p : chessList) {if (p != null && p.getX() == x && p.getY() == y) {return true;}}return false;}@Overridepublic void mouseClicked(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseEntered(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseExited(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mousePressed(MouseEvent e) {//游戏结束时,不能再下if (gameOver) {return ;}String colorName = isBlack ? "黑棋" : "白棋";//将鼠标点击的坐标位置转换成网络索引xIndex = (e.getX() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;yIndex = (e.getY() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;//若落在棋盘外或位置上以后棋子,不能下if (xIndex < 0 || xIndex > ROWS || yIndex < 0 || yIndex > COLS || findChess(xIndex, yIndex)){return ;}//可下时的处理Point chess = new Point(xIndex, yIndex, isBlack ? Color.BLACK : Color.WHITE);chessList[chessCount ++] = chess;repaint();  //通知系统重绘//如果为毁过棋,则标记为可悔棋if(chess.getColor() != regretColor) {regretColor = DEFAULT_COLOR;}//如果胜出则给出提示,不能继续下棋if (isWin()) {String msg = String.format("恭喜,%s赢了!", colorName);JOptionPane.showMessageDialog(this, msg);gameOver = true;}isBlack = !isBlack;}private boolean isWin() {int continueCount = 1;  //连续棋子的个数//横向向西寻找for (int i = xIndex - 1; i >= 0; i--) {Color color = isBlack ? Color.BLACK : Color.WHITE;if (getChess(i, yIndex, color) != null) {continueCount ++;} else {break;}}//横向向东寻找for (int i = xIndex + 1; i < COLS; i++) {Color color = isBlack ? Color.BLACK : Color.WHITE;if (getChess(i, yIndex, color) != null) {continueCount ++;} else {break;}}System.out.println("heng " + continueCount);if (continueCount >= 5) {return true;} else{continueCount = 1;}//继续另一种搜索//向上for (int j = yIndex - 1; j >= 0; j--) {Color color = isBlack ? Color.BLACK : Color.WHITE;if (getChess(xIndex, j, color) != null) {continueCount ++;} else {break;}}//向下for (int j = yIndex + 1; j < ROWS; j++) {Color color = isBlack ? Color.BLACK : Color.WHITE;if (getChess(xIndex, j, color) != null) {continueCount ++;} else {break;}}if (continueCount >= 5) {return true;} else{continueCount = 1;}//继续另一种搜索,对角线一侧for (int i = xIndex - 1,j = yIndex - 1; i >= 0 && j >= 0; i--, j--) {Color color = isBlack ? Color.BLACK : Color.WHITE;if (getChess(i, j, color) != null) {continueCount ++;} else {break;}}for (int i = xIndex + 1,j = yIndex + 1; i <= COLS && j <= ROWS; i++, j++) {Color color = isBlack ? Color.BLACK : Color.WHITE;if (getChess(i, j, color) != null) {continueCount ++;} else {break;}}if (continueCount >= 5) {return true;} else{continueCount = 1;}//继续另一种搜索,对角线另一侧for (int i = xIndex - 1,j = yIndex + 1; i >= 0 && j <= ROWS; i--, j++) {Color color = isBlack ? Color.BLACK : Color.WHITE;if (getChess(i, j, color) != null) {continueCount ++;} else {break;}}for (int i = xIndex + 1,j = yIndex - 1; i <= COLS && j >= ROWS; i++, j--) {Color color = isBlack ? Color.BLACK : Color.WHITE;if (getChess(i, j, color) != null) {continueCount ++;} else {break;}}if (continueCount >= 5) {return true;} else{continueCount = 1;}return false;}private Object getChess(int xIndex, int yIndex, Color color) {for (Point p : chessList) {if (p != null && p.getX() == xIndex && p.getY() == yIndex && p.getColor() == color) {return p;}}return null;}@Overridepublic void mouseReleased(MouseEvent e) {// TODO Auto-generated method stub}public void restartGame() {//清除棋子for (int i = 0;i < chessList.length; i++) {chessList[i] = null;}//恢复游戏相关的变量值isBlack = true;gameOver = false;  //游戏重新开始chessCount = 0;  //当前棋盘棋子个数repaint();}/** * 悔棋 */public void goback() {if (chessCount == 0) {return ;}//只有当前下棋那个人下完后可以悔棋一次if (regretColor != DEFAULT_COLOR) {return ;}regretColor = isBlack ? Color.BLACK : Color.WHITE;chessList[chessCount -1] = null;chessCount --;if (chessCount > 0) {xIndex = chessList[chessCount - 1].getX();yIndex = chessList[chessCount - 1].getY();}isBlack = !isBlack;repaint();}/** * 矩形Dimension */public Dimension getPreferredSize() {return new Dimension(MARGIN * 2 + GRID_SPAN * COLS, MARGIN * 2 + GRID_SPAN * ROWS);}}

五子棋主框架

import java.awt.BorderLayout;import java.awt.Container;import java.awt.FlowLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JMenu;import javax.swing.JMenuBar;import javax.swing.JMenuItem;import javax.swing.JPanel;/** * 五子棋主框架 * @author shenjingyi * */public class StartChessJFrame extends javax.swing.JFrame {private ChessBoard chessBoard;private JPanel toolbar;private JButton startButton, exitButton, backButton;private JMenuBar menuBar;private JMenu sysMenu;private JMenuItem startMenuItem, exitMenuItem, backMenuItem;public StartChessJFrame() {setTitle("单机版五子棋");chessBoard = new ChessBoard();initComponents();}private void initComponents() {Container contentPane = getContentPane();contentPane.add(chessBoard);chessBoard.setOpaque(true);//创建和添加菜单menuBar = new JMenuBar();  //初始化菜单栏sysMenu = new JMenu("系统");  //初始化菜单//初始化菜单项startMenuItem = new JMenuItem("重新开始");exitMenuItem = new JMenuItem("退出");backMenuItem = new JMenuItem("悔棋");//将三个菜单项添加到菜单上sysMenu.add(startMenuItem);sysMenu.add(exitMenuItem);sysMenu.add(backMenuItem);//初始化按钮事件监听器内部类MyItemListener listener = new MyItemListener();//将三个菜单注册到事件监听器上this.startMenuItem.addActionListener(listener);backMenuItem.addActionListener(listener);exitMenuItem.addActionListener(listener);menuBar.add(sysMenu);  //将系统菜单添加到菜单栏上setJMenuBar(menuBar);  //将menuBar设置为菜单栏toolbar = new JPanel();  //工具面板实例化//三个按钮初始化startButton = new JButton("重新开始");exitButton = new JButton("退出");backButton = new JButton("悔棋");//将工具面板按钮用FlowLayout布局toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));//将三个按钮添加到工具面板toolbar.add(startButton);toolbar.add(exitButton);toolbar.add(backButton);//将三个按钮注册监听事件startButton.addActionListener(listener);exitButton.addActionListener(listener);backButton.addActionListener(listener);//将工具面板布局到界面下方add(toolbar, BorderLayout.SOUTH);//将面板对象添加到窗体上add(chessBoard);//设置界面关闭事件setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//自适应大小pack();}private class MyItemListener implements ActionListener {@Overridepublic void actionPerformed(ActionEvent e) {//获得事件源Object obj = e.getSource();if (obj == StartChessJFrame.this.startMenuItem || obj == startButton) {//重新开始//JFiveFrame.this内部类引用外部类System.out.println("重新开始");chessBoard.restartGame();} else if (obj == exitMenuItem || obj == exitButton) {System.exit(0);} else if (obj == backMenuItem || obj == backButton) {System.out.println("悔棋");chessBoard.goback();}}}public static void main(String args[]) {StartChessJFrame frame = new StartChessJFrame();  //创建主框架frame.setVisible(true);}}






0 0
原创粉丝点击