gpt4 book ai didi

java - 在俄罗斯方 block 项目中添加其他形状。循环逻辑辅助

转载 作者:行者123 更新时间:2023-12-01 08:48:50 25 4
gpt4 key购买 nike

我正在创建一个俄罗斯方 block 克隆作为个人项目,以帮助我更好地绘制图像、移动图像以及学习碰撞检测。

一切都很顺利,但我对让程序在第一个停止移动时向框架添加新的方 block 形状背后的逻辑感到困惑。到目前为止,我使用随机数生成器随机创建四边形,并将其添加到框架中。我只是不知道如何循环它,以便一旦该形状停止移动,它就会在屏幕顶部添加另一个形状。

这是一个 pre-alpha 版本,在其当前实现中,我尚未添加碰撞检测、任何评分、背景、旋转形状的能力等。我只是无法克服这个逻辑障碍。请帮忙!

一些代码:

    public class tetrisGame extends JFrame
{
//Frame dimensions
private static final int FRAME_WIDTH = 600;
private static final int FRAME_HEIGHT = 600;

private final int MAX_VALUE = 7; //RNG MAX VALUE
private final int MIN_VALUE = 1; //RNG MIN VALUE
private static int dy = 10;
private static int dx = 0;

private JLabel welcomeLabel, imageLabel, blankLabel, blankLabel2, creditsLabel1, creditsLabel2, creditsLabel3;
private JButton startButton, creditsButton, exitButton, returnButton, leftButton, rightButton;
private Shapes component; //Tetrimino Shape

private JPanel totalGUI, buttonPanel, startPanel, creditsPanel, gamePanel, movePanel;

public tetrisGame()
{
createComponents();
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setTitle("Tetris");
}

//Moves tetrimino's down using a timer
class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
component.moveRectangleBy(dx,dy);
}
}

//Moves the tetrimino to the right
class moveRightListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
dy = 0;
component.moveRectangleBy(dx+10,dy);
dy = 10;
}
}

//Moves the tetrimino to the left.
class moveLeftListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
dy = 0;
component.moveRectangleBy(dx-10,dy);
dy = 10;
}
}

//Executed when a new game is started. The heart of the program.
class newGameListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
int randomNum = createRNG(MAX_VALUE, MIN_VALUE);

if (randomNum == 1)
{
component = new SquareShape();
}
else if (randomNum == 2)
{
component = new RectangleShape();
}
else if (randomNum == 3)
{
component = new JShape();
}
else if (randomNum == 4)
{
component = new SShape();
}
else if (randomNum == 5)
{
component = new TShape();
}
else if (randomNum == 6)
{
component = new LShape();
}
else
{
component = new ZShape();
}

//Creates and starts timer that moves shapes
int delay = 1000;
ActionListener timerListener = new TimerListener();
javax.swing.Timer t = new javax.swing.Timer(delay, timerListener);
t.start();

remove(totalGUI);
add(component, BorderLayout.CENTER);
add(movePanel, BorderLayout.SOUTH);
repaint();
revalidate();

}
}

//Adds components of the credit screen when button is pressed
class creditsListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
totalGUI.remove(startPanel);
totalGUI.add(creditsPanel);
repaint();
revalidate();
}
}

//Exits the program
class exitListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
}

//returns to the main menu screen.
class returnListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
totalGUI.remove(creditsPanel);
totalGUI.add(startPanel);
repaint();
}
}

//Creates all components of the GUI
private void createComponents()
{
//Imports Tetris image
try
{
String path = "http://static3.gamespot.com/uploads/screen_kubrick/1179/11799911/2550560-tetris.jpg";
URL url = new URL(path);
BufferedImage image = ImageIO.read(url);
Image newImage = image.getScaledInstance(300,120,java.awt.Image.SCALE_SMOOTH);
imageLabel = new JLabel(new ImageIcon(newImage));
} catch(Exception e){}
//Creates welcome prompt and new game buttons
welcomeLabel = new JLabel(" Welcome to Tetris!");
Font boldFont = welcomeLabel.getFont();
welcomeLabel.setFont(boldFont.deriveFont(boldFont.getStyle() ^ Font.BOLD));
welcomeLabel.setForeground(Color.orange);
blankLabel = new JLabel("");
blankLabel2 = new JLabel("");
startButton = new JButton("New Game");
creditsButton = new JButton("Credits");
exitButton = new JButton("Exit");

//Adds action listeners to new game buttons
ActionListener newGameListener = new newGameListener();
startButton.addActionListener(newGameListener);
ActionListener creditsListener = new creditsListener();
creditsButton.addActionListener(creditsListener);
ActionListener exitListener = new exitListener();
exitButton.addActionListener(exitListener);

//Adds new game buttons to panel
buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(6,1));
buttonPanel.setBackground(Color.black);
buttonPanel.add(blankLabel);
buttonPanel.add(blankLabel2);
buttonPanel.add(welcomeLabel);
buttonPanel.add(startButton);
buttonPanel.add(creditsButton);
buttonPanel.add(exitButton);

