您好:)我为一个学校项目制作了一个小游戏。它是一个基本的Javascript 2D Canvas游戏,带有来自数组的Tile Map。
我的问题是,我无法使碰撞起作用。在我的示例中,我要在带有“ 1”的图块上以“英雄”“行走”。0是“英雄”不行走的图块。
我对Canvas边界有一个简单的碰撞检测,所以我的英雄不能走出Canvas的外面。但是我不知道如何使它正常工作。
HTML
const inputElements = parentElement.getElementsByTagName('input')
if (inputChilds.length > 0) {
inputChilds.item(0).focus();
}
Charakter.js
<script type="text/javascript">
var Spielfeld, Spieler, Zuletzt, Collision;
function initialisieren( Anzeige ) {
Spielfeld = Anzeige ;
Spieler = new Spieler( Spielfeld ) ;
Spieler.Name = 'Ich' ;
Zuletzt = 0 ;
document.getElementsByTagName('body')[0].onkeydown = steuern ;
document.getElementsByTagName('body')[0].onkeyup = steuern ;
window.requestAnimationFrame( aktualisieren ) ;
}
function steuern( Ereignis ) {
switch( Ereignis.keyCode ) {
case 87: Spieler.setOben( Ereignis.type == 'keydown'); break;
case 83: Spieler.setUnten( Ereignis.type == 'keydown'); break;
case 65: Spieler.setLinks( Ereignis.type == 'keydown'); break;
case 68: Spieler.setRechts( Ereignis.type == 'keydown'); break;
case 38: Spieler.setOben( Ereignis.type == 'keydown'); break;
case 40: Spieler.setUnten( Ereignis.type == 'keydown'); break;
case 37: Spieler.setLinks( Ereignis.type == 'keydown'); break;
case 39: Spieler.setRechts( Ereignis.type == 'keydown'); break;
}
}
function aktualisieren() {
var Jetzt = new Date();
var Dauer = Jetzt.getTime() - Zuletzt ;
Zuletzt = Jetzt.getTime() ;
loeschen( Spielfeld ) ;
Spieler.aktualisieren( Dauer ) ;
window.requestAnimationFrame( aktualisieren ) ;
}
function loeschen( Anzeige ) {
Stift = Anzeige.getContext('2d') ;
Stift.clearRect( 0,0 , Anzeige.width, Anzeige.height ) ;}</script>
</head>
<body onload="initialisieren( document.getElementById('Spielfeld') ) ;">
<canvas id="Laufweg" width="1280" height="768" style="position: absolute; z-index: 3">Funktioniert nicht!</canvas>
<canvas id="Hintergrund" width="1280" height="768" style="position: absolute; z-index: 1">Funktioniert nicht!</canvas>
<canvas id="Spielfeld" width="1280" height="768" style="position: absolute; z-index: 2">Funktioniert nicht!</canvas>
<script type="text/javascript" src="./javascript/Charakter.js"></script>
</body>
使用此代码部分,我完成了边框碰撞工作:
function Spieler( Spielfeld ) {
var Held = document.createElement('img');
Held.src = '../Arbeitsdateien/items/item_berliner.png';
var Anzeige = Spielfeld ;
var Breite = 32 ;
var Hoehe = 32 ;
var PosX = 32 ;
var PosY = 192 +32 ;
var Schritt = 400 ;
var hero = Held;
var Oben, Unten, Links, Rechts ;
Oben = Unten = Links = Rechts = false ;
this.setOben = function( Schalter ) { Oben = Schalter == true ; }
this.setUnten = function( Schalter ) { Unten = Schalter == true ; }
this.setLinks = function( Schalter ) { Links = Schalter == true ; }
this.setRechts = function( Schalter ) { Rechts = Schalter == true ; }
this.aktualisieren = function( Dauer ) {
bewegen( Dauer ) ;
anzeigen() ;
}
//--------------------------------------------------------------------------------------------------------------------------
//Kollision für die Laufwege -----------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------------------
var fliese = {
fliesenGroesse: 32
};
var mapKollision = [ //004
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,1,1,1,0,0,0,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,0,0,0,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0],
[1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0],
[0,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
[0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
];
var viewport = document.getElementById('Laufweg');
var ctx = viewport.getContext('2d');
function renderMap() {
var i, j;
ctx.clearRect( 0, 0, 1280, 768 );
ctx.fillStyle = "rgba(255,0,0,0.5)";
for( i = 0; i < mapKollision.length; i++ ) {
for( j = 0; j < mapKollision[ i ].length; j++ ) {
if( mapKollision[ i ][ j ] !== 0 ) {
ctx.fillRect(
j * fliese.fliesenGroesse, i * fliese.fliesenGroesse,
fliese.fliesenGroesse, fliese.fliesenGroesse
);
}
}
}
}
renderMap();
function bewegen( Dauer ) {
var Etappe = Dauer / 1000 ;
if( Links ) PosX -= Schritt * Etappe ;
if( Rechts ) PosX += Schritt * Etappe ;
if( Oben ) PosY -= Schritt * Etappe ;
if( Unten ) PosY += Schritt * Etappe ;
if( PosX < 0 ) PosX = 0 ;
if( PosX > Anzeige.width -32 ) PosX = 1248 ;
if( PosY < 0 ) PosY = 0 ;
if( PosY > Anzeige.height -32 ) PosY = 736 ;
}
function anzeigen() {
Stift = Anzeige.getContext('2d') ;
Stift.drawImage( Held, PosX,PosY) ;
}
}
也许您可以帮助我解决我的问题,以使我的0个图块发生碰撞。 这是img的外观(红色是行走的路径(1)白色是不可行走的瓦片(0)) (https://imgur.com/a/YLu6HU2)
希望您能理解我的问题是什么。 我对Javascript真的很陌生,但在此之前,它对我来说还可以:)
答案 0 :(得分:1)
我尝试制作一个超级简化的版本,该版本简化了您正在使用的 concept ,并且希望它可以帮助您更好地了解如何修复代码。我相信它也介绍了一些您可能不熟悉的概念,但是它们将极大地帮助您以“游戏开发”模式进行思考!
因此,如果我没有直接修复您的代码,我深表歉意–我不得不说,变量名称的“本地语言”没有帮助:) –但是我仍然希望它会有所帮助。
这是 HTML 文件:
<canvas width="7" height="6"></canvas>
如您所见,我创建了一个超小画布。这可能对您没有用,但是实际测试事物和“重新组合”样式确实很棒。
这里是 CSS :
canvas {
border: 1px solid silver;
width: 350px;
height: 300px;
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
}
基本上,画布的1像素需要50 css像素。我们有巨大的像素:)
现在是有趣的部分。 JS :
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const w = canvas.width; // 7
const h = canvas.height; // 6
到目前为止,没有什么奇怪的,我只是获得了以后需要使用的参考。
const imageData = ctx.getImageData(0, 0, w, h);
const buff = new Uint32Array(imageData.data.buffer);
我不想使用Canvas 2D API,我希望ti直接“像素化”像素。 因此,我将整个画布设为ImageData,并将其数据缓冲区视为无符号32位整数数组。这样,该阵列的每个元素代表一个单个像素。一个像素由四个字节组成,每个通道分别对应一个颜色的字节:红色,绿色,蓝色和Alpha(不透明度)。当您通过CSS指定RGB颜色(例如0xffeedd)时,它几乎相同,唯一的区别是由于endianess,字节的顺序被颠倒了(所以您不必拥抱RGBA而是ABGR)。
注意:此代码假定我们使用小尾数法(对于这种情况,您可以放心地假设现在通常来说)。
const map = [
0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 0, 0,
0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1
];
这里的地图7x6
。
const palette = [0xff000000, 0xffffffff, 0xff0000ff];
在这里我们定义palette
:因此,我们的“游戏”目前只有三种颜色,第一种是黑色(最大不透明度,0xff,R,G和B为0),第二种是白色(每个分量为0xff),第三个为红色(记住字节序,Alpha和Red通道为0xff,绿色和蓝色为0)。
function drawMap() {
for (let k = 0; k < h; k++) {
for (let j = 0; j < w; j++) {
let i = j + k * w;
buff[i] = palette[map[i]]
}
}
}
这应该或多或少熟悉:我们有循环来迭代map
数组。根据地图的值(0
或1
),我们从调色板中选择颜色,因此墙壁为黑色,走廊为白色。
const hero = {x: 0, y: 1};
hero
用于存储当前坐标的绘制位置。
function drawHero() {
buff[hero.x + hero.y * w] = palette[2];
}
该逻辑与地图使用的逻辑几乎相同,但是在这种情况下,我们使用调色板中的第三种颜色。
// listen to keyboard
const Keys = {
pressed: {},
handleEvent({type, code}) {
this.pressed[code] = type === "keydown"
}
}
document.addEventListener("keydown", Keys);
document.addEventListener("keyup", Keys);
这用于“存储”按下的键。它没有经过优化,但足以满足此目的。它使用对象而不是函数作为事件侦听器(请参见:https://developer.mozilla.org/en-US/docs/Web/API/EventListener/handleEvent)
function update() {
let x = hero.x, y = hero.y;
if (Keys.pressed["ArrowLeft"]) {
x = Math.max(0, hero.x - 1);
}
if (Keys.pressed["ArrowRight"]) {
x = Math.min(w - 1, hero.x + 1);
}
if (Keys.pressed["ArrowUp"]) {
y = Math.max(0, hero.y - 1);
}
if (Keys.pressed["ArrowDown"]) {
y = Math.min(h - 1, hero.y + 1);
}
if (map[x + y * w]) {
hero.x = x;
hero.y = y;
}
}
这是检测到碰撞的地方!
update
函数根据所按下的按键,墙壁和画布的边缘来更新英雄坐标。
因此,首先,根据所按下的键(如果有)在画布的边界内设置x
和y
。
然后,如果“新提议的坐标”在1
中返回map
,则表示角色可以移动到那里,因此hero
对象也被更新。
否则它将不会被更新。
function loop() {
update();
drawMap();
drawHero();
// flush
ctx.putImageData(imageData, 0, 0);
requestAnimationFrame(loop);
}
loop();
那只是游戏循环,我相信这很简单。当然,我们需要“冲洗”我们在实际画布中写入到buff的所有内容。
这不是最优化的,还有很多事情要做(例如,您应该考虑时间更新坐标,现在太快了),但是希望对您有所帮助。
如果没有,请让我知道如何修改它,以简化您的问题,以便为您提供更好的帮助。
这里还有一个正在运行的示例代码: https://codepen.io/zer0/pen/JxxYgQ