我正在制作一个Agar.io克隆,而我却陷入了创建网格背景的困境。我已经看到了关于根据相机绘制背景的问题,但它们都只是用于图像。
以下是我的代码:
click = split
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
var width = innerWidth;
var height = innerHeight;
var evt = "mousemove";
var touchX = 0;
var touchY = 0;
var config = {
gameWidth: width,
gameHeight: height,
playerConfig: {
mass: 10,
hue: Math.round(Math.random() * 360),
border: 6
},
virusConfig: {
mass: 100,
fill: "#33ff33",
stroke: "#19D119",
border: 10
}
}
var maxSplits = 16;
var foods = [];
var viruses = [];
var clients = [];
var player = {
blobs: [],
lastSplit: 0,
extent: {
minX: 0,
minY: 0,
maxX: 0,
maxY: 0
}
};
var camera = {
x: 0,
y: 0
};
function movePlayer() {
for (var i = 0; i < player.blobs.length; i++) {
var b = player.blobs[i];
var e = player.extent;
var x = touchX + camera.x - b.x;
var y = touchY + camera.y - b.y;
var dist = Math.hypot(x, y);
b.velocity = {
x: x / dist * b.speed,
y: y / dist * b.speed
};
b.speed -= b.speed > 4 ? 0.25 : 0;
b.speed -= b.speed > 4 ? 0.25 : 0;
b.x += b.velocity.x * Math.min(1, Math.pow(x / b.r, 2));
b.y += b.velocity.y * Math.min(1, Math.pow(y / b.r, 2));
b.x = Math.min(Math.max(b.x, -config.gameWidth), config.gameWidth);
b.y = Math.min(Math.max(b.y, -config.gameHeight), config.gameHeight);
if (i == 0) {
e.minX = e.maxX = b.x;
e.minY = e.maxY = b.y;
} else {
e.minX = Math.min(b.x, e.minX);
e.minY = Math.min(b.y, e.minY);
e.maxX = Math.max(b.x, e.maxX);
e.maxY = Math.max(b.y, e.maxY);
}
}
}
function handleSelfCollision() {
for (var i = 0; i < player.blobs.length; i++) {
for (var j = 0; j < player.blobs.length; j++) {
if (j !== i && player.blobs[i] !== undefined) {
var b1 = player.blobs[i];
var b2 = player.blobs[j];
var radii = b1.r + b2.r;
var x = b2.x - b1.x;
var y = b2.y - b1.y;
var dist = Math.hypot(x, y);
if (dist < radii) {
if (player.lastSplit + 10000 > new Date().getTime()) {
x /= dist;
y /= dist;
// test
b1.x += ((b2.x - x * radii) - b1.x) * 0.6;
b1.y += ((b2.y - y * radii) - b1.y) * 0.5;
//test
} else if (dist < radii * 0.75) {
b1.mass = b1.mass + b2.mass;
b1.r = massToRadius(b1.mass);
player.blobs.splice(j, 1);
}
}
}
}
}
}
function handleVirusCollision() {
for (var i = 0; i < viruses.length; i++) {
for (var j = 0; j < player.blobs.length; j++) {
var b = player.blobs[j];
var v = viruses[i];
var x = v.x - b.x;
var y = v.y - b.y;
var dist = Math.hypot(x, y);
var radii = v.r + b.r;
if (dist < radii) {
b.r += v.r;
viruses.splice(i, 1);
if (player.blobs.length < maxSplits) {
while (b.r >= defaultPlayerR * 2) {
splitBlob(b);
}
}
}
}
}
}
function splitBlob(blob) {
if (blob.mass >= config.playerConfig.mass * 2 && player.blobs.length < maxSplits) {
blob.mass /= 2;
blob.r = massToRadius(blob.mass)
player.lastSplit = new Date().getTime();
player.blobs.push({
x: blob.x,
y: blob.y,
mass: blob.mass,
r: massToRadius(blob.mass),
speed: 20
});
}
}
function moveCamera() {
var e = player.extent;
camera.x = (e.maxX + e.minX) / 2;
camera.y = (e.maxY + e.minY) / 2;
camera.x -= width / 2;
camera.y -= height / 2;
}
function addFood(num) {
var rnd = random(1, 1.5);
while (num--) {
foods.push({
x: random(-config.gameWidth, config.gameWidth),
y: random(-config.gameHeight, config.gameHeight),
mass: rnd,
r: massToRadius(rnd),
hue: Math.round(Math.random() * 360)
});
}
}
function addVirus(num) {
while (num--) {
viruses.push({
x: random(-width, width),
y: random(-height, height),
mass: config.virusConfig.mass,
r: massToRadius(config.virusConfig.mass)
});
}
}
function updateFood() {
for (var i = 0; i < foods.length; i++) {
for (var j = 0; j < player.blobs.length; j++) {
var b = player.blobs[j];
var f = foods[i];
var x = f.x - b.x;
var y = f.y - b.y;
var dist = Math.hypot(x, y);
var radii = f.r + b.r;
if (dist < radii) {
b.mass += f.mass;
b.r = massToRadius(b.mass);
foods.splice(i, 1);
break;
}
}
}
if (foods.length < 100) {
addFood(1);
}
}
function drawPlayer(order) {
var sortedArr = player.blobs.sort(function(b1, b2) {
return b1.mass - b2.mass;
});
for (var i = 0; i < sortedArr.length; i++) {
var b = sortedArr[i];
ctx.fillStyle = "hsl(" + config.playerConfig.hue + ", 100%, 50%)";
ctx.strokeStyle = "hsl(" + config.playerConfig.hue + ", 100%, 45%)";
ctx.lineWidth = config.playerConfig.border;
ctx.beginPath();
ctx.arc(b.x - camera.x, b.y - camera.y, b.r, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.closePath();
}
}
function drawFood() {
for (var i = 0; i < foods.length; i++) {
var f = foods[i];
ctx.fillStyle = 'hsl(' + f.hue + ', 100%, 50%)';
ctx.beginPath();
ctx.arc(f.x - camera.x, f.y - camera.y, f.r, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
}
}
function drawVirus() {
for (var i = 0; i < viruses.length; i++) {
var v = viruses[i];
ctx.fillStyle = config.virusConfig.fill;
ctx.strokeStyle = config.virusConfig.stroke;
ctx.lineWidth = config.virusConfig.border;
ctx.beginPath();
ctx.arc(v.x - camera.x, v.y - camera.y, v.r, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.closePath();
}
}
function drawPlatform(bgcol, borcol, thickness) {
var x = -config.gameWidth - camera.x;
var y = -config.gameHeight - camera.y;
var w = 2 * config.gameWidth;
var h = 2 * config.gameHeight;
ctx.fillStyle = bgcol;
ctx.fillRect(x, y, w, h);
ctx.lineWidth = thickness;
ctx.strokeStyle = borcol;
ctx.strokeRect(x, y, w, h);
}
function drawBackground(col) {
ctx.fillStyle = col;
ctx.fillRect(0, 0, width, height);
}
function drawGrid() {
}
function updateAndDraw() {
movePlayer();
moveCamera();
updateFood();
handleSelfCollision();
//handleVirusCollision();
drawBackground("#f2fbff");
drawPlatform("#fff", "#000", 10);
drawGrid();
drawFood();
drawPlayer();
drawVirus();
requestAnimationFrame(updateAndDraw);
}
function handleEvent(event) {
touchX = event.clientX;
touchY = event.clientY;
}
function random(min, max) {
return (min + (Math.random() * (max - min)));
}
function massToRadius(mass) {
return 4 + Math.sqrt(mass) * 6;
}
function startTheGame() {
evt = width < 600 ? "click" : "mousemove";
canvas.width = width;
canvas.height = height;
addFood(100);
addVirus(5);
player.blobs.push({
x: width / 2,
y: height / 2,
mass: config.playerConfig.mass,
r: massToRadius(config.playerConfig.mass),
speed: 8
});
//test
canvas.addEventListener("click", function() {
var blobs = player.blobs.length;
for (var i = 0; i < blobs; i++) {
if (blobs < maxSplits) {
splitBlob(player.blobs[i]);
} else {
break;
}
}
});
addEventListener("resize", function() {
width = innerWidth;
height = innerHeight
});
// test
canvas.addEventListener(evt, handleEvent);
updateAndDraw();
}
startTheGame();
body {
padding: 0;
margin: 0;
}
<title>Gaario - A simple Agario clone</title>
<canvas>Awww! Your browser doesn't support canvas.</canvas>
答案 0 :(得分:1)
可以通过绘制水平线,然后添加垂直线来绘制网格。将ctx.lineTo()
和ctx.moveTo()
函数与ctx.beginPath()
和ctx.stroke()
结合使用,正在绘制网格。
我填充了drawGrid()函数的主体:
function drawGrid() {
var gridSize = 30; // define the space between each line
var x = -config.gameWidth - camera.x; // x start point of the field
var y = -config.gameHeight - camera.y // y start point of the field
var width = 2 * config.gameWidth;
var height = 2 * config.gameHeight;
ctx.lineWidth = 1;
ctx.beginPath();
for(var i = 0; i * gridSize < height; i++) { // draw the horizontal lines
ctx.moveTo(x, i * gridSize + y);
ctx.lineTo(x + width, i * gridSize + y);
}
for(var i = 0; i * gridSize < width; i++) { // draw the vertical lines
ctx.moveTo(i * gridSize + x, y);
ctx.lineTo(i * gridSize + x, y + height);
}
ctx.stroke();
}
在用于绘制线条的for循环中,我们使用了这个事实,即我们知道容器左上角的位置。变量分别为x
和y
。
因此,为了绘制垂直线,我们知道那些点从y坐标y
到y + height
。
我们可以通过在for循环中运行i * gridSize + x
来计算每一行的x坐标。
对于左起第一行i = 0
,我们只返回x
,这是我们游戏区域的左边界。
第二行是1 * gridSize + x
,第三行是2 * gridSize + x
,依此类推。
通过将i
增加为i * gridSize < width
为止,我们会在游戏字段中绘制所有垂直线。
for(var i = 0; i * gridSize < width; i++) { // draw the vertical lines
ctx.moveTo(i * gridSize + x, y);
ctx.lineTo(i * gridSize + x, y + height);
}
下面你会找到你的代码示例,添加了函数。
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
var width = innerWidth;
var height = innerHeight;
var evt = "mousemove";
var touchX = 0;
var touchY = 0;
var config = {
gameWidth: width,
gameHeight: height,
playerConfig: {
mass: 10,
hue: Math.round(Math.random() * 360),
border: 6
},
virusConfig: {
mass: 100,
fill: "#33ff33",
stroke: "#19D119",
border: 10
}
}
var maxSplits = 16;
var foods = [];
var viruses = [];
var clients = [];
var player = {
blobs: [],
lastSplit: 0,
extent: {
minX: 0,
minY: 0,
maxX: 0,
maxY: 0
}
};
var camera = {
x: 0,
y: 0
};
function movePlayer() {
for (var i = 0; i < player.blobs.length; i++) {
var b = player.blobs[i];
var e = player.extent;
var x = touchX + camera.x - b.x;
var y = touchY + camera.y - b.y;
var dist = Math.hypot(x, y);
b.velocity = {
x: x / dist * b.speed,
y: y / dist * b.speed
};
b.speed -= b.speed > 4 ? 0.25 : 0;
b.speed -= b.speed > 4 ? 0.25 : 0;
b.x += b.velocity.x * Math.min(1, Math.pow(x / b.r, 2));
b.y += b.velocity.y * Math.min(1, Math.pow(y / b.r, 2));
b.x = Math.min(Math.max(b.x, -config.gameWidth), config.gameWidth);
b.y = Math.min(Math.max(b.y, -config.gameHeight), config.gameHeight);
if (i == 0) {
e.minX = e.maxX = b.x;
e.minY = e.maxY = b.y;
} else {
e.minX = Math.min(b.x, e.minX);
e.minY = Math.min(b.y, e.minY);
e.maxX = Math.max(b.x, e.maxX);
e.maxY = Math.max(b.y, e.maxY);
}
}
}
function handleSelfCollision() {
for (var i = 0; i < player.blobs.length; i++) {
for (var j = 0; j < player.blobs.length; j++) {
if (j !== i && player.blobs[i] !== undefined) {
var b1 = player.blobs[i];
var b2 = player.blobs[j];
var radii = b1.r + b2.r;
var x = b2.x - b1.x;
var y = b2.y - b1.y;
var dist = Math.hypot(x, y);
if (dist < radii) {
if (player.lastSplit + 10000 > new Date().getTime()) {
x /= dist;
y /= dist;
// test
b1.x += ((b2.x - x * radii) - b1.x) * 0.6;
b1.y += ((b2.y - y * radii) - b1.y) * 0.5;
//test
} else if (dist < radii * 0.75) {
b1.mass = b1.mass + b2.mass;
b1.r = massToRadius(b1.mass);
player.blobs.splice(j, 1);
}
}
}
}
}
}
function handleVirusCollision() {
for (var i = 0; i < viruses.length; i++) {
for (var j = 0; j < player.blobs.length; j++) {
var b = player.blobs[j];
var v = viruses[i];
var x = v.x - b.x;
var y = v.y - b.y;
var dist = Math.hypot(x, y);
var radii = v.r + b.r;
if (dist < radii) {
b.r += v.r;
viruses.splice(i, 1);
if (player.blobs.length < maxSplits) {
while (b.r >= defaultPlayerR * 2) {
splitBlob(b);
}
}
}
}
}
}
function splitBlob(blob) {
if (blob.mass >= config.playerConfig.mass * 2 && player.blobs.length < maxSplits) {
blob.mass /= 2;
blob.r = massToRadius(blob.mass)
player.lastSplit = new Date().getTime();
player.blobs.push({
x: blob.x,
y: blob.y,
mass: blob.mass,
r: massToRadius(blob.mass),
speed: 20
});
}
}
function moveCamera() {
var e = player.extent;
camera.x = (e.maxX + e.minX) / 2;
camera.y = (e.maxY + e.minY) / 2;
camera.x -= width / 2;
camera.y -= height / 2;
}
function addFood(num) {
var rnd = random(1, 1.5);
while (num--) {
foods.push({
x: random(-config.gameWidth, config.gameWidth),
y: random(-config.gameHeight, config.gameHeight),
mass: rnd,
r: massToRadius(rnd),
hue: Math.round(Math.random() * 360)
});
}
}
function addVirus(num) {
while (num--) {
viruses.push({
x: random(-width, width),
y: random(-height, height),
mass: config.virusConfig.mass,
r: massToRadius(config.virusConfig.mass)
});
}
}
function updateFood() {
for (var i = 0; i < foods.length; i++) {
for (var j = 0; j < player.blobs.length; j++) {
var b = player.blobs[j];
var f = foods[i];
var x = f.x - b.x;
var y = f.y - b.y;
var dist = Math.hypot(x, y);
var radii = f.r + b.r;
if (dist < radii) {
b.mass += f.mass;
b.r = massToRadius(b.mass);
foods.splice(i, 1);
break;
}
}
}
if (foods.length < 100) {
addFood(1);
}
}
function drawPlayer(order) {
var sortedArr = player.blobs.sort(function(b1, b2) {
return b1.mass - b2.mass;
});
for (var i = 0; i < sortedArr.length; i++) {
var b = sortedArr[i];
ctx.fillStyle = "hsl(" + config.playerConfig.hue + ", 100%, 50%)";
ctx.strokeStyle = "hsl(" + config.playerConfig.hue + ", 100%, 45%)";
ctx.lineWidth = config.playerConfig.border;
ctx.beginPath();
ctx.arc(b.x - camera.x, b.y - camera.y, b.r, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.closePath();
}
}
function drawFood() {
for (var i = 0; i < foods.length; i++) {
var f = foods[i];
ctx.fillStyle = 'hsl(' + f.hue + ', 100%, 50%)';
ctx.beginPath();
ctx.arc(f.x - camera.x, f.y - camera.y, f.r, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
}
}
function drawVirus() {
for (var i = 0; i < viruses.length; i++) {
var v = viruses[i];
ctx.fillStyle = config.virusConfig.fill;
ctx.strokeStyle = config.virusConfig.stroke;
ctx.lineWidth = config.virusConfig.border;
ctx.beginPath();
ctx.arc(v.x - camera.x, v.y - camera.y, v.r, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.closePath();
}
}
function drawPlatform(bgcol, borcol, thickness) {
var x = -config.gameWidth - camera.x;
var y = -config.gameHeight - camera.y;
var w = 2 * config.gameWidth;
var h = 2 * config.gameHeight;
ctx.fillStyle = bgcol;
ctx.fillRect(x, y, w, h);
ctx.lineWidth = thickness;
ctx.strokeStyle = borcol;
ctx.strokeRect(x, y, w, h);
}
function drawBackground(col) {
ctx.fillStyle = col;
ctx.fillRect(0, 0, width, height);
}
function drawGrid() {
var gridSize = 30; // define the space between each line
var x = -config.gameWidth - camera.x; // x start point
var y = -config.gameHeight - camera.y // y start point
var width = 2 * config.gameWidth;
var height = 2 * config.gameHeight;
ctx.lineWidth = 1;
ctx.beginPath();
for(var i = 0; i * gridSize < height; i++) { // draw the horizontal lines
ctx.moveTo(x, i * gridSize + y);
ctx.lineTo(x + width, i * gridSize + y);
}
for(var i = 0; i * gridSize < width; i++) { // draw the vertical lines
ctx.moveTo(i * gridSize + x, y);
ctx.lineTo(i * gridSize + x, y + height);
}
ctx.stroke();
}
function updateAndDraw() {
movePlayer();
moveCamera();
updateFood();
handleSelfCollision();
//handleVirusCollision();
drawBackground("#f2fbff");
drawPlatform("#fff", "#000", 10);
drawGrid();
drawFood();
drawPlayer();
drawVirus();
requestAnimationFrame(updateAndDraw);
}
function handleEvent(event) {
touchX = event.clientX;
touchY = event.clientY;
}
function random(min, max) {
return (min + (Math.random() * (max - min)));
}
function massToRadius(mass) {
return 4 + Math.sqrt(mass) * 6;
}
function startTheGame() {
evt = width < 600 ? "click" : "mousemove";
canvas.width = width;
canvas.height = height;
addFood(100);
addVirus(5);
player.blobs.push({
x: width / 2,
y: height / 2,
mass: config.playerConfig.mass,
r: massToRadius(config.playerConfig.mass),
speed: 8
});
//test
canvas.addEventListener("click", function() {
var blobs = player.blobs.length;
for (var i = 0; i < blobs; i++) {
if (blobs < maxSplits) {
splitBlob(player.blobs[i]);
} else {
break;
}
}
});
addEventListener("resize", function() {
width = innerWidth;
height = innerHeight
});
// test
canvas.addEventListener(evt, handleEvent);
updateAndDraw();
}
startTheGame();
body {
padding: 0;
margin: 0;
}
<title>Gaario - A simple Agario clone</title>
<canvas>Awww! Your browser doesn't support canvas.</canvas>