내 생각 중요 코드 - LeaderBoard 중 DB
private void loadMySQLDriver() {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("MySQL JDBC Driver loaded successfully");
} catch (ClassNotFoundException e) {
System.out.println("Error loading MySQL JDBC Driver: " + e.getMessage());
e.printStackTrace();
}
}
이 메서드는 MySQL JDBC 드라이버를 로드해요!
만약 드라이버가 없으면 예외를 출력하는 코드예요!
private static final String DB_URL = "jdbc:mysql://localhost:3306/mypickjump";
private static final String USER = "newuser";
private static final String PASS = "password";
그리고 여기서는 데이터베이스 연결에 필요한 URL, 사용자명, 비밀번호를 설정해요!
제가 터미널에서 데이터베이스를 생성할 때 이름을 mypickjump 로 했고, 제 이름은 newuser 그리고 비번은 password 라고 했어요!
private void saveScore(String nickname, int distance) {
String selectSql = "SELECT distance FROM scores WHERE nickname = ?";
String insertSql = "INSERT INTO scores(nickname, distance) VALUES(?, ?)";
String updateSql = "UPDATE scores SET distance = ? WHERE nickname = ?";
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
PreparedStatement selectStmt = conn.prepareStatement(selectSql);
PreparedStatement insertStmt = conn.prepareStatement(insertSql);
PreparedStatement updateStmt = conn.prepareStatement(updateSql)) {
selectStmt.setString(1, nickname);
ResultSet rs = selectStmt.executeQuery();
if (rs.next()) {
int existingDistance = rs.getInt("distance");
if (distance > existingDistance) {
updateStmt.setInt(1, distance);
updateStmt.setString(2, nickname);
updateStmt.executeUpdate();
System.out.println("Score updated for " + nickname);
} else {
System.out.println("Existing score is higher, not updated");
}
} else {
insertStmt.setString(1, nickname);
insertStmt.setInt(2, distance);
insertStmt.executeUpdate();
System.out.println("New score inserted for " + nickname);
}
} catch (SQLException e) {
System.out.println("Error saving/updating score: " + e.getMessage());
e.printStackTrace();
}
}
닉네임을 기반으로 점수를 조회하고, 닉네임이 똑같으면 현재 점수와 기존 점수를 비교하여 더 큰 값이 들어가는 코드입니다.
SELECT 문으로 해당 닉네임의 기존 점수를 조회 후,
데이터가 있으면 두 개의 점수를 비교한 후 새 점수가 더 크면 UPDATE 를 실행합니다.
만약 데이터가 없다면 INSERT 문으로 새로운 닉네임과 점수를 삽입합니다.
private List<PlayerScore> getTopScores() {
List<PlayerScore> scores = new ArrayList<>();
String sql = "SELECT nickname, MAX(distance) as max_distance FROM scores GROUP BY nickname ORDER BY max_distance DESC";
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
String nickname = rs.getString("nickname");
int distance = rs.getInt("max_distance");
scores.add(new PlayerScore(nickname, distance));
System.out.println("Retrieved: " + nickname + " - " + distance);
}
} catch (SQLException e) {
System.out.println("Error getting top scores: " + e.getMessage());
e.printStackTrace();
}
return scores;
}
데이터베이스에서 상위 점수를 가져옵니다.
GROUP BY 와 MAX(distance) 를 사용하여 닉네임별 최고 점수를 조회합니다.
점수를 내림차순으로 정렬합니다.
내 생각 중요 코드 - Gamemain
// 점프 로직
jumpVelocity -= GRAVITY; // 점프 속도 감소 (중력 효과)
jumpHeight += jumpVelocity; // 점프 높이 계산
if (jumpHeight <= 0) {
// 캐릭터가 땅에 도달했을 때
jumpHeight = 0; // 점프 높이를 초기화
jumpVelocity = 0; // 속도 초기화
jumpCount = 0; // 점프 횟수 초기화
isJumping = false; // 점프 상태 해제
}
이 코드는 캐릭터가 점프하는 동작을 처리합니다.
중력 효과를 사용하여 캐릭터가 땅에 도달하면 점프 상태와 속도를 초기화합니다.
더블 점프도 가능하게 하였습니다. 위에서 최대 점수 횟수는 2 로 초기화 했답니다.
// 장애물 이동 및 충돌 검사
Rectangle characterBounds = getCharacterBounds();
for (Iterator<Rectangle> it = obstacles.iterator(); it.hasNext();) {
Rectangle obstacle = it.next();
obstacle.x -= backgroundSpeed; // 장애물 이동
// 충돌 감지
if (characterBounds.intersects(obstacle)) {
gameOver(); // 게임 오버 처리
return;
}
// 화면 밖으로 나간 장애물 제거
if (obstacle.x + obstacle.width < 0) {
it.remove();
}
}
장애물 충돌 및 이동 코드로, 장애물의 위치를 업데이트하면서 캐릭터와의 충돌을 감지합니다.
충돌 시 gameOver() 메서드를 호출해 게임 오버 상태로 전환하고,
만약 장애물이 화면 밖으로 나가면 리스트에서 제거하여 메모리를 효율적으로 사용합니다.
private void gameOver() {
timer.stop(); // 게임 루프 타이머 중지
isGameOver = true; // 게임 오버 상태 설정
repaint(); // 화면 갱신
// 1초 후에 게임 재시작 화면으로 전환
Timer restartTimer = new Timer(1000, e -> {
((Timer) e.getSource()).stop(); // 타이머 종료
SwingUtilities.invokeLater(() -> {
parentFrame.switchToRestart(distance); // 점수 데이터를 전달하며 재시작 화면으로 전환
});
});
restartTimer.setRepeats(false); // 한 번만 실행
restartTimer.start();
}
이 부분은 캐릭터와 장애물이 충돌했을 때 게임을 종료하는 로직입니다.
돌고 있던 게임 루프를 멈추고 게임 오버 상태를 true 로 만듭니다.
1초 후에 닉네임 입력 화면으로 전환되도록 타이머를 설정했습니다.
내 생각 중요 코드 - ChooseChr
private void handleMouseClick(int mouseX, int mouseY) {
// 왼쪽 화살표 클릭
if (mouseX >= (getWidth() / 2 - 230) && mouseX <= (getWidth() / 2 - 230 + leftarrowImage.getWidth() * 0.8)
&& mouseY >= (getHeight() / 2 - leftarrowImage.getHeight() * 0.8 / 2)
&& mouseY <= (getHeight() / 2 + leftarrowImage.getHeight() * 0.8 / 2)) {
moveLeft();
return;
}
// 오른쪽 화살표 클릭
if (mouseX >= (getWidth() / 2 + 230) && mouseX <= (getWidth() / 2 + 230 + rightarrowImage.getWidth() * 0.8)
&& mouseY >= (getHeight() / 2 - rightarrowImage.getHeight() * 0.8 / 2)
&& mouseY <= (getHeight() / 2 + rightarrowImage.getHeight() * 0.8 / 2)) {
moveRight();
return;
}
// 캐릭터 이미지 클릭
int imgX = (getWidth() - (int)(charactorImages.get(index).getWidth() * scaleFactor)) / 2;
int imgY = (getHeight() - (int)(charactorImages.get(index).getHeight() * scaleFactor)) / 2;
if (mouseX >= imgX && mouseX <= imgX + charactorImages.get(index).getWidth() * scaleFactor &&
mouseY >= imgY && mouseY <= imgY + charactorImages.get(index).getHeight() * scaleFactor) {
selectCharacter();
}
}
이 코드는 캐릭터를 선택하는 코드입니다.
왼쪽, 오른쪽 화살표 클릭을 통해 캐릭터를 이동시켜 캐릭터 이미지를 클릭하여 선택할 수 있는 로직입니다.
왼쪽과 오른쪽 화살표 클릭 코드가 다른 이유는 왼쪽은 음수가 발생할 수도 있기 때문이에요!
handleMouseClick() 메서드는 마우스 클릭 이벤트에 따라 캐릭터 인덱스를 변경하거나 캐릭터를 선택합니다.
private void startZoomEffect() {
if (zoomTimer != null && zoomTimer.isRunning()) {
zoomTimer.stop();
}
zoomTimer = new Timer(20, e -> {
scaleFactor += 0.05; // 확대 속도 조절
if (scaleFactor >= 1.0) { // 최대 확대 비율 설정
scaleFactor = 1.0;
zoomTimer.stop();
transitionTimer.start(); // 확대가 완료되면 전환 타이머 시작
}
repaint();
});
zoomTimer.start();
}
이 코드에서는 캐릭터 이미지가 선택될 때 확대되는 애니메이션을 구현한 코드입니다.
캐릭터가 확대되면 transitionTimer 을 통해 게임 메인 화면을 돌아갑니다.
내 생각 중요 코드 - Restart
nicknameField = new JTextField(10) {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (getText().isEmpty()) {
g.setColor(Color.GRAY);
g.setFont(getFont().deriveFont(Font.ITALIC));
g.drawString("6글자 이내", getInsets().left, g.getFontMetrics().getMaxAscent() + getInsets().top + 20);
}
}
};
nicknameField.setFont(parent.getGalmuriFont().deriveFont(24f));
nicknameField.setForeground(Color.BLACK);
nicknameField.setCaretColor(Color.BLACK);
nicknameField.setOpaque(false);
nicknameField.setBorder(BorderFactory.createEmptyBorder());
nicknameField.requestFocusInWindow();
// 6글자 제한 설정
((AbstractDocument)nicknameField.getDocument()).setDocumentFilter(new DocumentFilter() {
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
String string = fb.getDocument().getText(0, fb.getDocument().getLength()) + text;
if (string.length() <= 6) {
super.replace(fb, offset, length, text, attrs);
}
}
});
닉네임 필드에 6글자 이내 라는 힌트를 표시하고, JTextField 를 커스터마이징하여 텍스트가 없는 상태에서만 힌트가 보이도록 하였습니다.
DocumentFilter 를 사용하여 입력된 닉네임이 6글자를 초과하지 않도록 제한하였습니다.
내 생각 중요 코드 - MypickJump
public void switchToChooseChr() {
getContentPane().removeAll();
chooseChrPanel.resetSelection();
chooseChrPanel.setInitialIndex(0);
add(chooseChrPanel, BorderLayout.CENTER);
revalidate();
repaint();
chooseChrPanel.requestFocusInWindow();
}
다양한 화면 간의 전환을 책임지는 메소드입니다.
이전에 선택한 캐릭터 정보를 초기화할 수 있도록 하였습니다.
// BGMPlayer 인스턴스 생성 및 음악 재생
bgmPlayer = new BGMPlayer();
bgmPlayer.playMusic(); // 음악 재생 호출
BGMPlayer 클래스를 통해 배경 음악을 재생합니다.
'두런두런 회고록 . . . =)' 카테고리의 다른 글
2학기 나의 성적에 대하여 . . =) (1) | 2025.01.03 |
---|---|
혼공스 회고록 (0) | 2024.08.18 |
제 14회 e-ICON을 마무리 하며 . . . (0) | 2024.08.09 |
내 기말고사 1학기 성적에 관하여 . . . (0) | 2024.07.16 |