//Buttons that move the tetrimino's
leftButton = new JButton("<--");
ActionListener leftListener = new moveLeftListener();
leftButton.addActionListener(leftListener);
rightButton = new JButton("-->");
ActionListener rightListener = new moveRightListener();
rightButton.addActionListener(rightListener);
//Panel that contains movement buttons
movePanel = new JPanel();
movePanel.add(leftButton);
movePanel.add(rightButton);

//Continue to add elements to panel
startPanel = new JPanel();
startPanel.setLayout(new BorderLayout());
startPanel.add(imageLabel, BorderLayout.NORTH);
startPanel.add(buttonPanel, BorderLayout.CENTER);

//Create elements of credits screen
creditsLabel1 = new JLabel("The Tetris logo, block shapes, and dimensions are registered trademarks of The Tetris Company.");
creditsLabel1.setFont(boldFont.deriveFont(boldFont.getStyle() ^ Font.BOLD));
creditsLabel1.setForeground(Color.orange);
creditsLabel2 = new JLabel(" This product is an academic work intended for individual use only.");
creditsLabel2.setFont(boldFont.deriveFont(boldFont.getStyle() ^ Font.BOLD));
creditsLabel2.setForeground(Color.orange);
creditsLabel3 = new JLabel(" All programming written in the Java language by NAME REMOVED.");
creditsLabel3.setFont(boldFont.deriveFont(boldFont.getStyle() ^ Font.BOLD));
creditsLabel3.setForeground(Color.orange);
returnButton = new JButton("Return");
ActionListener returnListener = new returnListener();
returnButton.addActionListener(returnListener);
creditsPanel = new JPanel();
creditsPanel.setLayout(new GridLayout(5,1));
creditsPanel.setBackground(Color.black);
creditsPanel.add(creditsLabel1);
creditsPanel.add(creditsLabel2);
creditsPanel.add(blankLabel);
creditsPanel.add(creditsLabel3);
creditsPanel.add(returnButton);

//Initial game panel
totalGUI = new JPanel();
totalGUI.add(startPanel);
totalGUI.setBackground(Color.black);

add(totalGUI, BorderLayout.CENTER);
}

//generates a random number.
private int createRNG(int MAX_VALUE, int MIN_VALUE)
{
Random rand = new Random();
int randomNum = rand.nextInt(MAX_VALUE - MIN_VALUE + 1) + MIN_VALUE;

return randomNum;
}
}

这是形状类之一的代码,以防您需要引用它:

public class SquareShape extends Shapes
{
private static final int RECTANGLE_WIDTH = 40;
private static final int RECTANGLE_HEIGHT = 40;

private int xLeft;
private int yTop;
boolean stopped = false;

public SquareShape()
{
xLeft = 280;
yTop = 0;
}

public void paintComponent(Graphics g)
{
//draws 1 large square
g.setColor(Color.cyan);
g.fillRect(xLeft,yTop,RECTANGLE_WIDTH,RECTANGLE_HEIGHT);

//Divides the square into parts
g.setColor(Color.black);
g.drawLine(xLeft,yTop,xLeft+40,yTop);
g.drawLine(xLeft,yTop,xLeft,yTop+40);
g.drawLine(xLeft,yTop+40,xLeft+40,yTop+40);
g.drawLine(xLeft+40,yTop+40,xLeft+40,yTop);
g.drawLine(xLeft,yTop+20,xLeft+40,yTop+20);
g.drawLine(xLeft+20,yTop,xLeft+20,yTop+40);
}

public void moveRectangleBy(int dx, int dy)
{
if (yTop < 450)
{
xLeft += dx;
yTop += dy;
if (xLeft < 0)
{
xLeft = 0;
}
if (xLeft > 500)
{
xLeft = 500;
}
}
repaint();
}


}

预先感谢您的帮助。我相信,一旦解决了这个问题,我就可以实现程序的其余部分,因为我似乎不知道如何让形状继续下降。

