A flexible, reusable mini-map component for SpriteKit games that supports multiple entity types with customizable markers and positioning.
- Multiple Entity Types: Display any number of different entity types simultaneously
- Type-Safe API: Uses Swift's type system for compile-time safety
- Customizable Markers: Each entity type can have its own visual appearance
- Predefined Positions: 9 common window locations with easy setup
- Flexible Sizing: 4 predefined sizes plus custom sizing
- Camera View Frame: Shows current camera viewport on the mini-map
- Click Handling: Converts mini-map clicks to scene coordinates
- Cross-Platform: Supports iOS, macOS, tvOS, and watchOS
- Zero Dependencies: Pure Swift with only SpriteKit dependency
- iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 6.0+
- Swift 5.9+
- Xcode 15.0+
Add the package to your Xcode project:
- In Xcode, go to File → Add Package Dependencies
- Enter the package URL:
https://github.com/Atothendrew/MiniMapPackage.git - Select the version you want to use
- Click Add Package
- Clone the repository
- Add the
MiniMapPackagefolder to your Xcode project - Link against SpriteKit framework
Create entity types that conform to MiniMapEntity:
import MiniMapPackage
struct Worker: MiniMapEntity {
let position: CGPoint
let isActive: Bool
var markerColor: PlatformColor { isActive ? .green : .red }
var markerRadius: CGFloat { 1.5 }
var markerStrokeColor: PlatformColor { .white }
var markerLineWidth: CGFloat { 0.5 }
}
struct Gold: MiniMapEntity {
let position: CGPoint
let value: Int
var markerColor: PlatformColor { .yellow }
var markerRadius: CGFloat { 1.0 }
var markerStrokeColor: PlatformColor { .orange }
var markerLineWidth: CGFloat { 0.5 }
}import SpriteKit
import MiniMapPackage
class GameScene: SKScene {
private var miniMap: MiniMap!
override func didMove(to view: SKView) {
// Create mini-map in top-right corner with medium size
miniMap = MiniMap(size: .medium, location: .topRight, in: size)
miniMap.delegate = self
addChild(miniMap)
}
}extension GameScene {
func updateMiniMap() {
// Update base position
miniMap.updateBasePosition(base.position, sceneSize: size)
// Combine all entity types
let workers: [Worker] = getWorkers()
let golds: [Gold] = getGoldPieces()
let enemies: [Enemy] = getEnemies()
let allEntities: [AnyMiniMapEntity] =
workers.map(AnyMiniMapEntity.init) +
golds.map(AnyMiniMapEntity.init) +
enemies.map(AnyMiniMapEntity.init)
miniMap.updateEntityPositions(allEntities, sceneSize: size)
// Update camera view frame
miniMap.updateCameraViewFrame(
cameraPosition: camera.position,
cameraZoom: camera.xScale,
sceneSize: size
)
}
}extension GameScene: MiniMapDelegate {
func miniMapClicked(at position: CGPoint) {
// Move camera to clicked position
let moveAction = SKAction.move(to: position, duration: 0.5)
camera?.run(moveAction)
}
}For easy integration into existing games, use the convenience methods:
override func mouseDown(with event: NSEvent) {
let location = event.location(in: self)
// Handle mini-map interaction first
if miniMap.handleMouseDown(at: location, in: self) {
return
}
// Handle other game interactions here...
// Example: shopManager.handleTouch(at: location, in: self)
}
override func mouseDragged(with event: NSEvent) {
let location = event.location(in: self)
// Handle mini-map interaction first
if miniMap.handleMouseDragged(to: location, in: self) {
return
}
// Handle other game interactions here...
}
override func mouseUp(with event: NSEvent) {
let location = event.location(in: self)
// Handle mini-map interaction first
if miniMap.handleMouseUp(at: location, in: self) {
return
}
// Handle other game interactions here...
}
override func rightMouseDown(with event: NSEvent) {
let location = event.location(in: self)
// Handle mini-map interaction first
if miniMap.handleRightMouseDown(at: location, in: self) {
return
}
// Handle other game interactions here...
}
override func mouseMoved(with event: NSEvent) {
let location = event.location(in: self)
// Handle mini-map interaction first
if miniMap.handleMouseMoved(to: location, in: self) {
return
}
// Reset cursor if not over mini-map
NSCursor.arrow.set()
}📖 For comprehensive integration guidance, see the Integration Guide
Predefined window locations for easy positioning:
public enum MiniMapLocation {
case topLeft // Top-left corner
case topRight // Top-right corner
case bottomLeft // Bottom-left corner
case bottomRight // Bottom-right corner
case topCenter // Top center
case bottomCenter // Bottom center
case centerLeft // Left center
case centerRight // Right center
case center // Center of screen
}Predefined sizes for common use cases:
public enum MiniMapSize {
case small // 150x100
case medium // 200x150
case large // 300x200
case custom(CGSize) // Custom size
}Entities that can be displayed on the mini-map:
public protocol MiniMapEntity {
var position: CGPoint { get }
var markerColor: PlatformColor { get }
var markerRadius: CGFloat { get }
var markerStrokeColor: PlatformColor { get }
var markerLineWidth: CGFloat { get }
}Main mini-map component:
public class MiniMap: SKNode {
// Initializers
public init(size: CGSize)
public convenience init(size: MiniMapSize, location: MiniMapLocation, in sceneSize: CGSize, margin: CGFloat = 20)
// Configuration
public var backgroundColor: PlatformColor
public var backgroundStrokeColor: PlatformColor
public var backgroundLineWidth: CGFloat
public var backgroundAlpha: CGFloat
public var cameraFrameColor: PlatformColor
public var cameraFrameLineWidth: CGFloat
public var cameraFrameAlpha: CGFloat
public var miniMapZPosition: CGFloat
// Delegate
public weak var delegate: MiniMapDelegate?
// Methods
public func updateBasePosition(_ position: CGPoint, sceneSize: CGSize)
public func updateEntityPositions(_ entities: [AnyMiniMapEntity], sceneSize: CGSize)
public func updateCameraViewFrame(cameraPosition: CGPoint, cameraZoom: CGFloat, sceneSize: CGSize)
public func handleClick(at location: CGPoint)
public override func contains(_ point: CGPoint) -> Bool
}Handle mini-map interactions:
public protocol MiniMapDelegate: AnyObject {
func miniMapClicked(at position: CGPoint)
}miniMap.backgroundColor = SKColor.black.withAlphaComponent(0.8)
miniMap.backgroundStrokeColor = SKColor.white
miniMap.backgroundLineWidth = 3.0
miniMap.cameraFrameColor = SKColor.cyan
miniMap.cameraFrameLineWidth = 2.0struct Player: MiniMapEntity {
let position: CGPoint
let health: Int
var markerColor: PlatformColor { health > 50 ? .green : .red }
var markerRadius: CGFloat { 2.0 }
var markerStrokeColor: PlatformColor { .white }
var markerLineWidth: CGFloat { 1.0 }
}
struct Resource: MiniMapEntity {
let position: CGPoint
let type: ResourceType
var markerColor: PlatformColor {
switch type {
case .wood: return .brown
case .stone: return .gray
case .ore: return .orange
}
}
var markerRadius: CGFloat { 1.0 }
var markerStrokeColor: PlatformColor { .black }
var markerLineWidth: CGFloat { 0.5 }
}// Position based on screen size
let isLandscape = size.width > size.height
let location: MiniMapLocation = isLandscape ? .centerRight : .topRight
miniMap = MiniMap(size: .medium, location: location, in: size)See the included example app for a complete working implementation:
cd Examples/MiniMapExampleApp
swift runThe package is already integrated into the GatherGame project, demonstrating real-world usage with multiple entity types.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Build Errors
- Ensure you're using Swift 5.9+ and Xcode 15.0+
- Clean build folder:
swift package clean - Reset package cache:
swift package reset
Runtime Issues
- Make sure your entities conform to
MiniMapEntityprotocol - Verify scene coordinates are within expected bounds
- Check that mini-map is added to the scene before updating positions
Platform-Specific Notes
- On macOS, Y coordinates may be inverted compared to iOS
- Some platforms may have different touch/click handling
- Test on target platforms before release
- Check the examples for working implementations
- Review the API documentation for detailed usage
- Open an issue for bugs
- Start a discussion for questions
- Built for SpriteKit game development
- Inspired by the need for flexible mini-map solutions
- Designed with cross-platform compatibility in mind
- Initial release
- Support for multiple entity types
- Predefined locations and sizes
- Camera view frame
- Click handling
- Cross-platform support # Test automated release