javascript - 如何使视口(viewport)跟随此 javascript 代码中的矩形?

标签 javascript html css animation canvas

我已经创建了一些 Javascript 代码,可以在屏幕上绘制一个正方形并使其永久向上动画。我想要的是让正方形保持在屏幕中央,而它周围的世界( Canvas )向下移动,给人一种正方形无限向上移动的错觉。问题是,我不知道该怎么做,任何帮助将不胜感激!

我的代码

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var rectWidth = 50;
var rectHeight = 50;
var rectRad = 25;
var x = (canvas.width/2)-rectRad;
var y = canvas.height-rectHeight;
var dx = 2;
var dy = 4;
var ch = canvas.height;

function rect() {
	ctx.beginPath();
	ctx.rect(x, y, rectWidth, rectHeight);
	ctx.fillStyle = "#0095DD";
	ctx.fill();
	ctx.closePath();
}

function draw() {
	ctx.clearRect(0, 0, canvas.width, canvas.height);
	rect();

	if(y + dy < 0) {
		ch += 4;
	}

	if(y + dy > canvas.height-rectHeight) {
		dy = -dy;
	}

	y += dy;
}
setInterval(draw, 10);
* { padding: 0; margin: 0; }
		canvas { background: #eee; display: block; margin: 0 auto; }
<!DOCTYPE html>

<html>

<head>
	<meta charset="utf-8" />
	<title>Game</title>
	
	<style>
		* { padding: 0; margin: 0; }
		canvas { background: #eee; display: block; margin: 0 auto; }
	</style>

</head>
<body>

<canvas id="myCanvas" width="480" height="320"></canvas>

<script src="gameJS.js"></script>

</body>

</html>

最佳答案

您只需要绘制设计的背景,并按照您想要的速度平移背景的 y 位置。

这通常被称为相机。当正方形(或玩家实体)位于屏幕中间时,相机处理 x 和 y 位置的平移。

您还需要确保您的背景(图像、颜色、图案)在视口(viewport)中始终可见。

我会给你一个我为用 typescript 编写的测试游戏引擎制作的示例相机来转换坐标。

/**
 * calculates the position offset for camera following
 */
private static calculatePositionOffsetForCameraFollow(originalPosition: Vector2D, camera: Camera): Vector2D {

    // first check if there is any following
    let entity = camera.getFollowingEntity();

    // if no following is active, return the original position
    if (!entity) return originalPosition;

    // calculate the offset. the entity should be in the center of the screen
    let canvasDim = CameraOffsetCalculator.getCanvasDimension();

    // calculate the center position for the entity and shift the other
    // vectors.
    let tmpVector = originalPosition.substract(entity.getPosition()).add(
        canvasDim.divide(new Vector2D(2, 2))
    );

    // now check if the camera has world bounds
    let worldBounds = camera.getWorldBounds();
    if (!worldBounds) return tmpVector;

    // check if the original vector is smaller than the shifted vector
    // this will bound the left and top world bounds
    if (originalPosition.x < tmpVector.x) {

        // reset the x axis to fix the camera
        tmpVector.x = originalPosition.x;
    }

    if (originalPosition.y < tmpVector.y) {

        // reset the y axis to fix the camera
        tmpVector.y = originalPosition.y;
    }

    // now the left and bottom bounds
    // we need the world dimension to check if the camera reaches
    // the end of the world in the visible area
    let entityPosition = entity.getPosition();
    let worldBoundCanvas = worldBounds.substract(canvasDim.half());

    if (entityPosition.x > worldBoundCanvas.x) {

        // get the original position and substract
        // the distance from world bounds and canvas dim
        tmpVector.x = originalPosition.x - (worldBounds.x - canvasDim.x);
    }

    if (entityPosition.y > worldBoundCanvas.y) {

        // get the original position and substract
        // the distance from world bounds and canvas dim
        tmpVector.y = originalPosition.y - (worldBounds.y - canvasDim.y);
    }

    // return the corrected position vector
    return tmpVector;
}

此函数返回一个新点,供背景图像或图 block 在跟随实体(在您的例子中为正方形)时绘制。

如果对您有帮助,请告诉我!

这是使用非常简化的相机在您的代码中集成的错觉:

    var canvas = document.getElementById("myCanvas");
    var ctx = canvas.getContext("2d");
    var rectWidth = 50;
    var rectHeight = 50;
    var rectRad = 25;
    var x = (canvas.width / 2) - rectRad;
    var y = (canvas.height / 2) - rectHeight;
    //var dx = 2;
    //var dy = 4;
    var ch = canvas.height;

    // should be lower than bgHeight
    var scrollSpeed = .0475;

    // a boolean to make the background shifts differently at
    // y position to make the user think the player entity is moving
    // forwards
    var scroller = 0;

    // the repeating background
    var bg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAQCAMAAAA7+k+nAAAAKlBMVEXx8fH7+/v8/Pz5+fn29vb39/f19fXz8/P4+Pj6+vr09PTy8vL////o6OgghGlxAAAAk0lEQVR42nWPSQ7DMAwDZWujxPj/363dS1qk1YkCwQFG1p+Tdd33mXcxIppoSa4r0R6ZAHfR1kUwI9ZVLBpnu8p+nEGWY67LfXZijDyLgHmd2UEd7Hu2Czc4kE7d2MyATqk6qMgaraq984SWear99/g2uLMEaOTTRmSMgD1tRNsQ82kjnuX6w0ZazeSHjdAsE0+bFzAoDXEZIyZUAAAAAElFTkSuQmCC";
    var bgBitmap = createImageBitmap(b64ToBlob(bg, "image/png"));

    function rect() {
        ctx.beginPath();
        ctx.rect(x, y, rectWidth, rectHeight);
        ctx.fillStyle = "#0095DD";
        ctx.fill();
        ctx.closePath();
    }

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

        // first draw the background
        drawBackground();

        // and now the rectangle
        rect();
    }

    function drawBackground() {

        var bgWidth = 14, bgHeight = 14;

        // draw the full visible screen and on each edge, draw another tile
        // to make a smooth scrolling
        for (var x = -1; x < canvas.width / bgWidth; x++) {
            for (var y = -1; y < canvas.height / bgHeight; y++) {

                var yCorrectedCoordinate = y + (scroller * scrollSpeed);

                // draw!
                ctx.drawImage(
                    bgBitmap, x * bgWidth, yCorrectedCoordinate * bgHeight,
                    bgWidth, bgHeight
                );
            }
        }

        // change the scroller offset
        scroller++;
        if (scroller > 20)
            scroller = 0;
    }

    /**
    * converts a base64 string to a blob image capable for using in canvas environment
    * @see https://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript
    */
    function b64ToBlob(b64Data, contentType, sliceSize) {

        contentType = contentType || '';
        sliceSize = sliceSize || 512;

        var byteCharacters = atob(b64Data.split(',')[1]);
        var byteArrays = [];

        for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
            var slice = byteCharacters.slice(offset, offset + sliceSize);

            var byteNumbers = new Array(slice.length);
            for (var i = 0; i < slice.length; i++) {
                byteNumbers[i] = slice.charCodeAt(i);
            }

            var byteArray = new Uint8Array(byteNumbers);

            byteArrays.push(byteArray);
        }

        var blob = new Blob(byteArrays, { type: contentType });
        return blob;
    }

    // start the game loop after the image has beed loaded
    bgBitmap.then(function (bg) {

        bgBitmap = bg;
        setInterval(draw, 10);
    });

    // i would recommend to use window.requestAnimationFrame() instead

如果还有关于游戏开发的其他问题,这里是我的资料库:qhun-engine at Github.com

关于javascript - 如何使视口(viewport)跟随此 javascript 代码中的矩形?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45114651/

相关文章:

javascript - JS函数改变值

javascript - 发送电子邮件至,然后在 javascript 中重定向

javascript - 随机插入但切勿相邻

Javascript 动画 CSS float 属性

css - 重复图像过去设置的 div?

css - div/间距和格式问题中的文本

javascript - 在滚动条上激活字母动画

javascript - 如何通过 jQuery 或 Javascript 添加具有绝对位置的元素?

html - Flexbox一长一短列

javascript - Jquery 移动页面不扩展可折叠