자바로 만든 테트리스 질문

chossfox의 이미지

간단하게 만들어서

.블럭 생성
.블럭 이동
.블럭 회전
.꽉찬 라인 제거
.라인 제거 마다 점수증가

이정도...?

간단한 설명을 하면
블럭을 [4][4] array로, 게임 패널을 [30][20] array로 나타 냈습니다.
그리고 블럭 부분을 1로 하고 나머지는 0으로 초기화 해서 블럭을 표현했고,
이 것을 토대로 [30][20]개의 Label을 만든 후 1인 부분(블럭)을 BackgroundColor로 블럭 색을 만들었습니다.

움직이는 것은 백그라운드 제거, 배열 값 변경, 변경 값으로 백그라운드 설정 으로 나타냈습니다.
Thread로 3초마다 1칸씩 내리고, KeyListener로 좌, 우, 회전을 할 수 있게 했습니다.

게임패널 pre_array를 하나 더만들어서 블럭이 맨 아래로 가거나 1을 만나면 정지 후 pre_array에 array를 대입.
다음 블럭을 만들 때 array에 pre_array 대입해서 내려간 이전 블럭을 유지.
겹치는 블럭 확인은 내리다가 array[y][x] 값이 1이면 정지.

꽉찬 라인 없애는 건 array에서 x축 값이 모두 1이면 그 라인부터 처음 라인까지 덮었습니다.


질문
자바로 처음 만들어 보는거라 많이 조잡 합니다만..
근데 속도가 너무 느립니다. 너무 심하게 느려요.. 블럭이 부셔져서 보입니다.
속도가 느린 이유를 알 수 있을까요?

그리고 다른 방법으로 다시 만들어 보는 중인데
KeyListener를 mainclass에 만 설정 가능한가요? MouseListener하고 KeyListener를 같이 넣어봤는데
MouseListener만 반응하고 KeyListener는 반응하지 않아서 mainclass에 다시 달고 있네요.. requestFocus는 했습니다.

MainFrame

package Tetris;
 
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Iterator;
 
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
 
public class MainFrame extends JFrame
{
	Block block = new Block();
	Score ScorePanel = new Score();
 
	int gameX = 20;//Game X-length
	int gameY = 30;//Game Y-length
	JPanel GamePanel = new JPanel();
	JLabel[][] GL = new JLabel[gameY][gameX];
	int[][] GameArray = new int[gameY][gameX];
	int[][] StandardArray = new int[gameY][gameX];
	Down down = new Down();
	ArrayList<Integer> line = new ArrayList<Integer>();
 
	ArrayList<Integer> LineCheck()//full line check
	{
		ArrayList<Integer> Item = new ArrayList<Integer>();
		int count;
		for(int i = 0; i < gameY; i++)
		{
			count = 0;
 
			for(int j = 0; j < gameX; j++)
				if(GameArray[i][j] == 1) 
					count++;
 
			if(count == gameX) Item.add(i);
		}
 
		return Item;
	}
 
	void LineRemove()//full line remove
	{
		line = LineCheck();
		Iterator<Integer> iter = line.iterator();
		int index = 0;
		int size = line.size();
		ScorePanel.Scoring(size);
		while(iter.hasNext())
		{
			index = iter.next();
			for(int i = index; i > 1; i--)
				for(int j = 0; j < gameX; j++)
					GameArray[i][j] = GameArray[i-1][j];
 
		}
		index = 0;	 
	}
 
	boolean Overlap()//overlap
	{
		try
		{
			for(int i = 0; i < block.array_size; i++)
				for(int j = 0; j < block.array_size; j++)
					if(block.array[i][j] == 1 && 
					StandardArray[i+block.y][j+block.x] == 1)//block overlap
						throw new Exception();
			return false;
		}
		catch(Exception e)
		{
			return true;
		}
 
	}
 
	void Next()//next block
	{
		for(int i = 0; i < gameY; i++)//Game repaint
			for(int j = 0; j < gameX; j++)
				StandardArray[i][j] = GameArray[i][j];
		block = ScorePanel.Pre_block;//next block
		ScorePanel.Pre_block = new Block();
	}
 
	void View()//view
	{
		for(int i = 0; i < gameY; i++)
			for(int j = 0; j < gameX; j++)//Game repaint
			{
				GameArray[i][j] = StandardArray[i][j];
 
				if(GameArray[i][j] == 0)
					GL[i][j].setBackground(null);
			}
 
		for(int i = 0; i < block.array_size; i++)
			for(int j = 0; j < block.array_size; j++)//Block repaint
				if(block.array[i][j] == 1)
				{
					GameArray[i+block.y][j+block.x] = 1;
					GL[i+block.y][j+block.x].setBackground(block.color);
					GL[i+block.y][j+block.x].setOpaque(true);
				}
	}
 
