👋 Hey! Check out the Quake3-iOS repo (and others) by tomkidd. He used this code for the movement control. Badge of honor 🏅 (or 🦡 of honor).
Joystick
A custom UIView in Swift that presents a simple joystick interface. The custom view consists of two UIImageView
instances, one for the base and one for the handle. When the user moves the handle, it will report out a value
based on its position in relation to the joystick base. The type of information reported depends on the type of
monitor installed:
There is also support (since 3.0.1) for using an Objective-C block as a monitor, with a slight reduction in type
safety. The setPolarMonitor and setXYMonitor both take a closure that accepts two CGFloat arguments and
returns no value. Objective-C blocks can be used as well as Swift closures in these methods. Since 3.1.0, there is also
a tappedBlock attribute which one can use to receive a notification when the user just taps on the joystick handle.
The view supports an option (movable)
where the view will move when the user moves the handle to a
displacement beyond 1.0. This can be useful when the initial position of the joystick in an app is not ideal for
the user’s thumb. Double-tapping on the joystick moves it back to its original position.
In the animation above, there are two joysticks, one green and one magenta. The green is fixed and does not
move even when the touch motion would cause a displacement larger than 1.0. The magenta joystick however is
movable, with the base following the touch motion. For movable joysticks, the Base motion is optionally
restricted to a CGRect in the movableBounds property,
as is the case in the demonstration animation above where the magenta joystick cannot move out of the pink band.
Additional Properties
Here are some additional configurable features of the JoyStickView:
handleConstraint – optional CGRect which constrains where the handle can move. See the playground for an example.
baseImage – a UIImage to use for the base of the joystick.
handleImage – a UIImage to use for the handle of the joystick.
handleAlpha – opacity of the handle of the joystick.
handleTintColor – optional tint color applied to the joystick image.
handleSizeRatio – scaling applied to the joystick handle’s image. Note that default is 0.85 due to
historical reasons.
enableDoubleTapForFrameReset – if movable is true, allow user to double-tap on view to move base to original
location.
handlePositionMode – when set to .absolute (default) the handle will move to the initial (constrained) press location. When set to .relative the handle will move only after the touch moves.
Releases
v3.2.0 – Offer code as Swift package in addition to CocoaPod packaging
v3.1.1 – Added handlePositionMode property to control how handle movements are reported. Default behavior
is .absolute. New .relative mode offers finer control at initial touch (thanks to Michael Tyson)
v3.1.0 – Added tappedBlock property (thanks to Michael Tyson)
v3.0.2 – Fixed too much scaling in scaleHandleImageView
v3.0.1 – Added support for Obj-C monitor blocks
v3.0.0 – Swift 5 (no code changes, only Xcode configury)
v2.1.2 – Swift 4.2
Code
The Xcode workspace contains three components:
a framework called JoyStickView (when using CocoaPods import BRHJoyStickView instead of import JoyStickView)
Both the playground and the app rely on the framework for the JoyStickView UIView.
NOTE: due to the plumbing for CocoaPods, when editing in Xcode open the workspace JoyStickView.xcworkspace instead of the project JoyStickView.xcodeproj.
The Xcode playground code sets up the display environemnt and installs two joysticks, one that is fixed (green)
and the other that is movable (yellow). Both joysticks report out their positions in two labels, one for angles and
the other for displacement.
The JoyStickView.swift file defines the joystick view and behavior.
It resides inside the JoyStickView Swift package, and in the BRHJoyStickView framework in CocoaPods. There you will also find a file called
CoreGraphics+Additions.swift that contains various
extensions to some CoreGraphics structs that allow for some simplified mathematical expressions in the JoyStickView code.
By default the JoyStickView class uses two image assets found in the
Assets container.
folder:
DefaultBase — the image to use for the base of the joystick
DefaultHandle — the image to use for the handle of the joystick. Note: this will be tinted with the handleTintColor setting
Both exist in three resolutions for the various iOS devices out today. They were generated using the great Opacity app. The
Opacity documents are included in this repository in the Resources directory for
the JoyStickViewApp demonstration app.
To use your own images, simple set baseImage and/or handleImage attributes with the UIImage you wish to use.
There is a simple CocoaPods spec file available so you can add the code and resources
by adding “BRHJoyStickView” to your Podfile file and import with import BRHJoyStickView. Currently everything more or less works, except for the fact
that pointing to image resources via Interface Builder (IB) will result in invalid UImage results because the files won’t be
found where IB was able to find them. The only solution is to manually locate those files and set them in your
view loading code. Something like the following should help:
extension Bundle {
/**
Locate an inner Bundle generated from CocoaPod packaging.
- parameter name: the name of the inner resource bundle. This should match the "s.resource_bundle" key or
one of the "s.resoruce_bundles" keys from the podspec file that defines the CocoPod.
- returns: the resource Bundle or `self` if resource bundle was not found
*/
func podResource(name: String) -> Bundle {
guard let bundleUrl = self.url(forResource: name, withExtension: "bundle") else { return self }
return Bundle(url: bundleUrl) ?? self
}
}
In your setup code, you then will need to do something like so:
The podResource method attempts to locate a named inner bundle, defaulting to the original bundle if not found. The
viewDidLoad code will then use the right bundle object in the UIImage constructors.
👋 Hey! Check out the Quake3-iOS repo (and others) by tomkidd. He used this code for the movement control. Badge of honor 🏅 (or 🦡 of honor).
Joystick
A custom UIView in Swift that presents a simple joystick interface. The custom view consists of two UIImageView instances, one for the base and one for the handle. When the user moves the handle, it will report out a value based on its position in relation to the joystick base. The type of information reported depends on the type of monitor installed:
There is also support (since 3.0.1) for using an Objective-C block as a monitor, with a slight reduction in type safety. The
setPolarMonitor
andsetXYMonitor
both take a closure that accepts twoCGFloat
arguments and returns no value. Objective-C blocks can be used as well as Swift closures in these methods. Since 3.1.0, there is also atappedBlock
attribute which one can use to receive a notification when the user just taps on the joystick handle.The view supports an option (movable) where the view will move when the user moves the handle to a displacement beyond 1.0. This can be useful when the initial position of the joystick in an app is not ideal for the user’s thumb. Double-tapping on the joystick moves it back to its original position.
In the animation above, there are two joysticks, one green and one magenta. The green is fixed and does not move even when the touch motion would cause a displacement larger than 1.0. The magenta joystick however is movable, with the base following the touch motion. For movable joysticks, the Base motion is optionally restricted to a
CGRect
in the movableBounds property, as is the case in the demonstration animation above where the magenta joystick cannot move out of the pink band.Additional Properties
Here are some additional configurable features of the JoyStickView:
CGRect
which constrains where the handle can move. See the playground for an example.0.85
due to historical reasons.movable
is true, allow user to double-tap on view to move base to original location..absolute
(default) the handle will move to the initial (constrained) press location. When set to.relative
the handle will move only after the touch moves.Releases
handlePositionMode
property to control how handle movements are reported. Default behavior is.absolute
. New.relative
mode offers finer control at initial touch (thanks to Michael Tyson)tappedBlock
property (thanks to Michael Tyson)scaleHandleImageView
Code
The Xcode workspace contains three components:
import BRHJoyStickView
instead ofimport JoyStickView
)Both the playground and the app rely on the framework for the JoyStickView UIView.
The Xcode playground code sets up the display environemnt and installs two joysticks, one that is fixed (green) and the other that is movable (yellow). Both joysticks report out their positions in two labels, one for angles and the other for displacement.
The JoyStickView.swift file defines the joystick view and behavior. It resides inside the JoyStickView Swift package, and in the BRHJoyStickView framework in CocoaPods. There you will also find a file called CoreGraphics+Additions.swift that contains various extensions to some CoreGraphics structs that allow for some simplified mathematical expressions in the JoyStickView code.
By default the JoyStickView class uses two image assets found in the Assets container. folder:
handleTintColor
settingBoth exist in three resolutions for the various iOS devices out today. They were generated using the great Opacity app. The Opacity documents are included in this repository in the Resources directory for the
JoyStickViewApp
demonstration app.To use your own images, simple set
baseImage
and/orhandleImage
attributes with theUIImage
you wish to use.Documentation
Please see the code documentation for additional information.
CocoaPods
There is a simple CocoaPods spec file available so you can add the code and resources by adding “BRHJoyStickView” to your
Podfile
file and import withimport BRHJoyStickView
. Currently everything more or less works, except for the fact that pointing to image resources via Interface Builder (IB) will result in invalid UImage results because the files won’t be found where IB was able to find them. The only solution is to manually locate those files and set them in your view loading code. Something like the following should help:In your setup code, you then will need to do something like so:
The
podResource
method attempts to locate a named inner bundle, defaulting to the original bundle if not found. TheviewDidLoad
code will then use the rightbundle
object in the UIImage constructors.