2023-04-16 던전 기능 개발도중...
Java의 프로젝트인 RPG Game 을 만드는도중 던전에 입장을 하여 유저와 몬스터가 싸우는 것을 멀티스레드로 구현을 할려고 하였다. 던전에 입장하면 몬스터의 speed (공격속도) 유저의 speed (공격속도) 에 맞추어서 스레드를 2개를 돌려 서로 공격하고 누가 이기는지 나오는 기능을 만들려고하였다.
문제발생...
멀티스레드를 잘 해보지 않아서 그런지 스레드를 2개로 돌려 몬스터와 유저 한명이 이기게 된다면 2개의 스레드를 종료를 시켜야 한다. 내가 알고 있는 방법은 stop() 매서드를 이용하는 방법인데 stop() 은 강제종료로 비권장하는 방식이라 interrupt() 방식을 할려고 하였다.. 하지만 스레드를 돌린뒤 유저나 몬스터가 이기는 순간 2개의 스레드를 종료 시켜야하는데 이기는 순간을 어떻게 처리 해야 할지 몰랐다..
해결!
먼저 User / Monster 클래스로 나누고 이 클래스에 boolen check 이라는 전역변수로 선언하고 이기게 되면 check = true 로 값을 넣게 되었다. 이때 메인 클래스에서 User / Monster 클래스의 스레드를 돌리고 바로 while() 과 Thread.sleep(500) 을 통해 User / Monster 의 각각 check 의 true 여부를 확인 해서 이길시 interrupt() 매서드를 통한 Thread 종료와 함께 보상이 주어진다.
해결코드
Java_Game : https://github.com/Domae-back-end/Java_Game/tree/master
User_Fight.java
package project.game_project.game_service;
import java.util.Scanner;
import project.game_project.entity.Monster;
import project.game_project.cache.Decorate;
public class User_Fight implements Runnable {
private boolean winner = false;
private String name;
private int speed;
private int hp;
private int ap;
private int def;
private int mp;
Monster monster;
Scanner sc = new Scanner(System.in);
Decorate decorate = new Decorate();
public User_Fight(String name,int speed, int hp, int ap, int def, int mp,Monster monster){
this.speed = speed;
this.hp = hp;
this.ap = ap;
this.def = def;
this.name = name;
this.mp = mp;
this.monster = monster;
}
public void run() {
while (!Thread.currentThread().isInterrupted()) { // 승리할 때까지 반복
// 게임 로직 구현
System.out.println(decorate.bar);
System.out.println("1.기본 공격 / 2.스킬 ( 준비중 ..)");
System.out.println(decorate.bar);
int choice = sc.nextInt();
switch(choice){
case 1:{
attack();
break;
}
case 2:{
break;
}
}
if(monster.getHp() <= 0){
winner = true;
Thread.currentThread().interrupt();
break;
}
try {
Thread.sleep(speed * 1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public void attack(){
System.out.println(decorate.bar);
System.out.println(monster.getName()+"에게 "+ap+" 데미지를 주었습니다.");
monster.setHp(monster.getHp() - (ap - monster.getDef()));
System.out.println("현재 몬스터 남은 피 : "+monster.getHp());
System.out.println(decorate.bar);
}
public void setMp(int mp){
this.mp = mp;
}
public int getMp(){
return mp;
}
public void setDef(int def){
this.def = def;
}
public int getDef(){
return def;
}
public void setAp(int ap){
this.ap = ap;
}
public int getAp(){
return ap;
}
public void setHp(int hp){
this.hp = hp;
}
public int getHp(){
return hp;
}
public void setSpeed(int speed){
this.speed = speed;
}
public int getSpeed(){
return speed;
}
public boolean getWinner(){
return winner;
}
}
Monster.java
package project.game_project.game_service;
import project.game_project.cache.Decorate;
public class Monster_Fight implements Runnable {
private boolean winner = false;
private String name;
private int speed;
private int hp;
private int ap;
private int def;
private int mp;
User_Fight user_fight;
Decorate decorate = new Decorate();
public Monster_Fight(String name,int speed, int hp, int ap, int def, int mp, User_Fight user_fight){
this.speed = speed;
this.hp = hp;
this.ap = ap;
this.def = def;
this.name = name;
this.mp = mp;
this.user_fight = user_fight;
}
public void run() {
while (!Thread.currentThread().isInterrupted()) { // 승리할 때까지 반복
// 게임 로직 구현
attack();
if(user_fight.getHp() <= 0){
winner = true;
Thread.currentThread().interrupt();
return;
}
try {
Thread.sleep(speed * 1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public void attack(){
System.out.println(decorate.bar);
System.out.println(name+"에게서 "+ap+"만큼 데미지를 받았습니다.");
user_fight.setHp(user_fight.getHp() - (ap - user_fight.getDef()));
System.out.println("현재 자신의 남은 피 : "+user_fight.getHp());
System.out.println(decorate.bar);
}
public void setMp(int mp){
this.mp = mp;
}
public int getMp(){
return mp;
}
public void setDef(int def){
this.def = def;
}
public int getDef(){
return def;
}
public void setAp(int ap){
this.ap = ap;
}
public int getAp(){
return ap;
}
public void setHp(int hp){
this.hp = hp;
}
public int getHp(){
return hp;
}
public void setSpeed(int speed){
this.speed = speed;
}
public int getSpeed(){
return speed;
}
public boolean getWinner(){
return winner;
}
}
Dungeon.java
public void fight(){
String monster_name = monster.getName();
decorate.println(monster_name+" VS "+user.getNickname()+" / 대결 시작");
//멀티쓰레드
User_Fight user_fight = new User_Fight(user.getNickname(),user.getSpeed(),user.getHp(),user.getAp(),user.getDef(),user.getMp(),monster);
Monster_Fight monster_fight = new Monster_Fight(monster_name,monster.getSpeed(),monster.getHp(),monster.getAp(),monster.getDef(),monster.getMp(),user_fight);
Thread userThread = new Thread(user_fight);
Thread monsterThread = new Thread(monster_fight);
//멀티쓰레드 시작
userThread.start();
monsterThread.start();
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(user_fight.getWinner()){
//유저 승
userThread.interrupt();
monsterThread.interrupt();
System.out.println(decorate.bar);
decorate.println(monster_name+" 에게서 승리 하였다!!");
decorate.println(monster.getMoney()+" 만큼 돈을 획득했다!");
decorate.println(monster.getExp()+" 만큼 경험치를 획득했다!");
System.out.println(decorate.bar);
user.setMoney(user.getMoney() + monster.getMoney());
user.setExp(user.getExp() + monster.getExp());
//아이템 획득도 해야함. 아이템 테이블에 확률 있음.
return;
}
if(monster_fight.getWinner()){
//몬스터 승
userThread.interrupt();
monsterThread.interrupt();
System.out.println(decorate.bar);
decorate.println("눈앞이 캄캄해 진다...");
decorate.println(monster.getMoney()+" 만큼 돈을 잃었다....");
System.out.println(decorate.bar);
user.setMoney(user.getMoney() - monster.getMoney());
return;
}
}
'TIL' 카테고리의 다른 글
Spring Security AuthenticationProvider / BCryptPasswordEncoder match 에러 (2) | 2023.06.07 |
---|---|
RedisConfig 에서 오류 발생. (0) | 2023.06.01 |
동기와 비동기 방식 / 스레드 풀 (0) | 2023.04.27 |
Java_Game 프로젝트 진행중 발생한 문제 공부 ( 멀티스레드 ) (1) | 2023.04.25 |
개발 블로그 시작... (0) | 2023.04.18 |