编辑:我的问题到底是什么?我想要创建一个“视口”相机效果,它将跟随玩家而不移动背景。
我正在添加一个websocket支持,并将在地图上呈现更多的字符--我需要根据玩家而不是地图进行移动,这样我就可以正确地更新其他球员的移动位置。
原始员额:
关于这个问题,我已经翻阅了大多数其他的帖子。似乎,每个人都有自己独特的问题,为自己独特的实现“画布自上而下的游戏”。这使得在不重构整个代码的情况下很难找到解决问题的方法。
希望你们这次能帮我。
简单的游戏(到目前为止)-使用Vue3顺便,但这是除了重点-大部分的代码只是香草的东西。
简单的自顶向下的地图。X和Y轴
我在我的实现中所做的是使用我用平铺应用程序创建的PNG
放大约400% -用ctx.drawImage绘制它
我也在设定界限
然后画玩家
我现在要做的是在按下键的x和y位置上添加一个“强制”值,这意味着字符在地图上移动,碰撞检测起作用,我想要的是地图根据字符的位置绘制x个像素数量,而不移动地图,因为我已经实现了一些SocketIO代码来实现这个多人游戏。
我真的很迷茫,不知道我该怎么做才能把地图画成一个视图.
我希望这其中的一些有意义
一些代码
function create() {
const canvas: HTMLCanvasElement = document.getElementById("game") as HTMLCanvasElement;
if (!canvas) return console.error("canvas is undefined");
const ctx: CanvasRenderingContext2D = canvas.getContext("2d") as CanvasRenderingContext2D;
ctx.imageSmoothingEnabled = false;
initializeGameWindow(canvas, ctx);
setEvents(canvas, ctx);
const playerSpriteWidth = 192;
const playerSpriteHeight = 68;
const spriteFrames = 4;
background = new Sprite();
player = new Sprite();
update(canvas, ctx);
}
function update(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) {
window.requestAnimationFrame(() => update(canvas, ctx));
drawGame(canvas, ctx);
}
function drawGame(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) {
background.draw(ctx);
boundaries.forEach((boundary) => {
boundary.draw(ctx);
});
player.value.draw(ctx);
let moving: boolean = true;
player.value.moving = false;
if (keys.w.pressed && lastKey.value === "w") {
player.value.moving = true;
player.value.image = player.value.sprites.up;
for (let i = 0; i < boundaries.length; i++) {
if (
rectengularCollision(player.value, {
...boundaries[i],
position: { x: boundaries[i].position.x, y: boundaries[i].position.y + Sprite.force },
})
) {
moving = false;
break;
}
}
if (!moving) return;
player.value.position.y -= Sprite.force;
} else if (keys.a.pressed && lastKey.value === "a") {
player.value.moving = true;
player.value.image = player.value.sprites.left;
for (let i = 0; i < boundaries.length; i++) {
if (
rectengularCollision(player.value, {
...boundaries[i],
position: { x: boundaries[i].position.x + Sprite.force, y: boundaries[i].position.y },
})
) {
moving = false;
break;
}
}
if (!moving) return;
player.value.position.x -= Sprite.force;
} else if (keys.s.pressed && lastKey.value === "s") {
player.value.moving = true;
player.value.image = player.value.sprites.down;
for (let i = 0; i < boundaries.length; i++) {
if (
rectengularCollision(player.value, {
...boundaries[i],
position: { x: boundaries[i].position.x, y: boundaries[i].position.y - Sprite.force },
})
) {
moving = false;
break;
}
}
if (!moving) return;
player.value.position.y += Sprite.force;
} else if (keys.d.pressed && lastKey.value === "d") {
player.value.moving = true;
player.value.image = player.value.sprites.right;
for (let i = 0; i < boundaries.length; i++) {
if (
rectengularCollision(player.value, {
...boundaries[i],
position: { x: boundaries[i].position.x - Sprite.force, y: boundaries[i].position.y },
})
) {
moving = false;
break;
}
}
if (!moving) return;
player.value.position.x += Sprite.force;
}
}
export class Sprite {
static force: number = 3; // speed, velocity, acceleration, etc.
frames: number;
spriteIteration: number = 0;
elapsed: number = 0;
defaultSrc: string;
image: HTMLImageElement;
sprites: { up: HTMLImageElement; down: HTMLImageElement; left: HTMLImageElement;
right: HTMLImageElement };
position: { x: number; y: number };
width: number = 0;
height: number = 0;
moving: boolean = false;
constructor(
position: { x: number; y: number },
src : string,
frames: number = 1,
sprites: { up: string; down: string; left: string; right: string } = { up:
"", down: "", left: "", right: "" },
) {
this.defaultSrc = src;
this.moving = false;
const { up, down, left, right } = this.initSprites(sprites);
this.sprites = { up, down, left, right };
this.image = down;
this.frames = frames;
this.position = position;
this.image.onload = () => {
this.width = this.image.width / this.frames;
this.height = this.image.height;
};
}
draw(ctx: CanvasRenderingContext2D) {
ctx.drawImage(
// src
this.image,
// crop from x axis
this.spriteIteration * this.width,
// crop from y axis
0,
// crop width
this.image.width / this.frames,
// crop height
this.image.height,
// x position on canvas
this.position.x,
// y position on canvas
this.position.y,
// width on canvas
this.image.width / this.frames,
// height on canvas
this.image.height,
);
}
initSprites(sprites: { up: string; down: string; left: string; right: string }) {
const up = new Image();
up.src = sprites.up;
const down = new Image();
down.src = sprites.down !== "" ? sprites.down : this.defaultSrc;
const left = new Image();
left.src = sprites.left;
const right = new Image();
right.src = sprites.right;
return { up, down, left, right };
}
}发布于 2022-07-18 13:07:45
由于您还没有为我提供一个可运行的代码片段供我使用,下面是一个非常通用的示例,演示如何使用CanvasRenderingContext2D的转换方法更改场景的视口。
在draw中,您将看到:
<canvas>作为(0, 0)的中心:-x和-y乘以缩放因子H 114缩放factor
缩放画布
// Initialize
const cvs = document.createElement("canvas");
cvs.width = 200;
cvs.height = 200;
const ctx = cvs.getContext("2d");
// State
const players = [
[-20, -30, "green"],
[50, 70, "blue"]
];
let viewport = {
x: 0,
y: 0,
zoom: 1
};
// Drawing methods
const clear = () => {
ctx.fillStyle = "white";
ctx.fillRect(-cvs.width / 2, -cvs.height / 2, cvs.width, cvs.height);
};
const drawMap = () => {
const w = cvs.width - 25;
const h = cvs.height - 25;
ctx.fillStyle = "#efefef";
ctx.fillRect(
-w / 2,
-h / 2,
w,
h
);
}
const drawPlayers = () => {
for (const [x, y, color] of players) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, 10, Math.PI * 2, 0);
ctx.closePath();
ctx.fill();
}
}
const drawCenter = () => {
ctx.fillStyle = "rgba(255, 0, 0, 0.5)";
ctx.fillRect(-1, -15, 2, 30);
ctx.fillRect(-15, -1, 30, 2);
}
const draw = () => {
// Zoom out and set (0, 0) to center of canvas
ctx.setTransform(1, 0, 0, 1, cvs.width / 2, cvs.height / 2);
clear();
const { zoom, x, y } = viewport;
ctx.translate(-x * zoom, -y * zoom);
ctx.scale(zoom, zoom);
drawMap();
drawPlayers();
// For debugging: mark the center of the canvas
ctx.setTransform(1, 0, 0, 1, cvs.width / 2, cvs.height / 2);
drawCenter();
}
draw();
document.body.appendChild(cvs);
// UI
const updateViewport = () => {
const centerValue = document.querySelector("input[name=center]:checked").value;
const [x, y] = players[centerValue] || [0, 0];
const zoom = document.querySelector("input[type=range]").valueAsNumber;
viewport = { x: x, y: y, zoom };
draw();
};
document.querySelectorAll("input").forEach(el => {
el.addEventListener("input", updateViewport);
});body { display: flex; }
canvas { border: 1px solid red; position: relative; }
fieldset { margin-bottom: 1rem; }<div>
<fieldset>
<legend>View center:</legend>
<label>
<input type="radio" value="-1" name="center" checked> Map
</label>
<label>
<input type="radio" value="0" name="center"> Green player
</label>
<label>
<input type="radio" value="1" name="center"> Blue player
</label>
</fieldset>
<fieldset>
<legend>Zoom</legend>
<input type="range" min="0.1" max ="3" step="0.1" value="1">
</fieldset>
</div>
https://stackoverflow.com/questions/73003572
复制相似问题