2016-05-31 2 views
2

캔버스 API를 사용하여 타일 기반 게임을 자바 스크립트로 만들고 있습니다. 나는 MDN에서 square tilemap scrolling tutorial을 따라왔다. 작동하지만 카메라를 움직이면 모든 타일이 렌더링되지 않으며 특히 오른쪽으로 이동하면 타일이 렌더링되지 않습니다. 자습서로 코드 복사 및 붙여 넣기를 시도했지만 여전히 작동하지 않습니다.캔버스 - 타일이 완전히 렌더링되지 않습니다.

var canvas = document.getElementById('canvas'); 
var ctx = canvas.getContext('2d'); 
var tiles = new Image(); 
tiles.src = "img/tiles.png"; 
var socket = io(); 

function Loader(game) { 
    this.game = game; 
    this.images = {} 
} 

Loader.prototype.loadImage = function(id, url, tile) { 
    var image = new Image(); 
    image.src = url; 
    this.images[id] = { 
    img: image, 
    url: url, 
    tile: tile 
    } 
} 

Loader.prototype.ready = function() { 
    this.game.loadImages(this.images); 
} 



function Game(canvas, map,camera) { 
    this.canvas = canvas; 
    this.ctx = this.canvas.getContext('2d'); 
    this.monsters = []; 
    this.player = {}; 
    this.map = map; 
    this.timestamp = function() { 
    return window.performance && window.performance.now ? window.performance.now() : new Date().getTime(); 
    } 
    this.camera = camera||{ 
    x: 0, 
    y: 0, 
    width: 256, 
    height: 256 
    } 

} 

Game.prototype.init = function(ts) { 
    this.current = { 
    tileset: this.images[ts] 
    } 
    this.width = this.map.cols * this.map.tsize; 
    this.height = this.map.rows * this.map.tsize; 
    this.canvas.height=1000; 
    this.canvas.width=1000; 
    this.camera.maxX = this.map.cols * this.map.tsize - this.camera.width; 
    this.camera.maxY = this.map.rows * this.map.tsize - this.camera.height; 
} 

Game.prototype.loadImages = function(images) { 
    this.images = images; 
} 

Game.prototype.start = function() { 

    this.now = 0; 
    this.dt = 0; 
    this.last = this.timestamp(); 
    this.frame(); 
} 

Game.prototype.update = function(delta) { 
    var dirx = 0; 
    var diry = 0; 
    if (KEYS.LEFT) { dirx = -1; } 
    if (KEYS.RIGHT) { dirx = 1; } 
    if (KEYS.UP) { diry = -1; } 
    if (KEYS.DOWN) { diry = 1; } 

    this.camera.move(delta, dirx, diry); 
} 

Game.prototype.render = function(delta) { 
    this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height); 
    var startCol = Math.floor(this.camera.x/this.map.tsize); 
    var endCol = startCol + (this.camera.width/this.map.tsize); 
    var startRow = Math.floor(this.camera.y/this.map.tsize); 
    var endRow = startRow + (this.camera.height/this.map.tsize); 
    var offsetX = -this.camera.x + startCol * this.map.tsize; 
    var offsetY = -this.camera.y + startRow * this.map.tsize; 
    for(var c = startCol; c <= endCol; c++) { 
    for(var r = startRow; r <= endRow; r++) { 
     var tile = this.getTile(c, r); 
     var x = (c - startCol) * this.map.tsize + offsetX; 
     var y = (r - startRow) * this.map.tsize + offsetY; 
     if(tile !== 0) { 
     ctx.drawImage(
      this.current.tileset.img, //image 
      (tile - 1) * this.map.tsize, 
      0, 
      this.map.tsize, 
      this.map.tsize, 
      Math.round(x), 
      Math.round(y), 
      this.map.tsize, 
      this.map.tsize 
     ) 
     } 
    } 
    } 
} 

Game.prototype.frame = function() { 
    this.now = this.timestamp(); 
    this.dt = (this.now - this.last)/1000; // duration in seconds 
    this.update(this.dt); 
    this.render(this.dt); 
    this.last = this.now; 
    requestAnimationFrame(this.frame.bind(this)); 
}; 


