Javascript
// wrapper for our game "classes", "methods" and "objects" window.Game = {}; // wrapper for "class" Rectangle (function(){ function Rectangle(left, top, width, height){ this.left = left || 0; this.top = top || 0; this.width = width || 0; this.height = height || 0; this.right = this.left + this.width; this.bottom = this.top + this.height; } Rectangle.prototype.set = function(left, top, /*optional*/width, /*optional*/height){ this.left = left; this.top = top; this.width = width || this.width; this.height = height || this.height this.right = (this.left + this.width); this.bottom = (this.top + this.height); } //자신의 상자가 타겟(r)에 와벽하게 포함되어 있는지 체크 Rectangle.prototype.within = function(r) { return (r.left <= this.left && r.right >= this.right && r.top <= this.top && r.bottom >= this.bottom); } //자신의 상자가 타겟(r)에 결쳐서 포함되어 있는지 체크 Rectangle.prototype.overlaps = function(r) { return (this.left < r.right && r.left < this.right && this.top < r.bottom && r.top < this.bottom); } // add "class" Rectangle to our Game object Game.Rectangle = Rectangle; })(); // wrapper for "class" Camera (avoid global objects) (function(){ // possibles axis to move the camera var AXIS = { NONE: "none", HORIZONTAL: "horizontal", VERTICAL: "vertical", BOTH: "both" }; // Camera constructor function Camera(xView, yView, canvasWidth, canvasHeight, worldWidth, worldHeight) { // position of camera (left-top coordinate) this.xView = xView || 0; this.yView = yView || 0; // distance from followed object to border before camera starts move this.xDeadZone = 0; // min distance to horizontal borders this.yDeadZone = 0; // min distance to vertical borders // viewport dimensions this.wView = canvasWidth; this.hView = canvasHeight; // allow camera to move in vertical and horizontal axis this.axis = AXIS.BOTH; // object that should be followed this.followed = null; // rectangle that represents the viewport this.viewportRect = new Game.Rectangle(this.xView, this.yView, this.wView, this.hView); // rectangle that represents the world's boundary (room's boundary) this.worldRect = new Game.Rectangle(0, 0, worldWidth, worldHeight); } // gameObject needs to have "x" and "y" properties (as world(or room) position) Camera.prototype.follow = function(gameObject, xDeadZone, yDeadZone) { this.followed = gameObject; this.xDeadZone = xDeadZone; this.yDeadZone = yDeadZone; } Camera.prototype.update = function() { //픞레이어 추적. // keep following the player (or other desired object) if(this.followed != null) { if(this.axis == AXIS.HORIZONTAL || this.axis == AXIS.BOTH) { //데드 존역영을 followed객체가 벋어나도 카메라는 고정되도록 설정. x축 // moves camera on horizontal axis based on followed object position if(this.followed.x - this.xView + this.xDeadZone > this.wView) this.xView = this.followed.x - (this.wView - this.xDeadZone); else if(this.followed.x - this.xDeadZone < this.xView) this.xView = this.followed.x - this.xDeadZone; } if(this.axis == AXIS.VERTICAL || this.axis == AXIS.BOTH) { //데드 존역영을 followed객체가 벋어나도 카메라는 고정되도록 설정. y축 // moves camera on vertical axis based on followed object position if(this.followed.y - this.yView + this.yDeadZone > this.hView) this.yView = this.followed.y - (this.hView - this.yDeadZone); else if(this.followed.y - this.yDeadZone < this.yView) this.yView = this.followed.y - this.yDeadZone; } } // left / top 입니다. xView, yView // update viewportRect this.viewportRect.set(this.xView, this.yView); // 월드 영역에서 카메라가 벋어나지 못하게. // don't let camera leaves the world's boundary if(!this.viewportRect.within(this.worldRect)) { //어디가 벋어 났는지 파악해서 위치를 WORLD의 박스에 고정시킨다. if(this.viewportRect.left < this.worldRect.left){ this.xView = this.worldRect.left; } if(this.viewportRect.top < this.worldRect.top) this.yView = this.worldRect.top; if(this.viewportRect.right > this.worldRect.right) this.xView = this.worldRect.right - this.wView; if(this.viewportRect.bottom > this.worldRect.bottom) this.yView = this.worldRect.bottom - this.hView; } } // add "class" Camera to our Game object Game.Camera = Camera; })(); // wrapper for "class" Player (function(){ function Player(x, y){ // (x, y) = center of object // ATTENTION: // it represents the player position on the world(room), not the canvas position this.x = x; this.y = y; // move speed in pixels per second //초당 속도 200 this.speed = 200; // render properties this.width = 50; this.height = 50; } //world밖으로 빠져나가지 못하게 .. 월드간격을 준다. Player.prototype.update = function(step, worldWidth, worldHeight){ // parameter step is the time between frames ( in seconds ) // check controls and move the player accordingly // 속도에 dt를 곱해서 좌표를 변경. if(Game.controls.left) this.x -= this.speed * step; if(Game.controls.up) this.y -= this.speed * step; if(Game.controls.right) this.x += this.speed * step; if(Game.controls.down) this.y += this.speed * step; //월드를 벋어나지 못한다. // don't let player leaves the world's boundary if(this.x - this.width/2 < 0){ this.x = this.width/2; } if(this.y - this.height/2 < 0){ this.y = this.height/2; } if(this.x + this.width/2 > worldWidth){ this.x = worldWidth - this.width/2; } if(this.y + this.height/2 > worldHeight){ this.y = worldHeight - this.height/2; } } Player.prototype.draw = function(context, xView, yView){ // draw a simple rectangle shape as our player model context.save(); context.fillStyle = "black"; // before draw we need to convert player world's position to canvas position context.fillRect((this.x-this.width/2) - xView, (this.y-this.height/2) - yView, this.width, this.height); context.restore(); } // add "class" Player to our Game object Game.Player = Player; })(); // wrapper for "class" Map (function(){ function Map(width, height){ // map dimensions this.width = width; this.height = height; // map texture this.image = null; } // generate an example of a large map // 커다란 전체 이미지 그리기. Map.prototype.generate = function(){ var ctx = document.createElement("canvas").getContext("2d"); ctx.canvas.width = this.width; ctx.canvas.height = this.height; var rows = ~~(this.width/44) + 1; var columns = ~~(this.height/44) + 1; var color = "red"; ctx.save(); ctx.fillStyle = "red"; for (var x = 0, i = 0; i < rows; x+=44, i++) { ctx.beginPath(); for (var y = 0, j=0; j < columns; y+=44, j++) { ctx.rect (x, y, 40, 40); } color = (color == "red" ? "blue" : "red"); ctx.fillStyle = color; ctx.fill(); ctx.closePath(); } ctx.restore(); // store the generate map as this image texture this.image = new Image(); this.image.src = ctx.canvas.toDataURL("image/png"); // clear context ctx = null; } // draw the map adjusted to camera // @param 위치 좌표. Map.prototype.draw = function(context, xView, yView){ // easiest way: draw the entire map changing only the destination coordinate in canvas // canvas will cull the image by itself (no performance gaps -> in hardware accelerated environments, at least) //context.drawImage(this.image, 0, 0, this.image.width, this.image.height, -xView, -yView, this.image.width, this.image.height); // didactic way: var sx, sy, dx, dy; var sWidth, sHeight, dWidth, dHeight; // offset point to crop the image sx = xView; sy = yView; // dimensions of cropped image sWidth = context.canvas.width; //보여줄 사이즈 sHeight = context.canvas.height; // if cropped image is smaller than canvas we need to change the source dimensions if(this.image.width - sx < sWidth){ sWidth = this.image.width - sx; } if(this.image.height - sy < sHeight){ sHeight = this.image.height - sy; } // location on canvas to draw the croped image dx = 0; dy = 0; // match destination with source to not scale the image dWidth = sWidth; //확대 축소를 안하면...그대로 대입 dHeight = sHeight; /* - img : 사용할 이미지 - sx : 잘라낼 이미지의 시작점 x - sy : 잘라낼 이미지의 시작점 y - sWidth: 잘라낼 이미지의 마지막 위치 x - sHeight : 잘라낼 이미지의 마지막 위치 y - dx : 이미지의 x 좌표값 - dy : 이미지의 y 좌표값 - dWidth : 잘라낸 이미지의 x 값 크기 - dHeight : 잘라낸 이미지의 y 값 크기 */ context.drawImage(this.image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); } // add "class" Map to our Game object Game.Map = Map; })(); // Game Script (function(){ // prepaire our game canvas var canvas = document.getElementById("gameCanvas"); var context = canvas.getContext("2d"); // game settings: var FPS = 30; var INTERVAL = 1000/FPS; // milliseconds var STEP = INTERVAL/1000 // seconds // setup an object that represents the room var room = { width: 5000, height: 3000, map: new Game.Map(5000, 3000) }; // generate a large image texture for the room room.map.generate(); // setup player var player = new Game.Player(50, 50); // setup the magic camera !!! // 카메라에 배경도 달았음. var camera = new Game.Camera(0, 0, canvas.width, canvas.height, room.width, room.height); //카메라를 player한테 연결 camera.follow(player, canvas.width/2, canvas.height/2); //Update // Game update function var update = function(){ player.update(STEP, room.width, room.height); camera.update(); } //Render // Game draw function var draw = function(){ // clear the entire canvas context.clearRect(0, 0, canvas.width, canvas.height); // redraw all objects room.map.draw(context, camera.xView, camera.yView); player.draw(context, camera.xView, camera.yView); } // Game Loop var gameLoop = function(){ update(); draw(); } // <-- configure play/pause capabilities: // I'll use setInterval instead of requestAnimationFrame for compatibility reason, // but it's easy to change that. var runningId = -1; Game.play = function(){ if(runningId == -1){ runningId = setInterval(function(){ gameLoop(); }, INTERVAL); console.log("play"); } } Game.togglePause = function(){ if(runningId == -1){ Game.play(); } else { clearInterval(runningId); runningId = -1; console.log("paused"); } } // --> })(); // <-- configure Game controls: Game.controls = { left: false, up: false, right: false, down: false, }; window.addEventListener("keydown", function(e){ switch(e.keyCode) { case 37: // left arrow Game.controls.left = true; break; case 38: // up arrow Game.controls.up = true; break; case 39: // right arrow Game.controls.right = true; break; case 40: // down arrow Game.controls.down = true; break; } }, false); window.addEventListener("keyup", function(e){ switch(e.keyCode) { case 37: // left arrow Game.controls.left = false; break; case 38: // up arrow Game.controls.up = false; break; case 39: // right arrow Game.controls.right = false; break; case 40: // down arrow Game.controls.down = false; break; case 80: // key P pauses the game Game.togglePause(); break; } }, false); // --> // start the game when page is loaded window.onload = function(){ Game.play(); }