NUngiboy 6e95e864e48245c2afe38069f3b5551f
장르 | 정보전달, 그 외에 장르 |
---|---|
게임버전 | 1.17.1 |
원산지 | 국산 |
개발자 | NUngiboy |
저작권 | 알 수 없음 |
자료 출처 | https://skripthub.net/docs/ |
개요
1.17에는 skdragon 지원이 안 되어서 한번 만들어본 원과, 구, 포물선을 만드는 스크립트입니다
버전 및 필요 애드온
Skript 2.6 Beta 3 / Skript 2.6 정식 버전에서의 정상 작동을 확인하였으며
SKbee 애드온이 반드시 필요합니다
사용법
명령어는 총 3가지가 있습니다.
1. drawCircle
/drawCircle [숫자] [정수] [정수] [정수]
형태로 실행할 수 있으며 (ex. /drawCircle 4.1 256 256 256)
첫번째 숫자는 반지름을 나타내며
뒤의 정수 3개는 각각 R G B 색깔을 나타냅니다
현재 플레이어의 머리와 발 위치 사이에 원점을 잡습니다
2. drawSphere
/drawSphere [숫자] [정수] [정수] [정수]
형태로 실행할 수 있으며 (ex. /drawSphere 4.1 256 256 256)
첫번째 숫자는 반지름을 나타내며
뒤의 정수 3개는 각각 R G B 색깔을 나타냅니다
현재 플레이어의 머리와 발 위치 사이에 원점을 잡습니다
3.drawParabola
/drawParabola [숫자] [숫자] [정수] [정수] [정수]
형태로 실행할 수 있으며 (ex.drawParabola 1.7 50 256 256 256)
첫번째 숫자는 속도, 두번째 숫자는 발사각을 의미하며
뒤의 정수 3개는 각각 R G B 색깔을 나타냅니다
현재 플레이어의 머리와 발 위치 사이에 원점을 잡고, 플레이어가 바라보는 방향으로 포물선을 그립니다
구문 설명
※주의 : 일반물리 지식이 필요하여 이과가 아니신 분들에겐 조금 어려울 수 있습니다.
마크에서는 참으로 편리한 기능이 있습니다.
그것은 f3 키를 누르면 나오는 xyz 좌표입니다.
이는 우리가 흔히 쓰는 직교 좌표계(Cartesian Coordinate)로
마인크래프트 세계에서는 각각 x축과 z축이 평면, y축이 높이를 나타내는데 쓰이죠
그러나 우리가 이번에 구현할 것은 원, 구 같은 곡면입니다.
보통 이런 것들은 극좌표계(Polar Coordinate) 또는 구면좌표계(spherical coordinate)를 많이 사용합니다
따라서 이를 적절히 잘 변환하기만 하면, 마크 내에서도 충분히 자연스러운 원을 만들 수 있는 것이죠
첫 번째인 drawCircle, 즉 원과 극좌표계에 대해서 알아볼까요
극좌표계에서는 기본적으로 다음과 같은 두가지 요소로 좌표계 내에서 점의 위치를 결정합니다
1. 원점까지의 거리 r
2. 원점과 이루는 각도 θ(세타/theta)
[그림 1] polar coord의 개요
위 [그림 1]에서도 보다시피 점 A는 직교좌표계로 나타내면 (C, D)의 위치인데
이는 삼각법 cos과 sin을 이용하여 구할 수 있습니다.
C=x=r*cosθ
D=y(이번 마크에서는 z축)=r*sinθ
따라서 반지름 r의 길이만 정해주면, 0도부터 360도까지 적절하게 자른 theta값만 돌려서 원을 구현할 수 있습니다.
function drawCircle(loc:location, radius:number, r:integer, g:integer, b:integer): set {_loc0} to {_loc} #원점의 위치를 변수로 임시저장합니다 set {_index} to 1 #index를 설정합니다 set {_loop} to {_radius}*24 #radius 뒤의 숫자로 밀도 조절, 밀도 올릴시 계산량 증가 set {_theta} to (360/{_loop}) #정해준 밀도로 360도를 나눠줍니다 set {_theta0} to {_theta} #단위 각도를 변수로 임시저장합니다 loop {_loop} times: #밀도만큼 반복합니다 (360도를 다 돌아야 하므로) set {_dx} to {_radius}*cos({_theta}) #x변화량을 계산합니다 set {_dz} to {_radius}*sin({_theta}) #z변화량을 계산합니다 add {_dx} to {_loc}'s x-coord #x변화량을 원점에 더해줍니다 add {_dz} to {_loc}'s z-coord #z변화량을 원점에 더해줍니다 set {_loc::%{_index}%} to {_loc} #위치를 목록변수에 저장합니다 set {_loc} to {_loc0} #다시 위치를 원점으로 되돌리고 add 1 to {_index} #인덱스를 1 더합니다 set {_theta} to {_index}*{_theta0} #인덱스*단위 각도를 이용하여 다음 각도를 만듭니다 loop {_loc::*}: #아까 저장한 목록 변수에 대하여 반복 play 1 of dust using dustOption(rgb({_r}, {_g}, {_b}), 1) at loop-value #그 위치에 파티클을 뿌립니다
두 번째로, drawSphere과 구면좌표계입니다
구면좌표계는 평면에서 입체가 됨에 따라서 축이 한방향 더 늘어났기 때문에,
점을 구성하는 요소가 3가지가 됩니다.
1. 원점까지의 거리 r
2. 원점과 두 축이 이루는 각도 φ(파이/phi)
3. 원점과 남은 한 축이 이루는 각도 θ(세타/theta)
[그림 2] spherical coord의 개요
위와 같은 상황에서 각각 xyz는 다음과 같이 나타낼 수 있습니다
x=r*sinθ*cosϕ
y=r*sinθ*sinϕ
z=r*cosθ
마크에서는 y축과 z축의 역할이 바뀌었다는 것에 주의하여 코드를 짜면 다음과 같습니다
function drawCircle(loc:location, radius:number, r:integer, g:integer, b:integer): set {_loc0} to {_loc} #원점의 위치를 변수로 임시저장합니다 set {_index} to 1 #index를 설정합니다 set {_index.theta} to 1 #theta의 index를 설정합니다 set {_index.phi} to 1 #phi의 index를 설정합니다 set {_loop} to {_radius}*24 #radius 뒤의 숫자로 밀도 조절, 밀도 올릴시 계산량 증가 set {_theta} to (360/{_loop}) #정해준 밀도로 360도를 나눠줍니다 set {_theta0} to {_theta} #단위 각도를 변수로 임시저장합니다 set {_phi} to (360/{_loop}) #phi도 똑같이 해줍니다 set {_phi0} to {_phi} loop {_loop}/2 times: #phi는 180도만 돌아도 되므로 ÷2 해줍니다 loop {_loop} times: #밀도만큼 반복합니다 (360도를 다 돌아야 하므로) set {_dx} to {_radius}*sin({_theta})*cos({_phi}) #x변화량을 계산합니다 set {_dz} to {_radius}*sin({_theta})*sin({_phi}) #z변화량을 계산합니다 set {_dy} to {_radius}*cos({_theta}) #y변화량을 계산합니다 add {_dx} to {_loc}'s x-coord #x변화량을 원점에 더해줍니다 add {_dz} to {_loc}'s z-coord #z변화량을 원점에 더해줍니다 add {_dy} to {_loc}'s y-coord #y변화량을 원점에 더해줍니다 set {_loc::%{_index}%} to {_loc} #위치를 목록변수에 저장합니다 set {_loc} to {_loc0} #다시 위치를 원점으로 되돌리고 add 1 to {_index} #인덱스를 1 더합니다 add 1 to {_index.theta} #theta index를 1 더합니다 set {_theta} to {_index.theta}*{_theta0} #인덱스*단위 각도를 이용하여 다음 각도를 만듭니다 add 1 to {_index.phi} #phi도 똑같이 해줍니다 set {_phi} to {_index.phi}*{_phi0} loop {_loc::*}: #아까 저장한 목록 변수에 대하여 반복 play 1 of dust using dustOption(rgb({_r}, {_g}, {_b}), 1) at loop-value #그 위치에 파티클을 뿌립니다
마지막으로 drawParabola, 포물선에 관한 구문입니다
포물선은 간단하게 얘기하면 물체를 던질때 나타나는 궤적이며,
화살이나 눈덩이도 포물선의 궤적을 띈다는 것을 알 수 있습니다
[그림 3] 포물선 운동의 개요
2차원 상에서의 포물선은 다음과 같이 나타낼 수 있지만,
3차원 상에서의 포물선 운동은 각도 하나가 더 들어가게 됩니다
따라서 위의 구면좌표계와 같이 각도가 두 개 필요한데,
구를 만들 때에는 그냥 전체적으로 다 돌려버렸기에 특정한 세타값을 지정하지 않았지만
여기서는 세타값을 지정할 필요가 있습니다.
그러면 플레이어가 현재 바라보는 방향이 좌표계 내에서 어떤 각도를 가지는지 구해야 합니다
set {_unitvector} to vector from yaw ( yaw of player ) and pitch (+0) set {_unitvector} to "%{_unitvector}%" replace all ":" , "x","y","z"," " with "" in {_unitvector} set {_vector::*} to {_unitvector} split by "," loop {_vector::*}: set {_vector::%loop-index%} to {_vector::%loop-index%} parsed as number set {_theta} to fixPitchVectorToAngle({_vector::1}, {_vector::3})
일단 위의 구문을 통해 플레이어의 pitch and yaw가 벡터로 어떻게 나타내지며
각각 {_vector::*}에 x,y,z 벡터로 저장되어집니다.
이 때, 주어진 벡터로 어떻게 각을 구하는지 알아야 합니다
function fixPitchVectorToAngle(x:number, z:number) :: number: set {_length.xz} to sqrt((({_x})^2)+(({_z})^2)) set {_length.x} to abs({_x}) set {_theta} to acos((({_x})^2)/({_length.xz}*{_length.x})) if {_x} > 0: if {_z} > 0: return {_theta} #x증 z증 east-south else if {_z} < 0: set {_theta} to abs(90-{_theta}) add 270 to {_theta} #x증 z감 east-north return {_theta} else: set {_theta} to 0 #x증 z0 east return {_theta} else if {_x} < 0: if {_z} > 0: set {_theta} to abs(90-{_theta}) add 90 to {_theta} #x감 z증 west-south return {_theta} else if {_z} < 0: add 180 to {_theta} #x감 z감 west-north return {_theta} else: set {_theta} to 180 #x감 z0 west return {_theta} else: if {_z} > 0: set {_theta} to 90 #x0 z증 south return {_theta} else: set {_theta} to 270 #x0 z감 north return {_theta}
이런 함수를 통하여 x축 east 방향을 0도로 하는 좌표계를 만들 수 있습니다
이를 이용하여 이제 진짜 포물선을 구하는 공식을 대입하여 함수를 짜면
function drawParabola(loc:location, velocity:number, theta:number, phi:number, r:integer, g:integer, b:integer): set {_loc0} to {_loc} #원점의 위치를 변수로 임시저장합니다 set {_index} to 1 #index를 설정합니다 set {_time0} to 0.1 #시간에 관한 변수 / 기본은 1tick = 0.05초 set {_time} to {_time0} #단위 시간을 저장합니다 set {_gravity.acc} to 1 #중력가속도 변수 (원하는 대로 조절해보세요!) loop 100 times: #일단은 100번만 반복 (반복 횟수 조절 가능) set {_dx} to {_velocity}*cos({_phi})*cos({_theta})*{_time} set {_dy} to ({_velocity}*sin({_phi})*{_time})-(0.5*{_gravity.acc}*({_time}^2) set {_dz} to {_velocity}*cos({_phi})*sin({_theta})*{_time} add {_dx} to {_loc}'s x-coord add {_dy} to {_loc}'s y-coord add {_dz} to {_loc}'s z-coord set {_loc::%{_index}%} to {_loc} set {_loc} to {_loc0} add 1 to {_index} set {_time} to {_time0}*{_index} wait 1 tick loop {_loc::*}: play 1 of dust using dustOption(rgb({_r}, {_g}, {_b}), 1) at loop-value
이렇게 나타낼 수 있습니다
phi 값을 어떻게 설정하냐에 따라서 초기 발사 각도가 달라집니다!
파일 및 적용법
서버 실행 폴더 중에서
plugins > Skript > scripts
폴더에 위 파일을 집어 넣은 후,
서버를 재시작 하시거나, /sk reload all 명령어를 입력하여
서버가 스크립트를 인식하게 해주시면 됩니다!
여담
skdragon 1.17 나오면 그거 씁시다....
질문은 언제나 환영입니다
프리루트
2021.11.22와우 아주 구체적인 설명 좋습니다 bb
그 자료 적용법을 간단하게 본문에 추가해주시면 감사하겠습니다 :>
눙이
2021.11.22확인하였고 추가하였습니다!
깜빡했는데 감사합니다 ㅎㅎ
프리루트
2021.11.22빠른 반영 감사합니다 :D
앞으로도 이런 질좋은 창작물 잘부탁드립니다!
qsef1256
2021.11.23skript 공식 디코 채널에 skDragon 1.17버전이 올라와 있습니다. 제작자가 귀찮았는지 테스트도 안해봤다는군요.
눙이
2021.11.24헉 그랬군요 어쩐지 인터넷에는 없다 했습니다 ㅎ...