Есть ли способ нарисовать на холсте что-нибудь, что я бы частично вышел за границы экрана? - PullRequest
0 голосов
/ 16 октября 2019

Я думал о попытке создать игровой движок на JavaScript, чтобы улучшить свои навыки. Одна из вещей, о которой я думал, - игровая камера, у нее будет определенный диапазон x и y и глобальная позиция.

Все остальное также будет иметь глобальную координату. Когда пришло время рисовать экран, программа проверяет, какие объекты находятся в пределах границ камеры, получает координаты относительно камеры и рисует их.

Моя проблема в том, что некоторые объекты будут наполовинуна экране, поэтому мне было интересно, есть ли способ нарисовать эти вещи на холсте.

1 Ответ

1 голос
/ 17 октября 2019

Вы можете нарисовать их целиком, но часть, которая должна быть скрыта, не будет отображаться, потому что она будет нарисована вне холста.

Или вы можете нарисовать их частично. Определите, сколько из них должно отображаться, затем нарисуйте эту часть. Может быть полезно:

https://www.html5canvastutorials.com/advanced/html5-canvas-clipping-region-tutorial/

https://www.html5canvastutorials.com/tutorials/html5-canvas-image-crop/

EDIT : я написал что-то, что отображает серые квадраты, только если они полностью или частичнов поле зрения камеры (красным).

Вы можете изменить режим (нормальный: отображаются все квадраты, кроме камеры: отображать только квадраты в пределах диапазона камеры), и вы можете изменить размер диапазона камеры.

Вы также можете переместить красный квадрат с помощью клавиш со стрелками. В режиме исключения из камеры он исчезнет, ​​если выйдет из диапазона камеры.

let canvas, ctx;
let squares;
const color = {
	grey: '#aaa',
  black: '#000',
  red: '#f00'
};
const squareSize = 10;
const camera = {};
const mode = {
	NORMAL: 'NORMAL',
	EXCLUDE_OFF_CAMERA: 'EXCLUDE_OFF_CAMERA',
}
let currentMode;
let mainSquare;
let mainSquareSpeed;

const interval = 1000 / 30;
const KEY_LEFT = 37;
const KEY_RIGHT = 39;
const KEY_UP = 38;
const KEY_DOWN = 40;

let keyUpPressede;
let keyDownPressed;
let keyLeftPressed;
let keyRightPressed;

init();

function init() {
	canvas = document.getElementById("canvas");
  ctx = canvas.getContext("2d");
  
  camera.width =  camera.height = 70;
	camera.x = (canvas.width - camera.width) / 2;
	camera.y = (canvas.height - camera.height) / 2;
  
  currentMode = mode.EXCLUDE_OFF_CAMERA;
  
  keyUpPressed = false;
  keyDownPressed = false;
  keyLeftPressed = false;
  keyRightPressed = false;
  
  squares = createSquares(canvas, 20);
  mainSquare = squares[0];
  mainSquare.x = canvas.width / 2;
  mainSquare.y = canvas.height / 2;
  mainSquare.color = color.red;
  mainSquareSpeed = 3;
  
  window.addEventListener("keydown", onKeyDown, false);
	window.addEventListener("keyup", onKeyUp, false);
  document.getElementById("modeNormal").onclick = function() {
  	currentMode = mode.NORMAL;
  }
  document.getElementById("modeExcludeOffCamera").onclick = function() {
  	currentMode = mode.EXCLUDE_OFF_CAMERA;
  }
  document.getElementById("cameraSize").addEventListener("change", function(e) {
		camera.width =  camera.height = parseInt(e.currentTarget.value, 10);
    camera.x = (canvas.width - camera.width) / 2;
    camera.y = (canvas.height - camera.height) / 2;
  }, false);
  
    // requestAnim shim layer by Paul Irish
  window.requestAnimFrame = (function(){
    return  window.requestAnimationFrame       || 
      window.webkitRequestAnimationFrame || 
      window.mozRequestAnimationFrame    || 
      window.oRequestAnimationFrame      || 
      window.msRequestAnimationFrame     || 
      function(/* function */ callback, /* DOMElement */ element){
      window.setTimeout(callback, 1000 / 10);
    };
  })();

  step(canvas, ctx, camera, squares, mainSquare, squareSize, mainSquareSpeed);
}