最佳答案

I just can't figure out how to loop it so that once that shape stops moving it adds another shape at the top of the screen.

在你的计时器逻辑中你有:

component.moveRectangleBy(dx,dy);

因此,这假设您始终有一个“Activity ”组件。您需要能够确定组件何时位于底部,以便可以重置组件。

因此,您可以重新构造监听器代码,使其看起来像这样:

if (component == null)
component = // a new random shape
else
{
component.moveRectangleBy(...);

if (component.isAtBottom()) // a method you will need to write
component == null;
}

不管怎样,我也玩过我自己的俄罗斯方 block 游戏。目前:

  1. 添加随机碎片
  2. 在棋盘上移动棋子
  3. 使用 4 个箭头键移动/旋转俄罗斯方 block
  4. 删除整行

基本设计分为 4 类:

  1. TetrisIcon - 绘制一个带边框的正方形
  2. TetrisPiece - 俄罗斯方 block 的 4x4 数组表示。值为 1 表示应绘制 TetricIcon。
  3. TetrisBoard - 包含要绘制的俄罗斯方 block 图标列表以及当前在棋盘上移动的俄罗斯方 block 。当俄罗斯方 block 到达底部时,其各个俄罗斯方 block 图标将被移动到棋盘上。
  4. 俄罗斯方 block - 构建框架并开始游戏。

如果你想玩它,那就玩得开心:

俄罗斯方 block :

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import java.awt.geom.*;

public class Tetris extends JPanel
{
private final static int TETRIS_ICON_SIZE = 20;

private List<TetrisPiece> tetrisPieces = new ArrayList<TetrisPiece>();
private TetrisBoard board;
private Random random = new Random();

public Tetris()
{
setLayout( new BorderLayout() );

createTetrisPieces();

board = new TetrisBoard(20, 10, 20);
add(board, BorderLayout.LINE_START);
/*
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 5, 5);
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 5, 6);
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 6, 5);
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 0, 0);
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 0, 19);
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 9, 0);
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 9, 19);

board.setTetrisPiece( tetrisPieces.get(1) );
*/
JButton start = new JButton( new StartAction() );
add(start, BorderLayout.PAGE_END);
}

private void createTetrisPieces()
{
int[][] shape =
{
{0, 1, 0, 0},
{0, 1, 0, 0},
{0, 1, 0, 0},
{0, 1, 0, 0}
};

tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.RED, TETRIS_ICON_SIZE)) );

shape = new int[][]
{
{0, 1, 0, 0},
{0, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 0, 0}
};

tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.YELLOW, TETRIS_ICON_SIZE)) );

shape = new int[][]
{
{0, 0, 1, 0},
{0, 0, 1, 0},
{0, 1, 1, 0},
{0, 0, 0, 0}
};

tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.MAGENTA, TETRIS_ICON_SIZE)) );

shape = new int[][]
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 1, 1, 0},
{0, 0, 0, 0}
};

tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.CYAN, TETRIS_ICON_SIZE)) );

shape = new int[][]
{
{0, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 1, 0},
{0, 0, 0, 0}
};

tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.WHITE, TETRIS_ICON_SIZE)) );

shape = new int[][]
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{1, 1, 0, 0},
{0, 0, 0, 0}
};

tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.BLUE, TETRIS_ICON_SIZE)) );

shape = new int[][]
{
{0, 0, 0, 0},
{1, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 0, 0}
};

tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.GREEN, TETRIS_ICON_SIZE)) );
}

class StartAction extends AbstractAction
{
public StartAction()
{
super("Start Game");
}

@Override
public void actionPerformed(ActionEvent e)
{
new Timer(1000, new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e2)
{
if (board.getTetrisPiece() == null)
{
int piece = random.nextInt( tetrisPieces.size() );
board.setTetrisPiece( tetrisPieces.get( piece ) );
}
else
{
board.moveShapeDown();
}
}
}).start();
}
}


private static void createAndShowGUI()
{

JFrame frame = new JFrame("Tetris");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Tetris());
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}

public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}

俄罗斯方 block 板:

import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;

