public void PopulateFrom(CCTileMap tileMap) { //得到瓦片地图里面的瓦片信息,比如说哪些瓦片可以与entity接触,具体是瓦片的哪个方向的面可以接触 //每个小瓦片的边长加上0.5的误差 tileDimension = (int)(tileMap.TileTexelSize.Width + .5f); TileMapPropertyFinder finder = new TileMapPropertyFinder (tileMap); foreach (var propertyLocation in finder.GetPropertyLocations()) { //如果在这个位置的瓦片是一个固体 if (propertyLocation.Properties.ContainsKey ("SolidCollision")) { //worldX worldY 是每个瓦片的中心的坐标 float centerX = propertyLocation.WorldX; float centerY = propertyLocation.WorldY; //得到每个小瓦片的左边界和下边界 float left = centerX - tileDimension/2.0f; float bottom = centerY - tileDimension/2.0f; //在那个点构造一个小瓦片 RectWithDirection rectangle = new RectWithDirection { Left = left, Bottom = bottom, Width = tileDimension, Height = tileDimension }; //得到地图上所有的固体小块 collisions.Add (rectangle); } } // Sort by XAxis to speed future searches: //collisions是把整个瓦片地图按每个瓦片的左边的坐标进行排序的list //在每一个左边坐标有一列的瓦片 //debug看一下 collisions = collisions.OrderBy(item=>item.Left).ToList(); // now let's adjust the directions that these point //调整每个小块的角度 for (int i = 0; i < collisions.Count; i++) { var rect = collisions [i]; // By default rectangles can reposition objects in all directions: int valueToAssign = (int)Directions.All; //15 float centerX = rect.CenterX; float centerY = rect.CenterY; // If there are collisions on the sides, then this // rectangle can no longer repositon objects in that direction. // 一开始小瓦片的方向valueToAssign可能是所有的方向,每次减去一种不可能的方向值,最后得到的就是正确的方向的值的和 //direction是这个实体瓦片暴露在外,可以与entity接触的方向 //比如说瓦片地图里的地面,方向就为up if (HasCollisionAt (centerX - tileDimension, centerY)) { valueToAssign -= (int)Directions.Left; } if (HasCollisionAt (centerX + tileDimension, centerY)) { valueToAssign -= (int)Directions.Right; } if (HasCollisionAt (centerX, centerY + tileDimension)) { valueToAssign -= (int)Directions.Up; } if (HasCollisionAt (centerX, centerY - tileDimension)) { valueToAssign -= (int)Directions.Down; } rect.Directions = (Directions)valueToAssign; //更新瓦片列表中的瓦片的方向 collisions [i] = rect; } for (int i = collisions.Count - 1; i > -1; i--) { //经过筛选后,遍历删除那些没有方向的瓦片 if (collisions [i].Directions == Directions.None) { collisions.RemoveAt (i); } } }
bool Intersects(CCRect first, RectWithDirection second) { //判断两个rect是否有重叠 return first.UpperRight.X > second.Left && first.LowerLeft.X < second.Left + second.Width && first.UpperRight.Y > second.Bottom && first.LowerLeft.Y < second.Bottom + second.Height; }
CCVector2 GetSeparatingVector(CCRect first, RectWithDirection second) { // Default to no separation CCVector2 separation = CCVector2.Zero; // Only calculate separation if the rectangles intersect if (Intersects(first, second)) { // The intersectionRect returns the rectangle produced // by overlapping the two rectangles. // This is protected by partitioning and deep collision, so it // won't happen too often - it's okay to do a ToRect here var intersectionRect = first.Intersection (second.ToRect()); float minDistance = float.PositiveInfinity; float firstCenterX = first.Center.X; float firstCenterY = first.Center.Y; float secondCenterX = second.Left + second.Width / 2.0f; float secondCenterY = second.Bottom + second.Width / 2.0f; bool canMoveLeft = (second.Directions & Directions.Left) == Directions.Left && firstCenterX < secondCenterX; bool canMoveRight = (second.Directions & Directions.Right) == Directions.Right && firstCenterX > secondCenterX; bool canMoveDown = (second.Directions & Directions.Down) == Directions.Down && firstCenterY < secondCenterY; bool canMoveUp = (second.Directions & Directions.Up) == Directions.Up && firstCenterY > secondCenterY; if (canMoveLeft) { float candidate = first.UpperRight.X - second.Left; if (candidate > 0) { minDistance = candidate; separation.X = -minDistance; separation.Y = 0; } } if (canMoveRight) { float candidate = (second.Left + second.Width) - first.LowerLeft.X; if (candidate > 0 && candidate < minDistance) { minDistance = candidate; separation.X = minDistance; separation.Y = 0; } } if (canMoveUp) { float candidate = (second.Bottom + second.Height) - first.Origin.Y; if (candidate > 0 && candidate < minDistance) { minDistance = candidate; separation.X = 0; separation.Y = minDistance; } } if (canMoveDown) { float candidate = first.UpperRight.Y - second.Bottom; if (candidate > 0 && candidate < minDistance) { minDistance = candidate; separation.X = 0; separation.Y = -minDistance; } } } return separation; }
CCVector2 GetSeparatingVector(CCRect first, RectWithDirection second) { //返回一个向量,是player在碰撞之后反方向移动的向量 // Default to no separation CCVector2 separation = CCVector2.Zero; // Only calculate separation if the rectangles intersect if (Intersects(first, second)) { // The intersectionRect returns the rectangle produced // by overlapping the two rectangles. // This is protected by partitioning and deep collision, so it // won't happen too often - it's okay to do a ToRect here //得到两个rect重叠部分的rect var intersectionRect = first.Intersection (second.ToRect()); float minDistance = float.PositiveInfinity; float firstCenterX = first.Center.X; float firstCenterY = first.Center.Y; float secondCenterX = second.Left + second.Width / 2.0f; float secondCenterY = second.Bottom + second.Width / 2.0f; //second的方向和想要判断的方向(左)取交集,如果和想要判断的方向(左)一致,且第一个的中心点在第二个的中心点的(左边) //则当碰撞时,player可以向想要的方向移动 bool canMoveLeft = (second.Directions & Directions.Left) == Directions.Left && firstCenterX < secondCenterX; bool canMoveRight = (second.Directions & Directions.Right) == Directions.Right && firstCenterX > secondCenterX; bool canMoveDown = (second.Directions & Directions.Down) == Directions.Down && firstCenterY < secondCenterY; bool canMoveUp = (second.Directions & Directions.Up) == Directions.Up && firstCenterY > secondCenterY; if (canMoveLeft) { //左重叠 //得到重叠的rect的X方向边长 float candidate = first.UpperRight.X - second.Left; if (candidate > 0) { minDistance = candidate; //x方向移动回到地图实体瓦片的外面,y方向不动 separation.X = -minDistance; separation.Y = 0; } } if (canMoveRight) { //右重叠 float candidate = (second.Left + second.Width) - first.LowerLeft.X; if (candidate > 0 && candidate < minDistance) { minDistance = candidate; //向右移动 separation.X = minDistance; separation.Y = 0; } } //其他方向同理 if (canMoveUp) { float candidate = (second.Bottom + second.Height) - first.Origin.Y; if (candidate > 0 && candidate < minDistance) { minDistance = candidate; separation.X = 0; separation.Y = minDistance; } } if (canMoveDown) { float candidate = first.UpperRight.Y - second.Bottom; if (candidate > 0 && candidate < minDistance) { minDistance = candidate; separation.X = 0; separation.Y = -minDistance; } } } //左后返回player移动的vector return separation; }
public void PopulateFrom(CCTileMap tileMap) { tileDimension = (int)(tileMap.TileTexelSize.Width + .5f); TileMapPropertyFinder finder = new TileMapPropertyFinder (tileMap); foreach (var propertyLocation in finder.GetPropertyLocations()) { if (propertyLocation.Properties.ContainsKey ("SolidCollision")) { float centerX = propertyLocation.WorldX; float centerY = propertyLocation.WorldY; float left = centerX - tileDimension/2.0f; float bottom = centerY - tileDimension/2.0f; RectWithDirection rectangle = new RectWithDirection { Left = left, Bottom = bottom, Width = tileDimension, Height = tileDimension }; collisions.Add (rectangle); } } // Sort by XAxis to speed future searches: collisions = collisions.OrderBy(item=>item.Left).ToList(); // now let's adjust the directions that these point for (int i = 0; i < collisions.Count; i++) { var rect = collisions [i]; // By default rectangles can reposition objects in all directions: int valueToAssign = (int)Directions.All; float centerX = rect.CenterX; float centerY = rect.CenterY; // If there are collisions on the sides, then this // rectangle can no longer repositon objects in that direction. if (HasCollisionAt (centerX - tileDimension, centerY)) { valueToAssign -= (int)Directions.Left; } if (HasCollisionAt (centerX + tileDimension, centerY)) { valueToAssign -= (int)Directions.Right; } if (HasCollisionAt (centerX, centerY + tileDimension)) { valueToAssign -= (int)Directions.Up; } if (HasCollisionAt (centerX, centerY - tileDimension)) { valueToAssign -= (int)Directions.Down; } rect.Directions = (Directions)valueToAssign; collisions [i] = rect; } for (int i = collisions.Count - 1; i > -1; i--) { if (collisions [i].Directions == Directions.None) { collisions.RemoveAt (i); } } }