	class Down extends Thread//down
	{
		@Override
		public void run() 
		{
			// TODO Auto-generated method stub
			super.run();
 
			try 
			{
				while(true)
				{
 
					block.y++;
					if(block.y > 26 || Overlap())//bottom
						throw new Exception();
					View();
					sleep(3000);
				}
 
			} 
			catch (InterruptedException e)
			{
				// TODO Auto-generated catch block
				System.out.println("End");
				e.printStackTrace();
			}
			catch (Exception e)//bottom
			{
				LineRemove();
				Next();
				run();
				return;
			}
		}
	}
 
	class Keyboard implements KeyListener//keyboard
	{
 
		@Override
		public void keyTyped(KeyEvent e) {
			// TODO Auto-generated method stub
 
		}
 
		@Override
		public void keyPressed(KeyEvent e) 
		{
			// TODO Auto-generated method stub
			try
			{
				switch(e.getKeyCode())
				{
				case 37://←
					if(Overlap()) break;
					block.x--;
					View();
					break;
				case 38://↑
					block.Rotate();
					View();
					break;
				case 39://→
					if(Overlap()) break;
					block.x++;
					View();
					break;
				case 40://↓
					if(Overlap()) break;
					block.y++;
					View();
				}
			}
			catch(ArrayIndexOutOfBoundsException a)
			{
				switch(e.getKeyCode())
				{
				case 37://←
					block.x++;
					View();
					break;
				case 39://→
					block.x--;
					View();
					break;
				case 40://↓
					block.y--;
					View();
				}
			}
		}
 
		@Override
		public void keyReleased(KeyEvent e) {
			// TODO Auto-generated method stub	
 
		}	
	}
 
	MainFrame() //main
	{
		// TODO Auto-generated constructor stub
		setTitle("TETRIS");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLayout(null);
 
		ScorePanel.setBounds(240, 20, 90, 300);
		GamePanel.setBounds(20, 20, 200, 300);
		GamePanel.setLayout(new GridLayout(30, 20, 1, 1));
		GamePanel.setBackground(Color.lightGray);
		GamePanel.setOpaque(true);
 
		for(int i = 0; i < gameY; i++)
			for(int j = 0; j < gameX; j++)//Game initialize
			{
				GL[i][j] = new JLabel();
				GamePanel.add(GL[i][j]);
			}
 
		//////test(Bottom OBlock)//////
//		for(int i = gameY-2; i < gameY; i++)
//			for(int j = 2; j < gameX; j++)
//			{
//				StandardArray[i][j] = 1;
//				GL[i][j].setBackground(block.color);
//				GL[i][j].setOpaque(true);
//			}		
//		View();
		///////////////////////////////
		down.start();
 
		add(GamePanel);
		add(ScorePanel);
		setSize(350, 400);
		setVisible(true);
		addKeyListener(new Keyboard());
		requestFocus();
	}
 
	public static void main(String[] args) 
	{
		// TODO Auto-generated method stub
		new MainFrame();
 
	}
}

Block

package Tetris;
 
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
import java.util.Iterator;
 
import javax.swing.JLabel;
 
public class Block extends JLabel
{
	int[][][] block_array =
		{
			{//OBlock[0]
				{0, 0, 0, 0},
				{0, 0, 0, 0},
				{0, 1, 1, 0},
				{0, 1, 1, 0}
			},
			{//LBlock[1]
				{0, 0, 0, 0},
				{0, 1, 0, 0},
				{0, 1, 0, 0},
				{0, 1, 1, 0}
			},
			{//JBlock[2]
				{0, 0, 0, 0},
				{0, 0, 0, 1},
				{0, 0, 0, 1},
				{0, 0, 1, 1}
			},
			{//TBlock[3]
				{0, 0, 0, 0},
				{0, 0, 0, 0},
				{0, 1, 1, 1},
				{0, 0, 1, 0}
			},
			{//IBlock[4]
				{0, 1, 0, 0},
				{0, 1, 0, 0},
				{0, 1, 0, 0},
				{0, 1, 0, 0}
			},
			{//ZBlock[5]
				{0, 0, 0, 0},
				{0, 0, 0, 0},
				{0, 1, 1, 0},
				{0, 0, 1, 1}
			},
			{//SBlock[6]
				{0, 0, 0, 0},
				{0, 0, 0, 0},
				{0, 0, 1, 1},
				{0, 1, 1, 0}
			}	
		};
	int array_size = 4;//array size
	int array_index = 0;// select index
	int[][] array = new int[array_size][array_size];//selected array
	Random ran = new Random();
	int x = 9;//block X-coordinate
	int y = 0;//block Y-coordinate
	Color color = null;//block color
	boolean flag = true;//rotate flag
 
