public bool RaycastSquare(Vector2 origin, float size, TileDirection direction, float len, out TileHitInfo hitInfo) { size *= 0.95f; hitInfo = new TileHitInfo(); int iterations = Mathf.Max(Mathf.CeilToInt(size / TILE_SIZE), 1); Vector2 from = origin - GetTanget(origin, direction) * (size * 0.5f); Vector2 step = GetTanget(origin, direction) * (size / iterations); bool hitAny = false; TileHitInfo localHitInfo; for (int i = 0; i <= iterations; i++) { if (Raycast(from, direction, len, out localHitInfo)) { if (!hitAny) { hitAny = true; hitInfo = localHitInfo; } else if (localHitInfo.hitDistance < hitInfo.hitDistance) { hitInfo = localHitInfo; } } from += step; } return(hitAny); }
public bool Raycast(Vector2 origin, TileDirection direction, float len, out TileHitInfo hitInfo) { hitInfo = new TileHitInfo(); float dx = origin.x - position.x; float dy = origin.y - position.y; float originDistance = Mathf.Sqrt(dx * dx + dy * dy); Vector2 target; float targetdx; float targetdy; float targetDistance; float tangentDistance; float segmentSize; if (originDistance < 0.001f) { originDistance = 0.001f; } float originMapAngle = -Mathf.Atan2(dy, dx) + Mathf.PI * 0.5f; while (originMapAngle > Mathf.PI * 2.0f) { originMapAngle -= Mathf.PI * 2.0f; } while (originMapAngle < 0.0f) { originMapAngle += Mathf.PI * 2.0f; } Vector2 originNormal = new Vector2(dx / originDistance, dy / originDistance); Vector2 originTangent = new Vector2(originNormal.y, -originNormal.x); if (direction == TileDirection.Right) { target = origin + originTangent * len; targetdx = target.x - position.x; targetdy = target.y - position.y; targetDistance = Mathf.Sqrt(targetdx * targetdx + targetdy * targetdy); if (originDistance > circleHeights[circleHeights.Length - 1]) { //Origin point outside, not hit! return(false); } for (int i = 1; i < circleHeights.Length; i++) { if (originDistance < circleHeights[i]) { hitInfo.hitTileY = i - 1; break; } } segmentSize = (circleHeights[hitInfo.hitTileY] * 2.0f * Mathf.PI) / width; tangentDistance = ((originMapAngle / (Mathf.PI * 2.0f)) * width); hitInfo.hitTileX = (int)tangentDistance; hitInfo.hitTileX = (hitInfo.hitTileX + 1) % width; len -= segmentSize * (Mathf.Ceil(tangentDistance) - tangentDistance); while (hitInfo.hitTileX < width && len >= 0) { if (GetTile(hitInfo.hitTileX, hitInfo.hitTileY) != 0) { hitInfo.hitNormal = -GetTangentFromTileCoordinate(hitInfo.hitTileX, hitInfo.hitTileY); hitInfo.hitPosition = position + circleNormals[hitInfo.hitTileX] * originDistance; hitInfo.hitDistance = (origin - hitInfo.hitPosition).magnitude; return(true); } len -= segmentSize; hitInfo.hitTileX++; } } else if (direction == TileDirection.Left) { target = origin + originTangent * len; targetdx = target.x - position.x; targetdy = target.y - position.y; targetDistance = Mathf.Sqrt(targetdx * targetdx + targetdy * targetdy); if (originDistance > circleHeights[circleHeights.Length - 1]) { //Origin point outside, not hit! return(false); } for (int i = 1; i < circleHeights.Length; i++) { if (originDistance < circleHeights[i]) { hitInfo.hitTileY = i - 1; break; } } segmentSize = (circleHeights[hitInfo.hitTileY] * 2.0f * Mathf.PI) / width; tangentDistance = ((originMapAngle / (Mathf.PI * 2.0f)) * width); hitInfo.hitTileX = (int)tangentDistance; hitInfo.hitTileX = (hitInfo.hitTileX - 1) % width; if (hitInfo.hitTileX < 0) { hitInfo.hitTileX += width; } len -= segmentSize * (tangentDistance - Mathf.Floor(tangentDistance)); while (hitInfo.hitTileX >= 0 && len >= 0) { if (GetTile(hitInfo.hitTileX, hitInfo.hitTileY) != 0) { hitInfo.hitNormal = GetTangentFromTileCoordinate(hitInfo.hitTileX + 1, hitInfo.hitTileY); hitInfo.hitPosition = position + circleNormals[(hitInfo.hitTileX + 1) % width] * originDistance; hitInfo.hitDistance = (origin - hitInfo.hitPosition).magnitude; return(true); } len -= segmentSize; hitInfo.hitTileX--; } } else if (direction == TileDirection.Up) { target = origin + originNormal * len; targetdx = target.x - position.x; targetdy = target.y - position.y; targetDistance = Mathf.Sqrt(targetdx * targetdx + targetdy * targetdy); if (originDistance > circleHeights[circleHeights.Length - 1]) { //Origin point outside, not hit! return(false); } hitInfo.hitTileX = (int)((originMapAngle / (Mathf.PI * 2.0f)) * width); hitInfo.hitTileX = hitInfo.hitTileX % width; for (int i = 1; i < circleHeights.Length; i++) { if (originDistance < circleHeights[i]) { hitInfo.hitTileY = i; len -= circleHeights[i] - originDistance; break; } } while (hitInfo.hitTileY < height && len >= 0) { if (GetTile(hitInfo.hitTileX, hitInfo.hitTileY) != 0) { hitInfo.hitNormal = -originNormal; hitInfo.hitPosition = position + originNormal * circleHeights[hitInfo.hitTileY]; hitInfo.hitDistance = (origin - hitInfo.hitPosition).magnitude; return(true); } if (hitInfo.hitTileY < height - 1) { len -= (circleHeights[hitInfo.hitTileY + 1] - circleHeights[hitInfo.hitTileY]); } hitInfo.hitTileY++; } } else if (direction == TileDirection.Down) { target = origin - originNormal * len; targetdx = target.x - position.x; targetdy = target.y - position.y; targetDistance = Mathf.Sqrt(targetdx * targetdx + targetdy * targetdy); if (/*originDistance > circleHeights[circleHeights.Length - 1] &&*/ targetDistance > circleHeights[circleHeights.Length - 1]) { //Target outside, no hit! return(false); } else if (targetDistance < circleHeights[0]) { //Target inside core, core hit! hitInfo.hitTileY = 0; hitInfo.hitNormal = originNormal; hitInfo.hitPosition = position + originNormal * circleHeights[0]; hitInfo.hitDistance = (origin - hitInfo.hitPosition).magnitude; return(true); } hitInfo.hitTileX = (int)((originMapAngle / (Mathf.PI * 2.0f)) * width); hitInfo.hitTileX = hitInfo.hitTileX % width; for (int i = circleHeights.Length - 1; i >= 1; i--) { if (originDistance > circleHeights[i]) { hitInfo.hitTileY = i - 1; len -= originDistance - circleHeights[i]; break; } } while (hitInfo.hitTileY >= 0 && len > 0) { if (GetTile(hitInfo.hitTileX, hitInfo.hitTileY) != 0) { hitInfo.hitNormal = originNormal; hitInfo.hitPosition = position + originNormal * circleHeights[hitInfo.hitTileY + 1]; hitInfo.hitDistance = (origin - hitInfo.hitPosition).magnitude; return(true); } if (hitInfo.hitTileY > 0) { len -= (circleHeights[hitInfo.hitTileY] - circleHeights[hitInfo.hitTileY - 1]); } hitInfo.hitTileY--; } } return(false); }