Game.prototype.getTile = function(x, y) { 
    return this.map.layer[y * this.map.cols + x]; 
} 


function Camera(map, width, height) { 
    this.x = 0; 
    this.y = 0; 
    this.width = width; 
    this.height = height; 
    this.maxX = map.cols * map.tsize - width; 
    this.maxY = map.rows * map.tsize - height; 
} 

Camera.SPEED = 256; // pixels per second 

Camera.prototype.move = function (delta, dirx, diry) { 
    // move camera 
    this.x += dirx * Camera.SPEED * delta; 
    this.y += diry * Camera.SPEED * delta; 
    // clamp values 
    this.x = Math.max(0, Math.min(this.x, this.maxX)); 
    this.y = Math.max(0, Math.min(this.y, this.maxY)); 
}; 

var KEYS = { 

}; 

function handleKey(down, e, key) { 
    switch(key) { 
    case 37: 
     KEYS.LEFT = down; 
     break; 
    case 38: 
     KEYS.UP = down; 
     break; 
    case 39: 
     KEYS.RIGHT = down; 
     break; 
    case 40: 
     KEYS.DOWN = down; 
     break; 
    default: 
     KEYS[String.fromCharCode(key)] = down; 
     break; 
    } 
}; 


document.onkeydown = function(e) { 
    handleKey(true, e, e.which); 
}; 

document.onkeyup = function(e) { 
    handleKey(false, e, e.which); 
}; 

function getHelp(s) { 
    socket.emit('help', s); 
} 

var map = { 
    cols: 12, 
    rows: 12, 
    tsize: 64, 
    layer: [ 
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
     3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 
     3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 
     3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 
     3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 
     3, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 
     3, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3, 
     3, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3, 
     3, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 
     3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 
     3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 
3, 3, 3, 1, 1, 2, 3, 3, 3, 3, 3, 3 
    ] 
}; 
var camera = new Camera(map,256,256); 
var game = new Game(canvas, map,camera); 

var loader = new Loader(game); 

loader.loadImage('set1', 'img/tiles.png', 64); 
loader.ready(); 

game.init('set1'); 
game.start(); 

또한 저장소 here를 찾을 수 있습니다 여기에

클라이언트 코드입니다.

+0

이봐 spacegeek224, 내가 편집 한 대답을 - 실행 니펫에 코드를 설정 : 사용 중간에이 방법을 카메라 창을 중심으로. 편집을 승인 하시겠습니까? –

답변

1

게임이 정상적으로 작동합니다. 256x256 픽셀의 카메라 창이 있습니다. 렌더링하는 동안이 공간은 타일로 완전히 채워집니다. 해당 카메라 창 바깥에있는 '사라지는'타일로 인해 괴롭혀지면 clipping rectangle을 사용하거나 카메라 크기에 맞게 캔버스 크기를 줄이십시오.

당신이 고정 캔버스 크기 및 전자를 원한다면

var canvas = document.getElementById('canvas'); 
 
