Die Schnittstelle hier sieht nicht sehr gut aus, aber ich denke, dass es kein großes Problem darstellt, solange die Funktionen vorhanden sind!
Zwei Leinwände:
Leinwand 1: Wird zum Zeichnen statischer Dinge wie Spielbereichsgrenzen, Gitter, Punktebereichsfelder, Felder für den nächsten Bereich, Schaltflächen usw. verwendet, Teile, die nicht benötigt werden erfrischt sein.
Leinwand 2: Wird zum Zeichnen dynamischer Teile des Spiels verwendet, z. B. Gittermodell, Gitterbewegung, Rotationsverformung, Eliminierung, Punkteanzeige, nächste Grafikanzeige usw.
Erstellen Sie zunächst eine Spielformklasse GameFrame, erben Sie sie von JFrame und verwenden Sie sie zur Anzeige auf dem Bildschirm (Fensterobjekt). Legen Sie den Fenstertitel und die Größe fest warte auf das Layout.
/* * 游戏窗体类 */ public class GameFrame extends JFrame { public GameFrame() { setTitle("俄罗斯方块");//设置标题 setSize(488, 476);//设定尺寸 setLayout(new BorderLayout()); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//点击关闭按钮是关闭程序 setLocationRelativeTo(null); //设置居中 setResizable(false); //不允许修改界面大小 } }
Erstellen Sie den Panel-Container BackPanel und erben Sie ihn von JPanel.
/* * 背景画布类 */ public class BackPanel extends JPanel{ BackPanel panel=this; private JFrame mainFrame=null; //构造里面初始化相关参数 public BackPanel(JFrame frame){ this.setLayout(null); this.setOpaque(false); this.mainFrame = frame; mainFrame.setVisible(true); } }
Erstellen Sie eine Hauptklasse, um dieses Fenster zu starten.
public class Main { //主类 public static void main(String[] args) { GameFrame frame = new GameFrame(); BackPanel panel = new BackPanel(frame); frame.add(panel); frame.setVisible(true);//设定显示 } }
Klicken Sie mit der rechten Maustaste, um die Hauptklasse auszuführen, und das Fenster wird erstellt.
Menü erstellen ed-Methode
Zeichnen Sie den Spielbereich.
Zeichnen Sie den Rand des Spielbereichs.
private void initMenu(){ // 创建菜单及菜单选项 jmb = new JMenuBar(); JMenu jm1 = new JMenu("游戏"); jm1.setFont(new Font("仿宋", Font.BOLD, 15));// 设置菜单显示的字体 JMenu jm2 = new JMenu("帮助"); jm2.setFont(new Font("仿宋", Font.BOLD, 15));// 设置菜单显示的字体 JMenuItem jmi1 = new JMenuItem("开始新游戏"); JMenuItem jmi2 = new JMenuItem("退出"); jmi1.setFont(new Font("仿宋", Font.BOLD, 15)); jmi2.setFont(new Font("仿宋", Font.BOLD, 15)); JMenuItem jmi3 = new JMenuItem("操作说明"); jmi3.setFont(new Font("仿宋", Font.BOLD, 15)); JMenuItem jmi4 = new JMenuItem("失败判定"); jmi4.setFont(new Font("仿宋", Font.BOLD, 15)); jm1.add(jmi1); jm1.add(jmi2); jm2.add(jmi3); jm2.add(jmi4); jmb.add(jm1); jmb.add(jm2); mainFrame.setJMenuBar(jmb);// 菜单Bar放到JFrame上 jmi1.addActionListener(this); jmi1.setActionCommand("Restart"); jmi2.addActionListener(this); jmi2.setActionCommand("Exit"); jmi3.addActionListener(this); jmi3.setActionCommand("help"); jmi4.addActionListener(this); jmi4.setActionCommand("lost"); }
Zeichnen Sie den rechten Hilfsbereich (Punkte, Weiter, Schaltfläche usw.). Flächenzeichnungsmethoden gerade jetzt.
Zeichnen Sie den Wertungsbereich und den nächsten Bereich des Spiels//绘制边框 private void drawBorder(Graphics g) { BasicStroke bs_2=new BasicStroke(12L,BasicStroke.CAP_ROUND,BasicStroke.JOIN_MITER); Graphics2D g_2d=(Graphics2D)g; g_2d.setColor(new Color(128,128,128)); g_2d.setStroke(bs_2); RoundRectangle2D.Double rect = new RoundRectangle2D.Double(6, 6, 313 - 1, 413 - 1, 2, 2); g_2d.draw(rect); }
Canvas 2
GamePanel erbt von JPanel und überschreibt die Paint-Methode
Ändere die Hauptklasse und füge Canvas 2 in das Fenster ein
//绘制右边区域边框 private void drawBorderRight(Graphics g) { BasicStroke bs_2=new BasicStroke(12L,BasicStroke.CAP_ROUND,BasicStroke.JOIN_MITER); Graphics2D g_2d=(Graphics2D)g; g_2d.setColor(new Color(128,128,128)); g_2d.setStroke(bs_2); RoundRectangle2D.Double rect = new RoundRectangle2D.Double(336, 6, 140 - 1, 413 - 1, 2, 2); g_2d.draw(rect); //g_2d.drawRect(336, 6, 140, 413); }
Canvas 2 zeichnet ein kleines Quadrat
Da der Spielbereich in kleine Gitter unterteilt ist, Jedes kleine Gitter ist eine Einheit und das gesamte Gitter ist ein zweidimensionales Array von 15, 20.
Das erste Element in der ersten Zeile, ausgedrückt als Array-Index, ist also 0,0 und das zweite Element in der ersten Zeile ist 0,1Das ist einfach: Wir erstellen eine Blockklasse, legen die Koordinaten fest und Das Quadrat kann entsprechend der Breite und Höhe gezeichnet werden (Breite und Höhe sind auf 20 festgelegt, entsprechend dem Raster).//绘制积分区域 private void drawCount(Graphics g) { BasicStroke bs_2=new BasicStroke(2L,BasicStroke.CAP_ROUND,BasicStroke.JOIN_MITER); Graphics2D g_2d=(Graphics2D)g; g_2d.setColor(new Color(0,0,0)); g_2d.setStroke(bs_2); g_2d.drawRect(350, 17, 110, 80); //得分 g.setFont(new Font("宋体", Font.BOLD, 20)); g.drawString("得分:",380, 40); } //绘制下一个区域 private void drawNext(Graphics g) { BasicStroke bs_2=new BasicStroke(2L,BasicStroke.CAP_ROUND,BasicStroke.JOIN_MITER); Graphics2D g_2d=(Graphics2D)g; g_2d.setColor(new Color(0,0,0)); g_2d.setStroke(bs_2); g_2d.drawRect(350, 120, 110, 120); //得分 g.setFont(new Font("宋体", Font.BOLD, 20)); g.drawString("下一个:",360, 140); }
//绘制网格 private void drawGrid(Graphics g) { Graphics2D g_2d=(Graphics2D)g; g_2d.setColor(new Color(255,255,255,150)); int x1=12; int y1=20; int x2=312; int y2=20; for (int i = 0; i <= ROWS; i++) { y1 = 12 + 20*i; y2 = 12 + 20*i; g_2d.drawLine(x1, y1, x2, y2); } y1=12; y2=412; for (int i = 0; i <= COLS; i++) { x1 = 12 + 20*i; x2 = 12 + 20*i; g_2d.drawLine(x1, y1, x2, y2); } }
//初始化 private void init() { // 开始/停止按钮 btnStart = new JButton(); btnStart.setFont(new Font("黑体", Font.PLAIN, 18)); btnStart.setFocusPainted(false); btnStart.setText("暂停"); btnStart.setBounds(360, 300, 80, 43); btnStart.setBorder(BorderFactory.createRaisedBevelBorder()); this.add(btnStart); btnStart.addActionListener(this); btnStart.setActionCommand("start"); }
public class Main { //主类 public static void main(String[] args) { GameFrame frame = new GameFrame(); BackPanel panel = new BackPanel(frame); frame.add(panel); GamePanel gamePanel = new GamePanel(frame); panel.setGamePanel(gamePanel); frame.add(gamePanel); frame.setVisible(true);//设定显示 } }
package main; import java.awt.Graphics; public class Block { private int x=0;//x坐标 private int y=0;//y坐标 private GamePanel panel=null; public Block(int x,int y,int mX,int mY,GamePanel panel){ this.x=x; this.y=y; this.panel=panel; } //绘制 void draw(Graphics g){ g.fillRect(12+x*20, 12+y*20, 20, 20); } 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; } }
Grafiken erstellen
Sieben GrafikenWie im Bild oben gezeigt, wenn wir das kleine rote Quadrat als Ursprung nehmen (0,0) Dann analysieren wir die Positionen der anderen Quadrate in der Grafik.
Wenn in der obigen Abbildung beispielsweise das rote Kästchen (0,0) ist, dann ist das vordere (-1,0), da y und sie gleich sind, solange x um eins verschoben wird Position nach links. Analog dazu sollte der dritte Wert (1,0) sein und der vierte sollte (2,0) sein.此图形呢,标红的为(0,0),它正下方的那个应该是(0,1),它右边那个是(1,0),它右下角的那个应该是(1,1)
于是我们可以设计一个Data类,专门存储7种图形的位置信息,分别对应前面图的7种模型
public class Data { public static List datas = new ArrayList(); static void init(){ int[][] data1 = {{-1,0},{0,0},{1,0},{1,1}}; datas.add(data1); int[][] data2 = {{-1,0},{0,0},{1,0},{2,0}}; datas.add(data2); int[][] data3 = {{-1,0},{-1,1},{0,0},{1,0}}; datas.add(data3); int[][] data4 = {{-1,0},{0,0},{0,1},{1,1}}; datas.add(data4); int[][] data5 = {{0,0},{0,1},{1,0},{1,1}}; datas.add(data5); int[][] data6 = {{-1,1},{0,0},{0,1},{1,0}}; datas.add(data6); int[][] data7 = {{-1,0},{0,0},{0,1},{1,0}}; datas.add(data7); } }
其中创建的时候,随机从Data类里面7个数据里面取到一个,生成一个图形,根据对应二维数组作为下标来创建小方块。
public class Model { private int x=0; private int y=0; private GamePanel panel=null; private List blocks = new ArrayList(); boolean moveFlag=false; public Model(int x,int y,GamePanel panel){ this.x=x; this.y=y; this.panel=panel; createModel(); } private void createModel() { Random random = new Random(); int type = random.nextInt(7);//1-7种模型 int[][] data= (int[][])Data.datas.get(type); Block block=null; int mX=0; int mY=0; for (int i = 0; i < 4; i++) { mX = data[i][0]; mY = data[i][1]; block = new Block(x, y, mX , mY, panel); blocks.add(block); } } }
Block也要稍微做些变动
需要加入偏移坐标值,来设定4个小方块的相对位置
GamePanel类中实例化的就是Model类了,同时绘制的也是
curModel = new Model(x,y,this);
@Override public void paint(Graphics g) { super.paint(g); //当前模型 if(curModel!=null){ List blocks = curModel.getBlocks(); Block block=null; for (int i = 0; i < blocks.size(); i++) { block = (Block)blocks.get(i); block.draw(g); } } }
我这里设定创建Model的时候x为7,y为3,于是:
图形创建好了,怎么去移动这个图形呢
很简单就是键盘移动的时候,改成调用Model类的move方法了,此方法里面就是循环模型的4个Block实例,每个小块调用自己的move方法即可:
效果如下:
旋转万能公式 x=-y y=x 这里的x、y指的是Data类里面二维数组的值,也就是 Block中的偏移值
在Block中添加变形方法
//变形 public void rotate() { //旋转万能公式 x=-y y=x int x = mX; mX = -mY; mY = x; }
Model中添加变形方法,就是循环4个Block实例
这里加入了预变形方法,就是要先判断能否变形,比如变形会出边界,会碰到别的方块,则不让变形。
//旋转 void rotate(){ boolean flag = true;//允许变形 Block block=null; for (int i = 0; i < blocks.size(); i++) { block = (Block)blocks.get(i); if(!block.preRotate()){ //有一个不让变形就不能变形 flag = false;//不能变形 break; } } if(flag){ for (int i = 0; i < blocks.size(); i++) { block = (Block)blocks.get(i); block.rotate(); } } panel.repaint(); }
当图形触底或者接触往下接触到其他方块时,会累计在下面,并且创建新的图形出来。
public Block[][] blockStack = new Block[15][20];
这个二维数组用来存储累计的方块
图形触底后,会根据每个小block实例的位置一一对应插入到blockStack这个二维数组中。
在paint方法中加入累积块的绘制
//累计块 Block bott = null; for (int i = 0; i < 15; i++) { for (int j = 0; j < 20; j++) { bott = (Block)blockStack[i][j]; if(bott!=null ){ bott.draw(g); } } }
1.从当前撞击的模型中取出y坐标(注意去重)。
2.将y进行排序,让位置小的排在前面,也就是如果消除两行的话要先消上面的那行。
3.消除当前行采用的是数据替换,从当前行开始,上一行的数据往下一行赋值,当前行就等于被消除了。
4.积分处理。
//消除处理 private void clear() { Block block = null ; int num=0; int y=0; List hasDoList=new ArrayList(); List clearList=new ArrayList(); for (int i = 0; i < blocks.size(); i++) { block = (Block)blocks.get(i); y = block.getY() + block.getmY(); if(y<0 || y>19) continue; if(!hasDoList.contains(y)){ hasDoList.add(y); if(block.clear()){ clearList.add(y); num++; } } } if(num==1){ panel.curCount+=100; }else if(num==2){ panel.curCount+=300; }else if(num==3){ panel.curCount+=600; }else if(num==4){ panel.curCount+=1000; } //执行格子的消除动作 if(num>0){ Collections.sort(clearList); doClear(clearList); } } //执行消除 void doClear(List l){ int y=0; for (int i = 0; i < l.size(); i++) { y = Integer.parseInt(String.valueOf(l.get(i))); clearClock(y); } } void clearClock(int y){ Block[][] stack = panel.blockStack; Block block=null; for (int i = 0; i < 15; i++) { for (int j = 19; j >= 0; j--) {//从最下面往上 if(y>=j&&j>0){//消除行和上方的行,全部往下移动,即这行等于上一行的数据 block = stack[i][j-1]; if(block!=null){ block.setY(block.getY()+1); } stack[i][j]=block; }else if(j==0){//第一行,清空 stack[i][j]=null; } } } }
积分规则:1行100分、2行300分、3行600分、4行1000分
显示下一个
这个其实不难:
1.创建好当前模型的时候,同时创建好下一个模型,并绘制出来;
2.当前模型触底累计后,把下一个模型设置为当前模型。
3.同时创建一个新模型做为下一个模型。
//创建模型 public void createModel(int type) { if(type==0){//游戏刚开始时 curModel = new Model(x,y,this); nextModel = new Model(x,y,this); }else{//游戏运行中 curModel = nextModel; nextModel = new Model(x,y,this); } }
在paint方法中绘制‘下一个’,在右边的下一个区域显示
//下一个模型 if(nextModel!=null){ List blocks = nextModel.getBlocks(); Block block=null; for (int i = 0; i < blocks.size(); i++) { block = (Block)blocks.get(i); block.drawNext(g); } }
//游戏线程,用来自动下移 private class GameThread implements Runnable { @Override public void run() { while (true) { if("start".equals(gameFlag)){ curModel.move(false, 1); } try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } } }
最后加入积分、按键控制、游戏结束、重新开始等就完成了
Das obige ist der detaillierte Inhalt vonSo schreiben Sie Code zur Implementierung des Tetris-Spiels in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!