function step(canvas, ctx, camera, squares, mainSquare, squareSize, squareSpeed) {
  requestAnimFrame(function() {
  	step(canvas, ctx, camera, squares, mainSquare, squareSize, squareSpeed);
  });
  update(canvas, mainSquare, squareSize, squareSpeed);
  clear(canvas, ctx);
  draw(canvas, ctx, camera, squares, squareSize);
}

function update(canvas, mainSquare, squareSize, squareSpeed) {
	if (keyLeftPressed) {
  	mainSquare.x -= squareSpeed;
  } else if (keyRightPressed) {
  	mainSquare.x += squareSpeed;
  }
	if (keyUpPressed) {
  	mainSquare.y -= squareSpeed;
  } else if (keyDownPressed) {
  	mainSquare.y += squareSpeed;
  }
  
  if (mainSquare.x < 0) {
  	mainSquare.x = canvas.width - squareSize;
  } else if (mainSquare.x > canvas.width - squareSize) {
  	mainSquare.x = 0;
  }
  if (mainSquare.y < 0) {
  	mainSquare.y = canvas.height - squareSize;
  } else if (mainSquare.y > canvas.height - squareSize) {
  	mainSquare.y = 0;
  }
}

function clear(canvas, ctx) {
	ctx.clearRect(0, 0, canvas.width, canvas.height);
}

function draw(canvas, ctx, camera, squares, size) {
  drawSquares(ctx, squares, size, camera);
	drawCamera(canvas, ctx, camera);
}

function drawSquares(ctx, squares, size, camera) {
	for (let i = squares.length - 1; i >= 0; i -= 1) {
  	if (inViewRange(squares[i], camera, size) || currentMode === mode.NORMAL) {
      drawSquare(ctx, squares[i], size);  		
    }
  }
}

function drawSquare(ctx, square, size) {
	ctx.fillStyle = square.color ? square.color : color.grey;
	ctx.strokeStyle = color.black;
  ctx.fillRect(square.x, square.y, size, size);
  ctx.strokeRect(square.x, square.y, size, size);
}

function drawCamera(canvas, ctx, camera) {
	ctx.fillStyle = color.black;
	ctx.strokeStyle = color.red;
  ctx.lineWidth = 3;
  
  ctx.globalAlpha = 0.3;
  ctx.fillRect(camera.x, camera.y, camera.width, camera.height);
  ctx.globalAlpha = 1;
  ctx.strokeRect(camera.x, camera.y, camera.width, camera.height);
}

/**
 * Found here: /1086462/generatsiya-sluchainyh-tselyh-chisel-v-javascript-v-opredelennom-diapazone
 *
 * Returns a random integer between min (inclusive) and max (inclusive).
 * The value is no lower than min (or the next integer greater than min
 * if min isn't an integer) and no greater than max (or the next integer
 * lower than max if max isn't an integer).
 * Using Math.round() will give you a non-uniform distribution!
 */
function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function createSquares(canvas, number) {
	const squares = [];
  
  for (let i = 0; i < number; i += 1) {
  	
  	squares.push({ 
      x: getRandomInt(0, canvas.width), 
      y: getRandomInt(0, canvas.height) 
    });
  }
  
  return squares;
}

function inViewRange(square, camera, squareSize) {
	if (square.x + squareSize > camera.x && camera.x + camera.width > square.x) {
		if (square.y + squareSize > camera.y && camera.y + camera.height > square.y) {
  		return true;
  	}
  }
  return false;
}

function onKeyDown(e) {
	switch (e.keyCode) {
  	case KEY_LEFT: keyLeftPressed = true; break;
  	case KEY_RIGHT: keyRightPressed = true; break;
  	case KEY_UP: keyUpPressed = true; break;
  	case KEY_DOWN: keyDownPressed = true; break;l
  }
}

function onKeyUp(e) {
	switch (e.keyCode) {
  	case KEY_LEFT: keyLeftPressed = false; break;
  	case KEY_RIGHT: keyRightPressed = false; break;
  	case KEY_UP: keyUpPressed = false; break;
  	case KEY_DOWN: keyDownPressed = false; break;
  }
}
canvas {
  border: 1px solid black;
  margin: 1px;
}
<canvas id="canvas" width=100 height=100></canvas>
<br>
<button id="modeNormal">modeNormal</button>
<button id="modeExcludeOffCamera">modeExcludeOffCamera</button>
Camera size: <input id="cameraSize" type="range" min="10" max="100" value="70">
...