먼저 저는 몬스터(이하 좀비)가 플레이어를 따라오게 만드는 알고리즘을 짜고있습니다.
정확히는 플레이어가 걷는다던가등의 행동을 하면 좀비의 '소리'레벨을 일정수치 이상 오르게 하고
좀비가 이 '소리'레벨을 일정수치 이상(이하 '맥스소리'레벨) 가지게 된다면 플레이어가 마지막으로 '소리'레벨이 오르는 행동을 한 장소로
움직이게 하는 알고리즘을 짰습니다.
근데 좀비가 가지고있는 '소리'레벨이 너무 기하급수적으로 올라서 문제입니다. 이렇게 되면 플레이어가 움직이자마자 좀비가 바로 움직이게 되겠죠
저는 그래서 몇가지 알고리즘을 추가했습니다.
1. 좀비의 '소리'레벨이 정확히 1씩 올라가게 한다
2. 플레이어의 x좌표가 정확히 1.0 변경될때 좀비의 '소리'레벨이 1씩 오르게 한다
3. 플레이어가 움직이면 움직인 만큼 시간을 재서 (a키또는 d키를 누른만큼) 좀비의 '소리'레벨이 오르게 한다
이렇게 두가지 제약을 각각 두고 다시 실행 시켜봤는데도 결과는 다름없이 '소리'레벨이 기하급수적으로 올라버립니다.
이 기하급수적으로 오르는 '소리'값을 정상화 시키고싶어요 ㅠㅠㅠ
코드와 콘솔창 올리겠습니다.
public class PlayerCont : MonoBehaviour
{
public float moveSpeed = 5f;
public float soundLevelPerStep = 1f;
public float soundLevelPerSecond = 1f; // 초당 증가할 소리 레벨
private float keyPressDuration = 0f; // 키가 눌린 시간
private bool isKeyDown = false; // 키가 눌렸는지 여부
public GameObject meleeWeapon; // 근접 무기 오브젝트 연결
public GameObject rangedWeapon; // 원거리 무기 오브젝트 연결
public LayerMask enemyLayer;
public LayerMask destructibleLayer;
public Transform shootPoint;
public int dp = 10;
//public StatusUI statusUI;
public GameObject saveNotification; // 저장 알림 UI 오브젝트
public int attackPower = 10;
public int health = 100;
public int defense = 10;
public int stamina = 100;
private float previousXPosition; // 이전 프레임의 플레이어 x 좌표
private bool isRangedWeaponEquipped = true;
private bool isNearSavePoint = false; // 저장 지점 근처 여부
private void Start()
{
previousXPosition = transform.position.x; // 초기 x 좌표 저장
saveNotification.SetActive(false); // 게임 시작 시 알림을 숨깁니다.
LoadGame();
}
void Update()
{
// 좌우 이동
float horizontalInput = Input.GetAxisRaw("Horizontal");
transform.Translate(Vector3.right * horizontalInput * moveSpeed * Time.deltaTime);
// 키가 눌리는 동안 시간 누적
if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.RightArrow))
{
isKeyDown = true;
keyPressDuration += Time.deltaTime; // 눌린 시간 누적
}
// 키를 떼는 순간 소리 발생
if (Input.GetKeyUp(KeyCode.LeftArrow) || Input.GetKeyUp(KeyCode.RightArrow))
{
isKeyDown = false;
GenerateSoundBasedOnKeyPress();
keyPressDuration = 0f; // 시간 초기화
}
// 현재 x 좌표와 이전 x 좌표의 차이 계산
float distanceMovedX = transform.position.x - previousXPosition;
// x 좌표가 1.0씩 이동했을 때 정확히 한 번만 소리 발생
if (Mathf.Abs(distanceMovedX) >= 1.0f)
{
MakeSound(soundLevelPerStep); // 1씩 증가하는 소리 발생
previousXPosition += Mathf.Sign(distanceMovedX) * 1.0f; // 1.0 단위로 갱신
}
void MakeSound(float soundLevel)
{
MonsterAI[] monsters = FindObjectsOfType<MonsterAI>();
foreach (MonsterAI monster in monsters)
{
monster.HearSound(soundLevel);
}
}
void GenerateSoundBasedOnKeyPress()
{
// 키 누른 시간만큼 소리 계산
float generatedSoundLevel = keyPressDuration * soundLevelPerSecond;
// 몬스터들에게 소리 전달
MonsterAI[] monsters = FindObjectsOfType<MonsterAI>();
foreach (MonsterAI monster in monsters)
{
monster.HearSound(generatedSoundLevel);
}
Debug.Log($"키 눌림 시간: {keyPressDuration}s, 생성된 소리 레벨: {generatedSoundLevel}");
}
public class MonsterAI : MonoBehaviour
{
public float maxSoundThreshold = 20f; // 최대 소리 임계값
public float soundDecayRate = 1f; // 소리 감쇠 속도
public float movementSpeed = 5f; // 몬스터 이동 속도
public float baseDetectionRange = 2f; // 기본 감지 범위
public float detectionRangeMultiplier = 0.1f; // 감지 범위 증가량
public float currentSoundLevel = 0f; // 현재 소리 레벨
private Vector3 targetPosition; // 몬스터가 이동할 위치
private bool isMovingToSound = false; // 소리 위치로 이동 중인지 여부
// 플레이어의 행동에 따라 소리 레벨 조정
public void HearSound(float soundLevel)
{
currentSoundLevel += soundLevel; // soundLevel이 1씩만 전달되므로 1씩 증가하게 됨
Debug.Log("현재 소리 레벨 = " + currentSoundLevel);
}
}
게임시작하고 1초만에 소리값이 50이상 올라버립니다.
ps. 자대에서 챗지피티 가지고 메모장 코딩하다가 전역하고 그거 그대로 옮겨서 유니티에 적용시킨다고 여러가지 보기에 필요없는 코드가 많습니다...ㅎ
이거만 현재 4시간째 붙잡고 있습니다 형님들 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ
그냥 그대로 두고 기준값을 바꾸셈. max sound 어쩌고를 바꿔.
inf가 되는게 문제면 반영하는 값을 특정 값으로 나누든가. 로그 스케일로 증가하게 하든가 제곱근을 취하든가 증가 속도를 제어할 방법은 많음
쿨타임을 만드세염
마지막으로 소리가 증가했던 시간 체크해서
쿨타임 해봤었던거 같은데 다시한번 더 수정해서 고쳐볼게요 잠시만요
그리고 인풋, 좌표 두 조건 중에 하나만 남겨보셈 어떤 놈이 문제인지
노트펴고 기획부터 하자. 오로지 소리로만 어그로가 끌릴까? 빛은 어떻지? 경계레벨로 통합하는건? 키 누른 시간이 아니라 변화한 거리가 기준인건 어떨까? 음 이러면 플레이어가 살금살금 움직여도 감지가 되니까 플레이어의 상태를 참조해야되나? 이런식으로 생각하면서? - dc App
그러는 부분은 기획은 이미 다 되어있습니다 다만 저 '소리'레벨이 기하급수적으로 올라가는걸 수정하지 않는이상 다른걸 건드릴 수가 없어요 마찬가지로 변화한 거리가 기준인것도 시험 해봤는데 안되더라구요....
게이야 일단은 prevX 갱신이 잘못돼서 문제 생기는 것 같은데 prevX = transform.pos.x가 맞지 않겠노? 그거말고도 좌우 방향키 같이 눌렀다가 하나만 떼면 코드가 지금 어케되노? 중앙에서 좌우로 0.9씩 와리가리 털면 어케되노? 플로우를 다시 짜야될 것 같은데 - dc App
매 프레임 증가할 테니까 초당 프레임 만큼 증가할듯? 그럼 1초에 대충 60정도 올라가는 것 아닌지.. 저라면 누른 시간 비례해서 뗄 때 60이면 소리 레벨 1, 120이면 소리 레벨 2 이런 식으로 분기를 둔 다음, 소리 레벨을 따져서 어느 정도의 거리에 위치한 좀비가 반응하게 할 것인지 등등을 정할 것 같음.
코드에서 뉴비의 냄새가 난다
델타타임 곱하고있음? 델타타임안쓰면 안돼
아무리 봐도 여기가 문제인거 같은데
// 현재 x 좌표와 이전 x 좌표의 차이 계산 float distanceMovedX = transform.position.x - previousXPosition;// x 좌표가 1.0씩 이동했을 때 정확히 한 번만 소리 발생 if (Mathf.Abs(distanceMovedX) >= 1.0f) { MakeSound(soundLevelPerStep); // 1씩 증가하는 소리 발생 previousXPosition += Mathf.Sign(distanceMovedX) * 1.0f; // 1.0 단위로 갱신 }
말이 정리가 안됐는데 transform.position은 5 unit으로 움직이는데 previousXPosition이 1.0 단위로 갱신되니깐 여러번 불린다는 말임