😵 ~23.11.10
0725 | JS 볼 객체와 생성자, 프로토타입 만들기 / 선택한 좌표로 볼 이동시키기
unikue
2023. 7. 27. 10:02
✅ 스크립트 활용하기
자바스크립트는 객체를 가져다 쓰려면 메인에 스크립트 코드로 엮어줘야 한다.
단 사용되는 쪽이 먼저 로드가 되어야 한다 (game이 ball을 쓰게 되면 ball스크립트가 먼저 나와야 한다)
각 스크립트 안에 있는 변수들이 서로 충돌될 수 있으므로 위험성회피를 위해 여러 방법을 사용 ▶ es6에서 보완됨
canvas.onclick = function (e) {
// 캡슐화하지 않으면 모든 코드를 내가 만들게된다. 범위계산도 볼이 해야할 역할
if ((ball1.x - 30 <= e.x && e.x <= ball1.x + 30) && (ball1.y - 30 <= e.y && e.y <= ball1.y + 30)) {
ball2.isActive = false;
curBall = ball1;
console.log("ball1 선택")
curBall.setActive();
return;
}
if ((ball2.x - 30 <= e.x && e.x <= ball2.x + 30) && (ball2.y - 30 <= e.y && e.y <= ball2.y + 30)) {
ball1.isActive = false;
curBall = ball2;
console.log("ball2 선택")
curBall.setActive();
return;
}
//원이없는곳을 선택했을때 이동
curBall.moveTo(e.x, e.y);
console.log("외부선택")
}
✅ 볼 객체화
: 볼이 가져야 할 역할은 모두 볼에게 부여
function Ball(x, y, color) { // 클래스 겸 생성자로 만들어줌
this.x = x || 100;
this.y = y || 100;
this.vx = 0; // 1회에 x좌표로 이동하는 값. 즉 속도
this.vy = 0;
this.dx = 0; //입력받는 좌표값
this.dy = 0;
this.color = color || "black";
this.isActive = false;
this.radius = 30;
}
Ball.prototype = {//프로토타입에 메서드 업데이트
constructor: Ball
, moveTo: function (dx, dy) {
this.dx = dx;
this.dy = dy;
var w = this.dx - this.x; //멤버에 있는 변수는 this를 생략하면 안됨
var h = this.dy - this.y;
var d = Math.sqrt(w * w + h * h);
this.vx = w / d; // 기본보다 2배로 빠르게
this.vy = h / d;
}
, update: function () { // 볼에 대한 상태나 변화 체크
if ((this.x - 1<= this.dx && this.dx <= this.x + 1) && (this.y - 1 <= this.dy && this.dy <= this.y + 1)) {
this.vx = 0;
this.vy = 0;
}
// 누적하면서 진행됨
this.x += this.vx * this.speed;
this.y += this.vy * this.speed;
}
, draw: function (ctx) { //만약 매개변수를 받지못하면 전역변수 ctx를 가져온다
var shape = new Path2D();
shape.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
var originColor = ctx.fillStyle; // 색을 바로 적용하면 뒤에 들어올 공색깔에 영향을 미친다
ctx.fillStyle = this.color;
ctx.fill(shape);
ctx.fillStyle = originColor; // 색깔 원래대로 돌려놓기
if (this.isActive) { // 활성화된 볼에게 테두리 그려주기
var originColor = ctx.strokeStyle;
ctx.lineWidth = 3;
ctx.strokeStyle = 'red';
ctx.stroke(shape);
ctx.strokeStyle = originColor;
}
}
, setActive: function (active) {
if (active === undefined) { //비교되는 대상이 참조비교이기 때문에 '=='대신 '==='가 더 면밀하게 비교가능
this.isActive = true;
return;
}
this.isActive = active;
}
// 캡슐화하지 않으면 모든 코드를 내가 만들게된다. 범위계산도 볼이 해야할 역할
, isLocated: function (x, y) {
if ((this.x - this.radius <= x && x <= this.x + this.radius) && (this.y - this.radius <= y && y <= this.y + this.radius)) {
return true;
} else {
return false;
}
}
}
✅ 볼 인스턴스 관리하기
: 각 인스턴스별로 클릭여부, update, draw조건을 설정하면 인스턴스가 늘어날때마다 메서드가 추가되므로 배열에 객체를 모아서 순회하며 관리하는게 효율적이라 배열을 만들어준다
인덱스를 활용하지않고 볼을 넣고 (push) 인덱스를 활용하지않고 볼을 뽑지만 (for of) 인덱스가 필요할때는 인덱스를 출력해서 확인할 수 있어야함(indexOf)
var ball1 = new Ball(100, 100, "black"); // 생성자통해 객체 생성
var ball2 = new Ball(200, 100, "green");
var balls = []; // 볼을 넣을 공간 마련
balls.push(ball1);
balls.push(ball2);
var curBall = ball1;
//-----------------------------------------------
/** @type {HTMLCanvasElement} */
var canvas = document.querySelector("#canvas");
var ctx = canvas.getContext("2d");
// curBall.setActive(); //처음 선택된 버튼
canvas.onclick = function (e) {
for (var ball of balls) { // 볼을 순회하면서 해당 볼이 선택된 볼일때 curBall과 교체하기
if (ball.isLocated(e.x, e.y)) {
curBall.setActive(false);
curBall = ball;
console.log("선택")
curBall.setActive();
return;
}
}
curBall.moveTo(e.x, e.y);
console.log("외부선택")
}
// 인스턴스별로 조건을 모두 추가하면 update와 draw에도 인스턴스가 증가하기때문에 배열에 넣어서 객체를 관리하도록 함
//canvas.onclick = function (e) {
// if (ball1.isLocated) {
// curBall.setActive(false);
// curBall = ball1;
// console.log("볼1선택")
// curBall.setActive();
// return;
// }
// if (ball2.isLocated) {
// curBall.setActive(false);
// curBall = ball2;
// console.log("볼1선택")
// curBall.setActive();
// return;
// }
// }
window.setInterval(function () {
for (var ball of balls) { // 각 공의 상태 업데이트하기
ball.update();
}
ctx.clearRect(0, 0, 900, 700);
for (var ball of balls) { // 각 공 상태 그리기
ball.draw(ctx);
}
}, 17); // 1000/50 > 20fps 초당 20프레임