- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
已解决,最终算法见帖子底部
背景:我正在使用 JS 和 HTML Canvas 元素开发 2D 平台游戏。关卡 map 是基于图块的,但玩家不会被夹在图块上。我正在使用 "Tiny Platformer" on Code inComplete 中概述的碰撞检测算法.除了一种边缘情况(或“壁架”情况)外,它在很大程度上有效。
问题:
玩家正在跌倒并向右移动,进入墙壁。当它下落时,它会传送到壁架的高度。相反,玩家应该在没有传送的情况下正常坠落。
有没有办法改变算法来防止这种行为?如果没有,你能建议一个替代的碰撞检测算法吗? 理想情况下,任何修复都不会假设玩家总是摔倒,因为在游戏中玩家的摔倒方向会在上/下/左/右之间切换。
算法:
getBorderTiles
的函数获取一个对象(玩家)并返回接触玩家 4 个 Angular 落中的每个 Angular 落的瓷砖。由于玩家不比瓷砖大,那些边界瓷砖必然是玩家接触的唯一瓷砖。请注意,其中一些图块可能相同。例如,如果玩家只占据一列,则左上/右上图块将相同,左下/右下图块也是如此。如果发生这种情况,getBorderTiles
仍然返回所有四个图块,但有些是相同的。 var borderTiles = getBorderTiles(object), //returns 0 (a falsy value) for a tile if it does not fall within the level
tileTL = borderTiles.topLeft,
tileTR = borderTiles.topRight,
tileBL = borderTiles.bottomLeft,
tileBR = borderTiles.bottomRight,
coordsBR = getTopLeftXYCoordinateOfTile(tileBR), //(x, y) coordinates refer to top left corner of tile
xRight = coordsBR.x, //x of the right tile(s) (useful for adjusting object's position since it falls in middle of 4 tiles)
yBottom = coordsBR.y, //y of the bottom tile(s) (useful for adjusting object's position since it falls in middle of 4 tiles)
typeTL = tileTL ? level.map[tileTL.row][tileTL.col] : -1, //if tileTL is in the level, gets its type, otherwise -1
typeTR = tileTR ? level.map[tileTR.row][tileTR.col] : -1,
typeBL = tileBL ? level.map[tileBL.row][tileBL.col] : -1,
typeBR = tileBR ? level.map[tileBR.row][tileBR.col] : -1,
collidesTL = typeTL == TILETYPE.SOLID, //true if the tile is solid
collidesTR = typeTR == TILETYPE.SOLID,
collidesBL = typeBL == TILETYPE.SOLID,
collidesBR = typeBR == TILETYPE.SOLID,
collidesUp = false,
collidesDown = false,
collidesLeft = false,
collidesRight = false;
//down and up
if (object.vy < 0 && ((collidesTL && !collidesBL) || (collidesTR && !collidesBR))) {
collidesUp = true;
/*The object is pushed out of the bottom row, so the bottom row is now the top row. Change the collides__
variables as this affects collision testing, but is it not necessary to change the tile__ variables. */
collidesTL = collidesBL;
collidesTR = collidesBR;
} else if (object.vy > 0 && ((collidesBL && !collidesTL) || (collidesBR && !collidesTR))) {
collidesDown = true;
/*The object is pushed out of the bottom row, so the bottom row is now the top row. Change the collides__
variables as this affects collision testing, but is it not necessary to change the tile__ variables. */
collidesBL = collidesTL;
collidesBR = collidesTR;
}
//left and right
if (object.vx < 0 && ((collidesTL && !collidesTR) || (collidesBL && !collidesBR))) {
collidesLeft = true;
} else if (object.vx > 0 && ((collidesTR && !collidesTL) || (collidesBR && !collidesBL))) {
collidesRight = true;
}
if (collidesUp) {
object.vy = 0;
object.y = yBottom;
}
if (collidesDown) {
object.vy = 0;
object.y = yBottom - object.height;
}
if (collidesLeft) {
object.vx = 0;
object.x = xRight;
}
if (collidesRight) {
object.vx = 0;
object.x = xRight - object.width;
}
function handleCollision(object) {
var borderTiles = getBorderTiles(object), //returns 0 (a falsy value) for a tile if it does not fall within the level
tileTL = borderTiles.topLeft,
tileTR = borderTiles.topRight,
tileBL = borderTiles.bottomLeft,
tileBR = borderTiles.bottomRight,
coordsBR = getTopLeftXYCoordinateOfTile(tileBR), //(x, y) coordinates refer to top left corner of tile
xRight = coordsBR.x, //x of the right tile(s) (useful for adjusting object's position since it falls in middle of 4 tiles)
yBottom = coordsBR.y, //y of the bottom tile(s) (useful for adjusting object's position since it falls in middle of 4 tiles)
typeTL = tileTL ? level.map[tileTL.row][tileTL.col] : -1, //if tileTL is in the level, gets its type, otherwise -1
typeTR = tileTR ? level.map[tileTR.row][tileTR.col] : -1,
typeBL = tileBL ? level.map[tileBL.row][tileBL.col] : -1,
typeBR = tileBR ? level.map[tileBR.row][tileBR.col] : -1,
collidesTL = typeTL == TILETYPE.SOLID, //true if the tile is solid
collidesTR = typeTR == TILETYPE.SOLID,
collidesBL = typeBL == TILETYPE.SOLID,
collidesBR = typeBR == TILETYPE.SOLID,
collidesUp = false,
collidesDown = false,
collidesLeft = false,
collidesRight = false,
originalX = object.x, //the object's coordinates have already been adjusted according to its velocity, but not according to collisions
originalY = object.y,
px1 = originalX,
px2 = originalX,
py1 = originalY,
py2 = originalY,
vx1 = object.vx,
vx2 = object.vx,
vy1 = object.vy,
vy2 = object.vy,
d1 = 0,
d2 = 0,
conflict1 = false,
conflict2 = false,
tempCollidesTL = collidesTL,
tempCollidesTR = collidesTR,
tempCollidesBL = collidesBL,
tempCollidesBR = collidesBR;
//left and right
//step 1.1
if (object.vx > 0) {
if (collidesTR || collidesBR) {
vx1 = 0;
px1 = xRight - object.width;
conflict1 = true;
tempCollidesTR = false;
tempCollidesBR = false;
}
}
if (object.vx < 0) {
if (collidesTL || collidesBL) {
vx1 = 0;
px1 = xRight;
conflict1 = true;
tempCollidesTL = false;
tempCollidesBL = false;
collidesLeft = true;
}
}
//step 2.1
if (object.vy > 0) {
if (tempCollidesBL || tempCollidesBR) {
vy1 = 0;
py1 = yBottom - object.height;
}
}
if (object.vy < 0) {
if (tempCollidesTL || tempCollidesTR) {
vy1 = 0;
py1 = yBottom;
collidesUp = true;
}
}
//step 3.1
if (conflict1) {
d1 = Math.abs(px1 - originalX) + Math.abs(py1 - originalY);
} else {
object.x = px1;
object.y = py1;
object.vx = vx1;
object.vy = vy1;
return; //(the player's x and y position already correspond to its non-colliding values)
}
//reset the tempCollides variables for another runthrough
tempCollidesTL = collidesTL;
tempCollidesTR = collidesTR;
tempCollidesBL = collidesBL;
tempCollidesBR = collidesBR;
//step 1.2
if (object.vy > 0) {
if (collidesBL || collidesBR) {
vy2 = 0;
py2 = yBottom - object.height;
conflict2 = true;
tempCollidesBL = false;
tempCollidesBR = false;
}
}
if (object.vy < 0) {
if (collidesTL || collidesTR) {
vy2 = 0;
py2 = yBottom;
conflict2 = true;
tempCollidesTL = false;
tempCollidesTR = false;
}
}
//step 2.2
if (object.vx > 0) {
if (tempCollidesTR || tempCollidesBR) {
vx2 = 0;
px2 = xRight - object.width;
conflict2 = true;
}
}
if (object.vx < 0) {
if (tempCollidesTL || tempCollidesTL) {
vx2 = 0;
px2 = xRight;
conflict2 = true;
}
}
//step 3.2
if (conflict2) {
d2 = Math.abs(px2 - originalX) + Math.abs(py2 - originalY);
console.log("d1: " + d1 + "; d2: " + d2);
} else {
object.x = px1;
object.y = py1;
object.vx = vx1;
object.vy = vy1;
return;
}
//step 5
//special case: when colliding with the ceiling and left side (in which case the top right and bottom left tiles are solid)
if (collidesTR && collidesBL) {
if (d1 <= d2) {
object.x = px2;
object.y = py2;
object.vx = vx2;
object.vy = vy2;
} else {
object.x = px1;
object.y = py1;
object.vx = vx1;
object.vy = vy1;
}
return;
}
if (d1 <= d2) {
object.x = px1;
object.y = py1;
object.vx = vx1;
object.vy = vy1;
} else {
object.x = px2;
object.y = py2;
object.vx = vx2;
object.vy = vy2;
}
}
最佳答案
发生这种情况是因为您首先检测两个方向的碰撞,然后调整位置。 “向上/向下”首先更新(重力方向)。首先调整“左/右”只会使问题变得更糟(每次跌倒后,您可能会被向右或向左传送)。
我能想到的唯一快速而肮脏的解决方法(重力不变):
sizes: sTile = 50, sPlayer = 20
old position (fine, top-left corner): oX = 27, oY = 35
speeds: vX = 7, vY = 10
new position: x = oX + vX = 34, y = oY + vY = 45 => (34, 45)
solid: tile at (50, 50)
1.1. Checking x-direction, relevant points for positive vX are the ones to the right:
(54, 45) and (54, 65). The latter gives a conflict and we need to correct the
position to p1 = (30, 45) and speed v1 = (0, 10).
2.1. Checking y-direction based on previous position, relevant points: (30, 65) and
(50, 65). There is no conflict, p1 and v1 remain unchanged.
3.1. There was a conflict in step 1.1. so we cannot return the current result
immediately and have to calculate the distance d1 = 4 + 0 = 4.
1.2. Checking y-direction first this time, relevant points: (34, 65) and (54, 65).
Because the latter gives a conflict we calculate p2 = (34, 30) and v2 = (7, 0).
2.2. Checking x-direction based on step 1.2., relevant points: (54, 30) and (54, 50).
There is no conflict, p2 and v2 remain unchanged.
3.2. Because there was a conflict in step 1.2. we calculate the distance d2 = 15.
5. Change position and speed to p1 and v1 because d1 is smaller than d2.
关于javascript - 碰撞检测不应该使物体传送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44191923/
大家好,本文实现了相机碰撞检测,使相机不穿墙壁、物体,并给出了思路和代码,感谢大家~ 关键词:数字孪生、three.js、Web3D、WebGL、相机碰撞、游戏相机 我正在承接Web3D数字孪生项
我有一个大小为 12*30 的字符串的图像。我想创建一个动画,让它给人一种拉伸(stretch)字符串的感觉。我通过缩放图像来做到这一点,但我面临的问题是缩放图像没有发生碰撞。它仅出现在原始图像大小的
我的对象列表是如此初始化: $( function() { var $container = $('div.hikashop_products'); $container.isotop
我听说 swing 默认情况下是双缓冲的。我不想让 Swing 双缓冲。我正在使用双缓冲,我想添加一些 Swing 对象(现在只是添加到 JPanel 中的 JButton,然后再添加到 JFrame
几天来我一直在思考最好的解决方案,但似乎无法找到正确的想法。 我有一 block (物体),我想将它们放入尽可能小的空间中。我最终寻找的是这样的东西 http://i.stack.imgur.com/
我的纹理不仅仅是一个盒子或圆形,我的 body 需要与这个形状相同,所以我想结合多个 body 来达到我想要的形状,这甚至可能吗?或者有更好的方法吗?我正在使用带有 libgdx 框架的 java。
我遇到的情况是,我有很多计算机并且需要有唯一的 ID。 他们会通过 API 请求发送其 uniqueId。该对象看起来像 class ID { long timestamp; int id; }
我正在尝试检测一张卡片,但问题是有时图像不好并且有多个背景,如下所示: 没有很好地定义边缘 ![没有很好地定义边缘][1] 示例背景 ![示例背景][2] 我这样做了: gray = cv2.cvtC
我正在尝试从仅包含一辆车和简单背景的图像中分割汽车,如 但是我从我的实现中得到的是这个 和 分别 但它非常容易处理几乎已经分割的图像,例如。 给出类似 的结果 我使用的代码是 import cv2 i
我正在开发一个项目,在该项目中我从另一个对象/函数中引用一个变量。然而我总是返回 false。我不确定我是否正确调用它。 这是验证函数: app.validation = function(){
数组只是伪装的对象吗?为什么/为什么不呢?他们以什么方式(这样/不是)? 我一直认为 JS 中的数组和对象本质上是相同的,主要是因为访问它们是相同的。 var obj = {'I': 'me'}; v
我正在使用 PlayN 构建一个涉及石头的游戏,用户必须在物理世界中移动(通过重力等)。我希望用户能够使用触摸板直接操纵石头,并通过以下方式给它们一个速度拖拽并扔掷它们。 现在我有一个实现,其中每个石
http://jsfiddle.net/goldrunt/jGL84/42/这是来自这个 JS fiddle 的第 84 行。通过取消注释第 141-146 行,可以对球应用 3 种不同的效果。 'b
我学习Linux平台下的OpenGL。最近,我尝试使用 glutBitmapCharacter() 创建的文本作为 glu 或 glut 提供的一些二次对象的纹理。但是,glutBitmapChara
我正在使用 AndEngine 创建一个带有 box2d 扩展名的游戏。我想实现一个条件,当两个物体碰撞时,它们应该被移除或重生。最初我尝试使用 if(sprite1.collidesWith(spr
我制作了一个小型 3d 引擎。 但我在旋转功能方面遇到了一些问题。它们使物体不时拉伸(stretch)。这是数学: this.rotateX = function(angle) { var c
我在 Canvas 上制作了一个矩形 mask ,我需要 mask 外的任何东西都具有 0.8 的不透明度,因此 mask 外的所有对象都被视为不透明请看一下 fiddle 。 http://jsfi
我是 Direct3D 的新手,我在一个项目中从网络摄像头拍照并在它前面绘制一些 3D 对象。 我能够使用正交投影将网络摄像头图像渲染为背景。 //init matrix D3DXMatri
我是一名优秀的程序员,十分优秀!