【问题标题】:Is there a way to draw something on the canvas that I'd partially outside the bounds of the screen?有没有办法在画布上绘制一些我部分超出屏幕边界的东西?
【发布时间】:2019-10-17 17:12:48
【问题描述】:

我一直在考虑尝试用 JavaScript 创建一个游戏引擎来提高我的技能。 我正在考虑的一件事是游戏摄像机,它将具有一定的 x 和 y 范围以及全局位置。

其他所有东西也都有一个全局坐标。当需要绘制屏幕时,程序会检查哪些物体在相机的边界内,获取相对于相机的坐标,然后绘制它们。

我的问题是某些对象会在屏幕上显示一半,所以我想知道是否有办法在画布上绘制这些东西。

【问题讨论】:

    标签: javascript canvas html5-canvas game-engine


    【解决方案1】:

    您可以完全绘制它们,但应该隐藏的部分不会显示,因为它将被绘制在画布之外。

    或者您可以部分绘制它们。确定应该显示多少,然后绘制这部分。可能有用:

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

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

    编辑:我写了一些东西,只有当它们完全或部分在相机的视野范围内(红色)时才会显示灰色方块。

    您可以更改模式(正常:显示所有方块,不包括相机外:仅显示相机范围内的方块),您可以更改相机范围的大小。

    您也可以使用箭头键移动红色方块。在排除关闭相机模式下,如果它退出相机范围,它将消失。

    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: https://stackoverflow.com/questions/1527803/generating-random-whole-numbers-in-javascript-in-a-specific-range
     *
     * 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">

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-26
      • 2017-10-15
      • 1970-01-01
      • 2021-05-08
      • 1970-01-01
      • 2019-04-11
      相关资源
      最近更新 更多