본문 바로가기
Team Project/Strikers 1945 GUI Project

[개발 일지] Strikers 1945 게임 구현 프로젝트 0일차 (02/22)

by 스응 2023. 2. 23.
728x90
728x90

팀 프로젝트 주제

Swing을 이용하여 Strikers 1945 게임 구현하기

 

프로젝트 기간

2023/02/23 ~ 2023/02/27

 

 

 


첫 팀 프로젝트를 진행하게 되었다. 주제는 Java Swing을 이용해 GUI 게임을 구현하는 것이다.

우리 팀은 Strikers 1945라는 비행기 게임을 만들게 되었다.

원래 프로젝트 기간은 23일부터인데, 주제를 일찍 정해서 남는 시간동안 클래스 틀을 조금 만들어보기로 했다.

우선 주요 클래스는 AirlineFrame (메인프레임), Player, Enemy, Item, Bullet 정도.

나는 적군(Enemy) 클래스를 중점적으로 맡아서 설계하기로 했다. 적군 비행기의 종류에 따라 스텟을 다르게 설정하기, 적군을 한 번에 여러 개씩 생성하기 등등 고려할 것이 많았지만, 초반이니까 기본 틀부터 만들었다.

 

0일차의 목표

(패턴이 일정하면 지루하니까) 이동 방향과 이동 거리를 항상 랜덤으로 결정해서 움직이게 하자.

 

멤버 변수

public class Enemy extends JLabel implements Moveable {

// 생존 여부 (살아 있음 : 0, 죽음 : 1)
private int alive;

// 위치 상태
private int x;
private int y;

// 적군의 방향
private EnemyWay enemyWay;

// 움직임 상태 (움직이지 않음 : false)
private boolean left;
private boolean right;
private boolean up;
private boolean down;

// 적군 속도 상태
private final int SPEED = 2;

// 이미지
private ImageIcon enemyImage;

 

 

속도는 지금은 상수로 사용하고 있는데, 나중에 적군 종류별로 나눌 때는 변수로 바꿀 것이다.

 

 

랜덤한 이동 거리

@Override
public void left() {

    // 적군의 현재 x 좌표 저장
    int currentX = this.getX();

    // 최대 이동 거리 (여유 50)
    int tempX = currentX - 50;

    // 이동할 거리
    int goX = (int) (currentX * Math.random());

    new Thread(() -> {
        left = true;
        for (int i = 0; i < (goX / SPEED); i++) {
            // 적군이 죽었거나, 왼쪽 벽에 부딪치면 중단
            if (alive == 1 || left == false) {
                return;
            }
            x = x - SPEED;
            setLocation(x, y);

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();
    left = false;
} // end of left

 

 

Math.random();은 0부터 1까지의 소수로 된 난수를 반환하는 메서드. 이를 이용해서 이동 거리를 랜덤으로 결정했다.

쓰레드로 자연스럽게 움직이게 했다. 나중에 적군 종류를 나누게 되면, 이동 메서드에 speed를 매개변수로 받아서 사용할 것이다.

 

반응형
728x90

 

화면 밖으로 나가지 않게 하기

public class BackgroundEnemyService implements Runnable {
	
	private BufferedImage image;
	private Enemy enemy;

	public BackgroundEnemyService(Enemy enemy) {
		this.enemy = enemy;

		try {
			image = ImageIO.read(new File("imagesProject/backgroundService.png"));
		} catch (IOException e) {
			System.out.println("백그라운드 플레이어 서비스 객체에 사용하는 이미지 경로 및 파일명 확인!");
		}
	}

	@Override
	public void run() {
		while (true) {
			Color leftColor = new Color(image.getRGB(enemy.getX() - 20, enemy.getY()));
			Color rightColor = new Color(image.getRGB(enemy.getX() + 55, enemy.getY()));

			if (leftColor.getRed() == 255 && leftColor.getGreen() == 0 && leftColor.getBlue() == 0) {
				enemy.setLeft(false);
				enemy.setLeftWallCrash(true);
			} else if ((rightColor.getRed() == 255 && rightColor.getGreen() == 0 && rightColor.getBlue() == 0)) {
				enemy.setRight(false);
				enemy.setRightWallCrash(true);
			} else {
				enemy.setLeftWallCrash(false);
				enemy.setRightWallCrash(false);
			}
		
			try {
				Thread.sleep(3);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}// end

 

백그라운드 서비스에서 사용하는 배경 이미지에 있는 빨간색 벽에 닿으면 충돌했다고 감지하게 된다.

 

 

랜덤한 이동 방향

private void enemyDirection() {
    Random random = new Random();

    new Thread(() -> {
        // enemy가 살아있는 동안
        while (alive == 0) {

            // 이동 방향을 랜덤으로 선택함
            int randomDirection = random.nextInt(2); // 0 또는 1 생성

            // 이동 메서드 안에 적군이 죽으면 중간에 중단하라는 if 문이 있어서
            // 죽으면 left(), right() 메서드를 빠져나간 뒤 반복이 종료됨

            // 값이 0인 경우 왼쪽으로
            if (randomDirection == 0) {
                // 왼쪽 벽에 부딪친 상태면 left() 실행 X
                if (leftWallCrash == true) {
                    continue;
                }
                left();

                // 값이 1인 경우 오른쪽으로
            } else {
                // 오른쪽 벽에 부딪친 상태면 right() 실행 X
                if (rightWallCrash == true) {
                    continue;
                }
                right();
            }

            try {
                Thread.sleep(800);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } // end of while
    }).start();
}

 

생성자에서 가장 마지막에 호출하는 메서드다. 적군이 살아 있는 동안 계속 반복문을 돌면서 이동 메서드를 호출한다.

Random 클래스의 nextInt(2)로 0 또는 1을 랜덤으로 생성하고, 그 값에 따라 왼쪽 오른쪽 방향이 정해진다. 

만약 그 쪽 방향의 벽에 부딪친 상태라면 continue();로 밑의 코드를 건너뛰고 다시 반복문을 돌게 했다.

 

 


이 정도까지 코드를 짜고 나서, 메인 프레임 파일 받아서 테스트해보려는데 프레임에 표시가 안됐다.

문법이 틀린 게 있는지 계속 확인해도 문제가 없어보이고.. 런타임 에러가 뜨는 것도 아닌데 안 나오니 당황스러웠다.

 

알고 보니 이미지가 표시되는 JLabel의 크기보다, 원본 이미지의 크기가 커서 그런 것이었다.

(가로 100, 세로 100 정도씩 차이 났음)

처음에 그냥 임의로 지정해두는 거니까 대충 설정해놨다가 이거 때문에 확인하느라 30분 넘게 날렸다.......

앞으로는 이미지 크기를 항상 확인하자..

 

 


실행

 

의도대로, 화면을 넘어가지 않으면서 랜덤한 패턴으로 이동한다.

320x100
반응형

댓글