var ctx = canvas.getContext('2d'); 
 

 
function Loader(game) { 
 
    this.game = game; 
 
    this.images = {} 
 
} 
 

 
Loader.prototype.loadImage = function(id, url, tile) { 
 
    var image = new Image(); 
 
    image.src = url; 
 
    this.images[id] = { 
 
    img: image, 
 
    url: url, 
 
    tile: tile 
 
    } 
 
} 
 

 
Loader.prototype.ready = function() { 
 
    this.game.loadImages(this.images); 
 
} 
 

 
function Game(canvas, map,camera) { 
 
    this.canvas = canvas; 
 
    this.ctx = this.canvas.getContext('2d'); 
 
    this.monsters = []; 
 
    this.player = {}; 
 
    this.map = map; 
 
    this.timestamp = function() { 
 
    return window.performance && window.performance.now ? window.performance.now() : new Date().getTime(); 
 
    } 
 
    this.camera = camera||{ 
 
    x: 0, 
 
    y: 0, 
 
    width: 256, 
 
    height: 256 
 
    } 
 

 
} 
 

 
Game.prototype.init = function(ts) { 
 
    this.current = { 
 
    tileset: this.images[ts] 
 
    } 
 
    this.width = this.map.cols * this.map.tsize; 
 
    this.height = this.map.rows * this.map.tsize; 
 
    this.canvas.width = this.camera.width; 
 
    this.canvas.height = this.camera.height; 
 
    this.camera.maxX = this.map.cols * this.map.tsize - this.camera.width; 
 
    this.camera.maxY = this.map.rows * this.map.tsize - this.camera.height; 
 
} 
 

 
Game.prototype.loadImages = function(images) { 
 
    this.images = images; 
 
} 
 

 
Game.prototype.start = function() { 
 

 
    this.now = 0; 
 
    this.dt = 0; 
 
    this.last = this.timestamp(); 
 
    this.frame(); 
 
} 
 

 
Game.prototype.update = function(delta) { 
 
    var dirx = 0; 
 
    var diry = 0; 
 
    if (KEYS.LEFT) { dirx = -1; } 
 
    if (KEYS.RIGHT) { dirx = 1; } 
 
    if (KEYS.UP) { diry = -1; } 
 
    if (KEYS.DOWN) { diry = 1; } 
 

 
    this.camera.move(delta, dirx, diry); 
 
} 
 

 
Game.prototype.render = function(delta) { 
 
    this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height); 
 
    var startCol = Math.floor(this.camera.x/this.map.tsize); 
 
    var endCol = startCol + (this.camera.width/this.map.tsize); 
 
    var startRow = Math.floor(this.camera.y/this.map.tsize); 
 
    var endRow = startRow + (this.camera.height/this.map.tsize); 
 
    var offsetX = -this.camera.x + startCol * this.map.tsize; 
 
    var offsetY = -this.camera.y + startRow * this.map.tsize; 
 
    for(var c = startCol; c <= endCol; c++) { 
 
    for(var r = startRow; r <= endRow; r++) { 
 
     var tile = this.getTile(c, r); 
 
     var x = (c - startCol) * this.map.tsize + offsetX; 
 
     var y = (r - startRow) * this.map.tsize + offsetY; 
 
     if(tile !== 0) { 
 
     ctx.drawImage(
 
      this.current.tileset.img, //image 
 
      (tile - 1) * this.map.tsize, 
 
      0, 
 
      this.map.tsize, 
 
      this.map.tsize, 
 
      Math.round(x), 
 
      Math.round(y), 
 
      this.map.tsize, 
 
      this.map.tsize 
 
     ) 
 
     } 
 
    } 
 
    } 
 
} 
 

 
Game.prototype.frame = function() { 
 
    this.now = this.timestamp(); 
 
    this.dt = (this.now - this.last)/1000; // duration in seconds 
 
    this.update(this.dt); 
 
    this.render(this.dt); 
 
    this.last = this.now; 
 
    requestAnimationFrame(this.frame.bind(this)); 
 
}; 
 

 

 
Game.prototype.getTile = function(x, y) { 
 
    return this.map.layer[y * this.map.cols + x]; 
 
} 
 

 

 
function Camera(map, width, height) { 
 
    this.x = 0; 
 
    this.y = 0; 
 
    this.width = width; 
 
    this.height = height; 
 
    this.maxX = map.cols * map.tsize - width; 
 
    this.maxY = map.rows * map.tsize - height; 
 
} 
 

 
Camera.SPEED = 256; // pixels per second 
 

 
Camera.prototype.move = function (delta, dirx, diry) { 
 
    // move camera 
 
    this.x += dirx * Camera.SPEED * delta; 
 
    this.y += diry * Camera.SPEED * delta; 
 
    // clamp values 
 
    this.x = Math.max(0, Math.min(this.x, this.maxX)); 
 
    this.y = Math.max(0, Math.min(this.y, this.maxY)); 
 
}; 
 

 
var KEYS = { 
 

 
}; 
 

 
function handleKey(down, e, key) { 
 
    switch(key) { 
 
    case 37: 
 
     KEYS.LEFT = down; 
 
     break; 
 
    case 38: 
 
     KEYS.UP = down; 
 
     break; 
 
    case 39: 
 
     KEYS.RIGHT = down; 
 
     break; 
 
    case 40: 
 
     KEYS.DOWN = down; 
 
     break; 
 
    default: 
 
     KEYS[String.fromCharCode(key)] = down; 
 
     break; 
 
    } 
 
}; 
 

 

 
document.onkeydown = function(e) { 
 
    handleKey(true, e, e.which); 
 
}; 
 

 
document.onkeyup = function(e) { 
 
    handleKey(false, e, e.which); 
 
}; 
 

 
function getHelp(s) { 
 
    socket.emit('help', s); 
 
} 
 

 
var map = { 
 
    cols: 12, 
 
    rows: 12, 
 
    tsize: 64, 
 
    layer: [ 
 
     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
 
     3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 
 
     3, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 
 
     3, 3, 3, 1, 1, 2, 3, 3, 3, 3, 3, 3 
 
    ] 
 
}; 
 