	void Rotate()//rotate
	{	
		int[][] temp = new int[array_size][array_size];
 
		switch(array_index)
		{
		case 0://OBlock No rotate
			break;
		case 1://L, J, TBlock 90ºrotate 4times
		case 2:
		case 3:
			for(int i = 0; i < array_size; i++)
				for(int j = 0; j < array_size; j++)
				{
					temp[j][i] = array[i][j];
					array[i][j] = 0;
				}
 
			for(int i = 0; i < array_size; i++)
				for(int j = 0; j < array_size; j++)
					if(temp[i][j] == 1 && i < 2)
						array[2+Math.abs(i-2)][j] = temp[i][j];
					else if(temp[i][j] == 1)
						array[2-Math.abs(i-2)][j] = temp[i][j];
 
			break;
		case 4://I, Z, SBlock 90ºrotate 2times
		case 5:
		case 6:
			if(flag)//rotate check
			{		
				for(int i = 0; i < array_size; i++)
					for(int j = 0; j < array_size; j++)
					{
						temp[j][i] = array[i][j];
						array[i][j] = 0;
					}
 
				for(int i = 0; i < array_size; i++)
					for(int j = 0; j < array_size; j++)
						if(temp[i][j] == 1 && i < 2)
							array[2+Math.abs(i-2)][j] = temp[i][j];
						else if(temp[i][j] == 1)
							array[2-Math.abs(i-2)][j] = temp[i][j];
 
				flag = false;
			}
			else
			{
				for(int i = 0; i < array_size; i++)
					for(int j = 0; j < array_size; j++)
						array[i][j] = block_array[array_index][i][j];
 
				flag = true;
			}
		}	
	}
 
	public Block() 
	{
		// TODO Auto-generated constructor stub
 
		array_index = ran.nextInt(7);
//		array_index = *;//test(All *Block)
 
		for(int i = 0; i < array_size; i++)
			for(int j = 0; j < array_size; j++)//choice block
				array[i][j] = block_array[array_index][i][j];
 
		switch(array_index)
		{
		case 0://OBlock[0]
			color = Color.blue;
			break;
		case 1://LBlock[1]
			color = Color.magenta;
			break;
		case 2://JBlock[2]
			color = Color.yellow;
			break;
		case 3://TBlock[3]
			color = Color.green;
			break;
		case 4://IBlock[4]
			color = Color.red;
			break;
		case 5://ZBlock[5]
			color = Color.orange;
			break;
		case 6://SBlock[6]
			color = Color.cyan;
			break;
		}
	}
}

Score
package Tetris;
 
import java.awt.Color;
import java.awt.GridLayout;
 
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
 
public class Score extends JPanel
{
	Block Pre_block = new Block();
 
	int number = 0;
	JPanel PrePanel = new JPanel();//block view
	JLabel PreLabel = new JLabel("Pre Block");//block name
	JLabel ScoreTitle = new JLabel("Score");
	JLabel ScoreNumber = new JLabel(Integer.toString(number));//score view
	JLabel[][] PL = new JLabel[Pre_block.array_size][Pre_block.array_size];//block
 
	void Scoring(int size)
	{
		for(int i = 0; i < size; i++)//10 + bonus(line * 5);
			number += 10;
		number += size * 5;
 
		ScoreNumber.setText(Integer.toString(number));
	}
 
	public Score() 
	{
		// TODO Auto-generated constructor stub
		setBackground(Color.lightGray);
		setOpaque(true);
		setLayout(null);
		setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
 
		PreLabel.setBounds(15, 20, 80, 10);
		ScoreTitle.setBounds(30, 150, 60, 10);
		ScoreNumber.setBounds(40, 180, 60, 10);
 
		PrePanel.setBounds(35, 40, 40, 40);
		PrePanel.setBackground(Color.lightGray);
		PrePanel.setOpaque(true);
		PrePanel.setLayout(new GridLayout(4, 4, 1, 1));
 
		for(int i = 0; i < Pre_block.array_size; i++)
			for(int j = 0; j < Pre_block.array_size; j++)//block initialize
			{
				PL[i][j] = new JLabel();
				if(Pre_block.array[i][j] == 1)
				{
					PL[i][j].setBackground(Pre_block.color);
					PL[i][j].setOpaque(true);
				}
				PrePanel.add(PL[i][j]);
			}
 
		add(PreLabel);
		add(PrePanel);
		add(ScoreTitle);
		add(ScoreNumber);
	}
}
File attachments: 
첨부파일 크기
Package icon Tetris.zip16.13 KB
shint의 이미지


