오늘은 target의 앞에 뙇!
다가서는 pursuer를 표현하는 프로그램을 만들어 보겠습니다~~YEAH!!!
음~~^^* target의 미래 위치를 예상하고 그 앞에 다가가기 위해서는~~^^*,
하나. pursuer가 target의 운동속도 velocity에 대한 정보를 가질 수 있게 하고,
둘. target의 velocity의 크기를 몇 배 확장한 후,
셋. 몇 배 확장된 크기의 target velocity에 의해 영향 받은 target의 position에 다가가면,
넷, 이동한 target의 실제 position보다 몇 발자욱 앞선 위치에 pursuer가 도착해 있을 것 같아요~~^^*
아래 동영상 강의를 클릭하시면 오늘 공부 내용을 바로 시작(6:34)하실 수 있어요~^^* 9:10까지 보시면 오늘 공부 끝~^^*
이제, 핵심 코드를 우리 함께 살펴 볼까요~~^^*
새로운 함수 pursue()를 만들어 보겠습니다.
1. 추적하고자 하는 대상을 인자로 받습니다.
2. 추적하고자 하는 대상의 위치를 복사하여 변수 target에 저장합니다.
3. 추적하고자 하는 대상의 속도를 복사하여 변수 prediction에 저장합니다.
4. 추적하고자 하는 대상의 속도를 복사한 prediction의 크기를 10배 키웁니다.
5. 추적하고자 하는 대상의 위치를 복사한 target에 prediction을 더합니다. 이것은 함수 draw()가 10번 반복된 후 (10 frame 후)의 ‘추적하고자 하는 대상’의 예상 위치가 되겠네요.
6. (1) 함수 seek()를 호출하여 (추적하고자 하는 대상의 10 frame 후의 예상 위치인) target을 인자로 넘겨줍니다.
(2) (i) 함수 seek()는 (추적하고자 하는 대상의 10 frame 후의 예상 위치인 ) target에게,
(ii) pursuer 자신이 낼 수 있는 속력의 한계를 반영하고,
(iii) 현재 pursuer도 이동하고 있기 때문에 pursuer의 자신의 속도도 반영하고,
(vi) pursuer 자신이 발휘할 수 있는 힘의 한계도 반영하여,
(v) 가장 빨리 다가갈 수 있는 속도를 가진 힘을 계산하고
(iv) 자신을 호출했던 함수 pursue() 에게 이 힘을 return 합니다.
(3) 함수 pursue()는 함수 seek()가 return 해 준 (추적하고자 하는 대상의 10 frame 후의 예상 위치로, 자신의 이동 속도도 반영하고, 자신이 낼 수 있는 속력의 한계와 발휘할 수 있는 힘의 한계를 반영하여 가장 빨리 다가갈 수 있는 속도를 가진) 힘 force를 자신을 호출한 함수에게 return 합니다.
pursue(vehicle){ //1
let target = vehicle.position.copy(); //2
let prediction = vehicle.velocity.copy(); //3
prediction.mult(10); //4
target.add(prediction); //5
return this.seek(target);//6(1), 6(3)
}
seek(target) { //6(1)
let force = p5.Vector.sub(target, this.pos); //6(2)(i)
force.setMag(this.maxSpeed); //6(2)(ii)
force.sub(this.vel); //6(2)(iii)
force.limit(this.maxForce); //6(2)(vi)
return force; //6(2)(v,iv)
}
0. pursuer의 pursue함수를 호출하여 target을 인자로 넘겨 줍니다.
7. pursue함수가 return해 준 (target의 10 frame 후의 예상 위치에 가장 빨리 다가가는) 속도로 작용하는 힘을 변수 steering에 저장합니다.
8. pursuer의 applyForce함수를 호출하여 (target의 10 frame 후의 예상 위치에 가장 빨리 다가가는 속도로 작용하는 힘을 저장한) 변수 steering을 인자로 넘겨줍니다.
9. pusuer의 applyForce()는 (target의 10 frame 후의 예상 위치에 가장 빨리 다가가는 속도로 작용하는 힘)을 인자로 받아, pursuer에게 작용하는 전체 힘에 더합니다.
let steering = pursuer.pursue(target); //0, 7
pursuer.applyForce(steering); //8
applyForce(force) {
this.acc.add(force); //9
}
아 네!!! 꼬리에 꼬리를 무는 Return 실행문이 다시 곳곳에서 등장하는 군요~!!!
Returns Return!!!
핵심코드의 실제 작용 순서는 , 0 ->1,2,3,4,5,6(1) -> 6(2)(i,ii, iii, vi, v,iv)-> 6(3) -> 7,8 ->9 가 될 것 같아요~~^^*
이제 전체 코드를 살펴 볼까요~~^^*
Return 실행문의 작동 순서를 한 번 더 차근히 되짚어 보기 위해 실행문 순서 설명을 주석으로 다시 넣어 보았습니다~^^* 복습 삼아 가볍게 읽어 보셔도 좋을 듯 합니다~~^^*
<!DOCTYPE html>
<html>
<head>
https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.2.0/p5.min.js
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
http://vehicle.js
http://sketch.js
</body>
</html>
class Vehicle {
constructor(x, y) {
this.pos = createVector(x, y);
this.vel = createVector(0, 0);
this.acc = createVector(0, 0);
this.maxSpeed = 4;
this.maxForce = 0.25;
this.r = 16;
}
pursue(vehicle){ //1
let target = vehicle.pos.copy(); //2
let prediction = vehicle.vel.copy(); //3
prediction.mult(10); //4
target.add(prediction); //5
return this.seek(target);//6(1), 6(3)
}
seek(target) { //6(1)
let force = p5.Vector.sub(target, this.pos); //6(2)(i)
force.setMag(this.maxSpeed); //6(2)(ii)
force.sub(this.vel); //6(2)(iii)
force.limit(this.maxForce); //6(2)(vi)
return force; //6(2)(v,iv)
}
applyForce(force) {
this.acc.add(force); //9
}
update() {
this.vel.add(this.acc);
this.vel.limit(this.maxSpeed);
this.pos.add(this.vel);
this.acc.set(0, 0);
}
show() {
stroke(255);
strokeWeight(2);
fill(255);
push();
translate(this.pos.x, this.pos.y);
rotate(this.vel.heading());
triangle(-this.r, -this.r / 2, -this.r, this.r / 2, this.r, 0);
pop();
}
edges() {
if (this.pos.x > width + this.r) {
this.pos.x = -this.r;
} else if (this.pos.x < -this.r) {
this.pos.x = width + this.r;
}
if (this.pos.y > height + this.r) {
this.pos.y = -this.r;
} else if (this.pos.y < -this.r) {
this.pos.y = height + this.r;
}
}
}
class Target extends Vehicle {
constructor(x, y) {
super(x, y);
this.vel = p5.Vector.random2D();
this.vel.mult(5);
}
show() {
stroke(255);
strokeWeight(2);
fill(255,0,0);
push();
translate(this.pos.x, this.pos.y);
circle(0, 0, this.r * 2);
pop();
}
}
//1.추적하고자 하는 대상을 인자로 받습니다.
//2.추적하고자 하는 대상의 위치를 복사하여 변수 target에 저장합니다.
//3.추적하고자 하는 대상의 속도를 복사하여 변수 prediction에 저장합니다.
//4.추적하고자 하는 대상의 속도를 복사한 prediction의 크기를 10배 키웁니다.
//5.추적하고자 하는 대상의 위치를 복사한 target에 prediction을 더합니다. 이것은 함수 draw()가 10번 반복된 후 (10 frame 후)의 '추적하고자 하는 대상'의 예상 위치가 되겠네요.
//6.(1) 함수 seek()를 호출하여 (추적하고자 하는 대상의 10 frame 후의 예상 위치인) target을 인자로 넘겨줍니다.
// (2) (i) 함수 seek()는 (추적하고자 하는 대상의 10 frame 후의 예상 위치인 ) target에게,
// (ii) pursuer 자신이 낼 수 있는 속력의 한계를 반영하고,
// (iii) 현재 pursuer도 이동하고 있기 때문에 pursuer의 자신의 속도도 반영하고,
// (vi) pursuer 자신이 발휘할 수 있는 힘의 한계도 반영하여,
// (v) 가장 빨리 다가갈 수 있는 속도를 가진 힘을 계산하고
// (iv) 자신을 호출했던 함수 pursue() 에게 이 힘을 return 합니다.
// (3) 함수 pursue()는 함수 seek()가 return 해 준 (추적하고자 하는 대상의 10 frame 후의 예상 위치로, 자신의 이동 속도도 반영하고, 자신이 낼 수 있는 속력의 한계와 발휘할 수 있는 힘의 한계를 반영하여 가장 빨리 다가갈 수 있는 속도를 가진) 힘 force를 자신을 호출한 함수에게 return 합니다.
//9. pusuer의 applyForce()는 (target의 10 frame 후의 예상 위치에 가장 빨리 다가가는 속도로 작용하는 힘)을 인자로 받아, pursuer에게 작용하는 전체 힘에 더합니다.
let pursuer;
let target;
function setup() {
createCanvas(400, 400);
pursuer = new Vehicle(100, 100);
target = new Target(200, 100);
}
function draw() {
background(0);
let steering = (pursuer.pursue(target)); //0, 7
pursuer.applyForce(steering); //8
pursuer.update();
pursuer.show();
target.edges();
target.update();
target.show();
}
//0. pursuer의 pursue함수를 호출하여 target을 인자로 넘겨 줍니다.
//7. pursue함수가 return해 준 (target의 10 frame 후의 예상 위치에 가장 빨리 다가가는) 속도로 작용하는 힘을 변수 steering에 저장합니다.
//8. pursuer의 applyForce함수를 호출하여 (target의 10 frame 후의 예상 위치에 가장 빨리 다가가는 속도로 작용하는 힘을 저장한) 변수 steering을 인자로 넘겨줍니다.
target의 10 frame 후의 위치를 예상하여 다가서는 pursuer!! 그의 재빠름을 우리 함께 지켜 볼까요~^^*
몇 프레임 앞을 내다보며 움직이는 pursuer의 모습은, 박자를 쪼개고 쪼개어 몸을 움직이고 있는 와중에도 몇 박자 앞의 자신의 몸동작을 내다보고 있는, 절도있고 날렵하고 멋진 응원단원들의 모습 같아요!
오늘도 저와 함께 코딩 공부를 해주셔서 감사합니다~^^*
우리 내일도 만나서 코딩 공부 함께 해요~~^^*
네^^** 새로운 작은 도전이 몇 프레임 앞에서 우리를 기다리고 있어요~~^^*
오늘 많이 무더운 날씨인데요~^^* 시원한 샤워 후 편안하게 하루를 마무리 하실 수 있기를 바래요~^^*
네!!! 꿈은 이루어 집니다!!!
댓글 남기기