[Java]Java GUI로 Snake game 구현하기 & [BOJ]백준 3190번 뱀 (Java)

2023. 6. 30. 17:31· Java/Java GUI
목차
  1. 1. Snake game 이란?
  2. 2. Java GUI 코드
  3. 1. Main.java
  4. 2. GameFrame.java
  5. 3. GamePanel.java
  6. 3. 관련 알고리즘 문제 풀이
  7. 백준 3190. 뱀

https://www.coolmathgames.com/0-snake

 

1. Snake game 이란?

Snake game은 뱀을 조종하여 먹이를 먹어 길이를 늘리는 게임입니다.

 

게임의 규칙은 간단합니다.

  1. 먹이를 먹으면 뱀의 길이가 증가한다.
  2. 뱀의 머리가 뱀의 몸이나 벽에 부딪히면 종료된다.

 

 이를 Java GUI를 통해 구현해보았습니다.

 

2. Java GUI 코드

Snake game 실행 화면


코드는 아래와 같이 세 가지 파일로 구성됩니다.

 

  1. Main.java
  2. GamePanel.java  
  3. GameFrame.java

 

1. Main.java

public class SnakeMain {
    public static void main(String[] args) {
        new GameFrame();
    }
}

2. GameFrame.java

import javax.swing.JFrame;

public class GameFrame extends JFrame{
    GameFrame() {
        this.add(new GamePanel());
        this.setTitle("Snake Game");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        this.pack();
        this.setVisible(true);
        this.setLocationRelativeTo(null);
    }

}

3. GamePanel.java

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.util.Random;

public class GamePanel extends JPanel implements ActionListener{

    static final int SCREEN_WIDTH = 400;
    static final int SCREEN_HEIGHT = 400;
    static final int UNIT_SIZE = 20;
    static final int GAME_UNIT = (SCREEN_WIDTH*SCREEN_HEIGHT)/UNIT_SIZE;
    static final int DELAY = 100; // 0.1초마다 갱신

    final int x[] = new int[GAME_UNIT]; // 뱀 형상 x 값
    final int y[]  =new int[GAME_UNIT]; // 뱀 형상 y 값

    int bodyParts = 6; //뱀의 길이
    int foodAte; // 먹이를 먹은 횟수
    int foodX; //음식의 x값
    int foodY; //음식의 r값
    char direction = 'R'; //뱀 방향
    boolean running = false; //게임 시작 조건 플래그

    Timer timer;
    Random random;

    GamePanel(){
        random  = new Random();
        this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
        this.setBackground(Color.black); //게임 배경색
        this.setFocusable(true);
        this.addKeyListener(new MyKeyAdapter());
        startGame();
    }
    public void startGame() {
        newFood(); //먹이 생성
        running = true; // 플래그값, 종료조건시 false로 변경
        timer = new Timer(DELAY, this);
        timer.start();
    }

    //게임 보드 구현
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        draw(g);
    }
    public void draw(Graphics g) {
        if (running) { // 게임이 실행중이면
            for(int i=0; i<SCREEN_HEIGHT/UNIT_SIZE;i++){
                g.drawLine(i*UNIT_SIZE, 0, i*UNIT_SIZE, SCREEN_HEIGHT);
                g.drawLine(0, i*UNIT_SIZE, SCREEN_WIDTH, i*UNIT_SIZE);
            }
            g.setColor(Color.ORANGE); // 먹이색깔
            g.fillOval(foodX, foodY, UNIT_SIZE, UNIT_SIZE); // 먹이 원모양으로 좌표만큼

            for(int i = 0; i<bodyParts; i++){ // 뱀 형상
                if(i == 0){ // 뱀 머리 부분
                    g.setColor(Color.GREEN);
                    g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);
                }else{ // 나머지 부분
                    g.setColor(new Color(45, 100, 0));
                    g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);
                }
            }
            //먹이를 얼마나 먹었는지 score를 표현하기 위함
            g.setColor(Color.WHITE);
            g.setFont(new Font("Ink FREE", Font.BOLD, 30));
            FontMetrics metrics  =getFontMetrics(g.getFont());
            g.drawString("SCORE: "+foodAte,
                    (SCREEN_WIDTH-metrics.stringWidth("SCORE: "+foodAte))/2,
                    g.getFont().getSize());
        }
        else{
            gameOver(g); //게임 오버 창 표시
        }
    }
    public void move() {
        for(int i = bodyParts; i>0; i--){
            x[i] = x[i-1];
            y[i] = y[i-1];
        }
        switch(direction){
            case 'U':
                y[0] = y[0] - UNIT_SIZE;
                break;
            case 'D':
                y[0] = y[0] + UNIT_SIZE;
                break;
            case 'L':
                x[0] = x[0] - UNIT_SIZE;
                break;
            case 'R':
                x[0] = x[0] + UNIT_SIZE;
                break;
        }
    }
    public void newFood(){
        foodX =random.nextInt((int)(SCREEN_WIDTH/UNIT_SIZE))*UNIT_SIZE;
        foodY =random.nextInt((int)(SCREEN_HEIGHT/UNIT_SIZE))*UNIT_SIZE;
    }
    public void checkFood(){
        if((x[0]==foodX)&&(y[0]==foodY)){
            bodyParts++;
            foodAte++;
            newFood();
        }
    }
    public void checkCollision() {
        //뱀 머리가 몸통과 충돌하는지 체크
        for(int i= bodyParts; i>0; i--){
            if((x[0] == x[i])&&y[0]==y[i]){
                running = false;
            }
        }
        //뱀 머리가 경계선 벗어났는지 체크
        if(x[0]<0){
            running = false;
        }
        if(x[0]>SCREEN_WIDTH){
            running = false;
        }
        if(y[0]<0){
            running =false;
        }
        if(y[0]>SCREEN_HEIGHT){
            running =false;
        }
        if (!running) {
            timer.stop();
        }

    }
    public void gameOver(Graphics g) {
        g.setColor(Color.WHITE);
        g.setFont(new Font("Ink FREE", Font.BOLD, 75));
        FontMetrics metrics  =getFontMetrics(g.getFont());
        g.drawString("GAME OVER", (SCREEN_WIDTH-metrics.stringWidth("Game Over"))/2, SCREEN_HEIGHT/2);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if(running){
            move();
            checkFood();
            checkCollision();
        }
        repaint();

    }
    public class MyKeyAdapter extends KeyAdapter{
        @Override
        public void keyPressed(KeyEvent e) {
            switch (e.getKeyCode()) {
                case KeyEvent.VK_LEFT:
                    if(direction!='R'){
                        direction = 'L';
                    }
                    break;
                case KeyEvent.VK_RIGHT:
                    if(direction!='L'){
                        direction = 'R';
                    }
                    break;
                case KeyEvent.VK_UP:
                    if(direction!='D'){
                        direction = 'U';
                    }
                case KeyEvent.VK_DOWN:
                    if(direction!='U'){
                        direction = 'D';
                    }

                default:
                    break;
            }
        }
    }
}

 

 

 

