1. JS (배열 뽀개기 ,Collection : Set, Map) [23.01.05]
1) Array Destructring(배열 뽀개기)
let kors =[1,2,3];
let[kor1,kor2,kor3] = kors; //신기하네. let에 바로 붙여쓰네
console.log(kor1);
// 에러발생 : 이미 지역 변수가 있어서**
let kors2 = [2,3,4];
// let[kor1,kor2,kor3] = kors2; // 이렇게 쓰면 에러가 발생한다. 선언을 2개 해버려서..
[kor1,kor2,kor3] = kors2; // 따라서, 선언해주지 않는다.
console.log(kor1);
let std1 = {name:"dragon", phone:'010'};
// let {name, phone} = std1; // 에러발생!
// {name, phone} = std1; // 에러발생! 괄호를 묶어줘야 한다.(parenths 에러)
({name, phone} = std1); // 에러를 해결하기 위해서 전체에 괄호를 묶어준다.
// JS를 ";"안 쓰고 줄바꾸기 위해서 완전한 문장이여야 한다. 이 문장은 불안정하다!
let a, b; // 배열을 이런식으로 넣어 줄수도 있다.
[a, b] = kors2; // 뽀개기된 kor2를 다시 배열([a, b])에 넣어 줄수 있다.
console.log(a,b);
a = 20;
b = 30;
console.log(a);
[a,b] = [b,a]; // 자리바꾸기.. 이게 되네...
console.log(a);
let korss = [10, 20, 30];
let [kor4, kor5] = korss;
console.log(kor4);
console.log(kor5);
let[,,kor6] =korss; // 앞에는 뭐가 들어감?
console.log(kor6);
let numbers = [1,2,3,4,5,6,7,8,9,10];
let [n1,n2,rest] = numbers;
console.log(rest); // 배열의 나머지를 요소를 출력하려면 나머지 연산자가 필요하다!!
let numberss = [1,2,3,4,5,6,7,8,9,10];
let [n11,n22,...rrest] = numbers;
console.log(rrest); // 나머지 연산자(...)를 사용하기, 순서도 마지막에 배치해야 한다.
2) ES6 JS의 Set 콜렉션
- Iterator :
- 일괄적으로 뽑아낼 때, Iterator로 뽑아낸다
- of를 사용할 수 있으면 이터레이터이다.(반복적으로 값을 뽑아낼 때)
- Set 특징 :
- key가 따로 구현하지 않는다, 단독적으로 특정한 값을 꺼낼 수 없다,
- key가 충돌하지않아서 중복되는 값이 존재하지 않는다.
- set.add()로 Set 콜렉션에 값을 더 한다.
let set = new Set();
set.add(5); // add로 Set에 데이터를 대입해준다.
set.add("5"); // set은 데이터를 배열에 담는다.***
set.add(2);
set.add(5);
// ** size 이용, 크기를 출력하면, 중복제거된 상태로 값이 출력
console.log(set.size); // 3이 출력
console.log(`size : ${set.size}`);
// ** for of 이용
for(let n of set) { // set의 값을 하나씩 뽑아낸다.
console.log(n);
set.has(5)
}
// ** has 이용
set.has(5) // 5를 갖고 있는지 boolean형으로 반환
- forEach 구문!! vs for of와 비교하기(vs for in)
// **
set.forEach((v)=>{
console.log(v); // **** forEach로 각각의 값을 꺼내서 뽑아 쓸 때, 사용했다.
})
set.forEach((v)=>{
console.log(`value: ${v}`); // forEach로 각각의 값을 직접 꺼내서 사용했다.
}) // for of는 Set에서 값을 뽑아낸다.
// forEach는 예전 방식이라서 이런식으로도 사용한다.
// 요즘에는 값을 뽑아내기 위해서 for of를 이용한다.
// for in 문 사용!
for(let k in set)
console.log(k); // 그냥 key 값은 안 나온다.(Set이라서 key가 없다.)
console.log("----------------------------------------------------");
set.forEach((v,k) => {
console.log(`key:${k}, value:${v}`); // key와 value 모두 같은 값으로 출력(forEach)
});
// ***WeekSet : 중복이 제거되었을때 확인하기 위해 사용한다.(Set에 담지 않는다.)
- Map : key, value 이용하기(이제 Object를 이용하지 않는다**)
- 이터레이터 사용가능
- Object는 키 값으로 문자열만 가질 수 있지만, Map은 키로 모든 데이터 타입을 가질 수 있다. Map은 순서를 보장한다.
- Map 함수 모음 **
- keys : key들만 확인
- values : value들만 확인
- entries : key, value 모두 확인
- size : 크기 확인
@@
태그 : 심볼이라서 인터페이스가 제공되지 않아서 약속에 해당하는 것- ex)
@@species
,@@toStringTag
- ex)
let map = new Map();
map.set("id", 1);
map.set("title","map이란?");
console.log("\nforeach---------------------");
map.forEach(function(v,k){
console.log(`key:${k}, value:${v}`);
});
console.log("/foreach---------------------");
let notice = new Map(); // 속성을 묶어서 사용할 때, 사용하며 변수에 담을 수 있다.
notice.set("id",1); // 묶어서 한 번만 사용할 때, 임시형 데이터 집합을 사용할 때, Map을 사용한다.
notice.set("title","map is ...");
notice.set("writer", "newlec");
console.log(notice.get("title")); // 데이터 1개만 가져올 때, get으로 받아온다.
notice.forEach((v,k)=>{
console.log(`key:${k}, value:${v}`);
});
for(let key of notice.keys())
console.log(`key:${key}`); // Set으로 꺼내진다.
for(let v of notice.values())
console.log(`value:${v}`);
// for(let entry of notice.entries()){
// console.log() // 이것도 틀렸다.
// console.log(`key: ${entry.key}`); // 이건 올바르지 않는 방식이다.
// }
for(let [k,v] of notice.entries()) // notice.entries()가 iterator이다. notice도 iterator를 갖고 있다.*****
// entries는 iterator라서 map 타입으로 key-set을 하느냐? set 계열의 collection하느냐 이다.
console.log(`key: ${k}, value: ${v}`); // key: ~ , value : ~ 이런 형식으로 출력된다.
// forEach를 안 쓰고 for of를 사용하는 이유? ES5에서 예전에 사용하던 방식이며 화살표 함수와 같이 함수를 사용해야하므로 복잡하다.
- iterator 추가 개념**
/// ****
for(let [,v] of notice.entries()) // notice.entries()가 iterator이다. notice도 iterator를 갖고 있다.*****
// entries는 iterator라서 map 타입으로 key-set을 하느냐? set 계열의 collection하느냐 이다.
console.log(`value: ${v}`); // value만 출력!!!!
for(let [k,] of notice.entries()) // notice.entries()가 iterator이다. notice도 iterator를 갖고 있다.*****
// entries는 iterator라서 map 타입으로 key-set을 하느냐? set 계열의 collection하느냐 이다.
console.log(`key: ${k}`); // key만 출력!!!!
for(let n of notice) // notice.entries()가 iterator이다. notice도 iterator를 갖고 있다.*****
// entries는 iterator라서 map 타입으로 key-set을 하느냐? set 계열의 collection하느냐 이다.
console.log(`n: ${n[1]}`); // map의 1번째 데이터를 가져와서 출력한다.
- Object를 Map으로 바꿀 수 있는가?(map 함수 이용하기)
let exam3 = {
kor:10,
eng:20,
math:30
};
// *** 에러 발생
// for(let v of exam3) // iterable 에러 발생
// console.log(v); // 원래는 entry()에서 가져와야하는데 아니라서 에러가 발생
// // 따라서, key와 value를 갖고 있는 데이터 타입을 만들어서 거기서 가져와야 한다.
// 그래서, 나중에 Object의 static 메서드를 살펴보기****(mdn static methord 검색하기)
for(let [k,v] of Object.entries(exam3))
console.log(`key: ${k}, value: ${v}`);
- forEach 개념(map 함수와 비교하기
!=
Map 컬렉션)
let list = [
{id:1, title:"jsp is...", writerId:"newlec"},
{id:2, title:"servlet is...", writerId:"newlec"},
{id:3, title:"javascript is...", writerId:"newlec"},
{id:4, title:"spring is...", writerId:"newlec"}
]
list.forEach((n)=>{}); // forEach의 원래 개념
// *** map 함수 개념 (Map 콜렉션이 아니다!****) : 매핑시켜주는 것!!
// map 함수는 변환할 때, 좋은 도구이다.
// list라는 변수의 배열 데이터 타입을 n이라는 Object 타입으로 변경해준다.
// 화살표 함수에 의해 list라는 배열 타입의 변수를 map 함수에 의해 n이라는 Object 타입으로 변경하고
// n에 담아서 return으로 n의 속성을 반환한다.
let ar = list.map((n)=> {return `<span>${n.title}</span>`});
console.log(ar);
2) Game project
- this.dom.onclick = this.clickHandler.bind(this)의 부분 공부하기
// game-canvs.js는 사용자 입력과 출력을 담당한다.(중요!!) *****
class GameCanvas { // 클래스로 변경
constructor(){ // **** 중요한 개념 :
this.dom = document.querySelector(".game-canvas"); // 여기서 this는 GameCanvas의 new된 결과이다.
// dom이 canvas이다. canvas가 this의 멤버로 들어온 것이다.
// 원래 java에서는 canvas가 canvas를 갖는 것이 이상하다.
// 그래서, JS는 틀로 쓸 수 있는 것이 아니다.(프레임워크가 아니였다.)
// 앞으로는 this의 dom 기능을 이용한다.
/** @type {CanvasRenderingContext2D} */
this.ctx = this.dom.getContext('2d'); // var ctx가 아니라 this.ctx이다.(Boy의 ctx이므로)
this.boy = new Boy(100, 100);
this.gameover = false; // setTime을 위한 상태값!!****, 게임 오버는 아니고 애니메이션만
// 멈추게 해야 한다. 즉, 멈추면 상태값이 전부 날아가는 것이
// 아니라 정지인 상태이다.(배경과 적들은 움직임)
this.pause = false; // 그래서, 게임이 끝나는 것이 아니라 일시정지가 되어야 한다.
// **** 다른 애가 불러내서 위임되는 함수라고 부르며 "call back function"이라고 부른다.
// 사용자가 클릭해달라고 위임했기 때문이다. call back function은 지금 실행하는 것이 아니라 나중에 실행된다.(위임해야지 나중에 전화할 수 있기 때문이다.(나중에 실행))
// 전화하는 애가 주체가 된다.
// dom이 다시 호출해준다?
// this.dom.onclick = this.clickHandler; // ()처럼 함수를 호출한 결과 값 넣지 말기
this.dom.onclick = this.clickHandler.bind(this); // **** .bind() 처리하면서 .bind(this)의 this는 이벤트 핸들러를 위한 객체를 불러온다. 원래 this는 gamecanvas이다.
}
// **** 내장 객체의 함수와 새로만들어 지는 객체의 함수를 비교할 것.
// clickHandler는 사용자 입력에 의한 이벤트 핸들러이기 때문에
// window에서 가져와야 해서 .bind(this)를 뒤에 붙여준다.
// 이렇게 사용하면 위의 코드와 비교해서 dom은 이전의 생성자에서 넘겨받아서 this가 dom이 아니다.
//console.log(this)
run(){
if(this.pause)
return;
// 60 프레임으로 화면을 다시 그리는 코드!!
this.update();
this.draw();
// // 게임 만들 때, 심박동을 위해서 setTimeOut, setInterval, AnimationFrame 심박동을 우리가 맞출 수 없다.(조정이 불가능)
// // setTimeOut - 1회성, setInterval - 반복성, AnimationFrame - 프레임 1초에 60회로 고정
// window.setTimeout(function(){
// console.log("time out");
// },1000);
// // this를 알게 하기 위해서 호출하는 주체를 봐야 한다.
// window.setTimeout(function(){
// this.run().bind(this); // 여기서 함수를 호출하는 것이 window라고 앞에 적혀 있어서
// },1000); // 그래서 우리는 여기 있는 run을 실행하기 위해서 bind를 사용한다!!
// // ************ ES6 함수 정의 방법 : Arrow Function ************
// // 자기 this가 없으니까 밖의 this를 사용한다. (자기만의 영역이 없다. 지역화가 없다.)
// // 자기만의 this가 없어서 bind를 사용하지 않는다.****
// window.setTimeout(()=>{
// this.run();
// },1000);
window.setTimeout(()=>{ // 알람 맞추는 것과 같다.(60 프레임에 맞추어서 = 1000/60 = 17)
this.run();
},17);
// 여기까지 하면, 무한히 반복한다. 멈추고 싶으면? 이 안에서 멈추는 도구가 필요하다. 그래서 상태변수가 필요하다.
}
// canvas는 UI이고 UI에 의해서 꼭두각시처럼 컨트롤된다.
update(){ // update는 단위 계수마다 잘게 쪼개서 움직여야 한다.
// 시간에 국한에서 잘게 짜르려면 frame을 나누어야 한다.
// 이동하는 속도가 일정하려면,
this.boy.update(); // 이동하고
}
draw(){
this.boy.draw(this.ctx); // 다시 그리고
}
pause(){
}
// ------------------------------- event handler***** --------------------------------
// 이벤트가 발생했다!! 사용자 입력에 의해서 이벤트가 발생 // 사건의 구체적인 정보를 알아야내 한다.(어떤 위치에 마우스를 클릭했는지, 어떤 키보드를 눌렀는지)
clickHandler(e){ // 클릭하면, 타이머가 멈춘다!!
//this.pause = true; // 같은 함수 내부라서 함수 호출 시,
// 함수를 사용하는 것이 아니라 값을 입력해준다.
// this.boy.move(2); // 마우스로 move하는 것은 옳지 않고 방향키로 나중에 구현할 것
// 마우스는 사용자 입력이다.
// ** 상태 변수를 이용
this.boy.moveTo(e.x,e.y); // 이동할 때, 대각선 길이를 잘게 쪼개는데 가로 세로는 그 값이 얼마였든지간에 비율로 대각선 길이로 나눈다.
// 나중에 배우자! 이벤트 함수 : screen x, event x, osell x
// 화면 지우기
this.boy.draw(this.ctx); // 함수 호출자는 dom이다. 하지만, 우리는 this가 GameCanvas였으면 좋겠다. 서로 역할이 엇갈림.
// 그래서 우리는 보따리를 쌓아 줘야한다.(위에서 bind로 묶어줌.) *******
console.log(this); // 위의 dom이 앞에서 위임받아서 dom이 아니라 이전 생성자이다.
}
}
2. Game 관련 Canvas [23.01.06]
1) 스레드 개념
-
UI를 담당하는 부분 : 메인 스레드
-
게임을 동작하는 부분 : 게임 스레드
-
이 2개의 흐름이 소통하는 방법? 상태 변수를 사용하여 구분해야 한다.
-
게임 스레드가 계속 돌고 있으면서 캐릭터의 함수에서 값을 계속 확인하면서 상호 작용 후 진행된다.
-
스레드 순서를 중요하게 정해서 나열해야지 객체의 순서를 잘 보일 수 있다.(비행기, 메인, 배경 등등**)
2) 보정 기술 개념
- 먼거리를 이동할 때의 위치를 잡아주는 보정 기술이 필요하다.(우주 공학에서는 이런 것이 정밀하게 필요하다.)
- main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 순서가 중요하다.**** -->
<script src="./item/background.js"></script> <!-- 새로운 페이지 등록 시, url 연결 시켜주기! -->
<script src="./item/boy.js"></script>
<script src="./panel/game-canvas.js"></script>
<script src="./app.js"></script>
<script src="ex1-es6-var.js"></script>
<!-- 문서가 다 읽혀지고 읽어지는 방법 : html, js에서 해결 가능(document.addEventListener 이용) -->
</head>
<body>
<!-- 주의사항 : css를 키우면 배율이 커진다. 그래서 속성을 키워야 한다. 즉, canvas를 키워야 한다.
보통의 경우 속성을 키우고 css로 줄이는 경우는 이미지가 깨지는것을 방지해준다. -->
<input tabindex="2">
<img>
<div tabindex="1"> <!-- tabindex를 넣어야지 tab으로 이동할 수 있다. -->
test <!-- 마우스가 기본이라서 마우스가 우선 순위라서 사용자가 마우스를 클릭하고나서 키의 입력을 받을 수 있다. -->
</div> <!-- 그래서 키보드 입력하기 위해서 tabindex를 설정한다!! -->
<input tabindex="0">
<!-- style="display: none;"은 style 안보이지만 메모리에 올라가 있다 즉, dom에 올라가 있따. -->
<img src="./image/boy.png" id ="boy" style="display: none;">
<img src="./image/map.png" id ="bg" style="display: none;">
<canvas tabindex="0" class="game-canvas" width="500" height="1000"></canvas>
</body>
</html>
- app.js
window.addEventListener("load", function(){
var gameCanvas = new GameCanvas(); // 다른 파일을 가져오는 방식이 자바스크립트에서는 없다.
// 그래서 사용할 모듈을 html에게 요청한다.
// 에러 : GameCanvas 객체를 생성시, 참조는 소문자에 넣어준다.
gameCanvas.run();
// run()은 무한 loop해야 한다. UI 스레드는 별도의 흐름을 갖게 해야 한다.
// vscode에선 F12로 함수 선언과 이동 가능
});
- game-canvas.js
// game-canvs.js는 사용자 입력과 출력을 담당한다.(중요!!) *****
class GameCanvas { // 클래스로 변경
constructor(){ // **** 중요한 개념 :
this.dom = document.querySelector(".game-canvas"); // 여기서 this는 GameCanvas의 new된 결과이다.
// dom이 canvas이다. canvas가 this의 멤버로 들어온 것이다.
// 원래 java에서는 canvas가 canvas를 갖는 것이 이상하다.
// 그래서, JS는 틀로 쓸 수 있는 것이 아니다.(프레임워크가 아니였다.)
// 앞으로는 this의 dom 기능을 이용한다.
this.dom.focus(); // focus를 잡아주면 canvas에서 키보드 입력을 할 수 있다. **** 즉, 우선순위를 마우스에서 키보드로 넘겨준다.
// 키보드로 무브하는 방법????
/** @type {CanvasRenderingContext2D} */
this.ctx = this.dom.getContext('2d'); // var ctx가 아니라 this.ctx이다.(Boy의 ctx이므로)
this.boy = new Boy(100, 100);
this.bg = new Background();
this.gameover = false; // setTime을 위한 상태값!!****, 게임 오버는 아니고 애니메이션만
// 멈추게 해야 한다. 즉, 멈추면 상태값이 전부 날아가는 것이
// 아니라 정지인 상태이다.(배경과 적들은 움직임)
this.pause = false; // 그래서, 게임이 끝나는 것이 아니라 일시정지가 되어야 한다.
// **** 다른 애가 불러내서 위임되는 함수라고 부르며 "call back function"이라고 부른다.
// 사용자가 클릭해달라고 위임했기 때문이다. call back function은 지금 실행하는 것이 아니라 나중에 실행된다.(위임해야지 나중에 전화할 수 있기 때문이다.(나중에 실행))
// 전화하는 애가 주체가 된다.
// dom이 다시 호출해준다?
// this.dom.onclick = this.clickHandler; // ()처럼 함수를 호출한 결과 값 넣지 말기
this.dom.onclick = this.clickHandler.bind(this); // **** .bind() 처리하면서 .bind(this)의 this는 이벤트 핸들러를 위한 객체를 불러온다. 원래 this는 gamecanvas이다.
// this.dom.onclick = this.clickHandler; // **** .bind() 처리하면서 .bind(this)의 this는 이벤트 핸들러를 위한 객체를 불러온다. 원래 this는 gamecanvas이다.
this.dom.onkeydown = this.keyDownHandler.bind(this);
}
// **** 내장 객체의 함수와 새로만들어 지는 객체의 함수를 비교할 것.
// clickHandler는 사용자 입력에 의한 이벤트 핸들러이기 때문에
// window에서 가져와야 해서 .bind(this)를 뒤에 붙여준다.
// 이렇게 사용하면 위의 코드와 비교해서 dom은 이전의 생성자에서 넘겨받아서 this가 dom이 아니다.
//console.log(this)
run(){
//console.log(this);
if(this.pause)
return;
// 60 프레임으로 화면을 다시 그리는 코드!!
this.update();
this.draw();
// // 게임 만들 때, 심박동을 위해서 setTimeOut, setInterval, AnimationFrame 심박동을 우리가 맞출 수 없다.(조정이 불가능)
// // setTimeOut - 1회성, setInterval - 반복성, AnimationFrame - 프레임 1초에 60회로 고정
// window.setTimeout(function(){
// console.log("time out");
// },1000);
// window.setTimeout(this.run.bind(this), 10000);
// window.setTimeout(this.run.bind(this), 1000);
// // this를 알게 하기 위해서 호출하는 주체를 봐야 한다.
// window.setTimeout(function(){
// this.run(); // 여기서 함수를 호출하는 것이 window라고 앞에 적혀 있어서
// },1000).bind(this); // 그래서 우리는 여기 있는 run을 실행하기 위해서 bind를 사용한다!!
// // ************ ES6 함수 정의 방법 : Arrow Function ************
// // 자기 this가 없으니까 밖의 this를 사용한다. (자기만의 영역이 없다. 지역화가 없다.)
// // 자기만의 this가 없어서 bind를 사용하지 않는다.****
// window.setTimeout(()=>{
// this.run();
// },1000);
window.setTimeout(()=>{ // 알람 맞추는 것과 같다.(60 프레임에 맞추어서 = 1000/60 = 17)
this.run();
},17);
// 여기까지 하면, 무한히 반복한다. 멈추고 싶으면? 이 안에서 멈추는 도구가 필요하다. 그래서 상태변수가 필요하다.
}
// canvas는 UI이고 UI에 의해서 꼭두각시처럼 컨트롤된다.
update(){ // update는 단위 계수마다 잘게 쪼개서 움직여야 한다.
// 시간에 국한에서 잘게 짜르려면 frame을 나누어야 한다.
// 이동하는 속도가 일정하려면,
this.boy.update(); // 이동하고
//this.bg.update(); // 이동하고
}
draw(){
this.bg.draw(this.ctx); // 순서 중요!!
this.boy.draw(this.ctx);
//this.bg.draw(this.ctx);
}
pause(){
}
// ------------------------------- event handler***** --------------------------------
// 이벤트가 발생했다!! 사용자 입력에 의해서 이벤트가 발생 // 사건의 구체적인 정보를 알아야내 한다.(어떤 위치에 마우스를 클릭했는지, 어떤 키보드를 눌렀는지)
clickHandler(e){ // 클릭하면, 타이머가 멈춘다!!
//this.pause = true; // 같은 함수 내부라서 함수 호출 시,
// 함수를 사용하는 것이 아니라 값을 입력해준다.
// this.boy.move(2); // 마우스로 move하는 것은 옳지 않고 방향키로 나중에 구현할 것
// 마우스는 사용자 입력이다.
//console.log(this);
// ** 상태 변수를 이용
this.boy.moveTo(e.x,e.y); // 이동할 때, 대각선 길이를 잘게 쪼개는데 가로 세로는 그 값이 얼마였든지간에 비율로 대각선 길이로 나눈다.
// 나중에 배우자! 이벤트 함수 : screen x, event x, osell x
// 화면 지우기
this.boy.draw(this.ctx); // 함수 호출자는 dom이다. 하지만, 우리는 this가 GameCanvas였으면 좋겠다. 서로 역할이 엇갈림.
// 그래서 우리는 보따리를 쌓아 줘야한다.(위에서 bind로 묶어줌.) *******
//console.log(this); // 위의 dom이 앞에서 위임받아서 dom이 아니라 이전 생성자이다.
}
// ***** canvas나 div 태그는 키 입력을 안 받게 했다.
keyDownHandler(e){
this.boy.move(e.key);
console.log(e.key);
}
}
- boy.js
// 원래 웹에서는 파일명을 가장 앞에는 소문자로 구분하고 대쉬(-)로 구분한다
// 중요!!!!****
// 캡슐화 vs 캡슐(데이터를 구조화한 것)
// 캡슐화란 - 책임을 부여하는 것, 역할을 나누는 것, 기능을 부여하는 것
// 객체지향은 그림을 그릴 수 밖에 없고, 그 그림은 설계가 된다.
class Boy { // *******
constructor(x,y){
this.x = x || 200; // 6. 오버로드 생성자로 사용자가 넘겨줄 값이 있을 때, 가능하게 하려고 이렇게도 가능하다.
this.y = y || 100; // 사용자 입력이 없을 때는, x와 y는 || 뒤의 기본값이 들어간다.
this.vx = 0; // 단위 위치(잘게 조개진 값)
this.vy = 0;
this.dx = 0; // 목적지 위치
this.dy = 0;
this.img = document.querySelector("#boy"); // html에서 이미지를 이렇게 가져온다.(이젠, 생성자에서 그리기 위해서!) *************
this.ix = 1; // ix, iy는 스프라이트 사진에서 부분을 꺼낼수 있게 배열의 인덱스 값이다!
this.iy = 2;
this.walkDelay = 20; // 프레임 낮춰주기!!
this.sw = 106;
this.sh = 148.25;
this.sx = this.sw * this.ix;
this.sy = this.sh * this.iy; // 메인 스레드는 절차를 담당하는 기본 흐름이다. setTimeout인 보조 흐름이며 추가적으로 작동을 만든 것이 게임 스레드이다.
} // 이것의 차이를 알기!!****
// update와 draw는 메인 스레드(게임 스레드)이다.(사용자 입력이 없더라도, 내가 호출하는 것이 아니라 초당 60번씩 계속 돌고 있다.)
// 나머지는 UI 스레드이다.(사용자 입력이 있을 때만, 한 번만 움직임.)
draw(ctx){
this.sx = this.sw * this.ix;
this.sy = this.sh * this.iy;
ctx.drawImage(this.img, this.sx, this.sy, this.sw, this.sh, // **** 에러발생 : img는 생성자에서 가져오기 때문에 this.img 이다!!
this.x-this.sw/2, this.y-this.sh+15, this.sw, this.sh); // 발이 기준이 되게 값을 조정해주자!!
// var img = new Image();
// img.src = './image/boy.png'; // 이미지도 생성자에서 생성하자!!*****
// img.onload = function(){ // 이렇게 만들면 에러가 나는 이유?
// // sx는 source(원본의 x크기), dx(display의 x크기)
// }.bind(this); // 여기서는 Boy에서 img로 이벤트가 위임 되었다!!(중요)
// 개념적인 부분 : 위임? 다시 이벤트 위임 공부, Function.prototype.call()은 모든 함수에서 call이 있어야 한다.
// 중요!! 함수가 호출한 주체가 this가 된다. apply, call
//console.log(this);
}
update(){ // ** update는 상태값만 변경해줘야 한다.
// ======================================
// setInterval(draw, 10);
//this.draw().drawImage(this.img, this.sx*this.ix, this.sy*this.iy);
// 조건 설정!! dx가 중심점, dy가 중심점이라고 가정하에 조건문 설정!
// 정확히는 dx가 기준점이 되고 x가 움직이는 변수이다.
// x축 따로, y축 따로 구성해서 합쳐서 구현!!
if(this.dx - 1 < this.x && this.x < this.dx + 1 || this.dy - 1 < this.y && this.y < this.dy + 1){
this.vx = 0;
this.vy = 0;
this.ix = 1; // 멈출 때만 상태값을 바꿔줘도 되는가?***
}
if(this.vx == 0 && this.vy == 0 ) { // 멈출 때 조건 설정 : vx 설정 (이것도 되긴 된다.)
this.ix = 1; // 멈췄는지 안멈췄는지는 vx의 유무가 중요하다!!
return;
}
// ======================================
this.x += this.vx; // 여기서 목적직 위치까지 단위 위치(벡터)로 더하면서 업데이트 시킴
this.y += this.vy;
this.walkDelay--;
//this.ix=this.ix==2?0:2; // 3항 연산 중요!!!
if(this.walkDelay == 0){
if(this.ix == 0){
this.ix = 2;
}
else if(this.ix == 1){
this.ix = 0;
}
else if(this.ix == 2){
this.ix = 0;
}
this.walkDelay = 20;
}
}
moveTo(dx,dy){
let w = dx - this.x; // 목적지 위치 - 현재 위치(업데이트되고나서) = 남은 위치 거리 계산
let h = dy - this.y;
let d = Math.sqrt(w*w+h*h); // 대각선 길이 공식
this.vx = w / d; // 여기 this도 주의해서 적기, 그 남은 위치 거리를 다시 잘게 쪼개진 비율로 나누어서 이동한다.
this.vy = h / d;
this.dx = dx;
this.dy = dy;
}
move(dir){
switch(dir){
case 1: // 북쪽
this.y -= 50; // 브라우저 기준으로 시작을 생각해보면 된다.
break;
case 2: // 동쪽
this.x += 50;
break;
case 3: // 남쪽
this.y += 50;
break;
case 4: // 서쪽
this.x -= 50;
break;
}
}
}
-background.js
class Background {
constructor(){
this.x=0;
this.y=0;
this.img = document.querySelector("#bg");
}
draw(ctx){
ctx.drawImage(this.img, this.x, this.y);
}
update(){
}
}