Element Properties
Story Tellers iOS Starter Kit 2 Documentation
You’ve already seen in the initial setup how to place a Color Sprite into your scene, name it and give it a Custom Class of “Element”. Below is a quick reminder if you forgot though…
This article we’ll look at properties specific to Elements, which are the main building block of just about everything in the kit. Elements are really just images, or technically SKSpriteNodes, but by giving your image a custom class of “Element” you’re extending its capabilities so it can do more, for example, it might be a button.
Keep in mind, if you do not need to interact much with your sprite node, then you can lay out a simple Color Sprite in the Scene, give it a texture and be on your merry way.
One big difference between this kit and the original Story Tellers Kit is hopefully obvious to past users just by looking at the screenshot of the property list below. Notice how Puzzle1 has very few properties. That’s because a lot of the work is done by the Scene editor. Texture, size, rotation, z depth, location, blend mode, animation, physics properties, even Actions are initially taken care of by the Scene (oddly enough Alpha is one of the few you can’t set). Making changes to an Element can be done via Events later on. Events can do things like set a new texture, move it, hide it, reveal it, apply a new SKAction to it (which could move it, scaled it, change it’s animated textures), etc.
Point is, each of your dictionaries inside the Elements dictionary, will probably be relatively concise, and clutter-free.
As mentioned in Chapter 1, you can define an Elements dictionary on a per-page basis, or for commonly used elements in your Scene, you can also use the Elements dictionary in the Root. If both dictionaries had the same name, priority is given to the one for that particular page.
The Root Elements dictionary is intended for things like pause buttons, thumbnail images to jump to other pages, directional arrows to move character around, and other things that would potentially be used across multiple pages.
- Hidden – a Boolean property. Set to YES or NO to show or hide an Element initially. This is an important property because your Scene might have dozens of hidden Elements to use later. Events could set these Elements to show themselves (and move into their proper locations later).
- WillShowOnDay – a Number value. If the day of the month does not equal this value, the Element will be hidden.
- AllowSomeHiddenInteractions – a Boolean property. Default is NO when excluded from property list. Setting this to YES will make it so the Element can trigger some interactions when hidden. For example you might tap this hidden element to reveal another element in the scene. This property has no affect on the Show or ShowOrHide Events if they apply to the current node tapped. By default a hidden element shouldn’t allow for interaction, but this gives you the option to toggle that.
- IgnoreAllTouchEventsWhenHidden – a Boolean property. Default is NO when excluded from property list. Setting this to YES will make it so if the Element is hidden, it will completely be ignored from triggering touch events.
- SizeWidthToSceneWidth – a YES value will make the Element’s height match that of the scene (great for background art like the sky)
- SizeHeightToSceneHeight – a YES value will make the Element’s height match that of the scene
- PositionPercentageHeight – A decimal value to position an Element based on the height of the scene. Great for background elements like the sky. For example, 0.5 would put the Element at 50 percent of the height on the y axis (centered).
- PositionPercentageWidth – A decimal value to position an Element based on the width of the scene. Great for background elements like the sky. For example, 0.5 would put the Element at 50 percent of the width on the x axis (centered).
- Alpha – A number value for the alpha. 1 is 100%. This is a strangely absent option from the Scene editor. It is useful to set this to 0 if you want to perform an initial fade in Action.
- ZDepth – A number value for the z depth. This can be set much easier in the scene editor, but we’ve included it anyway.
- CameraOffset – A String value in {x, y} format to offset the Element IF it is following the Camera.
- CameraOffsetPhone – A String value in {x, y} format to offset the Element IF it is following the Camera and the device is an iPhone. This value is ignored on the iPad.
- MaxX – a Number value for the max X value the Element can be if it is following the user’s touch or being moved around dynamically.
- MaxY – a Number value for the max Y value the Element can be.
- MinX – a Number value for the minimum X value the Element can be.
- MinY – a Number value for the minimum Y value the Element can be.
Triggering Events with Touches
- TouchEvent – A Dictionary containing an unlimited amount of Events to run when the user touches the Element. If two Elements are touched at once, the higher visually of the two will win out and trigger the touch events. Events are detailed in their own article, but briefly, touch events can be relatively simple like the one in the image below…
Some extra reading on reusing event keys on multiple nodes
The event has a key (Increment1) and single value (SomeNumber). If you wanted to increment multiple values, you could change the value type from String to Array….
You can include an unlimited number of items in the Array, all will be affected. And generally speaking, if a property in the kit can be a String value, it can be switched to an Array to apply the same event on multiple items.
Some events require a dictionary of their own to set the values needed. For example…
RunAction is the event. MoveUpAndDown and LongFadeOut are the actions to perform. And Ball and Notes are the nodes being affected by the actions. Notice in this example, LongFadeOut is also an array that is affecting the nodes.
- TouchUpEvent – Identical to the TouchEvent dictionary but only runs when the user touches up after touching down on the Element. Like TouchEvent, this dictionary is optional
- MaxTouchCount – A number specifying the max number of times the Element can be touched and trigger an event. By default the amount is 0 (unlimited)
Actions
Every element can have their own Actions array to automatically run actions (on themselves). If you want an element to immediately trigger an Action on another node, use the Events dictionary and one of the action-related events, like RunAction. Keep in mind, the Scene editor is usually the best place to setup Actions that will run automatically, but you can do it with the property list as well.
Events
Every element can have their own Events dictionary to automatically run events. We’ll detail those events in a lengthy dedicated article. For the most part these are treated the same as other events, although if you want to act on the Element itself (the one running the Events), thats generally best done by setting the property directly in the Elements property list. For example, if you want to set a random texture, do that using the upcoming texture properties.
Read a little more on why this is
Technically what happens here is the entire Events dictionary gets passed up the food chain to the main page class and sorted there. But there’s really no reference inserted into it as to “who” passed it up. You could of course give a specific name in the dictionary equaling that of the Element passing along the dictionary, but in the case of randomly generated Elements (with identical names) this could potentially change all the same-named Elements.
Textures
- SetTexture – The texture name to set. This value should be that of an image in any of your Asset catalog folders (yes you can have more than one).
- SetTextureFromPool – the value will be a pool name (which contains 1 or more image names). The kit will cycle through these values starting with the first.
- SetRandomTextureFromPool – the value will also be a pool name (which contains image names). The kit will pick a random image to use. This is a great property to use when generating multiple Elements and have them vary their look.
- SetTextureFromPreference – The value should be equal to another value you set earlier (for example, using the SetValues dictionary or SetValuesIfNil dictionary). Essentially this is just an in-between reference to the texture. But like any variable, it can change over time. So the user might tap a button to change the value, then change the texture from the preference.
You could also do something like…..
Because SetValuesFromPool (and all SetValue-related code is run first), the event cycles through a new value from the pool, then uses that value for the texture. This would be a great way to cycle through things like clothing choices for a character in your book.
- SetRandomTextureFromPoolPreference – like SetRandomTextureFromPool but will use a saved value for the pool name.
Special cases
WillRotateWithGesture – A YES value will add the element to rotation array in the page (note the RotationControls dictionary must already be set in the page). This property is intended for nodes that get added at runtime (for example using a generator)
Setting up Physics on Elements
The Physics Definition window in the Scene editor has some cool features for making your Element (or SKSpriteNode) really come alive. To initially set a physics body, choose one from the Body Type pulldown. You can choose Bounding Rectangle, Bounding Circle or Alpha Mask.
Most likely you’ll want to use Alpha Mask because this sets the physics body to the actual shape of your image. For example if it was a star, the body would be a 5-pointed star. You can see the blue outline of the star’s physics body in the image below (ignore the purple rectangle used to resize the object). Keep in mind, these are bodies and just like in real life other objects can’t exist within another body.
- Dynamic – this toggle determines whether or not the body is part of the physics simulation. If you just want the body to define an immovable wall, toggle this off. If you want the body to be affected by gravity or another body pushing against it, toggle this on
- Allows Rotation – sometimes you just don’t want a body to rotate. For example, maybe the Element is a hot air balloon that should always be pointed upwards.
- Pinned – Toggle on or off to pin the body to it’s parent. We haven’t talked about parenting in this guide yet, but it is possible. So if the body shouldn’t venture from it’s parent, but still do things like rotate, turn this on.
- Affected By Gravity is obvious. This determines whether or not the Element is included in the gravity simulation. Keep in mind, you can have dynamic objects that aren’t affected by gravity.
- Friction is how slippery the body’s surface is. 0 is like glass, 1 is like sandpaper. This is very noticeable if you’ll have objects rolling down other surfaces like a marble roll.
- Restitution is how bouncy an object is. The higher, the more bouncy. 0 is not bouncy, 1 is very bouncy.
- Linear Damping – This property is used to simulate fluid or air friction forces on the body. The property must be a value between 0.0 and 1.0. The default value is 0.1. If the value is 0.0, no linear damping is applied to the object.
- Angular Damping – A property that reduces the body’s rotational velocity.
- Mass – the mass of the body in kilograms. But hey, its all relative.
Properties for Physics Contacts
To detect when one physics body has contacted any other physics body you’ll start by setting the Category Mask property (see the top green circle in the image).
Category Mask IDs must be defined as 1, 2, 4, 8, 16, 32, or 64. You can detect contacts with specific ID’s by using the Contact Mask property (see the next circled part of the image).
In the property list example above, Balloon has a Category Mask of 1 and will detect a contact with any Element with a Category Mask of 8. In which case, you might want to set the Balloon’s property list to have a dictionary of events for EventWithContact8 .
Note that an Element can detect contact with multiple categories. For example, Balloon2, Balloon3, and Balloon4, might each have different Category Masks, but as long as each of them sets 1 for their Contact Mask, then Balloon can react differently to each one.
Your physics based Element can also run events when it contacts ANY other element with a Category Mask (which is the first property below)…
- EventWithAnyContact – A String or more likely Dictionary with any events to do when the Element’s physics body collides with any other Element
- AllowMultipleContactsWithAny – A Bool value for whether the event can be triggered multiple times
- EventWithContact1 – A String or more likely Dictionary with any events to do when the Element’s physics body collides with any other Element of Category Mask equaling 1.
- AllowMultipleContactsWith1 – A Bool value for whether the event can be triggered multiple times when contacting an element with a Category Mask of 1
- EventWithContact2 – A String or more likely Dictionary with any events to do when the Element’s physics body collides with any other Element of Category Mask equaling 2
- AllowMultipleContactsWith2 – A Bool value for whether the event can be triggered multiple times when contacting an element with a Category Mask of 2
- EventWithContact4 – A String or more likely Dictionary with any events to do when the Element’s physics body collides with any other Element of Category Mask equaling 4
- AllowMultipleContactsWith4 – A Bool value for whether the event can be triggered multiple times when contacting an element with a Category Mask of 4
- EventWithContact8 – A String or more likely Dictionary with any events to do when the Element’s physics body collides with any other Element of Category Mask equaling 8
- AllowMultipleContactsWith8 – A Bool value for whether the event can be triggered multiple times when contacting an element with a Category Mask of 8
- EventWithContact16 – A String or more likely Dictionary with any events to do when the Element’s physics body collides with any other Element of Category Mask equaling 16
- AllowMultipleContactsWith16 – A Bool value for whether the event can be triggered multiple times when contacting an element with a Category Mask of 16
- EventWithContact32 – A String or more likely Dictionary with any events to do when the Element’s physics body collides with any other Element of Category Mask equaling 32
- AllowMultipleContactsWith32 – A Bool value for whether the event can be triggered multiple times when contacting an element with a Category Mask of 32
- EventWithContact64 – A String or more likely Dictionary with any events to do when the Element’s physics body collides with any other Element of Category Mask equaling 64
- AllowMultipleContactsWith64 – A Bool value for whether the event can be triggered multiple times when contacting an element with a Category Mask of 64
Initial Physics Movements
- ImpulseVector – You can set an initial impulse push on the Element in {x,y} format. So in the example below, the impulse would be 30 on the x axis and 30 on the y.
- ForceVector – You can set an initial force push on the Element in {x,y} format. Force is weaker than an impulse. It might take a much higher value to see an affect.
Buggy but working
IsCage – A Bool value set to YES will make the Element into a rectangular cage essentially. Objects can exist within it. The buggy part of this is where the body is in relation to the actual shape. Hopefully resolved by Xcode 7’s release.
Where to go next…
There’s plenty more Elements are capable of but most of that is done through Events, and other properties like Event Listeners, Generators, etc.