class TetrisBoard extends JPanel
{
private List<TetrisIcon[]> board;

private int rows;
private int columns;
private int size;

private TetrisPiece tetrisPiece;

public TetrisBoard(int rows, int columns, int size)
{
this.rows = rows;
this.columns = columns;
this.size = size;

board = new ArrayList<TetrisIcon[]>(rows);

for (int i = 0; i < rows; i++)
board.add( new TetrisIcon[columns] );

setBackground( Color.BLACK );

addKeyBindings();
}

private void addKeyBindings()
{
InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();

String leftName = "LEFT";
KeyStroke leftKeyStroke = KeyStroke.getKeyStroke( leftName );
inputMap.put(leftKeyStroke, leftName);
actionMap.put(leftName, new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
moveShapeLeft();
}
});

String rightName = "RIGHT";
KeyStroke rightKeyStroke = KeyStroke.getKeyStroke( rightName );
inputMap.put(rightKeyStroke, rightName);
actionMap.put(rightName, new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
moveShapeRight();
}
});

String downName = "DOWN";
KeyStroke downKeyStroke = KeyStroke.getKeyStroke( downName );
inputMap.put(downKeyStroke, downName);
actionMap.put(downName, new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
// moveShapeDown();
dropShape();
}
});

String upName = "UP";
KeyStroke upKeyStroke = KeyStroke.getKeyStroke( upName );
inputMap.put(upKeyStroke, upName);
actionMap.put(upName, new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
rotateShape();
}
});
}

public TetrisPiece getTetrisPiece()
{
return tetrisPiece;
}

public void setTetrisPiece(TetrisPiece tetrisPiece)
{
this.tetrisPiece = new TetrisPiece(tetrisPiece.getShape(), tetrisPiece.getIcon());
this.tetrisPiece.setLocation( new Point(4, 0) );
repaint();
}

public void setTetrisIconAt(TetrisIcon icon, int x, int y)
{
TetrisIcon[] row = board.get(y);
row[x] = icon;
}

public TetrisIcon getTetrisIconAt(int x, int y)
{
TetrisIcon[] row = board.get(y);

return row[x];
}

public void moveShapeLeft()
{
if (tetrisPiece == null) return;

Point possibleLocation = new Point(tetrisPiece.getX() - 1, tetrisPiece.getY());

if ( canMoveShape(possibleLocation, tetrisPiece.getShape()) )
{
tetrisPiece.setLocation( possibleLocation );
repaint();
}
}

public void moveShapeRight()
{
if (tetrisPiece == null) return;

Point possibleLocation = new Point(tetrisPiece.getX() + 1, tetrisPiece.getY());

if ( canMoveShape(possibleLocation, tetrisPiece.getShape()) )
{
tetrisPiece.setLocation( possibleLocation );
repaint();
}
}

public void dropShape()
{
if (tetrisPiece == null) return;

Point possibleLocation = new Point(tetrisPiece.getX(), tetrisPiece.getY() + 1);

while ( canMoveShape(possibleLocation, tetrisPiece.getShape()) )
{
moveShapeDown();
possibleLocation = new Point(tetrisPiece.getX(), tetrisPiece.getY() + 1);
}

// addTetrisPieceToBoard();
// tetrisPiece = null;
}

public void moveShapeDown()
{
if (tetrisPiece == null) return;

Point possibleLocation = new Point(tetrisPiece.getX(), tetrisPiece.getY() + 1);

if ( canMoveShape(possibleLocation, tetrisPiece.getShape()) )
{
tetrisPiece.setLocation( possibleLocation );
repaint();
}
else
{
tetrisPieceAtBottom();
}
}

private void tetrisPieceAtBottom()
{
Point location = tetrisPiece.getLocation();
int row = Math.min(rows, location.y + 4);
row--;

addTetrisPieceToBoard();

int rowsRemoved = 0;


for (; row >= location.y; row--)
{
// System.out.println(row);
TetrisIcon[] icons = board.get(row);

if ( fullRow(row) )
{
board.remove(row);
rowsRemoved++;
}
}

for (int i = 0; i < rowsRemoved; i++)
board.add(0, new TetrisIcon[columns]);

if (rowsRemoved > 0)
repaint();
}

private boolean fullRow(int row)
{
for (int column = 0; column < columns; column++)
{
// System.out.println(row + " : " + column);
if ( getTetrisIconAt(column, row) == null)
return false;
}

return true;
}

private void addTetrisPieceToBoard()
{
int x = tetrisPiece.getX();
int y = tetrisPiece.getY();

for (int r = 0; r < tetrisPiece.getRows(); r++)
{
for (int c = 0; c < tetrisPiece.getColumns(); c++)
{
TetrisIcon icon = tetrisPiece.getIconAt(r, c);

if (icon != null)
{
setTetrisIconAt(icon, x, y);
}

x++;
}

x = tetrisPiece.getX();
y++;
}

tetrisPiece = null;
}