var camera = new Camera(map,256,256); 
 
var game = new Game(canvas, map,camera); 
 

 
var loader = new Loader(game); 
 

 
loader.loadImage('set1', 'http://i.stack.imgur.com/PPVJH.jpg', 64); 
 
loader.ready(); 
 

 
game.init('set1'); 
 
game.start();
<canvas id="canvas"></canvas>
. 지.

var canvas = document.getElementById('canvas'); 
 
var ctx = canvas.getContext('2d'); 
 

 
function Loader(game) { 
 
    this.game = game; 
 
    this.images = {} 
 
} 
 

 
Loader.prototype.loadImage = function(id, url, tile) { 
 
    var image = new Image(); 
 
    image.src = url; 
 
    this.images[id] = { 
 
    img: image, 
 
    url: url, 
 
    tile: tile 
 
    } 
 
} 
 

 
Loader.prototype.ready = function() { 
 
    this.game.loadImages(this.images); 
 
} 
 

 
function Game(canvas, map,camera) { 
 
    this.canvas = canvas; 
 
    this.ctx = this.canvas.getContext('2d'); 
 
    this.monsters = []; 
 
    this.player = {}; 
 
    this.map = map; 
 
    this.timestamp = function() { 
 
    return window.performance && window.performance.now ? window.performance.now() : new Date().getTime(); 
 
    } 
 
    this.camera = camera||{ 
 
    x: 0, 
 
    y: 0, 
 
    width: 256, 
 
    height: 256 
 
    } 
 

 
} 
 

 
Game.prototype.init = function(ts) { 
 
    this.current = { 
 
    tileset: this.images[ts] 
 
    } 
 
    this.width = this.map.cols * this.map.tsize; 
 
    this.height = this.map.rows * this.map.tsize; 
 
    this.camera.maxX = this.map.cols * this.map.tsize - this.camera.width; 
 
    this.camera.maxY = this.map.rows * this.map.tsize - this.camera.height; 
 
} 
 

 
Game.prototype.loadImages = function(images) { 
 
    this.images = images; 
 
} 
 

 
Game.prototype.start = function() { 
 

 
    this.now = 0; 
 
    this.dt = 0; 
 
    this.last = this.timestamp(); 
 
    this.frame(); 
 
} 
 

 
Game.prototype.update = function(delta) { 
 
    var dirx = 0; 
 
    var diry = 0; 
 
    if (KEYS.LEFT) { dirx = -1; } 
 
    if (KEYS.RIGHT) { dirx = 1; } 
 
    if (KEYS.UP) { diry = -1; } 
 
    if (KEYS.DOWN) { diry = 1; } 
 

 
    this.camera.move(delta, dirx, diry); 
 
} 
 

 
Game.prototype.render = function(delta) { 
 
    this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height); 
 
    this.ctx.save(); 
 
    this.ctx.translate((this.canvas.width-this.camera.width)/2, (this.canvas.height-this.camera.height)/2); 
 
    this.ctx.rect(0,0,this.camera.width, this.camera.height); 
 
    this.ctx.clip(); 
 
    var startCol = Math.floor(this.camera.x/this.map.tsize); 
 
    var endCol = startCol + (this.camera.width/this.map.tsize); 
 
    var startRow = Math.floor(this.camera.y/this.map.tsize); 
 
    var endRow = startRow + (this.camera.height/this.map.tsize); 
 
    var offsetX = -this.camera.x + startCol * this.map.tsize; 
 
    var offsetY = -this.camera.y + startRow * this.map.tsize; 
 
    for(var c = startCol; c <= endCol; c++) { 
 
    for(var r = startRow; r <= endRow; r++) { 
 
     var tile = this.getTile(c, r); 
 
     var x = (c - startCol) * this.map.tsize + offsetX; 
 
     var y = (r - startRow) * this.map.tsize + offsetY; 
 
     if(tile !== 0) { 
 
     ctx.drawImage(
 
      this.current.tileset.img, //image 
 
      (tile - 1) * this.map.tsize, 
 
      0, 
 
      this.map.tsize, 
 
      this.map.tsize, 
 
      Math.round(x), 
 
      Math.round(y), 
 
      this.map.tsize, 
 
      this.map.tsize 
 
     ) 
 
     } 
 
    } 
 
    } 
 
    this.ctx.restore(); 
 
} 
 

 
Game.prototype.frame = function() { 
 
    this.now = this.timestamp(); 
 
    this.dt = (this.now - this.last)/1000; // duration in seconds 
 
    this.update(this.dt); 
 
    this.render(this.dt); 
 
    this.last = this.now; 
 
    requestAnimationFrame(this.frame.bind(this)); 
 
}; 
 

 

 
Game.prototype.getTile = function(x, y) { 
 
    return this.map.layer[y * this.map.cols + x]; 
 
} 
 

 

 
function Camera(map, width, height) { 
 
    this.x = 0; 
 
    this.y = 0; 
 
    this.width = width; 
 
    this.height = height; 
 
    this.maxX = map.cols * map.tsize - width; 
 
    this.maxY = map.rows * map.tsize - height; 
 
} 
 

 
Camera.SPEED = 256; // pixels per second 
 

 
Camera.prototype.move = function (delta, dirx, diry) { 
 
    // move camera 
 
    this.x += dirx * Camera.SPEED * delta; 
 
    this.y += diry * Camera.SPEED * delta; 
 
    // clamp values 
 
    this.x = Math.max(0, Math.min(this.x, this.maxX)); 
 
    this.y = Math.max(0, Math.min(this.y, this.maxY)); 
 
}; 
 

 
var KEYS = { 
 

 
}; 
 

 
function handleKey(down, e, key) { 
 
    switch(key) { 
 
    case 37: 
 
     KEYS.LEFT = down; 
 
     break; 
 
    case 38: 
 
     KEYS.UP = down; 
 
     break; 
 
    case 39: 
 
     KEYS.RIGHT = down; 
 
     break; 
 
    case 40: 
 
     KEYS.DOWN = down; 
 
     break; 
 
    default: 
 
     KEYS[String.fromCharCode(key)] = down; 
 
     break; 
 
    } 
 
}; 
 

 

 
document.onkeydown = function(e) { 
 
    handleKey(true, e, e.which); 
 
}; 
 

 
document.onkeyup = function(e) { 
 
    handleKey(false, e, e.which); 
 
}; 
 

 
function getHelp(s) { 
 
    socket.emit('help', s); 
 
} 
 

 
var map = { 
 
    cols: 12, 
 
    rows: 12, 
 
    tsize: 64, 
 
    layer: [ 
 
     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
 
     3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 
 
     3, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 
 
     3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 
 
     3, 3, 3, 1, 1, 2, 3, 3, 3, 3, 3, 3 
 
    ] 
 
}; 
 
var camera = new Camera(map,256,256); 
 
var game = new Game(canvas, map,camera); 
 

 
var loader = new Loader(game); 
 

 
loader.loadImage('set1', 'http://i.stack.imgur.com/PPVJH.jpg', 64); 
 
loader.ready(); 
 

 
game.init('set1'); 
 
game.start();
<canvas id="canvas" width="400" height="400"></canvas>

+0

문제의 절반을 수정했지만 공백이 타일 크기와 같아 질 때까지 아래쪽이나 오른쪽에 타일을로드하지 않습니다. – spacegeek224

+0

방금 ​​시도했지만 카메라 크기가 5에서 4로 변경되었습니다. – spacegeek224

+0

카메라 크기가 4 타일에서 64 픽셀에 해당하는 254 픽셀로 설정되었습니다. 카메라 창 밖에서 무엇을 렌더링하고 싶습니까? –

관련 문제