[STS] 버블버블 - 스레드 사용하여 이동

HootJem's avatar
Oct 28, 2024
[STS] 버블버블 - 스레드 사용하여 이동
한 번에 하나의 키 입력만 처리되므로, 'R'을 계속 눌러도 다른 키(U)를 누르면 R의 입력이 중단된다.
메인 스레드만 있기 때문에 키 전달을 여러 개 할 수 없고, 모든 루프가 완료 되어야 repaint 가 된다.
 
try { Thread.sleep(2000); // 2초 멈춰라 } catch (InterruptedException e) { e.printStackTrace(); }
따라서 RRRRR 5번 입력한다면 2*5 초인 10초만큼 멈춘 뒤 한번에 5칸 만큼 이동을 하게 될 것이다.
 
따라서 움직이는 코드에 스레드를 추가한다.
@Override public void right() { new Thread().start(); setIcon(playerR); x = x+10; setLocation(x, y); }
 
스레드에는 러너블이라는 익명 클래스가 필요하다.
notion image
notion image
@Override public void right() { new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start(); setIcon(playerR); x = x+10; setLocation(x, y); }
위의 코드를 람다식으로 적을 수 있다.
@Override public void right() { new Thread(()-> { }).start(); setIcon(playerR); x = x+10; setLocation(x, y); }
@Override public void left() { System.out.println("L 스레드 생성"); new Thread(()-> { setIcon(playerL); x = x-10; setLocation(x, y); System.out.println("L 스레드 종료"); }).start(); }
notion image
길게 누르고 있을 때, 누를 때 마다 매번 스레드를 생성하는 것 보다 L 키를 뗐을 때 스레드를 종료하는 것이 더 좋지 않을까?
아래처럼 코드를 작성하면 버튼을 1번만 눌렀을 때 while 을 통해 캐릭터가 계속해서 움직이게 된다.
(그러나 여전히 키보드를 누를 때 마다 스레드가 생성되고 있음)
@Override public void left() { System.out.println("L 스레드 생성"); new Thread(()-> { while (true) { setIcon(playerL); x = x-10; setLocation(x, y); try { Thread.sleep(10); // 0.01초 간격 } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); }
notion image
 
따라서 움직임 상태를 관리하는 boolean 을 통해 관리한다.
public class Player extends JLabel implements Moveable { // 위치 상태 private int x; private int y; // 움직임 상태 private boolean left; private boolean right; private boolean up; private boolean down; private ImageIcon playerR, playerL; public Player() { initObject(); initSetting(); } private void initObject() { playerR = new ImageIcon("image/playerR.png"); playerL = new ImageIcon("image/playerL.png"); } private void initSetting() { x = 55; y = 535; left = false; right = false; up = false; down = false; this.setIcon(playerR); setSize(50, 50); setLocation(x, y); } @Override public void right() { System.out.println('R'); right=true; new Thread(()-> { while (right) { setIcon(playerR); x = x+10; setLocation(x, y); try { Thread.sleep(10); // 0.01초 간격 } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } }
BubbleFrame 클래스에서 움직임 상태를 확인하여 동작 시킨다.
private void initListener() { addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { System.out.println(e.getKeyCode()); switch (e.getKeyCode()) { case KeyEvent.VK_LEFT: if(!player.isLeft()) { player.left(); } break; case KeyEvent.VK_RIGHT: if(!player.isRight()) { player.right(); } break; case KeyEvent.VK_UP: player.up(); break; } } }); }
right 와 left 가 ture 가 되어 충돌이 발생한 모습
right 와 left 가 ture 가 되어 충돌이 발생한 모습
키를 누르면 해당 방향의 상태가 true로 바뀌며 새로운 스레드가 생성되지 않고, 지속적으로 캐릭터가 움직이게 된다. 하지만 다른 방향의 키를 누르는 순간, rightleft 둘 다 true 상태가 되면서 두 개의 스레드가 동시에 실행된다. 이로 인해 캐릭터가 좌우로 빠르게 번갈아 움직이는 충돌 현상이 발생하게 된다.
이를 방지하기 위해, 키보드 입력이 끝났을 때 해당 방향의 상태를 false로 변경하여 스레드를 종료시켜야 한다."
 
private void initListener() { addKeyListener(new KeyAdapter() { // 키보드 이벤트 핸들러 @Override public void keyPressed(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_LEFT: if (!player.isLeft()) { player.left(); } break; case KeyEvent.VK_RIGHT: if (!player.isRight()) { player.right(); } break; case KeyEvent.VK_UP: player.up(); break; } } // 키보드 해제 이벤트 핸들러 @Override public void keyReleased(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_LEFT: player.setLeft(false); break; case KeyEvent.VK_RIGHT: player.setRight(false); break; } } }); }
키보드 해제 이벤트 핸들러를 통해 입력이 있을 때 마다 쓰레드가 생성되지 않고,
쓰레드 간의 충돌이 발생하지 않는 움직임을 만들어 낼 수 있다.
notion image
 
 
 
Share article

[HootJem] 개발 기록 블로그