有很多这样的主题,但没有具体的答案。我正在以传统的方式绘制一个瓷砖地图(两个用于循环)并保持我的播放器居中,除非到达地图的边缘。我如何创建碰撞检测?我需要知道如何将数组中的tile位置转换为我认为的屏幕坐标。
答案 0 :(得分:2)
我将为您提供我为point / tilemap碰撞检测编写的代码。代码假设您有一个点(xfrom,yfrom)并且您想将其移动到(xto,yto)并想要查看tilemap map [Y] [X]中是否存在与块的冲突。我假设一个方法isSolid(tileId),如果图块是实心的,它将返回true。
/**
* This method returns true if there is a collision between a point and a 2D tilemap map[Y][X].
* The isSolid method must be implemented to indicate if a tile is solid or not
* Assumes the tilemap starts at (0,0) and TILEWIDTH and TILEHEIGHT hold the size of a tile (in pixels)
* @param xfrom the original x-coordinate of the point
* @param yfrom the original y-coordinate of the point
* @param xto the destination x-coordinate of the point
* @param yto the destination y-coordinate of the point
* @param outCollisionPoint output the location where the collision occurs
* @return true if a collision is found
*/
public boolean collisionDetection(int xfrom, int yfrom, int xto, int yto, Point outCollisionPoint){
//Ref: A fast voxel traversal algorithm J.Amanatides, A. Woo
float tMaxX, tMaxY, tDeltaX, tDeltaY, collisionLength;
int X, Y, stepX, stepY, endX, endY, blkX, blkY;
//Calculate direction vector
float dirX = (xto - xfrom);
float dirY = (yto - yfrom);
float length = (float) Math.sqrt(dirX * dirX + dirY * dirY);
//Normalize direction vector
dirX /= length;
dirY /= length;
//tDeltaX: distance in terms of vector(dirX,dirY) between two consecutive vertical lines
tDeltaX = TILEWIDTH / Math.abs(dirX);
tDeltaY = TILEHEIGHT / Math.abs(dirY);
//Determine cell where we originally are
X = xfrom / TILEWIDTH;
Y = yfrom / TILEHEIGHT;
endX = xto / TILEWIDTH;
endY = yto / TILEHEIGHT;
//stepX: Determine in what way do we move between cells
//tMaxX: the distance in terms of vector(dirX,dirY) to the next vertical line
if (xto > xfrom){
blkX = 0;
stepX = 1;
tMaxX = ((X+1) * TILEWIDTH - xfrom) / dirX;
}else{
blkX = 1;
stepX = -1;
tMaxX = (X * TILEWIDTH - xfrom) / dirX;
}
if (yto > yfrom){
blkY = 0;
stepY = 1;
tMaxY = ((Y+1) * TILEHEIGHT - yfrom) / dirY;
}else{
blkY = 1;
stepY = -1;
tMaxY = (Y * TILEHEIGHT - yfrom) / dirY;
}
if (isSolid(map[Y][X])) {
//point already collides
outCollisionPoint = new Point(xfrom, yfrom);
return true;
}
//Scan the cells along the line between 'from' and 'to'
while (X != endX || Y !=endY){
if(tMaxX < tMaxY){
tMaxX += tDeltaX;
X += stepX;
if (isSolid(map[Y][X])) {
collisionLength = ((X + blkX) * TILEWIDTH - xfrom) / dirX;
outCollisionPoint = new Point((int)(xfrom + dirX * collisionLength), (int)(yfrom + dirY * collisionLength));
return true;
}
}else{
tMaxY += tDeltaY;
Y += stepY;
if (isSolid(map[Y][X])) {
collisionLength= ((Y + blkY) * TILEHEIGHT - yfrom) / dirY;
outCollisionPoint = new Point((int)(xfrom + dirX * collisionLength), (int)(yfrom + dirY * collisionLength));
return true;
}
}
}
return false;
}
答案 1 :(得分:1)
取决于型号。
如果您的模型(数据)是网格,则只有当两个不兼容的对象占据相同位置时才会发生冲突。处理此类碰撞的最简单方法是确保将游戏实体移动到哪里“可用”。如果是,则不会发生冲突,更新模型。如果它不是免费的,那么就会发生碰撞。
屏幕只是渲染模型。除了每像素碰撞检测(想想原始的旅鼠或蠕虫)之外,不会将其用于碰撞检测。
屏幕/视图只是渲染代理。虽然您可以将模型紧紧地绑在屏幕上(例如,您只需要更新屏幕中已发生变化的部分,例如一块被移动),屏幕不是,也不应该,通常被认为是模型的一部分。但是,凭借现代计算速度,您可以简单地每帧重新渲染整个可见模型。
(是的,我知道我重复了一遍。这是故意的。)
现在,回答标题中未提及的次要问题:
当您开始渲染时,只需向左侧绘制screen_width / cell_width / 2单元格,在播放器右侧绘制screen_width / cell_width / 2单元格(假设玩家采用1x1)。对于上下都做同样的事情。确保不会导致Index-Out-Of-Bounds异常。只要在使用它们之前进行钳位/过滤,就可以运行带有越界值的for循环。如果您希望仅在角色靠近时使角色“推”到边缘,也要跟踪当前的模型到视图参考。