synchronized(this)
{
    int i;
    int size = snow.size();
    for(i=0; i < size; i++)
    {
        Point p = snow.get(i);
        snow.remove(p);
    }
}

synchronized(this) 와 for() 문 2가지를 적용해야 오류가 나지 않았습니다.

스레드 오류를 수정하였습니다.
http://kin.naver.com/qna/detail.nhn?d1id=1&dirId=1040201&docId=221054316&qb=ZXh0ZW5kcyBKRnJhbWUsIGV4dGVuZHMgVGhyZWFk&enc=utf8&section=kin&rank=1&search_sort=0&spq=0

AWT-EventQueue-0

http://kin.naver.com/qna/detail.nhn?d1id=1&dirId=1040201&docId=241836507&qb=SmF2YSByYW5k&enc=utf8&section=kin&rank=1&search_sort=0&spq=0&pid=So2DcwoRR18ssvgjdQ0sssssss8-086974&sid=3ZSiXSWGS0A%2BSu/da7hOuA%3D%3D

http://blog.naver.com/robinnw/80211544638

http://blog.naver.com/kdw9242/70139152463

https://opentutorials.org/module/1335/8711

javac SnowThread.java
java SnowThread
 
--------------------------
 
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.util.Random;
 
import java.util.ArrayList;
import java.util.Iterator;
 
 
 
 
class SnowBallThread extends Thread
{
    ArrayList<Point> snow;//눈을 저장할 변수
 
    public SnowBallThread(ArrayList<Point> snow)
    {
        this.snow = snow;
    }
 
    public void run()
    {
        Random rand = new Random();
 
        while (true)
        {
            try
            {
                synchronized(this)
                {
                    Point point = new Point(rand.nextInt(500), 0);//눈생성
                    snow.add(point);//생성한 눈을 저장
                }
                Thread.sleep(300);
            }
            catch (InterruptedException e)
            {
                System.out.println("SnowBallThread run");
                return;
            }
        }
    }
}
 
class SnowThread extends JFrame
{
 
    SnowBallThread th;
    BackPanel backGround;
 
    Random rand = new Random();
    ArrayList<Point> snow = new ArrayList<Point>();
 
    public SnowThread()
    {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("SnowThread 예제");
        backGround = new BackPanel();
        setContentPane(backGround);
        setSize(500, 440);
        setLocation(200, 200);
        setVisible(true);
        backGround.requestFocus();
        th = new SnowBallThread(snow);//눈을 생성하기 위해 snow를 스레드에 넣어줌
        th.start();
 
        Thread t = new Thread(backGround);//눈을 움직이기 위한 스레드
        t.start();
    }
 
    public class BackPanel extends JPanel implements Runnable
    {
 
        Image imgSample;
 
        public BackPanel()
        {
            setLayout(null);
            ImageIcon icon = new ImageIcon("image.png");
            imgSample = icon.getImage();
        }
 
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            g.drawImage(imgSample, 0, 0, getWidth(), getHeight(), null);
 
            synchronized(this)
            {
                int i;
                int size = snow.size();
                for(i=0; i<size; i++)
                {
                    Point p = snow.get(i);
                    g.setColor(Color.white);//하얀색으로
                    g.fillOval(p.x, p.y, 5, 5);//눈위치에 5크기로 그리기
                }
            }
        }
 
        public void run()
        {
            while (true)
            {
                try
                {
                    synchronized(this)
                    {
                        int i;
                        int size = snow.size();
                        for(i=0; i<size; i++)
                        {
                            Point p = snow.get(i);
                            p.x = rand.nextInt(500);
                            p.y += 3;
 
                            if (p.y > 440)//화면 밖으로 나가면 삭제
                            {
                                snow.remove(i);
                                break;
                            }
                        } 
                    }
                    repaint();//화면 갱신   
                    Thread.sleep(50);
                }
                catch (InterruptedException e)
                {
                    System.out.println("SnowThread run");
                    return;
                }
            }
        }
    }
 
    public static void main(String[] args)
    {
        new SnowThread();
    }
}

댓글 첨부 파일: 

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.