public void rotateShape()
{
if (tetrisPiece == null) return;

int[][] rotatedShape = tetrisPiece.getRotatedShape();

if ( canMoveShape(tetrisPiece.getLocation(), rotatedShape) )
{
tetrisPiece.setShape( rotatedShape );
repaint();
}
}

private boolean canMoveShape(Point location, int[][] shape)
{
for (int r = 0; r < shape.length; r ++)
{
for (int c = 0; c < shape.length; c++)
{
if (shape[r][c] == 1)
{
int x = location.x + c;
int y = location.y + r;

// Past left edge

if (x < 0) return false;

// Past right edge

if (x >= columns) return false;

// Past bottom edge

if (y >= rows) return false;

// Collision with TetrisIcon

if (getTetrisIconAt(x, y) != null) return false;
}
}
}

return true;
}

@Override
public Dimension getPreferredSize()
{
int width = (columns * size) + columns - 1;
int height = (rows * size) + rows - 1;

return new Dimension(width, height);
}

@Override
protected void paintComponent(Graphics g)
{
super.paintComponent( g );

int x = 0;
int y = 0;
int offset = size + 1;

for (int r = 0; r < rows; r++)
{
TetrisIcon[] row = board.get(r);

for (int c = 0; c < row.length; c++)
{
TetrisIcon icon = row[c];

if (icon != null)
{
icon.paintIcon(this, g, x, y);
}

x += offset;
}

x = 0;
y += offset;
}

// paint shape

if (tetrisPiece != null)
{
paintShape(g, offset);
}
}

private void paintShape(Graphics g, int offset)
{
int x = tetrisPiece.getX() * offset;
int y = tetrisPiece.getY() * offset;

for (int r = 0; r < tetrisPiece.getRows(); r++)
{
for (int c = 0; c < tetrisPiece.getColumns(); c++)
{
TetrisIcon icon = tetrisPiece.getIconAt(r, c);

if (icon != null)
{
icon.paintIcon(this, g, x, y);
}

x += offset;
}

x = tetrisPiece.getX() * offset;
y += offset;
}
}
}

俄罗斯方 block :

import java.awt.Point;

public class TetrisPiece
{
private int[][] shape;
private TetrisIcon icon;
private Point location = new Point();

public TetrisPiece(int[][] shape, TetrisIcon icon)
{
setShape(shape);
this.icon = icon;
}

public TetrisIcon getIcon()
{
return icon;
}

public int[][] getShape()
{
return shape;
}

public void setShape(int[][] shape)
{
this.shape = shape;
}

public TetrisIcon getIconAt(int x, int y)
{
return (shape[x][y] == 1) ? icon : null;
}

public Point getLocation()
{
return location;
}

public void setLocation(Point location)
{
this.location = location;
}

public int getX()
{
return location.x;
}

public int getY()
{
return location.y;
}

public int getRows()
{
return shape.length;
}

public int getColumns()
{
return shape[0].length;
}

public int[][] getRotatedShape()
{
int[][] rotatedShape = new int[shape.length][shape[0].length];

int x = 0;
int y = 0;

for (int c = shape.length - 1; c >= 0; c--)
{
for (int r = 0; r < shape[0].length; r++)
{
rotatedShape[x][y] = shape[r][c];
y++;
}

x++;
y = 0;
}

return rotatedShape;
}

}

俄罗斯方 block 图标:

import java.awt.*;
import javax.swing.*;

public class TetrisIcon implements Icon
{
private Color color;
private int size;

public TetrisIcon(Color color, int size)
{
this.color = color;
this.size = size;
}

public int getIconWidth()
{
return size;
}

public int getIconHeight()
{
return size;
}

public void paintIcon(Component c, Graphics g, int x, int y)
{
int width = getIconWidth() - 1;
int height = getIconHeight() - 1;

g.translate(x, y);

g.setColor(color);
g.fillRect(0, 0, width, height);

g.setColor(Color.LIGHT_GRAY);
g.drawLine(0, 0, width, 0);
g.drawLine(0, 0, 0, height);

g.setColor(Color.DARK_GRAY);
g.drawLine(width, 0, width, height);
g.drawLine(0, height, width, height);

g.translate(-x, -y);
}
}

关于java - 在俄罗斯方 block 项目中添加其他形状。循环逻辑辅助,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42517544/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com