Từ bài Map Scrolling, ta có thể thấy đây là một sườn game rất phổ biến cho các loại game sử dụng bản đồ (như Pac-Man, Battle City hay Mario,…). Trong bài này tôi sẽ thay đổi một vài đặc điểm để tạo một demo dạng game phiêu lưu màn hình ngang.
Demo
Sourcecode
Tạo bản đồ
Bản đồ được dùng trong loại game này có thể được xem như một lưới với mỗi ô chứa một giá trị đại diện cho loại đối tượng (thường là vật cản như tường, đá, cây, …). Để đơn giản, tôi tạo một bản đồ chỉ gồm duy nhất một loại vật cản và được phân bố ngẫu nhiên:
map.js:
for(var i=1;i<MAP_WIDTH-1;i+=2) { this.data[i] = []; this.data[i+1] = []; for(var j=1;j<MAP_HEIGHT;j++) { this.data[i][j] = Math.floor(Math.random()*6); this.data[i+1][j] = this.data[i][j]; // create image buffer if(this.data[i][j]==BRICK) { context.fillRect(i*CELL_SIZE,j*CELL_SIZE,CELL_SIZE*2,CELL_SIZE); context.fill(); } } }
Kiểm tra va chạm
Ta có thể kiểm tra nhanh va chạm của nhân vật với các vật cản bằng cách xác định tọa độ ô tương ứng của bản đồ từ vị trí của nhân vật.
map.js:
this.contain = function(x,y){ var col = Math.floor(x/CELL_SIZE); var row = Math.floor(y/CELL_SIZE); if(!this.data[col]) return false; if(this.data[col][row]==BRICK) { var b = { left: col*CELL_SIZE, top: row*CELL_SIZE }; b.right = b.left+CELL_SIZE; b.bottom = b.top+CELL_SIZE; return b; } return false; }
Đối với nhân vật, tôi sử dụng 8 điểm bao quanh nhân vật để kiểm tra (các điểm màu đỏ trong hình sau). Muốn việc kiểm tra chính xác hơn, bạn chỉ cần tăng thêm số điểm tuy nhiên thời gian kiểm tra sẽ lâu hơn. Dựa vào các điểm này tôi có thể xác định được va chạm và ngừng việc di chuyển của nhân vật theo các trường hợp các điểm va chạm là:
– R1 hoặc R2: Va chạm bên phải. Nếu speedX>0, ta gán speedX = 0.
– L1 hoặc L2: Va chạm bên trái. Nếu speedX – H1 hoặc H2: Nhân vật nhảy lên và đụng đầu vào vật cản. Ta dặt speedY = 0 và falling = true để nhân vật dừng lại và bắt đầu rơi.
– H1 hoặc H2: Nhân vật nhảy rớt xuống đất hoặc vật cản. Ta dặt speedY = 0 và falling = false.
Player.prototype.update = function(){ if(this.isJumping) this.speedY += GRAVITY; var vtop = this.top+this.speedY; var vbottom = vtop+this.height; var vleft = this.left+this.speedX; var vright = vleft+this.width; if(this.isJumping) vbottom -= 1; var b; this.isJumping = true; if(vbottom >= this.map.height) { this.top = this.map.height-this.height; this.speedY = 0; this.isJumping = false; } else if(b = this.map.contain(this.left+2,vbottom) || this.map.contain(this.right-2,vbottom)) { this.top = b.top-this.height; this.speedY = 0; this.isJumping = false; } else if(b = this.map.contain(this.left+2,vtop) || this.map.contain(this.right-2,vtop)) { this.top = b.bottom; this.speedY = 0; } vtop = this.top+this.speedY; vbottom = vtop+this.height; if(this.left<=0 || (b = this.map.contain(vleft,vtop+6) || this.map.contain(vleft,vbottom-4))) { if(b) this.left = b.right; if(this.speedX<0) this.speedX = 0; }else if(this.right>=this.map.width || (b = this.map.contain(vright,vtop+6) || this.map.contain(vright,vbottom-4))) { if(b) this.left = b.left-this.width; if(this.speedX>0) this.speedX = 0; } this.top = vtop; this.bottom = vbottom; this.left += this.speedX; this.right = this.left + this.width; }
YinYangIt’s blog
Pingback: HTML5-Canvas: Viết game Mario – Part 1 « Warriorvn’s Blog
Bạn có thể hướng dẫn mình code tạo bản đồ theo dữ liệu có sẵn (là một mảng 1 chiều) không? Cám ơn bạn