생성일: 2023년 1월 11일 오전 12:18
2023.01.09 ~ 2023.01.12 코딩캠프
총 3개의 java파일로 구성된 미니 프로젝트
GraphicEditor.java
: JFrame
객체를 만들어 실행하는 역할을 하는 파일EditorFrame.java
: JFrame
클래스를 구현해놓은 파일EditorPanel.java
: JFrame
의 ContentPane
으로 설정해줄 JPanel
클래스를 구현해놓은 파일EditorPanel 객체를 EditorFrame 객체의 ContentPane으로 설정해주면서 그림판 역할을 하게했다.
public class GraphicEditor {
public static void main(String[] args) {
EditorFrame editorframe=new EditorFrame();
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class EditorFrame extends JFrame{
JMenuBar t=new JMenuBar();
EditorPanel editorPanel=null;
private String mode="";
public EditorFrame() {
super("도형편집기");
setSize(800,800); // 사이즈 지정
setLocation(500,200); // 위치 지정
editorPanel=new EditorPanel(this);
setContentPane(editorPanel); //에디터 패널 컨텐트팬 지정
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //창을 닫았을 시 메인 스레드 종료
makeToolbar(); //툴바를 생성해주는 메소드
setVisible(true);
}
private void makeToolbar() { //도형 선택 , 도형 저장 기능 구현
setJMenuBar(t);
JMenu shapeMenu=new JMenu("도형 선택");
JMenuItem circle=new JMenuItem("원");
JMenuItem square=new JMenuItem("사각형");
JMenuItem line=new JMenuItem("직선");
JMenu saveMenu=new JMenu("도형 저장");
JMenuItem save=new JMenuItem("저장");
JMenuItem read=new JMenuItem("불러오기");
saveMenu.add(save);
shapeMenu.add(circle);
shapeMenu.add(square);
shapeMenu.add(line);
t.add(shapeMenu);
t.add(saveMenu);
// JMenuItem EventListener 구현. 도형 그리기 시 EditorPanel 클래스의 도형그리기 메소드 가져와서 수행하도록 함.
circle.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//editorPanel.drawCircle(); // Circle 그리는 메소드 ?? EditorPanel 클래스에서 사용할지 여기서 사용할지 정해야함
mode="Circle";
}
});
square.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//editorPanel.drawSquare(); // Square 그리는 메소드 ?? EditorPanel 클래스에서 사용할지 여기서 사용할지 정해야함
mode="Square";
}
});
line.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
editorPanel.drawLine(); // Line 그리는 메소드 ?? EditorPanel 클래스에서 사용할지 여기서 사용할지 정해야함
mode="Line";
}
});
save.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
editorPanel.saveVector();
} //기능 구현 아직 하지 못함
});
/*read.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
editorPanel.readVector();
}
});*/
}
public String getMode() {
return mode;
}
}
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.Vector;
import javax.swing.JPanel;
public class EditorPanel extends JPanel{
private Point p1; //사각형이나 원을 그리기 위한 마우스 위치
private Point p2; //사각형이나 원을 그리기 위한 마우스 위치
private Vector<Point> vector=new Vector<Point>(); //포인트 형식으로 . 선을 그릴때 사용한다. //선 객체가 생성되는 것과 마찬가지고 , 이 벡터 객체를 따로 저장할 공간 필요.
private Vector<Vector> lists=new Vector<Vector>(); // 선 저장
private Vector<Square> squareLists=new Vector<Square>(); //사각형 좌표 객체 저장 , 벡터 컬렉션 내의 데이터는 Square class
private Vector<Circle> circleLists=new Vector<Circle>(); //사각형 좌표 객체 저장 , 벡터 컬렉션 내의 데이터는 Circle class
//벡터 바이너리파일로 저장.
private String mode=""; //EditorFrame 에서 mode 가져오기
private boolean count=false; //선 연결되는것 삭제 위함.
public EditorPanel(EditorFrame editorFrame) {
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
mode=editorFrame.getMode(); //마우스가 올려지는 순간 모드 가져오기
if(mode=="Square" || mode=="Circle") { //원이나 사각형 모드일 경우에
getMousePosition();
p1=getMousePosition();
}
}
@Override
public void mouseReleased(MouseEvent e) {
if(mode=="Line") {
lists.add(vector);
vector=new Vector<Point>();
setCount();
}
else if(mode=="Square") {
getMousePosition();
p2=getMousePosition();
squareLists.add(new Square(p1,p2)); //사각형 리스트에 저장
repaint();
revalidate();
}
else {
getMousePosition();
p2=getMousePosition();
circleLists.add(new Circle(p1,p2)); //사각형 리스트에 저장
repaint();
revalidate();
}
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) { //마우스 꾹 누를때 실행
if(mode=="Line") drawLine(); // 선 그리는 함수 실행. 사실상 벡터에 포인트 추가하는 것.
}
});
}
//도형 그리는 메소드 구현
//벡터 생성 후
public void drawLine() { //if mode==Line
if(this.count==false) {
getMousePosition();
this.count=true;
}
else vector.add(getMousePosition()); //마우스의 위치를 벡터에 추가
repaint();
revalidate(); //컴포넌트 재배치 및 다시 그리기
}
public void setCount() {
this.count=false;
}
public void paintComponent(Graphics g) { //그림판 초기화 시에 vector들 모두 초기화 해주어야 한다.
super.paintComponent(g);
// 선 그려주기
for(int i=1;i<vector.size();i++) {
g.drawLine(vector.get(i-1).x, vector.get(i-1).y, vector.get(i).x,vector.get(i).y); //선 그리기
}
for(int j=0;j<lists.size();j++) { // Vector 저장하는 Vector lists , 즉 선들을 그린다.
Vector<Point> v=lists.get(j);
for(int i=1;i<v.size();i++) {
g.drawLine(v.get(i-1).x, v.get(i-1).y, v.get(i).x,v.get(i).y); //선 그리기
}
}
// 사각형 그려주기
for(int i=0;i<squareLists.size();i++) {
Point p1=squareLists.get(i).p1;
Point p2=squareLists.get(i).p2;
int width=p2.x-p1.x;
int height=p2.y-p1.y;
g.drawRect(p1.x, p1.y, width, height);
}
//원 그려주기
for(int i=0;i<circleLists.size();i++) {
Point p1=circleLists.get(i).p1;
Point p2=circleLists.get(i).p2;
int width=p2.x-p1.x;
int height=p2.y-p1.y;
g.drawOval(p1.x, p1.y, width, height);
}
}
/*public void saveVector() {
// 1. 스트림 생성
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(new File("C:/Users/keonh/OneDrive/Desktop/객체지향언어2/eclipse프로젝트/CodingCamp/test.bin")));
// 2. 객체 스트림에 기록
oos.writeObject(vector);
oos.writeObject(lists);
oos.writeObject(squareLists);
oos.writeObject(circleLists);
// 3. 스트림의 내용 분출
oos.flush();
} catch(Exception e){
System.out.println("오류 발생");
}
}*/
}
class Square{
Point p1;
Point p2;
public Square(Point p1,Point p2) {
this.p1=p1;
this.p2=p2;
}
}
class Circle{
Point p1;
Point p2;
public Circle(Point p1,Point p2) {
this.p1=p1;
this.p2=p2;
}
}
EditorPanel.java파일 , 구현 시 컬렉션 객체에 저장되어있는 데이터들을 입출력을 구현하고 싶었는데 벡터 형식으로 저장되어있는 (선,원,사각형)을 나타내기 위한 Point 데이터를 저장하는 방식이 서로 다르기에 선 벡터 객체, 원 벡터 객체, 사각형 벡터 객체 각각 따로 저장을 하였는데 그 여러 벡터들을 저장은 할 수 있겠지만 나중에 데이터를 불러와야할 때, 즉 입력시에 어떻게 구분하여 각각의 벡터에 넣어주어야 할 지 생각을 하지 못했다.
이부분에 대해서는 파일입출력 공부를 따로 해야겠다고 느꼈다.
그리고 마우스의 위치를 Point 객체에 받는 것을 볼 수 있는데
그 부분을 잘 보면 getMousePosition() 메소드만 호출하여 마우스 위치를 나타내는 Point 객체를 버려주는 것을 확인할 수 있다.
이유는 getMousePosition() 메소드가 마우스리스너에서 사용된 마지막 마우스의 위치를 가지고 있기 때문에 , 한 번 버려준 뒤 다시 부르면 현재의 마우스 위치 Point 객체가 저장된다.
설명을 잘 하지 못해 아쉽다.
실행 결과는 아래와 같다.
원 선택 시
사각형 선택 시
직선(곡선) 선택 시
총 7개의 java 파일로 구성된 미니프로젝트
TetrisMain.java
: TetrisFrame
객체를 생성하여 프로젝트를 실행해준다.TetrisFrame.java
: TetrisFrame
클래스을 구현하였다.GamePanel.java
: 테트리스 게임이 진행되는 JPanel을 상속받은 패널로 , 각 객체(Block 객체)를 컬렉션에 add하고 객체의 좌표를 사용하여 GamePanel의 paintComponent 메소드에서 for(int i=0;i<blockVector.size();i++)
반복문을 돌며 그리게끔 구현해주었다.Block.java
: Block
객체의 필드 , 메소드를 정의해둔 클래스 파일. Block 객체를 GamePanel에 그릴 수 있게 하기위해 위치(x , y) 필드를 주어 좌표를 나타낼 수 있도록 했고 , color 필드로 Block 의 색을 표현할 수 있게 했다.BlockThread.java
: 필드에는 스레드의 run메소드를 돌며 Block 객체를 생성 후 바로 객체를 저장하기 위한 (GamePanel에서 받아올)Vector 객체의 인스턴스를 제외하고도 여러 필드를 선언해주었고 , 메소드로는 Block객체가 실제로 Y축으로 움직이게 해주는 blockMoveY() 메소드와 스레드를 돌아가게 해주는run()
메소드로 스레드를 구현하였다. 그 외의 메소드로는 속도 조절 메소드 , wait - notify
메소드등이 있다.KeyPanel.java
: 아직 구현은 안했지만 , 이 Panel
에는 방향키를 사용하지 못할 경우를 위해 방향키를 버튼으로 구현할까 생각중이다.ScorePanel.java
: 게임 진행 중 점수를 보여주며 , 일시정지 , 게임 재개 기능을 구현한 Panel
01/10 (화요일) 오전부터 시작하여 현재 진행중에 있는 미니 프로젝트다. 일반적인 테트리스와는 다르게 사각형 블럭 하나가 떨어지며 세개의 같은색 블록이 일자 , 대각선으로 있을 때 해당 3개 블록들을 삭제시키며 점수를 추가시키는 방식이다. 여기에 추가로 코딩을 더 진행한다면 , 중간중간 아이템을 가지고있는 블록들을 내려오게 하여 게임 중 여러 방식으로 점수를 획득할 수도 있겠다.
총 9시간정도 해당 미니프로젝트를 진행하였는데 , 알고리즘 구현 시 가장 힘들었던 부분은 블록이 세개가 모이며 사라지게 해주는 조건문을 작성할 때였다. 물론 현재 구현은 했지만 , 맘에 들지는 않는다.. 결국 좋지 못한 코드인 셈이다.
현재 어느정도 구현한 상태이다. 테트리스 코드는 미니 프로젝트를 완성시키고 난 뒤 올려보도록 하겠다.
코딩 잘하는 친구에게 조금의 조언을 받았는데 , Vector 컬렉션 객체에 저장되어있는 Block 객체에 마킹을 하는 식으로 진행하면 수월하게 구현될 것이라고 말을 해줬다. 이해한 바로는 DFS (깊이 우선 탐색) 알고리즘과 비슷하게 진행하면 될 것 같은데 , 빠르게 마무리하고 남은 코딩캠프 기간동안 다른 미니프로젝트도 진행해보기 위해 첫번째 방법을 택하게 됐다.
이상으로 포스팅을 마치도록 하겠다.