robotics-and-intelligent-systems
Creating a Location-based Game with Arkit and Scenekit in Ios
Table of Contents
Augmented reality (AR) games that tie virtual content to real-world locations create deeply engaging experiences, encouraging players to explore their surroundings. Apple's ARKit and SceneKit, combined with Core Location, provide a robust toolkit for building such location-based AR games on iOS. This guide expands on the fundamental steps needed to get started, covering not just the basics but also production considerations, coordinate systems, and performance optimization.
Prerequisites and Project Setup
Before writing any code, ensure you have Xcode (version 12 or later) installed and a physical iOS device with an A9 chip or newer. The simulator lacks the ARKit sensors and GPS hardware required for accurate testing. Begin by creating a new Xcode project:
- Open Xcode and select File → New → Project.
- Choose the Augmented Reality App template under the iOS tab.
- Set the product name, team, and organization identifier. Select Swift as the language and SceneKit as the content technology.
This template provides a default ARSCNView wired to an AR session, plus a scene graph ready for 3D content. The boilerplate handles session lifecycle events, lighting estimation, and default rendering. From here, you can extend the project with location awareness.
ARKit and SceneKit: A Quick Refresher
ARKit isn't a rendering engine by itself — it tracks the device's motion, estimates real-world lighting, and detects horizontal planes. SceneKit, on the other hand, is a full 3D scene graph framework that renders polygons, applies materials, and handles physics. Together they allow developers to place virtual objects into the camera feed with realistic scaling and shadows.
Key ARKit concepts for location-based games:
- World tracking: Uses visual-inertial odometry to track the device's position and orientation in six degrees of freedom.
- ARAnchor: A fixed point in the real world that ARKit can refer back to across sessions. Anchors are used to pin virtual objects to specific locations.
- Hit testing: Casts rays from the screen to intersect real-world surfaces, useful for placing objects where the user taps.
SceneKit complements ARKit by providing SCNNode objects that can be attached to ARAnchor instances. The ARSCNView automatically synchronizes the scene graph with ARKit's coordinate system.
Integrating Core Location for GPS Data
To make your game truly location-based, you need the user's real-world latitude and longitude. Core Location provides GPS coordinates, altitude, and heading information. You'll need to add the appropriate privacy descriptions in Info.plist:
NSLocationWhenInUseUsageDescription— a string explaining why your app needs location access.- Optionally,
NSLocationAlwaysAndWhenInUseUsageDescriptionif you want background updates.
Create an instance of CLLocationManager and implement its delegate. The locationManager(_:didUpdateLocations:) method delivers an array of CLLocation objects. Filter by accuracy using desiredAccuracy — kCLLocationAccuracyBest is typical for AR gaming. Also request authorization with requestWhenInUseAuthorization().
A common pitfall is assuming GPS accuracy is uniform. In urban canyons, accuracy can degrade to tens of meters. Always check the horizontalAccuracy property and discard readings that are too poor. Combine GPS with ARKit's visual tracking to smooth the position and reduce jitter.
The Challenge of Coordinate Systems
The hardest part of location-based AR is aligning GPS coordinates with ARKit's local coordinate space. ARKit uses meters from the initial camera position: the device's starting point is the origin (0,0,0). A point 100 meters north is (0, 0, -100) assuming the device is facing +Z. But GPS uses a global coordinate system (WGS84). To bridge them, you need a reference location and a mapping function.
Setting a Reference Location
When your AR session starts, record the device's current GPS coordinate as a reference. For example, use the first high-accuracy location update. Then, for any target GPS coordinate, calculate the north-south and east-west offset using the haversine formula or a simpler equirectangular approximation. For short distances (<1 km), the equirectangular projection is sufficiently accurate:
let lat1 = referenceLocation.coordinate.latitude * .pi / 180
let lon1 = referenceLocation.coordinate.longitude * .pi / 180
let lat2 = targetLocation.coordinate.latitude * .pi / 180
let lon2 = targetLocation.coordinate.longitude * .pi / 180
let dLat = lat2 - lat1
let dLon = lon2 - lon1
let x = dLon * cos((lat1 + lat2) / 2) * 6371000
let z = dLat * 6371000
Here, x is the east-west offset (positive east) and z is the north-south offset (positive north). In ARKit's coordinate system, +X is to the right and +Z is toward the camera's initial direction. If your reference direction (heading) is not true north, you must rotate the offset by the initial device heading. Use CLLocationManager's heading updates or the device's compass.
Applying Rotation for Heading
If the device starts facing east, then the ARKit +Z axis points east. To place a virtual object that is geographically north of the user, you need to rotate the (x,z) offset by the negative of the initial heading. A common approach is to capture the device's orientation at the start of the AR session using CMAttitude from Core Motion, which gives yaw, pitch, roll relative to magnetic north. Alternatively, use the first ARFrame's camera transform to extract the heading.
Once you have the rotated offset, create an SCNVector3 and add it to the node's position relative to the camera's initial position. For more advanced alignment, consider using the community-built library ARKit-CoreLocation which handles coordinate conversion and filtering.
Placing Virtual Objects Based on Location
With the coordinate conversion in place, you can now spawn 3D objects at real-world locations. For example, if you want a floating gem at the coordinates of a local park, compute the offset from the reference location and set the node's position. Avoid using absolute distances greater than a few hundred meters, because ARKit's tracking drifts over long distances. Instead, periodically reset the reference location as the user moves.
func placeObject(at targetLocation: CLLocation, referenceLocation: CLLocation, heading: Float) {
let offset = offsetFrom(reference: referenceLocation, to: targetLocation)
let rotated = rotate(offset, by: -heading)
let node = SCNNode(geometry: SCNBox(width: 0.2, height: 0.2, length: 0.2, chamferRadius: 0))
node.position = SCNVector3(rotated.x, 0, rotated.z)
sceneView.scene.rootNode.addChildNode(node)
}
For a more realistic effect, anchor the node to the ground using ARKit's plane detection or by placing it at a fixed height (e.g., 1.5 meters off the ground for eye-level interaction). Use ARAnchor with the geographic coordinate stored in its identifier so that if the AR session resets, you can restore the object's location.
Enhancing Gameplay with Location Events
A location-based game should react to the player's real-world movement. Define geofences around points of interest. When the user enters a radius, trigger game logic: show a character, start a dialogue, or spawn enemies. Use CLLocationManager's startMonitoring(for:) method with CLCircularRegion objects. However, be aware that Geofencing has a minimum radius of around 100 meters on iOS. For finer granularity, check distances on every location update and compare against your virtual object positions.
Interactive Objects and State Management
Objects that appear based on location can have multiple states. For instance, a treasure chest may be closed until the player is within 20 meters, then open when tapped. Use SceneKit's SCNTransaction for smooth animations. Manage a dictionary of placed nodes keyed by their location or identifier. When the player moves far away, remove the nodes or reduce their LOD (level of detail) to save performance.
Multiplayer Considerations
For a seamless multiplayer experience across devices, you need a server that shares GPS coordinates and AR session snapshots. Apple's Multiuser ARKit uses ARWorldMap to synchronize anchors. In a location-based context, each device starts from its own reference location. Share target object positions as GPS coordinates and let each device compute the offset relative to its own starting point. This approach avoids ARKit drift differences.
Performance Optimization
Location-based AR games tax both the CPU (location updates, coordinate math) and GPU (3D rendering). Follow these best practices:
- Limit polygon counts: Use low-poly models, especially if multiple objects are visible. SceneKit supports LOD (level of detail) geometry.
- Reuse nodes: Pool common objects (collectibles) and recycle them instead of allocating new ones.
- Control location update frequency: Set
distanceFilterto 5–10 meters. High frequency updates waste battery and can cause positional jitter. - Use asynchronous hit testing: Avoid blocking the render loop with heavy coordinate computations. Offload math to a background queue and update node positions on the main thread.
- Lighting estimation: ARKit provides ambient light intensity. Enable it via
ARWorldTrackingConfiguration.isLightEstimationEnabled. SceneKit will automatically use this to illuminate your objects, making them look more realistic.
Battery and Thermal Management
Running GPS, ARKit, and a 3D renderer simultaneously can drain the battery quickly. Apple's ARConfiguration documentation suggests disabling features you don't need: e.g., if your game doesn't need plane detection, set planeDetection = []. Also, lower the frame rate to 30 fps if the game doesn't require smooth 60 fps animations.
Testing on Real Devices
The simulator cannot emulate GPS or true ARKit tracking. Always test on a physical iPhone or iPad. Walk around outdoor areas with clear sky view for GPS accuracy. Indoor testing is possible using location spoofing (simulate a GPX file in Xcode), but ARKit will still rely on camera images. For city-wide games, test in multiple neighborhoods to catch edge cases like tunnels or tall buildings that block GPS.
Use Xcode's debug options: in the scheme editor, set Core Location → Allow Location Simulation to a specific GPX route. Record the AR session with ARSession's writeWorldMap(to:error:) to replay and debug positioning issues.
Conclusion
Creating a location-based game with ARKit and SceneKit is a challenging but rewarding endeavor. Success depends on mastering the interplay between global GPS coordinates and ARKit's local reference frame. By carefully converting positions, handling heading, and optimizing performance, you can build immersive experiences that blend digital content with the real world. Start simple with a few static objects, then iterate: add animations, sound effects, and social features. The combination of ARKit, SceneKit, and Core Location offers a uniquely powerful canvas for mobile game developers.
For further reading, explore Apple's ARKit documentation and the SceneKit framework reference. The open-source ARKit-CoreLocation project provides a production-tested implementation of GPS-to-ARKit conversion. Experiment with these tools, and you'll soon have a prototype that encourages players to explore their neighborhoods like never before.