지난번 AimOffset의 연장선으로 Yaw 값이 일정값을 넘어서면 해당하는 방향으로 캐릭터가 회전하도록 하였습니다.
회전할때 하반신 모션이 좀 어색하긴한데 Mixamo에서 이것보다 괜찮은게 안보여서 해당 모션을 사용했습니다.
아마 추후에 더 괜찮은 모션을 찾게 된다면 수정될 것 같습니다.
[2. 사격 기능#1]
사격시 총알은 총구에서 플레이어의 화면의 중앙으로 발사되도록 하였습니다.
또한 사격 시 탄피가 생성되고 해당 탄피에서 충돌 이벤트 발생 시 탄피 떨어지는 소리를 한 번 내고 4초 뒤에 사라지도록 하였습니다.
처음 사격 방향 계산하는 거에서 참고한 자료에선 트레이스 채널을 ECC_Visibility로 해서 플레이어 캐릭터에 막혀서 반대로 쏘거나 하는 상황이 생겨 ECC_Camera로 변경하였으나 오른쪽으로 이동하면서 사격 시 이전과 같은 문제가 발생해서 이에 대해 수정할 예정입니다.
#include<string>#include<vector>#include<algorithm>#include<iostream>usingnamespace std;
/*
[x, y, a, b]
x, y는 기둥 또는 보를 설치할 교차점의 좌표
a = 0은 기둥, 1은 보
b = 0은 삭제, 1은 설치
구조물은 좌표 기준 보는 오른쪽, 기둥은 위쪽으로 설치
설치 조건
기둥은 바닥 위, 보의 한쪽 끝 부분, 기둥 위에 있어야함
보는 한쪽 끝 부분이 기둥 위에 있거나 양쪽 끝 부분이 다른 보와 연결되어 있어야함
+ 구조물이 겹치도록 설치되는 경우는 주어지지 않음
삭제 조건
삭제한 후에도 남은 기둥과 보들이 설치 조건을 만족한 상태여야 삭제 가능
+ 없는 기둥을 삭제하는 경우는 주어지지 않음
정렬 조건
x 좌표 기준 오름차순 정렬, x 좌표가 같으면 y 좌표 기준 오름차순 정렬
x, y 동일 시 기둥이 보보다 앞으로
*/int N;
bool Pillar[101][101];
bool Beam[101][101];
structSTRUCTURE {int x;
int y;
int type;
bool isDeleted;
};
vector<STRUCTURE> list;
// 기둥 설치 가능 여부boolcheckDeployPillar(int x, int y){
// 바닥이면if(x == N) returntrue;
// 보의 오른쪽에 설치할 때if(Beam[x][y - 1] && y >= 1) returntrue;
// 보의 왼쪽에 설치할 때if(Beam[x][y]) returntrue;
// 기둥 위에 설치할 때if(Pillar[x + 1][y]) returntrue;
returnfalse;
}
// 보 설치 가능 여부boolcheckDeployBeam(int x, int y){
// 왼쪽 끝에 기둥이 있을 때if(Pillar[x + 1][y]) returntrue;
// 오른쪽 끝에 기둥이 있을 때if(Pillar[x + 1][y + 1] && y + 1 <= N) returntrue;
// 양쪽 끝에 보가 있을 때if(Beam[x][y - 1] && Beam[x][y + 1]) returntrue;
returnfalse;
}
// 기둥 삭제 가능 여부voidDeletePillar(int x, int y){
int idx = 0;
// 해당 기둥이 설치되지 않음을 가정
Pillar[x][y] = false;
for(int i = 0; i < list.size(); i++) {
int curX = list[i].x;
int curY = list[i].y;
int Type = list[i].type;
// 현재 구조물이 삭제하려는 기둥과 같다면if(x == curX && y == curY && Type == 0) {
idx = i;
continue;
}
// 이미 삭제된 구조물이면if(list[i].isDeleted)
continue;
// 리스트에 있는 기둥 중 설치가 불가능한 기둥이 나온다면if(Type == 0 && checkDeployPillar(curX, curY) == false) {
Pillar[x][y] = true;
return;
}
// 리스트에 있는 보 중 설치가 불가능한 보가 나온다면if(Type == 1 && checkDeployBeam(curX, curY) == false) {
Pillar[x][y] = true;
return;
}
}
list[idx].isDeleted = true;
}
// 보 삭제 가능 여부voidDeleteBeam(int x, int y){
int idx = 0;
// 해당 보가 설치되지 않았음을 가정
Beam[x][y] = false;
for(int i = 0; i < list.size(); i++) {
int curX = list[i].x;
int curY = list[i].y;
int Type = list[i].type;
// 현재 구조물이 삭제하려는 보과 같다면if(x == curX && y == curY && Type == 1) {
idx = i;
continue;
}
// 이미 삭제된 구조물이면if(list[i].isDeleted)
continue;
// 리스트에 있는 기둥 중 설치가 불가능한 보가 나온다면if(Type == 0 && !checkDeployPillar(curX, curY)) {
Beam[x][y] = true;
return;
}
// 리스트에 있는 보 중 설치가 불가능한 보가 나온다면if(Type == 1 && !checkDeployBeam(curX, curY)) {
Beam[x][y] = true;
return;
}
}
list[idx].isDeleted = true;
}
boolcmp(STRUCTURE a, STRUCTURE b){
if(a.y <= b.y) {
if(a.y == b.y) {
if(a.x >= b.x) {
if(a.x == b.x) {
if(a.type < b.type) {
returntrue;
}
returnfalse;
}
returntrue;
}
returnfalse;
}
returntrue;
}
returnfalse;
}
vector<vector<int>> solution(int n, vector<vector<int>> build_frame) {
N = n;
vector<vector<int>> answer;
for(int i = 0; i < build_frame.size(); i++) {
int x = n - build_frame[i][1];
int y = build_frame[i][0];
int type = build_frame[i][2];
int deploy = build_frame[i][3];
// 설치일 때if(deploy == 1) {
// 기둥if(type == 0 && checkDeployPillar(x, y)) {
list.push_back({x, y, type, false});
Pillar[x][y] = true;
}
// 보if(type == 1 && checkDeployBeam(x, y)) {
list.push_back({x, y, type, false});
Beam[x][y] = true;
}
}
// 제거일 때else {
// 기둥if(type == 0) {
DeletePillar(x, y);
}
// 보if(type == 1) {
DeleteBeam(x, y);
}
}
}
sort(list.begin(), list.end(), cmp);
for(int i = 0; i < list.size(); i++) {
if(list[i].isDeleted)
continue;
answer.push_back({list[i].y, N - list[i].x, list[i].type});
}
return answer;
}
#include<string>#include<vector>#include<algorithm>usingnamespace std;
/*
이분 탐색
최소 시간을 1명을 1분으로 끝낸다고 가정하면 1
최대 시간은 가장 오래 걸리는 심사원에게 모든 인원이 심사를 받으러 갔을 때
위 둘을 각각 left, right로 하여 이분탐색 직행
mid를 각 심사위원이 심사하는데 걸리는 시간으로 나눈 값을 더하면 mid분일 때 심사할 수 있는 인원이 나옴
mid분에서 처리할 수 있는 인원이 n보다 크면 right를 mid - 1로 하고 작으면 left를 mid + 1로 해서 계속 탐색
left == right가 되면 탐색을 중단
*/longlongsolution(int n, vector<int> times){
longlong answer = 0;
// times 배열 정렬sort(times.begin(), times.end());
// 최소 시간longlong left = 1;
// 최대 시간, 데이터 타입에 주의longlong right = n * (longlong)times.back();
while(left <= right) {
longlong mid = (left + right) / 2;
// mid분에서 심사를 끝낼 수 있는 인원 수longlong cnt = 0;
for(int i = 0; i < times.size(); i++)
cnt += mid / (longlong)times[i];
// n보다 많거나 같은 수의 인원의 심사를 끝낼 수 있다면if(cnt >= n) {
right = mid - 1;
answer = mid;
}
// n 보다 적은 수의 인원의 심사를 끝낼 수 있다면else {
left = mid + 1;
}
}
return answer;
}
콘이 최대한 늦게 버스 정류장에 도착하여 사무실로 가려면 마지막 버스를 마지막으로 타면 됨
#include<string>#include<vector>#include<algorithm>usingnamespace std;
// 셔틀은 9시부터 t분 간격으로 n번 도착// 셔틀이 도착한 순간에 자리가 남고 그 순간에 도착한 크루가 있으면 탑승 가능// 콘은 최대한 늦게, 그러니까 마지막 버스를 타야함// 일단 시:분 형태로 주어지는 문자열을 시 * 60 + 분 형태의 int형으로 변환string solution(int n, int t, int m, vector<string> timetable){
string answer = "";
int time = 0;
vector<int> timeTable;
for(auto& time : timetable)
timeTable.push_back(stoi(time.substr(0, 2)) * 60 + stoi(time.substr(3, 2)));
sort(timeTable.begin(), timeTable.end());
int cnt = 0;
int arrivalTime = 540;
for(int i = 1; i <= n; i++) {
int cntInBus = 0;
while(cntInBus < m && cnt < timeTable.size()) {
if(timeTable[cnt] <= arrivalTime) {
cntInBus++;
cnt++;
}
elsebreak;
}
// 마지막 버스일 때if(i == n) {
// 자리가 남으면 버스 도착시간에 맞춰 오면 됨if(cntInBus < m)
time = arrivalTime;
// 자리가 안남으면 마지막 사람보다 1분 일찍 오면 됨else
time = timeTable[cnt - 1] - 1;
}
arrivalTime += t;
}
int hour = time / 60;
int minute = time % 60;
if(hour < 10)
answer = "0" + to_string(hour) + ":";
else
answer = to_string(hour) + ":";
if(minute < 10)
answer += "0" + to_string(minute);
else
answer += to_string(minute);
return answer;
}