├── DynamicWater.gif
├── Demo
├── DemoSource
│ ├── rock.png
│ ├── sky.png
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── GameScene.sks
│ ├── GameViewController.h
│ ├── GameScene.h
│ ├── Rock.h
│ ├── SettingsTitleCell.h
│ ├── AppDelegate.h
│ ├── main.m
│ ├── SettingsSliderCell.h
│ ├── Rock.m
│ ├── SettingsCellInfo.m
│ ├── SettingsTitleCell.m
│ ├── SettingsCellInfo.h
│ ├── SettingsView.h
│ ├── GameViewController.m
│ ├── SettingsSliderCell.m
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── DynamicWaterNode.h.orig
│ ├── AppDelegate.m
│ ├── SettingsSliderCell.xib
│ ├── SettingsTitleCell.xib
│ ├── SettingsView.xib
│ ├── GameScene.m
│ └── SettingsView.m
└── DynamicWater.xcodeproj
│ ├── xcuserdata
│ └── stevebarnegren.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── DynamicWater.xcscheme
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── stevebarnegren.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
│ └── project.pbxproj
├── SBDynamicWaterNode
├── Droplet.png
├── Droplets.fsh
├── SBDynamicWaterNode.h
└── SBDynamicWaterNode.m
├── Xcode.gitignore
├── LICENSE
├── SBDynamicWaterNode.podspec
└── README.md
/DynamicWater.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SteveBarnegren/SBDynamicWaterNode/HEAD/DynamicWater.gif
--------------------------------------------------------------------------------
/Demo/DemoSource/rock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SteveBarnegren/SBDynamicWaterNode/HEAD/Demo/DemoSource/rock.png
--------------------------------------------------------------------------------
/Demo/DemoSource/sky.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SteveBarnegren/SBDynamicWaterNode/HEAD/Demo/DemoSource/sky.png
--------------------------------------------------------------------------------
/Demo/DemoSource/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Demo/DemoSource/GameScene.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SteveBarnegren/SBDynamicWaterNode/HEAD/Demo/DemoSource/GameScene.sks
--------------------------------------------------------------------------------
/SBDynamicWaterNode/Droplet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SteveBarnegren/SBDynamicWaterNode/HEAD/SBDynamicWaterNode/Droplet.png
--------------------------------------------------------------------------------
/Demo/DynamicWater.xcodeproj/xcuserdata/stevebarnegren.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/Demo/DynamicWater.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Demo/DynamicWater.xcodeproj/project.xcworkspace/xcuserdata/stevebarnegren.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SteveBarnegren/SBDynamicWaterNode/HEAD/Demo/DynamicWater.xcodeproj/project.xcworkspace/xcuserdata/stevebarnegren.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/Demo/DemoSource/GameViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // GameViewController.h
3 | // DynamicWater
4 | //
5 |
6 | // Copyright (c) 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface GameViewController : UIViewController
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/SBDynamicWaterNode/Droplets.fsh:
--------------------------------------------------------------------------------
1 | void main() {
2 |
3 |
4 | vec4 texture = texture2D(u_texture, v_tex_coord);
5 | if (texture.a > 0.8) {
6 | texture = u_colour;
7 | }
8 | else{
9 | texture = vec4(0.0, 0.0, 0.0, 0.0);
10 | }
11 |
12 | gl_FragColor = texture;
13 |
14 | }
--------------------------------------------------------------------------------
/Demo/DemoSource/GameScene.h:
--------------------------------------------------------------------------------
1 | //
2 | // GameScene.h
3 | // DynamicWater
4 | //
5 |
6 | // Copyright (c) 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GameScene : SKScene
12 |
13 | @property float splashWidth;
14 | @property float splashForceMultiplier;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/Demo/DemoSource/Rock.h:
--------------------------------------------------------------------------------
1 | //
2 | // Rock.h
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 08/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface Rock : SKSpriteNode
12 |
13 | @property BOOL isAboveWater;
14 | @property CGPoint velocity;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/Demo/DemoSource/SettingsTitleCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // SettingsTitleCell.h
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 09/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SettingsTitleCell : UITableViewCell
12 |
13 | -(void)setTitle:(NSString*)title;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Demo/DemoSource/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 07/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/Demo/DemoSource/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 07/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Demo/DemoSource/SettingsSliderCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // SettingsSliderCell.h
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 09/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "SettingsCellInfo.h"
11 |
12 | @interface SettingsSliderCell : UITableViewCell
13 |
14 | @property (nonatomic, strong) NSString *title;
15 |
16 | -(void)setupWithInfo:(SettingsCellSliderInfo*)info;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/Xcode.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
--------------------------------------------------------------------------------
/Demo/DemoSource/Rock.m:
--------------------------------------------------------------------------------
1 | //
2 | // Rock.m
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 08/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import "Rock.h"
10 |
11 | @interface Rock ()
12 | @end
13 |
14 |
15 | @implementation Rock
16 |
17 | -(instancetype)initWithImageNamed:(NSString *)name{
18 |
19 | if (self = [super initWithImageNamed:name]) {
20 | self.isAboveWater = YES;
21 | self.velocity = CGPointZero;
22 | }
23 | return self;
24 | }
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/Demo/DemoSource/SettingsCellInfo.m:
--------------------------------------------------------------------------------
1 | //
2 | // SettingsCellInfo.m
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 09/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import "SettingsCellInfo.h"
10 |
11 | @implementation SettingsCellInfo
12 | +(SettingsCellInfo*)cellInfoWithTitle:(NSString*)title{
13 | SettingsCellInfo *info = [[SettingsCellInfo alloc ]init];
14 | info.title = title;
15 | return info;
16 | }
17 |
18 | @end
19 |
20 | @implementation SettingsCellSliderInfo
21 | @end
22 |
23 |
--------------------------------------------------------------------------------
/Demo/DemoSource/SettingsTitleCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // SettingsTitleCell.m
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 09/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import "SettingsTitleCell.h"
10 |
11 | @interface SettingsTitleCell ()
12 | @property (nonatomic, weak) IBOutlet UILabel *label;
13 | @end
14 |
15 | @implementation SettingsTitleCell
16 |
17 | - (void)awakeFromNib {
18 | // Initialization code
19 | }
20 |
21 | -(void)setTitle:(NSString*)title{
22 | self.label.text = title;
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/Demo/DynamicWater.xcodeproj/xcuserdata/stevebarnegren.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | DynamicWater.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 67DA19381C8DE6C400BB9382
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Demo/DemoSource/SettingsCellInfo.h:
--------------------------------------------------------------------------------
1 | //
2 | // SettingsCellInfo.h
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 09/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SettingsCellInfo : NSObject
12 | @property (nonatomic, strong) NSString *title;
13 | +(SettingsCellInfo*)cellInfoWithTitle:(NSString*)title;
14 | @end
15 |
16 | @interface SettingsCellSliderInfo : SettingsCellInfo
17 | @property float startValue;
18 | @property float endValue;
19 | @property (nonatomic, copy) float (^getCurrentValue)();
20 | @property (nonatomic, copy) void (^updateCallback)(float newValue);
21 | @property BOOL showValueReadout;
22 | @end
23 |
--------------------------------------------------------------------------------
/Demo/DemoSource/SettingsView.h:
--------------------------------------------------------------------------------
1 | //
2 | // SettingsView.h
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 09/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "SBDynamicWaterNode.h"
11 |
12 | @class GameScene;
13 |
14 | @protocol SettingsViewDelegate;
15 |
16 | @interface SettingsView : UIView
17 | @property (nonatomic, weak) id delegate;
18 |
19 | @property (nonatomic, weak) GameScene *gameScene;
20 | @property (nonatomic, weak) SBDynamicWaterNode *waterNode;
21 | +(id)instanceFromNib;
22 |
23 | @end
24 |
25 | @protocol SettingsViewDelegate
26 | -(void)settingsViewShouldClose:(SettingsView*)settingsView;
27 | -(void)settingsViewWantsRestoreDefaultValues:(SettingsView*)settingsView;
28 | @end
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 Steve Barnegren
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/SBDynamicWaterNode.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "SBDynamicWaterNode"
3 | s.version = "1.0.1"
4 | s.summary = "Physical water simulation for SpriteKit"
5 |
6 | s.description = <<-DESC
7 | Physical water simulation for SpriteKit with demo application
8 | DESC
9 |
10 | s.homepage = "https://github.com/SteveBarnegren/DynamicWaterNode"
11 | # s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2"
12 | s.license = 'MIT'
13 | s.author = { "Steve Barnegren" => "steve.barnegren@gmail.com" }
14 | s.source = { :git => "https://github.com/SteveBarnegren/SBDynamicWaterNode.git", :tag => s.version.to_s }
15 | s.social_media_url = 'https://twitter.com/stevebarnegren'
16 |
17 | s.platform = :ios, '8.0'
18 | s.requires_arc = true
19 |
20 | s.source_files = 'SBDynamicWaterNode/**/*.{h,m}'
21 | s.resources = 'SBDynamicWaterNode/**/*.{png,fsh}'
22 | #s.resource_bundles = {
23 | # 'SBDynamicWaterNode' => ['SBDynamicWaterNode/*.{png,fsh}']
24 | #}
25 |
26 | # s.public_header_files = 'Pod/Classes/**/*.h'
27 | s.frameworks = 'SpriteKit'
28 | end
29 |
--------------------------------------------------------------------------------
/Demo/DemoSource/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "29x29",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "29x29",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "40x40",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "40x40",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "76x76",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "76x76",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "83.5x83.5",
66 | "scale" : "2x"
67 | }
68 | ],
69 | "info" : {
70 | "version" : 1,
71 | "author" : "xcode"
72 | }
73 | }
--------------------------------------------------------------------------------
/Demo/DemoSource/GameViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // GameViewController.m
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 07/03/2016.
6 | // Copyright (c) 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import "GameViewController.h"
10 | #import "GameScene.h"
11 |
12 | @implementation GameViewController
13 |
14 | - (void)viewDidLoad
15 | {
16 | [super viewDidLoad];
17 |
18 | // Configure the view.
19 | SKView * skView = (SKView *)self.view;
20 | skView.showsFPS = YES;
21 | skView.showsNodeCount = YES;
22 | /* Sprite Kit applies additional optimizations to improve rendering performance */
23 | skView.ignoresSiblingOrder = YES;
24 |
25 | // Create and configure the scene.
26 | GameScene *scene = [GameScene nodeWithFileNamed:@"GameScene"];
27 | scene.scaleMode = SKSceneScaleModeAspectFill;
28 |
29 | // Present the scene.
30 | [skView presentScene:scene];
31 | }
32 |
33 | - (BOOL)shouldAutorotate
34 | {
35 | return YES;
36 | }
37 |
38 | - (UIInterfaceOrientationMask)supportedInterfaceOrientations
39 | {
40 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
41 | return UIInterfaceOrientationMaskAllButUpsideDown;
42 | } else {
43 | return UIInterfaceOrientationMaskAll;
44 | }
45 | }
46 |
47 | - (void)didReceiveMemoryWarning
48 | {
49 | [super didReceiveMemoryWarning];
50 | // Release any cached data, images, etc that aren't in use.
51 | }
52 |
53 | - (BOOL)prefersStatusBarHidden {
54 | return YES;
55 | }
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/Demo/DemoSource/SettingsSliderCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // SettingsSliderCell.m
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 09/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import "SettingsSliderCell.h"
10 |
11 | @interface SettingsSliderCell ()
12 | @property (nonatomic, strong) SettingsCellSliderInfo *info;
13 |
14 | @property (nonatomic, weak) IBOutlet UILabel *label;
15 | @property (nonatomic, weak) IBOutlet UISlider *slider;
16 |
17 | @end
18 |
19 | @implementation SettingsSliderCell
20 |
21 | - (void)awakeFromNib {
22 | // Initialization code
23 | }
24 |
25 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
26 | [super setSelected:selected animated:animated];
27 |
28 | // Configure the view for the selected state
29 | }
30 |
31 | -(void)setupWithInfo:(SettingsCellSliderInfo*)info{
32 | self.info = info;
33 |
34 | self.slider.minimumValue = info.startValue;
35 | self.slider.maximumValue = info.endValue;
36 | self.slider.continuous = YES;
37 | self.slider.value = info.getCurrentValue();
38 |
39 | [self updateLabel];
40 | }
41 |
42 | -(IBAction)sliderValueChanged:(UISlider*)slider{
43 | NSLog(@"slider value changed");
44 | self.info.updateCallback(slider.value);
45 | [self updateLabel];
46 | }
47 |
48 |
49 | -(void)updateLabel{
50 |
51 | NSString *text = self.info.title;
52 | if (self.info.showValueReadout) {
53 | text = [text stringByAppendingString:[NSString stringWithFormat:@" (%g)", self.slider.value]];
54 | }
55 | self.label.text = text;
56 | }
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/Demo/DemoSource/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UIStatusBarHidden
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationLandscapeLeft
38 | UIInterfaceOrientationLandscapeRight
39 |
40 | UISupportedInterfaceOrientations~ipad
41 |
42 | UIInterfaceOrientationPortrait
43 | UIInterfaceOrientationPortraitUpsideDown
44 | UIInterfaceOrientationLandscapeLeft
45 | UIInterfaceOrientationLandscapeRight
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Demo/DemoSource/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Demo/DemoSource/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DynamicWaterNode
2 |
3 | [](http://cocoadocs.org/docsets/SBDynamicWaterNode/)
4 | [](http://cocoadocs.org/docsets/SBDynamicWaterNode/)
5 | [](http://cocoadocs.org/docsets/SBDynamicWaterNode/)
6 |
7 | 2D physical water simulation for SpriteKit
8 |
9 | 
10 |
11 | # How to use
12 |
13 | Add DynamicWaterNode.h, DynamicWaterNode.m, Droplet.png and Droplets.fsh to your project
14 |
15 | Add to your scene:
16 |
17 | ```
18 | - (void)didMoveToView:(SKView *)view {
19 | self.waterNode = [[DynamicWaterNode alloc]initWithWidth:self.size.width
20 | numJoints:100
21 | surfaceHeight:kSurfaceHeight
22 | fillColour:[UIColor colorWithRed:0 green:0 blue:1 alpha:0.5]];
23 | self.waterNode.position = CGPointMake(self.size.width/2, 0);
24 | [self addChild:self.waterNode];
25 |
26 | }
27 | ```
28 |
29 | Step the simulation in your scene’s update method. See demo project for an example of a fixed time step implementation
30 |
31 | ```
32 | [self.waterNode update:dt];
33 | ```
34 |
35 | Call render: after the simulation has been updated. Only call render once each frame.
36 |
37 | ```
38 | [self.waterNode render];
39 | ```
40 |
41 | Making splashes:
42 |
43 | ```
44 | [self.waterNode splashAtX:100 force:20 width:20];
45 | ```
46 |
47 | Various properties of DynamicWaterNode can be changed to control the feel of the water. The demo project includes a settings screen where you can alter these to see their effect.
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Demo/DemoSource/DynamicWaterNode.h.orig:
--------------------------------------------------------------------------------
1 | //
2 | // DynamicWaterNode.h
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 07/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface DynamicWaterNode : SKNode
12 |
13 | @property float surfaceHeight;
14 | @property (nonatomic) float tension;
15 | @property (nonatomic) float damping;
16 | @property float spread;
17 |
18 | #pragma mark - Init
19 | /**
20 | Designated Initialiser.
21 | @param width The width of the water
22 | @param numJoints The number of joints used to simulate the waves. More joints will result in a smoother wave curve, fewer joints will look more jagged, but may may improve performance.
23 | @param surfaceHeight the height of the water's surface
24 | @param fillColour The colour of the water
25 | */
26 | -(instancetype)initWithWidth:(float)width numJoints:(NSInteger)numJoints surfaceHeight:(float)surfaceHeight fillColour:(UIColor*)fillColour;
27 |
28 | #pragma mark - Set Defaults
29 | /** Reset simulation variables to defaults */
30 | -(void)setDefaultValues;
31 |
32 | #pragma mark - Update
33 | /**
34 | Step the time of the simulation
35 | @param dt: delta time since last update
36 | */
37 | -(void)update:(CFTimeInterval)dt;
38 |
39 | <<<<<<< HEAD
40 | -(void)renderWater;
41 | =======
42 | >>>>>>> master
43 |
44 | #pragma mark - Splash
45 | /**
46 | Make a splash (width will be 0)
47 | @param xLocation The X location to make the splash at
48 | @param force The force of the splash
49 | */
50 | -(void)splashAtX:(float)xLocation force:(CGFloat)force;
51 | /**
52 | Make a splash
53 | @param xLocation The X location to make the splash at
54 | @param force The force of the splash
55 | @param width the width of the splash
56 | */
57 | -(void)splashAtX:(float)xLocation force:(CGFloat)force width:(float)width;
58 |
59 | #pragma mark - Render
60 | /**
61 | Render the water. Only call this once per frame. You can still call update to update the simulation multiple times per frame (eg. fixed time-step).
62 | */
63 | -(void)render;
64 |
65 | @end
66 |
--------------------------------------------------------------------------------
/Demo/DemoSource/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 07/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 | - (void)applicationWillResignActive:(UIApplication *)application {
24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
26 | }
27 |
28 | - (void)applicationDidEnterBackground:(UIApplication *)application {
29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | - (void)applicationWillEnterForeground:(UIApplication *)application {
34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | - (void)applicationDidBecomeActive:(UIApplication *)application {
38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/SBDynamicWaterNode/SBDynamicWaterNode.h:
--------------------------------------------------------------------------------
1 | //
2 | // SBDynamicWaterNode.h
3 | // SBDynamicWaterNode
4 | //
5 | // Created by Steve Barnegren on 07/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SBDynamicWaterNode : SKNode
12 |
13 | /** Height of the water's surface */
14 | @property float surfaceHeight;
15 | /** Tension the water, shoud probably be less than damping */
16 | @property (nonatomic) float tension;
17 | /** Tension the water, shoud probably be greater than damping */
18 | @property (nonatomic) float damping;
19 | /** Controls how fast/far waves propogate across water surface */
20 | @property float spread;
21 | /** The amount of force applied to splash droplets */
22 | @property float dropletsForce;
23 | /** Higher values will result splahes producing more water droplets */
24 | @property float dropletsDensity;
25 | /** Size of water droplets */
26 | @property float dropletSize;
27 |
28 | #pragma mark - Init
29 | /**
30 | Designated Initialiser.
31 | @param width The width of the water
32 | @param numJoints The number of joints used to simulate the waves. More joints will result in a smoother wave curve, fewer joints will look more jagged, but may may improve performance.
33 | @param surfaceHeight the height of the water's surface
34 | @param fillColour The colour of the water
35 | */
36 | -(instancetype)initWithWidth:(float)width numJoints:(NSInteger)numJoints surfaceHeight:(float)surfaceHeight fillColour:(UIColor*)fillColour;
37 |
38 | #pragma mark - Set Defaults
39 | /** Reset simulation variables to defaults */
40 | -(void)setDefaultValues;
41 |
42 | #pragma mark - Colour
43 | /** Set the water colour */
44 | -(void)setColour:(UIColor*)colour;
45 |
46 | #pragma mark - Update
47 | /**
48 | Step the time of the simulation
49 | @param dt: delta time since last update
50 | */
51 | -(void)update:(CFTimeInterval)dt;
52 |
53 |
54 | #pragma mark - Splash
55 | /**
56 | Make a splash
57 | @param xLocation: Location of the splash
58 | @param force: Force of the splash
59 | */
60 | -(void)splashAtX:(float)xLocation force:(CGFloat)force;
61 | /**
62 | Make a splash
63 | @param xLocation: Location of the splash
64 | @param force: Force of the splash
65 | @param width: The width of the splash. Set to higher values to simulate objects with a larger surface area
66 | */
67 | -(void)splashAtX:(float)xLocation force:(CGFloat)force width:(float)width;
68 |
69 | #pragma mark - Render
70 | /**
71 | Render the water. Only call this once per frame. You can still call update to update the simulation multiple times per frame (eg. fixed time-step).
72 | */
73 | -(void)render;
74 |
75 | @end
76 |
--------------------------------------------------------------------------------
/Demo/DynamicWater.xcodeproj/xcuserdata/stevebarnegren.xcuserdatad/xcschemes/DynamicWater.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/Demo/DemoSource/SettingsSliderCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Demo/DemoSource/SettingsTitleCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Demo/DemoSource/SettingsView.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/Demo/DemoSource/GameScene.m:
--------------------------------------------------------------------------------
1 | //
2 | // GameScene.m
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 07/03/2016.
6 | // Copyright (c) 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import "GameScene.h"
10 | #import "SBDynamicWaterNode.h"
11 | #import "Rock.h"
12 | #import "SettingsView.h"
13 |
14 | #define kFixedTimeStep (1.0f/500)
15 |
16 | #define kSurfaceHeight 235
17 |
18 | typedef enum : NSUInteger {
19 | ZPositionSky,
20 | ZPositionRock,
21 | ZPositionWater,
22 | } ZPositions;
23 |
24 | @interface GameScene ()
25 | @property (nonatomic, strong) SettingsView *settingsView;
26 |
27 | @property (nonatomic, strong) SKSpriteNode *skySprite;
28 | @property (nonatomic, strong) SBDynamicWaterNode *waterNode;
29 |
30 | @property CFTimeInterval lastFrameTime;
31 | @property BOOL hasReferenceFrameTime;
32 |
33 | @property (nonatomic, strong) NSMutableArray *rocks;
34 |
35 | @end
36 |
37 | @implementation GameScene
38 |
39 | -(void)didMoveToView:(SKView *)view {
40 |
41 | self.rocks = [[NSMutableArray alloc]init];
42 |
43 | // Sky
44 | self.skySprite = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:@"sky"]];
45 | self.skySprite.xScale = self.size.width/self.skySprite.texture.size.width;
46 | self.skySprite.yScale = self.size.height/self.skySprite.texture.size.height;
47 | self.skySprite.position = CGPointMake(self.size.width/2, self.size.height/2);
48 | self.skySprite.zPosition = ZPositionSky;
49 | [self addChild:self.skySprite];
50 |
51 | // Water
52 | self.waterNode = [[SBDynamicWaterNode alloc]initWithWidth:self.size.width
53 | numJoints:100
54 | surfaceHeight:kSurfaceHeight
55 | fillColour:[UIColor colorWithRed:0 green:0 blue:1 alpha:0.5]];
56 | self.waterNode.position = CGPointMake(self.size.width/2, 0);
57 | self.waterNode.zPosition = ZPositionWater;
58 | [self addChild:self.waterNode];
59 |
60 | // Settings Button
61 | UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
62 | [button setTitle:@"Settings" forState:UIControlStateNormal];
63 | [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
64 | button.translatesAutoresizingMaskIntoConstraints = NO;
65 | [button addTarget:self action:@selector(showSettingsView) forControlEvents:UIControlEventTouchUpInside];
66 | [self.view addSubview:button];
67 | [self.view addConstraint:[NSLayoutConstraint constraintWithItem:button
68 | attribute:NSLayoutAttributeRight
69 | relatedBy:NSLayoutRelationEqual
70 | toItem:self.view
71 | attribute:NSLayoutAttributeRight
72 | multiplier:1
73 | constant:-8]];
74 | [self.view addConstraint:[NSLayoutConstraint constraintWithItem:button
75 | attribute:NSLayoutAttributeTop
76 | relatedBy:NSLayoutRelationEqual
77 | toItem:self.view
78 | attribute:NSLayoutAttributeTop
79 | multiplier:1
80 | constant:8]];
81 |
82 | // Set Default Values
83 | [self setDefaultValues];
84 |
85 | }
86 |
87 | -(void)setDefaultValues{
88 | self.waterNode.surfaceHeight = kSurfaceHeight;
89 | self.splashWidth = 20;
90 | self.splashForceMultiplier = 0.125;
91 | [self.waterNode setDefaultValues];
92 | }
93 |
94 | #pragma mark - Touch Handling
95 |
96 | -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
97 |
98 | for (UITouch *touch in touches) {
99 | CGPoint location = [touch locationInNode:self];
100 | Rock *rock = [[Rock alloc]initWithImageNamed:@"rock"];
101 | rock.position = location;
102 | rock.zPosition = ZPositionRock;
103 | [self addChild:rock];
104 | [self.rocks addObject:rock];
105 | }
106 | }
107 |
108 | #pragma mark - Update
109 |
110 | -(void)update:(CFTimeInterval)currentTime {
111 | /* Called before each frame is rendered */
112 |
113 | if (!self.hasReferenceFrameTime) {
114 | self.lastFrameTime = currentTime;
115 | self.hasReferenceFrameTime = YES;
116 | return;
117 | }
118 |
119 | CFTimeInterval dt = currentTime - self.lastFrameTime;
120 |
121 | // Fixed Update
122 | CFTimeInterval accumilator = 0;
123 | accumilator += dt;
124 |
125 | while (accumilator >= kFixedTimeStep) {
126 | [self fixedUpdate:kFixedTimeStep];
127 | accumilator -= kFixedTimeStep;
128 | }
129 | [self fixedUpdate:accumilator];
130 |
131 | // Late Update
132 | [self lateUpdate:dt];
133 |
134 | self.lastFrameTime = currentTime;
135 |
136 | }
137 |
138 | -(void)fixedUpdate:(CFTimeInterval)dt{
139 | [self.waterNode update:dt];
140 |
141 |
142 | NSMutableArray *rocksToRemove = [[NSMutableArray alloc]init];
143 |
144 | const float gravity = -1200;
145 | for (Rock *rock in self.rocks) {
146 |
147 | // Apply Gravity
148 | rock.velocity = CGPointMake(rock.velocity.x,
149 | rock.velocity.y + gravity * dt);
150 |
151 | rock.position = CGPointMake(rock.position.x + rock.velocity.x * dt,
152 | rock.position.y + rock.velocity.y * dt);
153 |
154 | // Splash
155 | if (rock.isAboveWater && rock.position.y <= self.waterNode.surfaceHeight) {
156 | rock.isAboveWater = NO;
157 | [self.waterNode splashAtX:rock.position.x
158 | force:-rock.velocity.y * self.splashForceMultiplier
159 | width:self.splashWidth];
160 |
161 | }
162 |
163 | // Remove if off-screen
164 | if (rock.position.y < - rock.size.height/2) {
165 | [rocksToRemove addObject:rock];
166 | }
167 | }
168 |
169 | for (Rock *rock in rocksToRemove) {
170 | [self.rocks removeObject:rock];
171 | }
172 |
173 | }
174 |
175 | -(void)lateUpdate:(CFTimeInterval)dt{
176 | [self.waterNode render];
177 | }
178 |
179 | #pragma mark - Settings View
180 |
181 | -(void)showSettingsView{
182 | if (self.settingsView) { return; }
183 |
184 | self.settingsView = [SettingsView instanceFromNib];
185 | self.settingsView.frame = self.view.bounds;
186 | self.settingsView.delegate = self;
187 | self.settingsView.gameScene = self;
188 | self.settingsView.waterNode = self.waterNode;
189 | [self.view addSubview:self.settingsView];
190 |
191 | }
192 |
193 | -(void)settingsViewShouldClose:(SettingsView *)settingsView{
194 |
195 | if (self.settingsView) {
196 | [self.settingsView removeFromSuperview];
197 | self.settingsView = nil;
198 | }
199 |
200 | }
201 |
202 | -(void)settingsViewWantsRestoreDefaultValues:(SettingsView *)settingsView{
203 | [self setDefaultValues];
204 | }
205 |
206 | @end
207 |
--------------------------------------------------------------------------------
/Demo/DemoSource/SettingsView.m:
--------------------------------------------------------------------------------
1 | //
2 | // SettingsView.m
3 | // DynamicWater
4 | //
5 | // Created by Steve Barnegren on 09/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import "SettingsView.h"
10 | #import "SettingsSliderCell.h"
11 | #import "SettingsTitleCell.h"
12 | #import "SettingsCellInfo.h"
13 | #import "GameScene.h"
14 |
15 | #define kCellHeight 45
16 |
17 | @interface SettingsView()
18 | @property (nonatomic, weak) IBOutlet UIView *containerView;
19 | @property (nonatomic, weak) IBOutlet UITableView *tableView;
20 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *tableViewHeightConstraint;
21 | @property (nonatomic, strong) NSArray *cellInfos;
22 | @end
23 |
24 | @implementation SettingsView
25 |
26 | +(id)instanceFromNib{
27 |
28 | id result = nil;
29 | NSArray* elements = [[NSBundle mainBundle] loadNibNamed: NSStringFromClass([self class]) owner:self options: nil];
30 | for (id anObject in elements)
31 | {
32 | if ([anObject isKindOfClass:[self class]])
33 | {
34 | result = anObject;
35 | break;
36 | }
37 | }
38 | NSAssert1(result, @"Failed to load %@ from nib", NSStringFromClass(self));
39 |
40 | return result;
41 | }
42 |
43 | -(void)awakeFromNib{
44 | [super awakeFromNib];
45 |
46 | self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3];
47 | [self createCellInfos];
48 |
49 | // Container View
50 | self.containerView.layer.cornerRadius = 15;
51 | self.containerView.clipsToBounds = YES;
52 |
53 | // TableView
54 | self.tableViewHeightConstraint.constant = kCellHeight * self.cellInfos.count;
55 | self.tableView.dataSource = self;
56 | self.tableView.delegate = self;
57 | [self.tableView registerNib:[UINib nibWithNibName:@"SettingsSliderCell" bundle:nil]
58 | forCellReuseIdentifier:NSStringFromClass([SettingsSliderCell class])];
59 | [self.tableView registerNib:[UINib nibWithNibName:@"SettingsTitleCell" bundle:nil]
60 | forCellReuseIdentifier:NSStringFromClass([SettingsTitleCell class])];
61 | [self.tableView reloadData];
62 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
63 |
64 |
65 | }
66 |
67 | -(void)createCellInfos{
68 |
69 | NSMutableArray *cellInfos = [[NSMutableArray alloc]init];
70 |
71 | __weak __typeof__(self) weakSelf = self;
72 |
73 | [cellInfos addObject:[SettingsCellInfo cellInfoWithTitle:@"Water"]];
74 |
75 | // Surface Height
76 | {
77 | SettingsCellSliderInfo *info = [[SettingsCellSliderInfo alloc]init];
78 | info.title = @"Surface Height";
79 | info.startValue = 150;
80 | info.endValue = 500;
81 | info.showValueReadout = YES;
82 | [info setGetCurrentValue:^float{
83 | return weakSelf.waterNode.surfaceHeight;
84 | }];
85 | [info setUpdateCallback:^void(float newValue) {
86 | weakSelf.waterNode.surfaceHeight = newValue;
87 | }];
88 | [cellInfos addObject:info];
89 | }
90 |
91 | // Tension
92 | {
93 | SettingsCellSliderInfo *info = [[SettingsCellSliderInfo alloc]init];
94 | info.title = @"Tension";
95 | info.startValue = 0.05;
96 | info.endValue = 15;
97 | info.showValueReadout = YES;
98 | [info setGetCurrentValue:^float{
99 | return weakSelf.waterNode.tension;
100 | }];
101 | [info setUpdateCallback:^void(float newValue) {
102 | weakSelf.waterNode.tension = newValue;
103 | }];
104 | [cellInfos addObject:info];
105 | }
106 |
107 | // Damping
108 | {
109 | SettingsCellSliderInfo *info = [[SettingsCellSliderInfo alloc]init];
110 | info.title = @"Damping";
111 | info.startValue = 0.15;
112 | info.endValue = 15;
113 | info.showValueReadout = YES;
114 | [info setGetCurrentValue:^float{
115 | return weakSelf.waterNode.damping;
116 | }];
117 | [info setUpdateCallback:^void(float newValue) {
118 | weakSelf.waterNode.damping = newValue;
119 | }];
120 | [cellInfos addObject:info];
121 | }
122 |
123 | // Spread
124 | {
125 |
126 | SettingsCellSliderInfo *info = [[SettingsCellSliderInfo alloc]init];
127 | info.title = @"Spread";
128 | info.startValue = 3;
129 | info.endValue = 100;
130 | info.showValueReadout = YES;
131 | [info setGetCurrentValue:^float{
132 | return weakSelf.waterNode.spread;
133 | }];
134 | [info setUpdateCallback:^void(float newValue) {
135 | weakSelf.waterNode.spread = newValue;
136 | }];
137 | [cellInfos addObject:info];
138 | }
139 |
140 | [cellInfos addObject:[SettingsCellInfo cellInfoWithTitle:@"Splashes"]];
141 |
142 | // Splash Force Multiplier
143 | {
144 |
145 | SettingsCellSliderInfo *info = [[SettingsCellSliderInfo alloc]init];
146 | info.title = @"Splash Force";
147 | info.startValue = 0.02;
148 | info.endValue = 2.5;
149 | info.showValueReadout = NO;
150 | [info setGetCurrentValue:^float{
151 | return weakSelf.gameScene.splashForceMultiplier;
152 | }];
153 | [info setUpdateCallback:^void(float newValue) {
154 | weakSelf.gameScene.splashForceMultiplier = newValue;
155 | }];
156 | [cellInfos addObject:info];
157 | }
158 |
159 | // Splash Width
160 | {
161 |
162 | SettingsCellSliderInfo *info = [[SettingsCellSliderInfo alloc]init];
163 | info.title = @"Splash Width";
164 | info.startValue = 0;
165 | info.endValue = 200;
166 | info.showValueReadout = YES;
167 | [info setGetCurrentValue:^float{
168 | return weakSelf.gameScene.splashWidth;
169 | }];
170 | [info setUpdateCallback:^void(float newValue) {
171 | weakSelf.gameScene.splashWidth = newValue;
172 | }];
173 | [cellInfos addObject:info];
174 | }
175 |
176 | [cellInfos addObject:[SettingsCellInfo cellInfoWithTitle:@"Droplets"]];
177 |
178 | // Droplets Force
179 | {
180 |
181 | SettingsCellSliderInfo *info = [[SettingsCellSliderInfo alloc]init];
182 | info.title = @"Droplets Force";
183 | info.startValue = 0.2;
184 | info.endValue = 3;
185 | info.showValueReadout = YES;
186 | [info setGetCurrentValue:^float{
187 | return weakSelf.waterNode.dropletsForce;
188 | }];
189 | [info setUpdateCallback:^void(float newValue) {
190 | weakSelf.waterNode.dropletsForce = newValue;
191 | }];
192 | [cellInfos addObject:info];
193 | }
194 |
195 | // Droplets Density
196 | {
197 |
198 | SettingsCellSliderInfo *info = [[SettingsCellSliderInfo alloc]init];
199 | info.title = @"Droplets Density";
200 | info.startValue = 0;
201 | info.endValue = 2;
202 | info.showValueReadout = YES;
203 | [info setGetCurrentValue:^float{
204 | return weakSelf.waterNode.dropletsDensity;
205 | }];
206 | [info setUpdateCallback:^void(float newValue) {
207 | weakSelf.waterNode.dropletsDensity = newValue;
208 | }];
209 | [cellInfos addObject:info];
210 | }
211 |
212 | // Droplet Size
213 | {
214 |
215 | SettingsCellSliderInfo *info = [[SettingsCellSliderInfo alloc]init];
216 | info.title = @"Droplet Size";
217 | info.startValue = 1;
218 | info.endValue = 10;
219 | info.showValueReadout = YES;
220 | [info setGetCurrentValue:^float{
221 | return weakSelf.waterNode.dropletSize;
222 | }];
223 | [info setUpdateCallback:^void(float newValue) {
224 | weakSelf.waterNode.dropletSize = newValue;
225 | }];
226 | [cellInfos addObject:info];
227 | }
228 |
229 | self.cellInfos = [NSArray arrayWithArray:cellInfos];
230 | }
231 |
232 | #pragma mark - Actions
233 |
234 | -(IBAction)restoreDefaultsButtonPressed:(id)sender{
235 |
236 | if ([self.delegate respondsToSelector:@selector(settingsViewWantsRestoreDefaultValues:)]) {
237 | [self.delegate settingsViewWantsRestoreDefaultValues:self];
238 | }
239 | [self.tableView reloadData];
240 | }
241 |
242 | -(IBAction)closeButtonPressed:(id)sender{
243 |
244 | if ([self.delegate respondsToSelector:@selector(settingsViewShouldClose:)]) {
245 | [self.delegate settingsViewShouldClose:self];
246 | }
247 | }
248 |
249 | #pragma mark - UITableView Datasource / Delegate
250 |
251 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
252 | return 1;
253 | }
254 |
255 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
256 | return self.cellInfos.count;
257 | }
258 |
259 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
260 |
261 | SettingsCellInfo *info = self.cellInfos[indexPath.row];
262 |
263 | if ([info isMemberOfClass:[SettingsCellInfo class]]) {
264 | SettingsTitleCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([SettingsTitleCell class])];
265 | cell.title = info.title;
266 | return cell;
267 | }
268 |
269 | if ([info isMemberOfClass:[SettingsCellSliderInfo class]]) {
270 | SettingsSliderCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([SettingsSliderCell class])];
271 | [cell setupWithInfo:self.cellInfos[indexPath.row]];
272 | return cell;
273 | }
274 |
275 | return nil;
276 | }
277 |
278 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
279 | return kCellHeight;
280 | }
281 |
282 | @end
283 |
--------------------------------------------------------------------------------
/SBDynamicWaterNode/SBDynamicWaterNode.m:
--------------------------------------------------------------------------------
1 | //
2 | // SBDynamicWaterNode.m
3 | // SBDynamicWaterNode
4 | //
5 | // Created by Steve Barnegren on 07/03/2016.
6 | // Copyright © 2016 Steve Barnegren. All rights reserved.
7 | //
8 |
9 | #import "SBDynamicWaterNode.h"
10 |
11 | @interface UIColor (SBDynamicWaterNodeExtensions)
12 | -(GLKVector4)vector4Value;
13 | @end
14 |
15 | @implementation UIColor (SBDynamicWaterNodeExtensions)
16 |
17 | -(GLKVector4)vector4Value{
18 |
19 | CGFloat r, g, b, a;
20 | [self getRed:&r green:&g blue:&b alpha:&a];
21 | return GLKVector4Make(r, g, b, a);
22 | }
23 |
24 | @end
25 |
26 | //**********************************************
27 | #pragma mark - ***** Droplet *****
28 | //**********************************************
29 |
30 | @interface SBDroplet : SKSpriteNode
31 | @property CGPoint velocity;
32 | @end
33 |
34 | @implementation SBDroplet
35 |
36 | +(instancetype)droplet{
37 | SBDroplet *droplet = [[SBDroplet alloc]initWithImageNamed:@"Droplet"];
38 | droplet.velocity = CGPointZero;
39 | return droplet;
40 | }
41 |
42 | @end
43 |
44 | //**********************************************
45 | #pragma mark - ***** WaterJoint *****
46 | //**********************************************
47 |
48 | @interface SBWaterJoint : NSObject
49 |
50 | @property (nonatomic) CGPoint position;
51 | @property (nonatomic) CGFloat velocity;
52 | @property (nonatomic) CGFloat damping;
53 | @property (nonatomic) CGFloat tension;
54 | @end
55 |
56 | @implementation SBWaterJoint
57 |
58 | -(instancetype)init{
59 |
60 | if (self = [super init]) {
61 | self.position = CGPointZero;
62 | self.velocity = 0;
63 | self.damping = 0;
64 | self.tension = 0;
65 | }
66 | return self;
67 | }
68 |
69 | -(void)setYPosition:(float)yPos{
70 | self.position = CGPointMake(self.position.x, yPos);
71 | }
72 |
73 | - (void)update:(NSTimeInterval)dt {
74 |
75 | CGFloat y = self.position.y;
76 | CGFloat acceleration = (-self.tension * y) - (self.velocity * self.damping);
77 |
78 | self.position = CGPointMake(self.position.x, self.position.y + (self.velocity * 60 * dt));
79 | self.velocity += acceleration * dt;
80 | }
81 |
82 | @end
83 |
84 | //**********************************************
85 | #pragma mark - ***** DynamicWaterNode *****
86 | //**********************************************
87 |
88 | @interface SBDynamicWaterNode ()
89 | @property (nonatomic, strong) NSArray *joints;
90 | @property (nonatomic, strong) SKShapeNode *shapeNode;
91 | @property float width;
92 |
93 | @property CGPathRef path;
94 |
95 | @property (nonatomic, strong) NSMutableArray *droplets;
96 | @property (nonatomic, strong) NSMutableArray *dropletsCache;
97 |
98 | @property (nonatomic, strong) SKEffectNode *effectNode;
99 |
100 | @end
101 |
102 |
103 | @implementation SBDynamicWaterNode
104 |
105 | #pragma mark - LifeCycle
106 |
107 | -(instancetype)initWithWidth:(float)width numJoints:(NSInteger)numJoints surfaceHeight:(float)surfaceHeight fillColour:(UIColor*)fillColour{
108 |
109 | self = [super init];
110 | if (!self) { return nil; }
111 |
112 | // Init Properties
113 | self.surfaceHeight = surfaceHeight;
114 | self.width = width;
115 | self.droplets = [[NSMutableArray alloc]init];
116 | self.dropletsCache = [[NSMutableArray alloc]init];
117 |
118 | // Effect Node
119 | self.effectNode = [[SKEffectNode alloc]init];
120 | self.effectNode.position = CGPointZero;
121 | self.effectNode.zPosition = 1;
122 | self.effectNode.shouldRasterize = NO;
123 | self.effectNode.shouldEnableEffects = YES;
124 | self.effectNode.shader = [SKShader shaderWithFileNamed:@"Droplets.fsh"];
125 | self.effectNode.shader.uniforms = @[[SKUniform uniformWithName:@"u_colour" floatVector4:[fillColour vector4Value]]];
126 | [self addChild:self.effectNode];
127 |
128 | // Shape Node
129 | self.shapeNode = [[SKShapeNode alloc]init];
130 | self.shapeNode.fillColor = [UIColor blackColor];
131 | self.shapeNode.strokeColor = [UIColor greenColor];
132 | self.shapeNode.glowWidth = 2;
133 | self.shapeNode.zPosition = 2;
134 | [self.effectNode addChild:self.shapeNode];
135 |
136 | // Create joints
137 | NSMutableArray *mutableJoints = [[NSMutableArray alloc]initWithCapacity:numJoints];
138 | for (NSInteger i = 0; i < numJoints; i++) {
139 | SBWaterJoint *joint = [[SBWaterJoint alloc]init];
140 | CGPoint position;
141 | position.x = -(width/2) + ((width/(numJoints-1)) * i);
142 | position.y = 0;
143 | joint.position = position;
144 | [mutableJoints addObject:joint];
145 | }
146 | self.joints = [NSArray arrayWithArray:mutableJoints];
147 |
148 | // Set default simulation variables
149 | [self setDefaultValues];
150 |
151 | // Initial render
152 | [self render];
153 |
154 | return self;
155 | }
156 |
157 | -(void)dealloc{
158 | CGPathRelease(self.path);
159 | }
160 |
161 | #pragma mark - Simulation Variables
162 |
163 | -(void)setDefaultValues{
164 | self.tension = 1.8;
165 | self.damping = 2.4;
166 | self.spread = 9;
167 | self.dropletsForce = 1;
168 | self.dropletsDensity = 1;
169 | self.dropletSize = 3;
170 | }
171 |
172 | -(void)setTension:(float)tension{
173 | _tension = tension;
174 | for (SBWaterJoint *joint in self.joints) {
175 | joint.tension = tension;
176 | }
177 | }
178 |
179 | -(void)setDamping:(float)damping{
180 | _damping = damping;
181 | for (SBWaterJoint *joint in self.joints) {
182 | joint.damping = damping;
183 | }
184 | }
185 |
186 | -(void)setColour:(UIColor*)colour{
187 | [self.effectNode.shader uniformNamed:@"u_colour"].floatVector4Value = [colour vector4Value];
188 | }
189 |
190 | #pragma mark - Splash
191 |
192 | -(void)splashAtX:(float)xLocation force:(CGFloat)force{
193 | [self splashAtX:xLocation force:force width:0];
194 | }
195 |
196 | -(void)splashAtX:(float)xLocation force:(CGFloat)force width:(float)width{
197 |
198 | xLocation -= self.width/2;
199 |
200 | CGFloat shortestDistance = CGFLOAT_MAX;
201 | SBWaterJoint *closestJoint;
202 |
203 | for (SBWaterJoint *joint in self.joints) {
204 |
205 | CGFloat distance = fabs(joint.position.x - xLocation);
206 | if (distance < shortestDistance) {
207 | shortestDistance = distance;
208 | closestJoint = joint;
209 | }
210 | }
211 |
212 | closestJoint.velocity = -force;
213 |
214 | for (SBWaterJoint *joint in self.joints) {
215 | CGFloat distance = fabs(joint.position.x - closestJoint.position.x);
216 | if (distance < width) {
217 | joint.velocity = distance / width * -force;
218 | }
219 | }
220 |
221 |
222 | // Add droplets
223 | NSInteger numDroplets = 20 * force/100 * self.dropletsDensity;
224 | //NSLog(@"Num Droplets: %li", (long)numDroplets);
225 | for (NSInteger i = 0; i < numDroplets; i++) {
226 | const float maxVelY = 500 * force/100*self.dropletsForce;
227 | const float minVelY = 200 * force/100*self.dropletsForce;
228 | const float maxVelX = -350 * force/100*self.dropletsForce;
229 | const float minVelX = 350 * force/100*self.dropletsForce;
230 |
231 | float velY = minVelY + (maxVelY - minVelY) * [self randomFloatBetween0and1];
232 | float velX = minVelX + (maxVelX - minVelX) * [self randomFloatBetween0and1];
233 |
234 | [self addDropletAt:CGPointMake(xLocation, self.surfaceHeight)
235 | velocity:CGPointMake(velX, velY)];
236 | }
237 |
238 | }
239 |
240 | -(float)randomFloatBetween0and1{
241 | return (float)rand() / RAND_MAX;
242 | }
243 |
244 | #pragma mark - Droplets
245 |
246 | -(void)addDropletAt:(CGPoint)position velocity:(CGPoint)velocity{
247 |
248 | SBDroplet *droplet;
249 |
250 | if (self.dropletsCache.count) {
251 | droplet = [self.dropletsCache lastObject];
252 | [self.dropletsCache removeLastObject];
253 | }
254 | else{
255 | droplet = [SBDroplet droplet];
256 | }
257 |
258 | droplet.velocity = velocity;
259 | droplet.position = position;
260 | droplet.zPosition = 1;
261 | droplet.blendMode = SKBlendModeAlpha;
262 | droplet.color = [UIColor blueColor];
263 | droplet.colorBlendFactor = 1;
264 | droplet.xScale = droplet.yScale = self.dropletSize;
265 | [self.effectNode addChild:droplet];
266 | [self.droplets addObject:droplet];
267 | }
268 |
269 | -(void)removeDroplet:(SBDroplet*)droplet{
270 |
271 | [droplet removeFromParent];
272 | [self.droplets removeObject:droplet];
273 | [self.dropletsCache addObject:droplet];
274 | }
275 |
276 |
277 | #pragma mark - Update
278 |
279 | -(void)update:(CFTimeInterval)dt{
280 | [self updateJoints:dt];
281 | [self updateDroplets:dt];
282 | }
283 |
284 | -(void)updateJoints:(CFTimeInterval)dt{
285 |
286 |
287 | for (SBWaterJoint *joint in self.joints) {
288 | [joint update:dt];
289 | }
290 |
291 | float leftDeltas[self.joints.count];
292 | float rightDeltas[self.joints.count];
293 |
294 | for (NSInteger pass = 0; pass < 1; pass++) {
295 |
296 | for (NSInteger i = 0; i < self.joints.count; i++) {
297 |
298 | SBWaterJoint *currentJoint = self.joints[i];
299 |
300 | if (i > 0) {
301 | SBWaterJoint *previousJoint = self.joints[i-1];
302 | leftDeltas[i] = self.spread * (currentJoint.position.y - previousJoint.position.y);
303 | previousJoint.velocity += leftDeltas[i] * dt;
304 | }
305 | if (i < self.joints.count-1) {
306 | SBWaterJoint *nextJoint = self.joints[i+1];
307 | rightDeltas[i] = self.spread * (currentJoint.position.y - nextJoint.position.y);
308 | nextJoint.velocity += rightDeltas[i] * dt;
309 | }
310 | }
311 |
312 | for (NSInteger i = 0; i < self.joints.count; i++) {
313 |
314 | if (i > 0) {
315 | SBWaterJoint *previousJoint = self.joints[i-1];
316 | [previousJoint setYPosition:previousJoint.position.y + leftDeltas[i] * dt];
317 | }
318 | if (i < self.joints.count - 1) {
319 | SBWaterJoint *nextJoint = self.joints[i+1];
320 | [nextJoint setYPosition:nextJoint.position.y + rightDeltas[i] * dt];
321 | }
322 |
323 | }
324 |
325 | }
326 | }
327 |
328 | -(void)updateDroplets:(CFTimeInterval)dt{
329 |
330 | const float gravity = -1200;
331 |
332 | NSMutableArray *dropletsToRemove = [[NSMutableArray alloc]init];
333 |
334 | for (SBDroplet *droplet in self.droplets) {
335 |
336 | // Apply Gravity
337 | droplet.velocity = CGPointMake(droplet.velocity.x,
338 | droplet.velocity.y + gravity * dt);
339 |
340 | droplet.position = CGPointMake(droplet.position.x + droplet.velocity.x * dt,
341 | droplet.position.y + droplet.velocity.y * dt);
342 |
343 | // Remove if below surface
344 | if (droplet.position.y + droplet.texture.size.height/2 + 30 < self.surfaceHeight) {
345 | [dropletsToRemove addObject:droplet];
346 | }
347 | }
348 |
349 | for (SBDroplet *droplet in dropletsToRemove) {
350 | [self removeDroplet:droplet];
351 | }
352 |
353 | }
354 |
355 | #pragma mark - Render
356 |
357 | -(void)render{
358 |
359 | CGPathRelease(self.path);
360 | self.path = [self pathFromJoints:self.joints];
361 |
362 | [self.shapeNode setPath:self.path];
363 | }
364 |
365 | - (CGPathRef)pathFromJoints:(NSArray*)joints {
366 |
367 | CGMutablePathRef path = CGPathCreateMutable();
368 |
369 | NSInteger index = 0;
370 | for (SBWaterJoint *joint in self.joints) {
371 |
372 | if (index == 0) {
373 | CGPathMoveToPoint(path,
374 | nil,
375 | joint.position.x,
376 | joint.position.y + self.surfaceHeight);
377 | }
378 | else{
379 | CGPathAddLineToPoint(path,
380 | nil,
381 | joint.position.x,
382 | joint.position.y + self.surfaceHeight);
383 | }
384 |
385 | index++;
386 | }
387 |
388 | // Bottom Right
389 | CGPathAddLineToPoint(path,
390 | nil,
391 | self.width/2,
392 | 0);
393 |
394 | // Bottom Left
395 | CGPathAddLineToPoint(path,
396 | nil,
397 | -self.width/2,
398 | 0);
399 |
400 | CGPathCloseSubpath(path);
401 |
402 |
403 | return path;
404 | }
405 |
406 |
407 | @end
408 |
--------------------------------------------------------------------------------
/Demo/DynamicWater.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 67AC79761CBEE56700551E1F /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 67DA19521C8DE6C500BB9382 /* Info.plist */; };
11 | 67DA193E1C8DE6C500BB9382 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 67DA193D1C8DE6C500BB9382 /* main.m */; };
12 | 67DA19411C8DE6C500BB9382 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 67DA19401C8DE6C500BB9382 /* AppDelegate.m */; };
13 | 67DA19441C8DE6C500BB9382 /* GameScene.m in Sources */ = {isa = PBXBuildFile; fileRef = 67DA19431C8DE6C500BB9382 /* GameScene.m */; };
14 | 67DA19461C8DE6C500BB9382 /* GameScene.sks in Resources */ = {isa = PBXBuildFile; fileRef = 67DA19451C8DE6C500BB9382 /* GameScene.sks */; };
15 | 67DA19491C8DE6C500BB9382 /* GameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 67DA19481C8DE6C500BB9382 /* GameViewController.m */; };
16 | 67DA194C1C8DE6C500BB9382 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 67DA194A1C8DE6C500BB9382 /* Main.storyboard */; };
17 | 67DA194E1C8DE6C500BB9382 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 67DA194D1C8DE6C500BB9382 /* Assets.xcassets */; };
18 | 67DA19511C8DE6C500BB9382 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 67DA194F1C8DE6C500BB9382 /* LaunchScreen.storyboard */; };
19 | 67DA195A1C8DE6F400BB9382 /* SBDynamicWaterNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 67DA19591C8DE6F400BB9382 /* SBDynamicWaterNode.m */; };
20 | 67DA195F1C8E542300BB9382 /* rock.png in Resources */ = {isa = PBXBuildFile; fileRef = 67DA195C1C8E542300BB9382 /* rock.png */; };
21 | 67DA19601C8E542300BB9382 /* sky.png in Resources */ = {isa = PBXBuildFile; fileRef = 67DA195D1C8E542300BB9382 /* sky.png */; };
22 | 67DA19B31C8F39A400BB9382 /* Rock.m in Sources */ = {isa = PBXBuildFile; fileRef = 67DA19B21C8F39A400BB9382 /* Rock.m */; };
23 | 67DA19BA1C8F8B7900BB9382 /* Droplets.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 67DA19B91C8F8B7900BB9382 /* Droplets.fsh */; };
24 | 67DA19C71C90794800BB9382 /* SettingsSliderCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 67DA19C51C90794800BB9382 /* SettingsSliderCell.m */; };
25 | 67DA19C81C90794800BB9382 /* SettingsSliderCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 67DA19C61C90794800BB9382 /* SettingsSliderCell.xib */; };
26 | 67DA19CB1C90809D00BB9382 /* SettingsCellInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 67DA19CA1C90809D00BB9382 /* SettingsCellInfo.m */; };
27 | 67DA19CF1C909FEF00BB9382 /* SettingsView.h in Sources */ = {isa = PBXBuildFile; fileRef = 67DA19B41C8F7E2D00BB9382 /* SettingsView.h */; };
28 | 67DA19D01C909FEF00BB9382 /* SettingsView.m in Sources */ = {isa = PBXBuildFile; fileRef = 67DA19B51C8F7E2D00BB9382 /* SettingsView.m */; };
29 | 67DA19D21C90A06A00BB9382 /* Droplet.png in Resources */ = {isa = PBXBuildFile; fileRef = 67DA19D11C90A06A00BB9382 /* Droplet.png */; };
30 | 67DA19D31C90A2C300BB9382 /* SettingsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 67DA19B71C8F7E4500BB9382 /* SettingsView.xib */; };
31 | 67DA19D71C90C0EC00BB9382 /* SettingsTitleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 67DA19D51C90C0EC00BB9382 /* SettingsTitleCell.m */; };
32 | 67DA19D81C90C0EC00BB9382 /* SettingsTitleCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 67DA19D61C90C0EC00BB9382 /* SettingsTitleCell.xib */; };
33 | /* End PBXBuildFile section */
34 |
35 | /* Begin PBXFileReference section */
36 | 67DA19391C8DE6C400BB9382 /* DynamicWater.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DynamicWater.app; sourceTree = BUILT_PRODUCTS_DIR; };
37 | 67DA193D1C8DE6C500BB9382 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
38 | 67DA193F1C8DE6C500BB9382 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
39 | 67DA19401C8DE6C500BB9382 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
40 | 67DA19421C8DE6C500BB9382 /* GameScene.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GameScene.h; sourceTree = ""; };
41 | 67DA19431C8DE6C500BB9382 /* GameScene.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GameScene.m; sourceTree = ""; };
42 | 67DA19451C8DE6C500BB9382 /* GameScene.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = GameScene.sks; sourceTree = ""; };
43 | 67DA19471C8DE6C500BB9382 /* GameViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GameViewController.h; sourceTree = ""; };
44 | 67DA19481C8DE6C500BB9382 /* GameViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GameViewController.m; sourceTree = ""; };
45 | 67DA194B1C8DE6C500BB9382 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
46 | 67DA194D1C8DE6C500BB9382 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
47 | 67DA19501C8DE6C500BB9382 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
48 | 67DA19521C8DE6C500BB9382 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
49 | 67DA19581C8DE6F400BB9382 /* SBDynamicWaterNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBDynamicWaterNode.h; sourceTree = ""; };
50 | 67DA19591C8DE6F400BB9382 /* SBDynamicWaterNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBDynamicWaterNode.m; sourceTree = ""; };
51 | 67DA195C1C8E542300BB9382 /* rock.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = rock.png; sourceTree = ""; };
52 | 67DA195D1C8E542300BB9382 /* sky.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = sky.png; sourceTree = ""; };
53 | 67DA19B11C8F39A400BB9382 /* Rock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Rock.h; sourceTree = ""; };
54 | 67DA19B21C8F39A400BB9382 /* Rock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Rock.m; sourceTree = ""; };
55 | 67DA19B41C8F7E2D00BB9382 /* SettingsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsView.h; sourceTree = ""; };
56 | 67DA19B51C8F7E2D00BB9382 /* SettingsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsView.m; sourceTree = ""; };
57 | 67DA19B71C8F7E4500BB9382 /* SettingsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsView.xib; sourceTree = ""; };
58 | 67DA19B91C8F8B7900BB9382 /* Droplets.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = Droplets.fsh; sourceTree = ""; };
59 | 67DA19C41C90794800BB9382 /* SettingsSliderCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsSliderCell.h; sourceTree = ""; };
60 | 67DA19C51C90794800BB9382 /* SettingsSliderCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsSliderCell.m; sourceTree = ""; };
61 | 67DA19C61C90794800BB9382 /* SettingsSliderCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsSliderCell.xib; sourceTree = ""; };
62 | 67DA19C91C90809D00BB9382 /* SettingsCellInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsCellInfo.h; sourceTree = ""; };
63 | 67DA19CA1C90809D00BB9382 /* SettingsCellInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsCellInfo.m; sourceTree = ""; };
64 | 67DA19D11C90A06A00BB9382 /* Droplet.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Droplet.png; sourceTree = ""; };
65 | 67DA19D41C90C0EC00BB9382 /* SettingsTitleCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsTitleCell.h; sourceTree = ""; };
66 | 67DA19D51C90C0EC00BB9382 /* SettingsTitleCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsTitleCell.m; sourceTree = ""; };
67 | 67DA19D61C90C0EC00BB9382 /* SettingsTitleCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsTitleCell.xib; sourceTree = ""; };
68 | /* End PBXFileReference section */
69 |
70 | /* Begin PBXFrameworksBuildPhase section */
71 | 67DA19361C8DE6C400BB9382 /* Frameworks */ = {
72 | isa = PBXFrameworksBuildPhase;
73 | buildActionMask = 2147483647;
74 | files = (
75 | );
76 | runOnlyForDeploymentPostprocessing = 0;
77 | };
78 | /* End PBXFrameworksBuildPhase section */
79 |
80 | /* Begin PBXGroup section */
81 | 67DA19301C8DE6C400BB9382 = {
82 | isa = PBXGroup;
83 | children = (
84 | 67DA19CC1C90950500BB9382 /* SBDynamicWaterNode */,
85 | 67DA193B1C8DE6C500BB9382 /* Demo */,
86 | 67DA193A1C8DE6C400BB9382 /* Products */,
87 | );
88 | sourceTree = "";
89 | };
90 | 67DA193A1C8DE6C400BB9382 /* Products */ = {
91 | isa = PBXGroup;
92 | children = (
93 | 67DA19391C8DE6C400BB9382 /* DynamicWater.app */,
94 | );
95 | name = Products;
96 | sourceTree = "";
97 | };
98 | 67DA193B1C8DE6C500BB9382 /* Demo */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 67DA195C1C8E542300BB9382 /* rock.png */,
102 | 67DA195D1C8E542300BB9382 /* sky.png */,
103 | 67DA193F1C8DE6C500BB9382 /* AppDelegate.h */,
104 | 67DA19401C8DE6C500BB9382 /* AppDelegate.m */,
105 | 67DA19421C8DE6C500BB9382 /* GameScene.h */,
106 | 67DA19431C8DE6C500BB9382 /* GameScene.m */,
107 | 67DA19B11C8F39A400BB9382 /* Rock.h */,
108 | 67DA19B21C8F39A400BB9382 /* Rock.m */,
109 | 67DA19451C8DE6C500BB9382 /* GameScene.sks */,
110 | 67DA19471C8DE6C500BB9382 /* GameViewController.h */,
111 | 67DA19481C8DE6C500BB9382 /* GameViewController.m */,
112 | 67DA194A1C8DE6C500BB9382 /* Main.storyboard */,
113 | 67DA19D91C90C0F200BB9382 /* Settings */,
114 | 67DA194D1C8DE6C500BB9382 /* Assets.xcassets */,
115 | 67DA194F1C8DE6C500BB9382 /* LaunchScreen.storyboard */,
116 | 67DA19521C8DE6C500BB9382 /* Info.plist */,
117 | 67DA193C1C8DE6C500BB9382 /* Supporting Files */,
118 | );
119 | name = Demo;
120 | path = DemoSource;
121 | sourceTree = "";
122 | };
123 | 67DA193C1C8DE6C500BB9382 /* Supporting Files */ = {
124 | isa = PBXGroup;
125 | children = (
126 | 67DA193D1C8DE6C500BB9382 /* main.m */,
127 | );
128 | name = "Supporting Files";
129 | sourceTree = "";
130 | };
131 | 67DA19CC1C90950500BB9382 /* SBDynamicWaterNode */ = {
132 | isa = PBXGroup;
133 | children = (
134 | 67DA19D11C90A06A00BB9382 /* Droplet.png */,
135 | 67DA19581C8DE6F400BB9382 /* SBDynamicWaterNode.h */,
136 | 67DA19591C8DE6F400BB9382 /* SBDynamicWaterNode.m */,
137 | 67DA19B91C8F8B7900BB9382 /* Droplets.fsh */,
138 | );
139 | name = SBDynamicWaterNode;
140 | path = ../SBDynamicWaterNode;
141 | sourceTree = "";
142 | };
143 | 67DA19D91C90C0F200BB9382 /* Settings */ = {
144 | isa = PBXGroup;
145 | children = (
146 | 67DA19B41C8F7E2D00BB9382 /* SettingsView.h */,
147 | 67DA19B51C8F7E2D00BB9382 /* SettingsView.m */,
148 | 67DA19B71C8F7E4500BB9382 /* SettingsView.xib */,
149 | 67DA19C91C90809D00BB9382 /* SettingsCellInfo.h */,
150 | 67DA19CA1C90809D00BB9382 /* SettingsCellInfo.m */,
151 | 67DA19C41C90794800BB9382 /* SettingsSliderCell.h */,
152 | 67DA19C51C90794800BB9382 /* SettingsSliderCell.m */,
153 | 67DA19C61C90794800BB9382 /* SettingsSliderCell.xib */,
154 | 67DA19D41C90C0EC00BB9382 /* SettingsTitleCell.h */,
155 | 67DA19D51C90C0EC00BB9382 /* SettingsTitleCell.m */,
156 | 67DA19D61C90C0EC00BB9382 /* SettingsTitleCell.xib */,
157 | );
158 | name = Settings;
159 | sourceTree = "";
160 | };
161 | /* End PBXGroup section */
162 |
163 | /* Begin PBXNativeTarget section */
164 | 67DA19381C8DE6C400BB9382 /* DynamicWater */ = {
165 | isa = PBXNativeTarget;
166 | buildConfigurationList = 67DA19551C8DE6C500BB9382 /* Build configuration list for PBXNativeTarget "DynamicWater" */;
167 | buildPhases = (
168 | 67DA19351C8DE6C400BB9382 /* Sources */,
169 | 67DA19361C8DE6C400BB9382 /* Frameworks */,
170 | 67DA19371C8DE6C400BB9382 /* Resources */,
171 | );
172 | buildRules = (
173 | );
174 | dependencies = (
175 | );
176 | name = DynamicWater;
177 | productName = DynamicWater;
178 | productReference = 67DA19391C8DE6C400BB9382 /* DynamicWater.app */;
179 | productType = "com.apple.product-type.application";
180 | };
181 | /* End PBXNativeTarget section */
182 |
183 | /* Begin PBXProject section */
184 | 67DA19311C8DE6C400BB9382 /* Project object */ = {
185 | isa = PBXProject;
186 | attributes = {
187 | LastUpgradeCheck = 0720;
188 | ORGANIZATIONNAME = "Steve Barnegren";
189 | TargetAttributes = {
190 | 67DA19381C8DE6C400BB9382 = {
191 | CreatedOnToolsVersion = 7.2;
192 | };
193 | };
194 | };
195 | buildConfigurationList = 67DA19341C8DE6C400BB9382 /* Build configuration list for PBXProject "DynamicWater" */;
196 | compatibilityVersion = "Xcode 3.2";
197 | developmentRegion = English;
198 | hasScannedForEncodings = 0;
199 | knownRegions = (
200 | en,
201 | Base,
202 | );
203 | mainGroup = 67DA19301C8DE6C400BB9382;
204 | productRefGroup = 67DA193A1C8DE6C400BB9382 /* Products */;
205 | projectDirPath = "";
206 | projectRoot = "";
207 | targets = (
208 | 67DA19381C8DE6C400BB9382 /* DynamicWater */,
209 | );
210 | };
211 | /* End PBXProject section */
212 |
213 | /* Begin PBXResourcesBuildPhase section */
214 | 67DA19371C8DE6C400BB9382 /* Resources */ = {
215 | isa = PBXResourcesBuildPhase;
216 | buildActionMask = 2147483647;
217 | files = (
218 | 67DA19D21C90A06A00BB9382 /* Droplet.png in Resources */,
219 | 67DA19461C8DE6C500BB9382 /* GameScene.sks in Resources */,
220 | 67DA19D81C90C0EC00BB9382 /* SettingsTitleCell.xib in Resources */,
221 | 67DA19511C8DE6C500BB9382 /* LaunchScreen.storyboard in Resources */,
222 | 67AC79761CBEE56700551E1F /* Info.plist in Resources */,
223 | 67DA195F1C8E542300BB9382 /* rock.png in Resources */,
224 | 67DA19C81C90794800BB9382 /* SettingsSliderCell.xib in Resources */,
225 | 67DA194E1C8DE6C500BB9382 /* Assets.xcassets in Resources */,
226 | 67DA19601C8E542300BB9382 /* sky.png in Resources */,
227 | 67DA19D31C90A2C300BB9382 /* SettingsView.xib in Resources */,
228 | 67DA19BA1C8F8B7900BB9382 /* Droplets.fsh in Resources */,
229 | 67DA194C1C8DE6C500BB9382 /* Main.storyboard in Resources */,
230 | );
231 | runOnlyForDeploymentPostprocessing = 0;
232 | };
233 | /* End PBXResourcesBuildPhase section */
234 |
235 | /* Begin PBXSourcesBuildPhase section */
236 | 67DA19351C8DE6C400BB9382 /* Sources */ = {
237 | isa = PBXSourcesBuildPhase;
238 | buildActionMask = 2147483647;
239 | files = (
240 | 67DA19D71C90C0EC00BB9382 /* SettingsTitleCell.m in Sources */,
241 | 67DA19CF1C909FEF00BB9382 /* SettingsView.h in Sources */,
242 | 67DA19D01C909FEF00BB9382 /* SettingsView.m in Sources */,
243 | 67DA19491C8DE6C500BB9382 /* GameViewController.m in Sources */,
244 | 67DA19CB1C90809D00BB9382 /* SettingsCellInfo.m in Sources */,
245 | 67DA19411C8DE6C500BB9382 /* AppDelegate.m in Sources */,
246 | 67DA19B31C8F39A400BB9382 /* Rock.m in Sources */,
247 | 67DA19C71C90794800BB9382 /* SettingsSliderCell.m in Sources */,
248 | 67DA19441C8DE6C500BB9382 /* GameScene.m in Sources */,
249 | 67DA195A1C8DE6F400BB9382 /* SBDynamicWaterNode.m in Sources */,
250 | 67DA193E1C8DE6C500BB9382 /* main.m in Sources */,
251 | );
252 | runOnlyForDeploymentPostprocessing = 0;
253 | };
254 | /* End PBXSourcesBuildPhase section */
255 |
256 | /* Begin PBXVariantGroup section */
257 | 67DA194A1C8DE6C500BB9382 /* Main.storyboard */ = {
258 | isa = PBXVariantGroup;
259 | children = (
260 | 67DA194B1C8DE6C500BB9382 /* Base */,
261 | );
262 | name = Main.storyboard;
263 | sourceTree = "";
264 | };
265 | 67DA194F1C8DE6C500BB9382 /* LaunchScreen.storyboard */ = {
266 | isa = PBXVariantGroup;
267 | children = (
268 | 67DA19501C8DE6C500BB9382 /* Base */,
269 | );
270 | name = LaunchScreen.storyboard;
271 | sourceTree = "";
272 | };
273 | /* End PBXVariantGroup section */
274 |
275 | /* Begin XCBuildConfiguration section */
276 | 67DA19531C8DE6C500BB9382 /* Debug */ = {
277 | isa = XCBuildConfiguration;
278 | buildSettings = {
279 | ALWAYS_SEARCH_USER_PATHS = NO;
280 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
281 | CLANG_CXX_LIBRARY = "libc++";
282 | CLANG_ENABLE_MODULES = YES;
283 | CLANG_ENABLE_OBJC_ARC = YES;
284 | CLANG_WARN_BOOL_CONVERSION = YES;
285 | CLANG_WARN_CONSTANT_CONVERSION = YES;
286 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
287 | CLANG_WARN_EMPTY_BODY = YES;
288 | CLANG_WARN_ENUM_CONVERSION = YES;
289 | CLANG_WARN_INT_CONVERSION = YES;
290 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
291 | CLANG_WARN_UNREACHABLE_CODE = YES;
292 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
293 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
294 | COPY_PHASE_STRIP = NO;
295 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
296 | ENABLE_STRICT_OBJC_MSGSEND = YES;
297 | ENABLE_TESTABILITY = YES;
298 | GCC_C_LANGUAGE_STANDARD = gnu99;
299 | GCC_DYNAMIC_NO_PIC = NO;
300 | GCC_NO_COMMON_BLOCKS = YES;
301 | GCC_OPTIMIZATION_LEVEL = 0;
302 | GCC_PREPROCESSOR_DEFINITIONS = (
303 | "DEBUG=1",
304 | "$(inherited)",
305 | );
306 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
307 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
308 | GCC_WARN_UNDECLARED_SELECTOR = YES;
309 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
310 | GCC_WARN_UNUSED_FUNCTION = YES;
311 | GCC_WARN_UNUSED_VARIABLE = YES;
312 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
313 | MTL_ENABLE_DEBUG_INFO = YES;
314 | ONLY_ACTIVE_ARCH = YES;
315 | SDKROOT = iphoneos;
316 | TARGETED_DEVICE_FAMILY = "1,2";
317 | };
318 | name = Debug;
319 | };
320 | 67DA19541C8DE6C500BB9382 /* Release */ = {
321 | isa = XCBuildConfiguration;
322 | buildSettings = {
323 | ALWAYS_SEARCH_USER_PATHS = NO;
324 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
325 | CLANG_CXX_LIBRARY = "libc++";
326 | CLANG_ENABLE_MODULES = YES;
327 | CLANG_ENABLE_OBJC_ARC = YES;
328 | CLANG_WARN_BOOL_CONVERSION = YES;
329 | CLANG_WARN_CONSTANT_CONVERSION = YES;
330 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
331 | CLANG_WARN_EMPTY_BODY = YES;
332 | CLANG_WARN_ENUM_CONVERSION = YES;
333 | CLANG_WARN_INT_CONVERSION = YES;
334 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
335 | CLANG_WARN_UNREACHABLE_CODE = YES;
336 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
337 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
338 | COPY_PHASE_STRIP = NO;
339 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
340 | ENABLE_NS_ASSERTIONS = NO;
341 | ENABLE_STRICT_OBJC_MSGSEND = YES;
342 | GCC_C_LANGUAGE_STANDARD = gnu99;
343 | GCC_NO_COMMON_BLOCKS = YES;
344 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
345 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
346 | GCC_WARN_UNDECLARED_SELECTOR = YES;
347 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
348 | GCC_WARN_UNUSED_FUNCTION = YES;
349 | GCC_WARN_UNUSED_VARIABLE = YES;
350 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
351 | MTL_ENABLE_DEBUG_INFO = NO;
352 | SDKROOT = iphoneos;
353 | TARGETED_DEVICE_FAMILY = "1,2";
354 | VALIDATE_PRODUCT = YES;
355 | };
356 | name = Release;
357 | };
358 | 67DA19561C8DE6C500BB9382 /* Debug */ = {
359 | isa = XCBuildConfiguration;
360 | buildSettings = {
361 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
362 | INFOPLIST_FILE = "$(SRCROOT)/DemoSource/Info.plist";
363 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
364 | PRODUCT_BUNDLE_IDENTIFIER = SteveBarnegren.DynamicWater;
365 | PRODUCT_NAME = "$(TARGET_NAME)";
366 | };
367 | name = Debug;
368 | };
369 | 67DA19571C8DE6C500BB9382 /* Release */ = {
370 | isa = XCBuildConfiguration;
371 | buildSettings = {
372 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
373 | INFOPLIST_FILE = "$(SRCROOT)/DemoSource/Info.plist";
374 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
375 | PRODUCT_BUNDLE_IDENTIFIER = SteveBarnegren.DynamicWater;
376 | PRODUCT_NAME = "$(TARGET_NAME)";
377 | };
378 | name = Release;
379 | };
380 | /* End XCBuildConfiguration section */
381 |
382 | /* Begin XCConfigurationList section */
383 | 67DA19341C8DE6C400BB9382 /* Build configuration list for PBXProject "DynamicWater" */ = {
384 | isa = XCConfigurationList;
385 | buildConfigurations = (
386 | 67DA19531C8DE6C500BB9382 /* Debug */,
387 | 67DA19541C8DE6C500BB9382 /* Release */,
388 | );
389 | defaultConfigurationIsVisible = 0;
390 | defaultConfigurationName = Release;
391 | };
392 | 67DA19551C8DE6C500BB9382 /* Build configuration list for PBXNativeTarget "DynamicWater" */ = {
393 | isa = XCConfigurationList;
394 | buildConfigurations = (
395 | 67DA19561C8DE6C500BB9382 /* Debug */,
396 | 67DA19571C8DE6C500BB9382 /* Release */,
397 | );
398 | defaultConfigurationIsVisible = 0;
399 | defaultConfigurationName = Release;
400 | };
401 | /* End XCConfigurationList section */
402 | };
403 | rootObject = 67DA19311C8DE6C400BB9382 /* Project object */;
404 | }
405 |
--------------------------------------------------------------------------------