我正在使用JavaScript和画布创建一款游戏,我想执行一个视窗来显示一个更大的游戏世界。我已经创建了一个canvas元素,并加载了一些固定的对象和一个可以使用键盘输入移动的播放器对象。
然而,我不确定如何实现一个视窗,只显示游戏世界的一部分,并允许玩家在它周围移动。有人可以提供一个例子,如何实现一个viewport使用JavaScript和画布,基于所提供的代码?
具体来说,我正在寻找允许我定义视口大小和位置的代码,并根据玩家的移动更新游戏世界的位置,以便玩家在移动时保持在视口中心。
这是我当前的代码。注意,我是js的新手:
// Get the canvas element and its context
const canvas = document.createElement("canvas");
document.body.append(canvas);
const ctx = canvas.getContext("2d");
// Player coords and update method that moves the player based on input
const player = {
x: 0,
y: 0,
vel: 1,
update(){
if(key.left) this.x -= this.vel;
if(key.right) this.x += this.vel;
if(key.up) this.y -= this.vel;
if(key.down) this.y += this.vel;
}
};
// Keys pressed (Used for movement)
const key = {
left: false,
right: false,
up: false,
down: false
}
// Get Input
window.addEventListener('keydown', (e) =>
{
switch(e.code){
case "KeyW":
key["up"] = true;
break;
case "KeyS":
key["down"] = true;
break;
case "KeyA":
key["left"] = true;
break;
case "KeyD":
key["right"] = true;
break;
}
});
// Relieve Input
window.addEventListener('keyup', (e) =>
{
switch(e.code){
case "KeyW":
key["up"] = false;
break;
case "KeyS":
key["down"] = false;
break;
case "KeyA":
key["left"] = false;
break;
case "KeyD":
key["right"] = false;
break;
}
});
function update(){
ctx.clearRect(0,0,canvas.width, canvas.height);
// Draw stationary objects
ctx.fillRect(100, 100, 10, 10);
ctx.fillRect(100, 120, 10, 10);
// Draw Player and update position
player.update();
ctx.fillRect(player.x, player.y, 10, 10);
requestAnimationFrame(update);
}
update();
我已经尝试保存上下文并翻译然后恢复。但这并不奏效,我希望玩家能够保持在屏幕中央。下面是我试过的代码:
function update(){
ctx.clearRect(0,0,canvas.width, canvas.height);
// Draw stationary objects
ctx.fillRect(100, 100, 10, 10);
ctx.fillRect(100, 120, 10, 10);
// Draw Player and update position
ctx.save();
ctx.translate(player.x, player.y);
player.update();
ctx.fillRect(canvas.width/2 - 5, canvas.height/2 - 5, 10, 10);
ctx.restore();
requestAnimationFrame(update);
}
游戏中的大多数2D场景实现都使用父/子树当场景是顶层父级()时,父级对象的位置只是使它们依赖于另一个对象的位置。)
一旦你有了这个,你可以很容易地通过将每个对象添加到包含所有对象的相同父对象(例如,场景)来移动视口,并移动父对象来模拟相机。
下面是一些伪代码,可以了解这种系统背后的思想。
//Pseudo code, don't simply copy-paste it
// Make a class from which all the objects in the game will inherit; it'll take care of managing the position.
class GameObject {
position: {x: 0, y: 0}
parent: null;
children: [];
function setPosition(pX, pY) { //Sets the position within the parent
position.x = pX;
position.y = pY;
}
//This is the core of our parent/child tree
function addChild(pGameObject) {
children.push(pGameObject);
pGameObject.parent = this;
}
function removeChild() //take care of updating the parent/children vars
function toGlobalCoordinates() { //Allows us to get the global coordinates (= coordinates on the canvas)
let lParent = this.parent;
let globalPos = {x: 0, y: 0}
//Goes up the parents tree, breaks when there's no more parent thanks to the default: parent = null in the class
while(lParent) {
globalPos.x += lParent.position.x;
globalPos.y += lParent.position.y;
lParent = lParent.parent;
}
globalPos.x += this.position.x;
globalPos.y += this.position.y;
return globalPos;
}
function draw(pCtx) { //We pass the canvas ctx to be able to draw on it
//Use the global position to draw your object
let drawingPos = this.toGlobalCoordinates();
pCtx.fillRect(drawingPos.x, drawingPos.y, 100, 100);
}
}
然后,我们有其他类,比如Player我们必须处理渲染
//extends from GameObject to benefit from the position and its methods
class Player extends GameObject {
methods() ... //Implement methods specific to the player
}
//Use the scene as the base gameobject (our top parent)
let scene = new GameObject();
let player = new Player();
let stationnaryObject1 = new GameObject()
scene.addChild(player)
scene.addChild(stationnaryObject1)
//The function called on requestAnimationFrame
update() {
//clearRect to clean the canvas then
//On key press, move the player, move the scene in the opposite direction to keep the keep focus on the player
if(keypress) {
player.setPosition(player.position.x + newX, player.position.x + newY)
scene.setPosition(scene.position.x - newX, scene.position.x - newY)
}
//Draw the objects with their new position
scene.draw(ctx);
player.draw(ctx);
}
这或多或少是处理能够制作摄像机(即在游戏世界中移动视口)的基本方法。
你应该看看PixiJS如果你正在寻找一个非常强大的方式来处理,以及更多。这是一个非常强大且易于学习的JS库,用于处理WebGL上的2D显示。画布(不用自己画了!)
为了了解更多关于场景图/树的信息,我谈到了:https://pixijs.io/guides/basics/scene-graph.html同样的树也被用于Flash游戏中。
TLDR:制作相机是在改变所有物体的位置。
我希望你在开发游戏中玩得开心!