이전까지는 사실 강의에서 나온대로 거의 그대로 만들었지만, 이번에는 나만의 기능들을 추가해서 만들어보았다.
게임에 추가되는 기능은 다음과 같다.
1. DAO, VO, DTO :
- DAO 는 DB 와 연결하기 위해서 만들어두는 클래스 DataBase Access Object
- DTO 는 ValueObject DB 에서 가져온 데이터를 저장하고 db 레코드와 데이터를 매핑하기 위한 클래스이다.
- 아래 코드에 전부 VO 로 되어있는데 공부하다보니 VO 가 아니라 DTO 를 사용했었던거네요ㅠ.ㅠ 확인하시고 봐주시면 감사하겠습니다
- VO라는 것도 있는데 사실 VO 랑 비슷한 느낌으로 쓰인다. 이 3가지는 나중에 한번 더 정리하겠다.
2. 로그인 창 : 게임 실행 시 로그인 창이 존재하고 로그인 후 게임 실행이 가능하도록
3. 게임이 끝난 뒤 점수창 출력 : 본인의 점수와 콤보수 를 종합한 랭크를 출력한다.
4. 게임이 실행된 후 음악 선택 화면에서 SCORE BOARD 를 출력해서 각 음악별 가장 점수가 높은 5명을 출력한다.
코드에 대한 설명은 대부분 주석을 달아두었기 때문에 주석을 참고하는 것이 훨~~씬 좋을 것이고, 특히나 중요한 본인의 점수&콤보수 음악 선택 화면에서 score board 를 출력하는 부분만 추가적으로 설명하겠다.
혹은 아래의 git 에서 코드에 있는 주석과 readme 를 참고해주시기 바랍니다!!
https://github.com/SeJonJ/DynamicMusic.git
1. DAO
- DAO 에는 Spring 쪽 member table 과 연동하여 해당 table 정보를 끌고와서 로그인하고, 로그인한 사용자로 게임 진행 시 최종 점수를 저장하고, 게임 노래별로 점수를 출력할 수 있게 하는 등 전체적인 DB 연동 및 DB 에서 정보를 가져오는 역할을 한다.
- 상속받은 DB_info 클래스에는 DB에 관한 정보가 담겨있는 추상 클래스이다. 해당 글래스에 DB 주소, 로그인정보 등이 담겨있고, 그 정보들을 상속받아서 사용한다.
package DynamicMusic;
import java.sql.*;
import java.util.ArrayList;
public class LoginDAO extends DB_info {
// DB 연결을 위한 statement, resultSet
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql;
// 사용자가 입력한 ID, PW
private String loginID;
private String loginPW;
// DB에서 가져온 ID PW
private int getMemberCODE;
private String getID;
public LoginDAO() {
try {
conn = DriverManager.getConnection(getHjDB(), getUser(), getPasswd());
} catch (SQLException e) {
System.out.println("DB conn 에러 : " + e.getMessage());
e.printStackTrace();
}
}
public boolean loginStart() {
sql = "SELECT MEMBER_CODE, MID, MPASSWD FROM MEMBER WHERE MID = ? AND MPASSWD = ?";
try {
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, loginID);
pstmt.setString(2, loginPW);
rs = pstmt.executeQuery();
// System.out.println("현재 멤버 코드 : "+getMemberCODE);
// System.out.println("현재 아이디 : "+getID);
// System.out.println("현재 패스워드 : "+getPW);
if (rs.next()) {
getMemberCODE = rs.getInt("MEMBER_CODE");
getID = rs.getString("MID");
System.out.println("로그인 정보 확인 로그인 완료");
return true;
}
return false;
} catch (Exception e) {
System.out.println("SQL 에러 발생 : " + e.getMessage());
return false;
}
}
public void scoreUpdate(int highscore, int highcombo, String musicName) {
// System.out.println("최고 스코어 : "+highscore);
// System.out.println("최고 콤보 : "+highcombo);
try{
if (musicName.equals("DAYBREAK FRONTLINE")) {
sql = "UPDATE DMUSIC SET DF_SCORE = ?, DF_COMBO = ? WHERE MEMBER_CODE = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, highscore);
pstmt.setInt(2, highcombo);
// pstmt.setInt(3, getMemberCODE);
pstmt.setInt(3, getMemberCODE);
pstmt.executeUpdate();
// conn.commit();
System.out.println("점수 입력 완료");
} else if (musicName.equals("Lose Yourself - Eminem")) {
sql = "UPDATE DMUSIC SET LYS_SCORE = ?, LYS_COMBO = ? WHERE MEMBER_CODE = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, highscore);
pstmt.setInt(2, highcombo);
pstmt.setInt(3, getMemberCODE);
pstmt.executeUpdate();
// conn.commit();
} else if (musicName.equals("TheFatRat - The Calling")) {
sql = "UPDATE DMUSIC SET TFR_SCORE = ?, TFR_COMBO = ? WHERE MEMBER_CODE = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, highscore);
pstmt.setInt(2, highcombo);
pstmt.setInt(3, getMemberCODE);
pstmt.executeUpdate();
// conn.commit();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public ArrayList<UserVO> scorePanel(String musicName){
ArrayList<UserVO> list = new ArrayList<UserVO>();
try {
// 노래에 맞춰 SQL 변경
if(musicName.equals("DAYBREAK FRONTLINE")) {
sql = "SELECT M.MNAME AS NAME, D.DF_SCORE AS SCORE FROM MEMBER M NATURAL JOIN DMUSIC D ORDER BY DF_SCORE DESC LIMIT 5";
}else if(musicName.equals("Lose Yourself - Eminem")){
sql = "SELECT M.MNAME AS NAME, D.LYS_SCORE AS SCORE FROM MEMBER M NATURAL JOIN DMUSIC D ORDER BY LYS_SCORE DESC LIMIT 5";
}else if(musicName.equals("TheFatRat - The Calling")){
sql = "SELECT M.MNAME AS NAME, D.TFR_SCORE AS SCORE FROM MEMBER M NATURAL JOIN DMUSIC D ORDER BY TFR_SCORE DESC LIMIT 5";
}
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
// rs.next();
// System.out.println(rs.getString("D.MEMBER_CODE"));
while (rs.next()) {
String name = rs.getString("NAME");
int score = rs.getInt("SCORE");
list.add(new UserVO(name, score));
// System.out.println(name+" : "+score);
}
return list;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
private void closeDB() {
try {
if (rs != null) {
rs.close();
}
if (pstmt != null) {
pstmt.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
// System.out.println("자원 반납 완료");
}
public String getLoginID() {
return loginID;
}
public void setLoginID(String loginID) {
this.loginID = loginID;
}
public String getLoginPW() {
return loginPW;
}
public void setLoginPW(String loginPW) {
this.loginPW = loginPW;
}
public String getGetID() {
return getID;
}
// public static void main(String[] args) {
// LoginDAO dao = new LoginDAO();
//// dao.scoreUpdate(50,50,"DAYBREAK FRONTLINE");
//
// ArrayList<UserVO> list = dao.scorePanel("TheFatRat - The Calling");
// for(UserVO user : list){
// System.out.println(user.getName() + " : "+user.getScoreTFR());
// }
//
// }
}
2. LoginFrame
- 로그인 프레임 클래스는 로그인 GUI 창을 띄우기 위한 클래스이다. 게임 실행 이전에 로그인 프레임 클래스가 먼저 실행되고, 해당 클래스에서 loginDAO 에 있는 loginStart() 클래스를 실행하고 true 를 반납할때만 게임이 실행되도록 한다.
- 만약 false 인 경우 "로그인 에러" 창이 뜨게된다.
package DynamicMusic;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class LoginFrame extends JFrame {
// DB 접속 클래스
LoginDAO loginDAO = new LoginDAO();
JPanel jp = new JPanel();
JButton jbtnLogin;
JButton jbtnRegister;
JTextField jtfID;
// Password 암호화해서 보이게하는것은 JTextField 가 아니라 JPasswordField
JPasswordField jtfPW;
JLabel jlbID, jlbPW;
private boolean loginResult;
public void loginWindow(){
jp.setLayout(null);
jlbID = new JLabel("ID");
jlbID.setBounds(180,50,50,20);
jp.add(jlbID);
jlbPW = new JLabel("Password");
jlbPW.setBounds(150,100,60,20);
jp.add(jlbPW);
jtfID = new JTextField();
jtfID.setBounds(230,50,100,20);
jp.add(jtfID);
jtfPW = new JPasswordField();
jtfPW.setBounds(230,100,100,20);
jp.add(jtfPW);
jbtnLogin = new JButton("login");
jbtnLogin.setBounds(150,175,100,50);
jbtnLogin.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
loginDAO.setLoginID(jtfID.getText());
loginDAO.setLoginPW(String.valueOf(jtfPW.getPassword()));
if (loginDAO.loginStart()){
// 한개의 창만 닫기 : 현재 창만 닫음
dispose();
// DynamicMusic 게임 시작
// DynamicMusic 클래스
DynamicMusic dynamicMusic = new DynamicMusic(loginDAO);
dynamicMusic.musicStart();
}else{
System.out.println("로그인 실패");
JOptionPane.showConfirmDialog(jlbID,"로그인 정보를 확인해주세요","로그인 에러",JOptionPane.DEFAULT_OPTION);
}
}
});
jp.add(jbtnLogin);
jbtnRegister = new JButton("회원가입");
jbtnRegister.setBounds(300,175,100,50);
jp.add(jbtnRegister);
add(jp);
setTitle("Login");
setSize(600,300);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(null);
setFocusable(true);
}
}
3. UserDTO
- userDTO 는 DB 에서 정보를 가져오고 DB 에 정보를 저장하기위한 통로로서 사용된다. 즉 DB 의 각 엔티티와 매칭되어 엔티티에 정보를 저장하고, 꺼내와서 사용하기 위해 사용한다고 생각하면 편하다.
package DynamicMusic;
public class UserVO {
String name;
int scoreDF;
int scoreLYS;
int scoreTFR;
public UserVO(String name, int score){
this.name = name;
this.scoreTFR = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScoreDF() {
return scoreDF;
}
public void setScoreDF(int scoreDF) {
this.scoreDF = scoreDF;
}
public int getScoreLYS() {
return scoreLYS;
}
public void setScoreLYS(int scoreLYS) {
this.scoreLYS = scoreLYS;
}
public int getScoreTFR() {
return scoreTFR;
}
public void setScoreTFR(int scoreTFR) {
this.scoreTFR = scoreTFR;
}
}
4. scoreResult
- scoreResult 클래스는 게임이 종료 된 후 점수와 콤보를 출력하기 위한 클래스이다.
- Thread 를 사용해서 run 메소드가 실행되면 graphics 를 이용해서 점수 화면 그림과 최고 점수와 현재 콤보수, 점수에 해당하는 랭크를 출력한다 -> 최고 점수와 콤보를 저장하는 메소드는 DAO 클래스에 있고, DynamicMusic 클래스에서 실행한다.
package DynamicMusic;
import javax.swing.*;
import java.awt.*;
public class scoreResult extends Thread {
private Image scoreResult = new ImageIcon(getClass().getResource("/menu_images/scoreResult.png")).getImage();
Graphics2D g;
public scoreResult(Graphics2D g){
this.g = g;
}
public void screenDraw(Graphics2D g){
String grade=null;
int totalScore = DynamicMusic.game.score;
int totalCombo = DynamicMusic.game.combo;
// int totalScore = 1000;
// int totalCombo = 50;
if(totalScore > (300*100*0.9)) {
grade = "S";
}else if(totalScore > (300*100*0.6)) {
grade = "A";
}else if(totalScore > (300*100*0.4)) {
grade = "B";
}else if(totalScore >= 0) {
grade = "C";
}
g.drawImage(scoreResult, 240, 70, null);
g.setFont(new Font("Arial", Font.BOLD, 100));
g.setColor(Color.white);
g.drawString("Score : "+String.valueOf(totalScore), 350, 290);
g.drawString("Combo : "+String.valueOf(totalCombo), 350,400);
g.setColor(Color.pink);
g.drawString(grade, 600, 500);
}
@Override
public void run() {
screenDraw(g);
}
public void close(){
interrupt();
}
}
5. DynamicMusic, Game 클래스
- 이 두 클래스는 각 기능들이 추가될 때마다 정말 많이 바뀌었다. 그에 따라서 코드도 많이 길어졌기 때문에 아무래도 블로그에 전체 코드를 올릴 수는 없을 듯 하다.
- 그나마 가장 크게 바뀐 것은 게임의 배경이 일반적인 jpg 가 아닌 gif 로 바뀌었다는 점이다. 이렇게 바뀌었기 때문에 코드도 바꾸었는데 이 부분만큼은 한번 정리하고 넘어가겠다 => 고치는데 너무 힘들었어서 기억하기 위해서ㅠㅠ
- Jframe 에서 GIF를 사용하는 방법은 URL 클래스를 사용하는 것이다. 물론 다른 방법도 있지만 URL 객체를 사용하는 가장 큰 이유는 JFrame 외에도 추후 Jar 파일로 빌드하였을 때에도 에러 없이 실행하기 위해서이다.
- 즉 바로 Image 를 사용해서 읽어오는 것이 아니라 URL 클래스를 이용해서 GIF 파일을 한 번 읽어온 후 다시 ImageIcon 으로 형변환하여 저장하면 무난하게 GIF 를 읽어올 수 있게 된다.
- 물론 이후 Graphic 를 사용해서 그래픽 작업은 하는 것은 Image 와 동일하다. 이것을 잘만 사용하면 게임이 실행되는 화면에서도 배경으로 gif 를 보여줄 수 있을 것 같은데 다만 원활하게 실행하기 위해서는 Thread 를 통해서 실행해야할 듯하고, 그 후 쓰레드를 좀 더 잘 쓰게? 재정리하는 과정이 필요할 듯 하다.
// URL 객체를 사용하면 gif 를 graphic 에 띄울 수 있다
URL bakgroundGIF = getClass().getResource("/menu_images/Intro_bakground.gif");
private Image introBackground= new ImageIcon(bakgroundGIF).getImage();
6. 실행 사진
- 원래는 동영상으로 찍고 싶었지만 사진으로 대체한다.
- 내가 로그인한 super 라는 유저가 보이는 것을 확인할 수 있다
- 해당 곡의 1~5위 까지를 보여준다.
'토이 프로젝트 > Spring&Java 갖고놀기' 카테고리의 다른 글
DataPlay project - 1 : word cloud 생성기 코드 정리 (0) | 2022.05.10 |
---|---|
DataPlay project - 1 : java로 Word Cloud 생성기- 크롤링, API, JSON (0) | 2022.05.04 |
자바 리듬 게임 만들기(4) (0) | 2022.03.23 |
자바 리듬 게임 만들기(3) (0) | 2022.03.22 |
자바 리듬 게임 만들기 (2) : Game(feat. 노트찍기모드) (0) | 2022.03.21 |
댓글