3. 관련 알고리즘 문제 풀이

백준 3190. 뱀

문제

https://www.acmicpc.net/problem/3190

 

3190번: 뱀

'Dummy' 라는 도스게임이 있다. 이 게임에는 뱀이 나와서 기어다니는데, 사과를 먹으면 뱀 길이가 늘어난다. 뱀이 이리저리 기어다니다가 벽 또는 자기자신의 몸과 부딪히면 게임이 끝난다. 게임

www.acmicpc.net


소스코드

import java.util.*;

public class B3190_뱀 {

    static int N, time;
    static int direction;
    static int head_r, head_c;
    static int[][] board;

    static int[] dr = {0,1,0,-1};
    static int[] dc = {1,0,-1,0};
    static Map<Integer, String> map = new HashMap<>();

    public static void main(String[] args) {
        input();
        play();
        System.out.println(time+1);
    }

    static void play(){
        Queue<int[]> snakeBody = new LinkedList<>(); //head
        head_r = 0;
        head_c = 0;
        time = 0;
        direction = 0; // 0 오 / 1 아 / 2 왼 / 3 위
        board[0][0] = 1;

        snakeBody.add(new int[]{0,0});

        while(true) {
            if(map.containsKey(time)){
                if(map.get(time).equals("L")) {
                    direction = direction-1;
                    if(direction<0) direction = 4+direction;
                }
                if(map.get(time).equals("D")){
                    direction = direction+1;
                    if(direction>=4) direction = direction-4;
                }
            }
            head_r += dr[direction];
            head_c += dc[direction];
            //다음 머리

            if(head_r<0||head_c<0||head_r>=N||head_c>=N) break;
            if(board[head_r][head_c]==1) break;

            if(board[head_r][head_c]==0){
                board[head_r][head_c] = 1;
                snakeBody.add(new int[]{head_r,head_c});
                int[] tail = snakeBody.poll();
                board[tail[0]][tail[1]] = 0;
            }

            if(board[head_r][head_c]==2){
                board[head_r][head_c] = 1;
                snakeBody.add(new int[]{head_r,head_c});
            }
            time++;
        }
    }
    
    static void input(){
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        board = new int[N][N];

        int K = sc.nextInt();
        for(int i = 0; i<K;i++){
            int r = sc.nextInt()-1;
            int c = sc.nextInt()-1;
            board[r][c] = 2;
        }
        int L = sc.nextInt();
        for(int i =0;i<L;i++){
            int sec = sc.nextInt();
            String C = sc.next(); //L: 왼쪽 / D: 오른쪽
            map.put(sec,C);
        }
    }
}
  1. 1. Snake game 이란?
  2. 2. Java GUI 코드
  3. 1. Main.java
  4. 2. GameFrame.java
  5. 3. GamePanel.java
  6. 3. 관련 알고리즘 문제 풀이
  7. 백준 3190. 뱀
동구름이
동구름이
동구름동구름이 님의 블로그입니다.
동구름이
동구름
동구름이
전체
오늘
어제
  • 분류 전체보기 (178)
    • Java (63)
      • Java 를 파헤쳐보자 (13)
      • BOJ (45)
      • 프로그래머스 (3)
      • SWEA (1)
      • Java GUI (1)
    • JavaScript (17)
      • JS를 파헤쳐보자 (7)
      • 프로그래머스 (7)
      • JS 학습 정리 (1)
    • Backend (33)
      • Spring (3)
      • HTTP (7)
      • 프로젝트 (10)
      • MySQL (6)
      • Redis (3)
      • Elastic Search (1)
      • 인증, 인가 (3)
    • CS (57)
      • 운영체제 (35)
      • Network (22)
    • Git (2)
    • 개발 관련 이것저것 (2)
    • etc (1)
    • 독서 (0)
    • 사설 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • OS
  • 구현
  • JCF
  • 모든 개발자를 위한 HTTP 웹 기본 지식
  • 스택
  • 네트워크
  • 자바
  • 프로그래머스
  • 이석복
  • 운영체제
  • 한양대
  • 자바스크립트
  • 백준
  • BOJ
  • 큐
  • 반효경
  • 인프런
  • 레디스
  • Java
  • 김영한

최근 글

hELLO · Designed By 정상우.v4.2.2
동구름이
[Java]Java GUI로 Snake game 구현하기 & [BOJ]백준 3190번 뱀 (Java)
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.