├── 过山车思维导图.png
├── 过山车思维导图.mindnode
├── contents.xml
├── viewState.plist
├── QuickLook
│ └── Preview.jpg
└── style.mindnodestyle
│ ├── contents.xml
│ └── metadata.plist
├── README.md
└── OC
└── RollerCoasterOC
├── RollerCoasterOC.xcodeproj
├── xcuserdata
│ └── stan.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── RollerCoasterOC.xcscheme
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── stan.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── project.pbxproj
└── RollerCoasterOC
├── Assets.xcassets
├── car.imageset
│ ├── 屏幕快照 2016-06-11 上午10.22.13.png
│ └── Contents.json
├── cloud.imageset
│ ├── 屏幕快照 2016-06-13 下午7.56.46.png
│ └── Contents.json
├── tree.imageset
│ ├── 屏幕快照 2016-06-13 下午8.34.37.png
│ └── Contents.json
├── green.imageset
│ ├── 屏幕快照 2016-06-09 下午3.49.00副本.png
│ └── Contents.json
├── yellow.imageset
│ ├── 屏幕快照 2016-06-09 下午3.49.00副本.png
│ └── Contents.json
├── otherCar.imageset
│ ├── 屏幕快照 2016-06-11 上午10.22.13.png
│ └── Contents.json
├── ground.imageset
│ ├── 1D6CBE84-9CFE-4F1C-91AB-5218C7FADC68.png
│ └── Contents.json
└── AppIcon.appiconset
│ └── Contents.json
├── ViewController.h
├── AppDelegate.h
├── main.m
├── Info.plist
├── Base.lproj
├── Main.storyboard
└── LaunchScreen.storyboard
├── AppDelegate.m
└── ViewController.m
/过山车思维导图.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/过山车思维导图.png
--------------------------------------------------------------------------------
/过山车思维导图.mindnode/contents.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/过山车思维导图.mindnode/contents.xml
--------------------------------------------------------------------------------
/过山车思维导图.mindnode/viewState.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/过山车思维导图.mindnode/viewState.plist
--------------------------------------------------------------------------------
/过山车思维导图.mindnode/QuickLook/Preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/过山车思维导图.mindnode/QuickLook/Preview.jpg
--------------------------------------------------------------------------------
/过山车思维导图.mindnode/style.mindnodestyle/contents.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/过山车思维导图.mindnode/style.mindnodestyle/contents.xml
--------------------------------------------------------------------------------
/过山车思维导图.mindnode/style.mindnodestyle/metadata.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/过山车思维导图.mindnode/style.mindnodestyle/metadata.plist
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #RollerCoaster
2 | 完成一个在轨道上面运行的过山车。所有的图片都是通过贝塞尔曲线绘制出来的。通过这个例子,全面复习了绝大部分的layer和动画。
3 | 关注作者简书:http://www.jianshu.com/u/5a2b13c9b33a 有全部的iOS动画系列文章
4 | 简书名:非典型技术宅
5 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC.xcodeproj/xcuserdata/stan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/car.imageset/屏幕快照 2016-06-11 上午10.22.13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/car.imageset/屏幕快照 2016-06-11 上午10.22.13.png
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/cloud.imageset/屏幕快照 2016-06-13 下午7.56.46.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/cloud.imageset/屏幕快照 2016-06-13 下午7.56.46.png
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/tree.imageset/屏幕快照 2016-06-13 下午8.34.37.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/tree.imageset/屏幕快照 2016-06-13 下午8.34.37.png
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/green.imageset/屏幕快照 2016-06-09 下午3.49.00副本.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/green.imageset/屏幕快照 2016-06-09 下午3.49.00副本.png
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/yellow.imageset/屏幕快照 2016-06-09 下午3.49.00副本.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/yellow.imageset/屏幕快照 2016-06-09 下午3.49.00副本.png
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/otherCar.imageset/屏幕快照 2016-06-11 上午10.22.13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/otherCar.imageset/屏幕快照 2016-06-11 上午10.22.13.png
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/ground.imageset/1D6CBE84-9CFE-4F1C-91AB-5218C7FADC68.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/ground.imageset/1D6CBE84-9CFE-4F1C-91AB-5218C7FADC68.png
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC.xcodeproj/project.xcworkspace/xcuserdata/stan.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Stanbai/rollercoaster/HEAD/OC/RollerCoasterOC/RollerCoasterOC.xcodeproj/project.xcworkspace/xcuserdata/stan.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // RollerCoasterOC
4 | //
5 | // Created by Stan on 2017-04-28.
6 | // Copyright © 2017 stan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // RollerCoasterOC
4 | //
5 | // Created by Stan on 2017-04-28.
6 | // Copyright © 2017 stan. 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 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // RollerCoasterOC
4 | //
5 | // Created by Stan on 2017-04-28.
6 | // Copyright © 2017 stan. 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 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/car.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "屏幕快照 2016-06-11 上午10.22.13.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/cloud.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "屏幕快照 2016-06-13 下午7.56.46.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/tree.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "屏幕快照 2016-06-13 下午8.34.37.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/green.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "屏幕快照 2016-06-09 下午3.49.00副本.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/otherCar.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "屏幕快照 2016-06-11 上午10.22.13.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/yellow.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "屏幕快照 2016-06-09 下午3.49.00副本.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/ground.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "1D6CBE84-9CFE-4F1C-91AB-5218C7FADC68.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC.xcodeproj/xcuserdata/stan.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | RollerCoasterOC.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | F63649011EB3442600F50A7C
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | }
43 | ],
44 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/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 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/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 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/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 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // RollerCoasterOC
4 | //
5 | // Created by Stan on 2017-04-28.
6 | // Copyright © 2017 stan. 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 |
24 | - (void)applicationWillResignActive:(UIApplication *)application {
25 | // 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.
26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
27 | }
28 |
29 |
30 | - (void)applicationDidEnterBackground:(UIApplication *)application {
31 | // 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.
32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33 | }
34 |
35 |
36 | - (void)applicationWillEnterForeground:(UIApplication *)application {
37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
38 | }
39 |
40 |
41 | - (void)applicationDidBecomeActive:(UIApplication *)application {
42 | // 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.
43 | }
44 |
45 |
46 | - (void)applicationWillTerminate:(UIApplication *)application {
47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
48 | }
49 |
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC.xcodeproj/xcuserdata/stan.xcuserdatad/xcschemes/RollerCoasterOC.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 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | F63649071EB3442600F50A7C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F63649061EB3442600F50A7C /* main.m */; };
11 | F636490A1EB3442600F50A7C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F63649091EB3442600F50A7C /* AppDelegate.m */; };
12 | F636490D1EB3442600F50A7C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F636490C1EB3442600F50A7C /* ViewController.m */; };
13 | F63649101EB3442600F50A7C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F636490E1EB3442600F50A7C /* Main.storyboard */; };
14 | F63649121EB3442600F50A7C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F63649111EB3442600F50A7C /* Assets.xcassets */; };
15 | F63649151EB3442600F50A7C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F63649131EB3442600F50A7C /* LaunchScreen.storyboard */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | F63649021EB3442600F50A7C /* RollerCoasterOC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RollerCoasterOC.app; sourceTree = BUILT_PRODUCTS_DIR; };
20 | F63649061EB3442600F50A7C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
21 | F63649081EB3442600F50A7C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
22 | F63649091EB3442600F50A7C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
23 | F636490B1EB3442600F50A7C /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
24 | F636490C1EB3442600F50A7C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
25 | F636490F1EB3442600F50A7C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
26 | F63649111EB3442600F50A7C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
27 | F63649141EB3442600F50A7C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
28 | F63649161EB3442600F50A7C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | F63648FF1EB3442600F50A7C /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | F63648F91EB3442600F50A7C = {
43 | isa = PBXGroup;
44 | children = (
45 | F63649041EB3442600F50A7C /* RollerCoasterOC */,
46 | F63649031EB3442600F50A7C /* Products */,
47 | );
48 | sourceTree = "";
49 | };
50 | F63649031EB3442600F50A7C /* Products */ = {
51 | isa = PBXGroup;
52 | children = (
53 | F63649021EB3442600F50A7C /* RollerCoasterOC.app */,
54 | );
55 | name = Products;
56 | sourceTree = "";
57 | };
58 | F63649041EB3442600F50A7C /* RollerCoasterOC */ = {
59 | isa = PBXGroup;
60 | children = (
61 | F63649081EB3442600F50A7C /* AppDelegate.h */,
62 | F63649091EB3442600F50A7C /* AppDelegate.m */,
63 | F636490B1EB3442600F50A7C /* ViewController.h */,
64 | F636490C1EB3442600F50A7C /* ViewController.m */,
65 | F636490E1EB3442600F50A7C /* Main.storyboard */,
66 | F63649111EB3442600F50A7C /* Assets.xcassets */,
67 | F63649131EB3442600F50A7C /* LaunchScreen.storyboard */,
68 | F63649161EB3442600F50A7C /* Info.plist */,
69 | F63649051EB3442600F50A7C /* Supporting Files */,
70 | );
71 | path = RollerCoasterOC;
72 | sourceTree = "";
73 | };
74 | F63649051EB3442600F50A7C /* Supporting Files */ = {
75 | isa = PBXGroup;
76 | children = (
77 | F63649061EB3442600F50A7C /* main.m */,
78 | );
79 | name = "Supporting Files";
80 | sourceTree = "";
81 | };
82 | /* End PBXGroup section */
83 |
84 | /* Begin PBXNativeTarget section */
85 | F63649011EB3442600F50A7C /* RollerCoasterOC */ = {
86 | isa = PBXNativeTarget;
87 | buildConfigurationList = F63649191EB3442600F50A7C /* Build configuration list for PBXNativeTarget "RollerCoasterOC" */;
88 | buildPhases = (
89 | F63648FE1EB3442600F50A7C /* Sources */,
90 | F63648FF1EB3442600F50A7C /* Frameworks */,
91 | F63649001EB3442600F50A7C /* Resources */,
92 | );
93 | buildRules = (
94 | );
95 | dependencies = (
96 | );
97 | name = RollerCoasterOC;
98 | productName = RollerCoasterOC;
99 | productReference = F63649021EB3442600F50A7C /* RollerCoasterOC.app */;
100 | productType = "com.apple.product-type.application";
101 | };
102 | /* End PBXNativeTarget section */
103 |
104 | /* Begin PBXProject section */
105 | F63648FA1EB3442600F50A7C /* Project object */ = {
106 | isa = PBXProject;
107 | attributes = {
108 | CLASSPREFIX = ST;
109 | LastUpgradeCheck = 0830;
110 | ORGANIZATIONNAME = stan;
111 | TargetAttributes = {
112 | F63649011EB3442600F50A7C = {
113 | CreatedOnToolsVersion = 8.3.1;
114 | ProvisioningStyle = Automatic;
115 | };
116 | };
117 | };
118 | buildConfigurationList = F63648FD1EB3442600F50A7C /* Build configuration list for PBXProject "RollerCoasterOC" */;
119 | compatibilityVersion = "Xcode 3.2";
120 | developmentRegion = English;
121 | hasScannedForEncodings = 0;
122 | knownRegions = (
123 | en,
124 | Base,
125 | );
126 | mainGroup = F63648F91EB3442600F50A7C;
127 | productRefGroup = F63649031EB3442600F50A7C /* Products */;
128 | projectDirPath = "";
129 | projectRoot = "";
130 | targets = (
131 | F63649011EB3442600F50A7C /* RollerCoasterOC */,
132 | );
133 | };
134 | /* End PBXProject section */
135 |
136 | /* Begin PBXResourcesBuildPhase section */
137 | F63649001EB3442600F50A7C /* Resources */ = {
138 | isa = PBXResourcesBuildPhase;
139 | buildActionMask = 2147483647;
140 | files = (
141 | F63649151EB3442600F50A7C /* LaunchScreen.storyboard in Resources */,
142 | F63649121EB3442600F50A7C /* Assets.xcassets in Resources */,
143 | F63649101EB3442600F50A7C /* Main.storyboard in Resources */,
144 | );
145 | runOnlyForDeploymentPostprocessing = 0;
146 | };
147 | /* End PBXResourcesBuildPhase section */
148 |
149 | /* Begin PBXSourcesBuildPhase section */
150 | F63648FE1EB3442600F50A7C /* Sources */ = {
151 | isa = PBXSourcesBuildPhase;
152 | buildActionMask = 2147483647;
153 | files = (
154 | F636490D1EB3442600F50A7C /* ViewController.m in Sources */,
155 | F636490A1EB3442600F50A7C /* AppDelegate.m in Sources */,
156 | F63649071EB3442600F50A7C /* main.m in Sources */,
157 | );
158 | runOnlyForDeploymentPostprocessing = 0;
159 | };
160 | /* End PBXSourcesBuildPhase section */
161 |
162 | /* Begin PBXVariantGroup section */
163 | F636490E1EB3442600F50A7C /* Main.storyboard */ = {
164 | isa = PBXVariantGroup;
165 | children = (
166 | F636490F1EB3442600F50A7C /* Base */,
167 | );
168 | name = Main.storyboard;
169 | sourceTree = "";
170 | };
171 | F63649131EB3442600F50A7C /* LaunchScreen.storyboard */ = {
172 | isa = PBXVariantGroup;
173 | children = (
174 | F63649141EB3442600F50A7C /* Base */,
175 | );
176 | name = LaunchScreen.storyboard;
177 | sourceTree = "";
178 | };
179 | /* End PBXVariantGroup section */
180 |
181 | /* Begin XCBuildConfiguration section */
182 | F63649171EB3442600F50A7C /* Debug */ = {
183 | isa = XCBuildConfiguration;
184 | buildSettings = {
185 | ALWAYS_SEARCH_USER_PATHS = NO;
186 | CLANG_ANALYZER_NONNULL = YES;
187 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
188 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
189 | CLANG_CXX_LIBRARY = "libc++";
190 | CLANG_ENABLE_MODULES = YES;
191 | CLANG_ENABLE_OBJC_ARC = YES;
192 | CLANG_WARN_BOOL_CONVERSION = YES;
193 | CLANG_WARN_CONSTANT_CONVERSION = YES;
194 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
195 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
196 | CLANG_WARN_EMPTY_BODY = YES;
197 | CLANG_WARN_ENUM_CONVERSION = YES;
198 | CLANG_WARN_INFINITE_RECURSION = YES;
199 | CLANG_WARN_INT_CONVERSION = YES;
200 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
201 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
202 | CLANG_WARN_UNREACHABLE_CODE = YES;
203 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
204 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
205 | COPY_PHASE_STRIP = NO;
206 | DEBUG_INFORMATION_FORMAT = dwarf;
207 | ENABLE_STRICT_OBJC_MSGSEND = YES;
208 | ENABLE_TESTABILITY = YES;
209 | GCC_C_LANGUAGE_STANDARD = gnu99;
210 | GCC_DYNAMIC_NO_PIC = NO;
211 | GCC_NO_COMMON_BLOCKS = YES;
212 | GCC_OPTIMIZATION_LEVEL = 0;
213 | GCC_PREPROCESSOR_DEFINITIONS = (
214 | "DEBUG=1",
215 | "$(inherited)",
216 | );
217 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
218 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
219 | GCC_WARN_UNDECLARED_SELECTOR = YES;
220 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
221 | GCC_WARN_UNUSED_FUNCTION = YES;
222 | GCC_WARN_UNUSED_VARIABLE = YES;
223 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
224 | MTL_ENABLE_DEBUG_INFO = YES;
225 | ONLY_ACTIVE_ARCH = YES;
226 | SDKROOT = iphoneos;
227 | };
228 | name = Debug;
229 | };
230 | F63649181EB3442600F50A7C /* Release */ = {
231 | isa = XCBuildConfiguration;
232 | buildSettings = {
233 | ALWAYS_SEARCH_USER_PATHS = NO;
234 | CLANG_ANALYZER_NONNULL = YES;
235 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
236 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
237 | CLANG_CXX_LIBRARY = "libc++";
238 | CLANG_ENABLE_MODULES = YES;
239 | CLANG_ENABLE_OBJC_ARC = YES;
240 | CLANG_WARN_BOOL_CONVERSION = YES;
241 | CLANG_WARN_CONSTANT_CONVERSION = YES;
242 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
243 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
244 | CLANG_WARN_EMPTY_BODY = YES;
245 | CLANG_WARN_ENUM_CONVERSION = YES;
246 | CLANG_WARN_INFINITE_RECURSION = YES;
247 | CLANG_WARN_INT_CONVERSION = YES;
248 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
249 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
250 | CLANG_WARN_UNREACHABLE_CODE = YES;
251 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
252 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
253 | COPY_PHASE_STRIP = NO;
254 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
255 | ENABLE_NS_ASSERTIONS = NO;
256 | ENABLE_STRICT_OBJC_MSGSEND = YES;
257 | GCC_C_LANGUAGE_STANDARD = gnu99;
258 | GCC_NO_COMMON_BLOCKS = YES;
259 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
260 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
261 | GCC_WARN_UNDECLARED_SELECTOR = YES;
262 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
263 | GCC_WARN_UNUSED_FUNCTION = YES;
264 | GCC_WARN_UNUSED_VARIABLE = YES;
265 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
266 | MTL_ENABLE_DEBUG_INFO = NO;
267 | SDKROOT = iphoneos;
268 | VALIDATE_PRODUCT = YES;
269 | };
270 | name = Release;
271 | };
272 | F636491A1EB3442600F50A7C /* Debug */ = {
273 | isa = XCBuildConfiguration;
274 | buildSettings = {
275 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
276 | INFOPLIST_FILE = RollerCoasterOC/Info.plist;
277 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
278 | PRODUCT_BUNDLE_IDENTIFIER = com.byeonline.RollerCoasterOC;
279 | PRODUCT_NAME = "$(TARGET_NAME)";
280 | };
281 | name = Debug;
282 | };
283 | F636491B1EB3442600F50A7C /* Release */ = {
284 | isa = XCBuildConfiguration;
285 | buildSettings = {
286 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
287 | INFOPLIST_FILE = RollerCoasterOC/Info.plist;
288 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
289 | PRODUCT_BUNDLE_IDENTIFIER = com.byeonline.RollerCoasterOC;
290 | PRODUCT_NAME = "$(TARGET_NAME)";
291 | };
292 | name = Release;
293 | };
294 | /* End XCBuildConfiguration section */
295 |
296 | /* Begin XCConfigurationList section */
297 | F63648FD1EB3442600F50A7C /* Build configuration list for PBXProject "RollerCoasterOC" */ = {
298 | isa = XCConfigurationList;
299 | buildConfigurations = (
300 | F63649171EB3442600F50A7C /* Debug */,
301 | F63649181EB3442600F50A7C /* Release */,
302 | );
303 | defaultConfigurationIsVisible = 0;
304 | defaultConfigurationName = Release;
305 | };
306 | F63649191EB3442600F50A7C /* Build configuration list for PBXNativeTarget "RollerCoasterOC" */ = {
307 | isa = XCConfigurationList;
308 | buildConfigurations = (
309 | F636491A1EB3442600F50A7C /* Debug */,
310 | F636491B1EB3442600F50A7C /* Release */,
311 | );
312 | defaultConfigurationIsVisible = 0;
313 | };
314 | /* End XCConfigurationList section */
315 | };
316 | rootObject = F63648FA1EB3442600F50A7C /* Project object */;
317 | }
318 |
--------------------------------------------------------------------------------
/OC/RollerCoasterOC/RollerCoasterOC/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // RollerCoasterOC
4 | //
5 | // Created by Stan on 2017-04-28.
6 | // Copyright © 2017 stan. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 |
11 | #define k_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
12 | #define k_LAND_BEGIN_HEIGHT k_SCREEN_HEIGHT - 20
13 | #define k_SIZE self.view.frame.size
14 |
15 | @interface ViewController ()
16 | @property(strong,nonatomic)CALayer *landLayer;
17 | @property(strong,nonatomic)CAShapeLayer *greenTrack;
18 | @property(strong,nonatomic)CAShapeLayer *yellowTrack;
19 | @end
20 |
21 | @implementation ViewController
22 |
23 | - (void)viewDidLoad {
24 | [super viewDidLoad];
25 |
26 | self.view.backgroundColor = [UIColor lightGrayColor];
27 |
28 | // 初始化背景渐变的天空
29 | [self initBackgroundSky];
30 | // 初始化雪山
31 | [self initSnowberg];
32 | // 加载草坪
33 | [self initLawn];
34 | // 加载大地
35 | [self initLand];
36 | // 加载黄色轨道
37 | [self initYellowTrack];
38 | // 加载绿色轨道
39 | [self initGreenTrack];
40 | // 点缀小树
41 | [self initTree];
42 | // 启动云彩
43 | [self initCloudAnimation];
44 | // 添加黄色轨道小车动画
45 | [self carAnimationWith:@"car" TrackLayer:_yellowTrack AnimationDuration:8.0 BeginTime:CACurrentMediaTime() + 1];
46 | // 添加绿色轨道小车动画
47 | [self carAnimationWith:@"otherCar" TrackLayer:_greenTrack AnimationDuration:5.0 BeginTime:CACurrentMediaTime()];}
48 |
49 | //初始化背景天空渐变色
50 | - (void)initBackgroundSky{
51 | CAGradientLayer *backgroundLayer = [[CAGradientLayer alloc] init];
52 | // 设置背景渐变色层的大小。要减去屏幕最下方土地那条水平线的高度
53 | backgroundLayer.frame = CGRectMake(0, 0, k_SIZE.width, k_LAND_BEGIN_HEIGHT);
54 |
55 | UIColor *lightColor = [UIColor colorWithRed:40.0 / 255.0 green:150.0 / 255.0 blue:200.0 / 255.0 alpha:1.0];
56 | UIColor *darkColor = [UIColor colorWithRed:255.0 / 255.0 green:250.0 / 255.0 blue:250.0 / 255.0 alpha:1.0];
57 | backgroundLayer.colors = @[(__bridge id)lightColor.CGColor,(__bridge id)darkColor.CGColor];
58 |
59 | // 让变色层成45度角变色
60 | backgroundLayer.startPoint = CGPointMake(0, 0);
61 | backgroundLayer.endPoint = CGPointMake(1, 1);
62 |
63 | [self.view.layer addSublayer:backgroundLayer];
64 | }
65 |
66 | //初始化雪山,有两个雪山
67 | - (void)initSnowberg{
68 |
69 | // 左边第一座山顶,其实就是一个白色的三角形
70 | CAShapeLayer *leftSnowberg = [[CAShapeLayer alloc] init];
71 | UIBezierPath *leftSnowbergPath = [[UIBezierPath alloc] init];
72 |
73 | // 把bezierpath的起点移动到雪山左下角
74 | [leftSnowbergPath moveToPoint:CGPointMake(0, k_SIZE.height - 120)];
75 |
76 | // 画一条线到山顶
77 | [leftSnowbergPath addLineToPoint:CGPointMake(100, 100)];
78 |
79 | // 画一条线到右下角->左下角->闭合
80 | [leftSnowbergPath addLineToPoint:CGPointMake(k_SIZE.width / 2, k_LAND_BEGIN_HEIGHT)];
81 | [leftSnowbergPath addLineToPoint:CGPointMake(0, k_LAND_BEGIN_HEIGHT)];
82 | [leftSnowbergPath closePath];
83 |
84 | leftSnowberg.path = leftSnowbergPath.CGPath;
85 | leftSnowberg.fillColor = [UIColor whiteColor].CGColor;
86 | [self.view.layer addSublayer:leftSnowberg];
87 |
88 |
89 | // 开始画山体没有被雪覆盖的部分
90 | CAShapeLayer *leftSnowbergBody = [[CAShapeLayer alloc] init];
91 | UIBezierPath *leftSnowbergBodyPath = [[UIBezierPath alloc] init];
92 |
93 | // 把bezierpath的起点移动到雪山左下角相同的位置
94 | CGPoint startPoint = CGPointMake(0, k_SIZE.height - 120);
95 | CGPoint endPoint = CGPointMake(100, 100);
96 | CGPoint firstPathPoint = [self calculateWithXValue:20 startPoint:startPoint endpoint:endPoint];
97 | [leftSnowbergBodyPath moveToPoint:startPoint];
98 |
99 | [leftSnowbergBodyPath addLineToPoint:firstPathPoint];
100 | [leftSnowbergBodyPath addLineToPoint:CGPointMake(60, firstPathPoint.y)];
101 | [leftSnowbergBodyPath addLineToPoint:CGPointMake(100, firstPathPoint.y + 30)];
102 | [leftSnowbergBodyPath addLineToPoint:CGPointMake(140, firstPathPoint.y)];
103 | [leftSnowbergBodyPath addLineToPoint:CGPointMake(180, firstPathPoint.y - 20)];
104 |
105 | CGPoint secondPathPoint = [self calculateWithXValue:(k_SIZE.width / 2 - 125) startPoint:endPoint endpoint:CGPointMake(k_SIZE.width / 2, k_LAND_BEGIN_HEIGHT)];
106 | [leftSnowbergBodyPath addLineToPoint:CGPointMake(secondPathPoint.x - 30, firstPathPoint.y)];
107 |
108 | [leftSnowbergBodyPath addLineToPoint:secondPathPoint];
109 |
110 | [leftSnowbergBodyPath addLineToPoint:CGPointMake(k_SIZE.width / 2, k_LAND_BEGIN_HEIGHT)];
111 | [leftSnowbergBodyPath addLineToPoint:CGPointMake(0, k_LAND_BEGIN_HEIGHT)];
112 | [leftSnowbergBodyPath closePath];
113 |
114 | leftSnowbergBody.path = leftSnowbergBodyPath.CGPath;
115 | UIColor *snowColor = [UIColor colorWithDisplayP3Red:139.0 /255.0 green:92.0 /255.0 blue:0.0 /255.0 alpha:1.0];
116 | leftSnowbergBody.fillColor = snowColor.CGColor;
117 | [self.view.layer addSublayer:leftSnowbergBody];
118 |
119 |
120 | // 中间的山
121 | CAShapeLayer *middleSnowberg = [[CAShapeLayer alloc] init];
122 | UIBezierPath *middleSnowbergPath = [[UIBezierPath alloc] init];
123 |
124 | // 把bezierpath的起点移动到雪山左下角。然后画一条线到山顶,再画一条线到右下角,闭合。
125 | CGPoint middleStartPoint = CGPointMake(k_SIZE.width / 3, k_LAND_BEGIN_HEIGHT);
126 | CGPoint middleTopPoint = CGPointMake(k_SIZE.width /2, 200);
127 | CGPoint middleEndPoint = CGPointMake(k_SIZE.width / 1.2, k_LAND_BEGIN_HEIGHT);
128 |
129 | [middleSnowbergPath moveToPoint:middleStartPoint];
130 | [middleSnowbergPath addLineToPoint:middleTopPoint];
131 | [middleSnowbergPath addLineToPoint:middleEndPoint];
132 |
133 | [middleSnowbergPath closePath];
134 |
135 | middleSnowberg.path = middleSnowbergPath.CGPath;
136 | middleSnowberg.fillColor = [UIColor whiteColor].CGColor;
137 | [self.view.layer insertSublayer:middleSnowberg above:leftSnowbergBody];
138 |
139 | // 开始画山体没有被雪覆盖的部分
140 | CAShapeLayer *middleSnowbergBody = [[CAShapeLayer alloc] init];
141 | UIBezierPath *middleSnowbergBodyPath = [[UIBezierPath alloc] init];
142 |
143 | // 把bezierpath的起点移动到雪山左下角相同的位置
144 | [middleSnowbergBodyPath moveToPoint:middleStartPoint];
145 |
146 |
147 | CGPoint middleFirstPathPoint = [self calculateWithXValue:(middleStartPoint.x + 70) startPoint:middleStartPoint endpoint:middleTopPoint];
148 |
149 | [middleSnowbergBodyPath addLineToPoint:middleFirstPathPoint];
150 | [middleSnowbergBodyPath addLineToPoint:CGPointMake(middleFirstPathPoint.x + 20, middleFirstPathPoint.y)];
151 | [middleSnowbergBodyPath addLineToPoint:CGPointMake(middleFirstPathPoint.x + 50, middleFirstPathPoint.y + 30)];
152 | [middleSnowbergBodyPath addLineToPoint:CGPointMake(middleFirstPathPoint.x + 80, middleFirstPathPoint.y - 10)];
153 | [middleSnowbergBodyPath addLineToPoint:CGPointMake(middleFirstPathPoint.x + 120, middleFirstPathPoint.y + 20)];
154 |
155 | CGPoint middleSecondPathPoint = [self calculateWithXValue:(middleEndPoint.x - 120) startPoint:middleTopPoint endpoint:middleEndPoint];
156 |
157 | [middleSnowbergBodyPath addLineToPoint:CGPointMake(middleSecondPathPoint.x - 30, middleSecondPathPoint.y)];
158 | [middleSnowbergBodyPath addLineToPoint:middleSecondPathPoint];
159 |
160 | [middleSnowbergBodyPath addLineToPoint:middleEndPoint];
161 |
162 | [middleSnowbergBodyPath closePath];
163 |
164 | middleSnowbergBody.path = middleSnowbergBodyPath.CGPath;
165 | UIColor *middleSnowColor = [UIColor colorWithDisplayP3Red:125.0 /255.0 green:87.0 /255.0 blue:7.0 /255.0 alpha:1.0];
166 | middleSnowbergBody.fillColor = middleSnowColor.CGColor;
167 | [self.view.layer insertSublayer:middleSnowbergBody above:middleSnowberg];
168 |
169 | }
170 |
171 | //初始化草坪
172 | - (void)initLawn{
173 | CAShapeLayer *leftLawn = [[CAShapeLayer alloc] init];
174 | UIBezierPath *leftLawnPath = [[UIBezierPath alloc] init];
175 |
176 | CGPoint leftStartPoint = CGPointMake(0, k_LAND_BEGIN_HEIGHT);
177 |
178 | [leftLawnPath moveToPoint:leftStartPoint];
179 | [leftLawnPath addLineToPoint:CGPointMake(0, k_SIZE.height - 100)];
180 |
181 | // 画一个二次贝塞尔曲线
182 | [leftLawnPath addQuadCurveToPoint:CGPointMake(k_SIZE.width / 3.0, k_LAND_BEGIN_HEIGHT) controlPoint:CGPointMake(k_SIZE.width / 5.0, k_SIZE.height - 100)];
183 |
184 | leftLawn.path = leftLawnPath.CGPath;
185 | leftLawn.fillColor = [UIColor colorWithDisplayP3Red:82.0 / 255.0 green:177.0 / 255.0 blue:52.0 / 255.0 alpha:1.0].CGColor;
186 | [self.view.layer addSublayer:leftLawn];
187 |
188 | CAShapeLayer *rightLawn = [[CAShapeLayer alloc] init];
189 | UIBezierPath *rightLawnPath = [[UIBezierPath alloc] init];
190 |
191 | [rightLawnPath moveToPoint:leftStartPoint];
192 | // 画一个二次贝塞尔曲线
193 | [rightLawnPath addQuadCurveToPoint:CGPointMake(k_SIZE.width, k_SIZE.height - 80) controlPoint:CGPointMake(k_SIZE.width / 2.0, k_SIZE.height - 100)];
194 | [rightLawnPath addLineToPoint:CGPointMake(k_SIZE.width, k_LAND_BEGIN_HEIGHT)];
195 |
196 | rightLawn.path = rightLawnPath.CGPath;
197 | rightLawn.fillColor = [UIColor colorWithDisplayP3Red:92.0/255.0 green:195.0/255.0 blue:52.0/255.0 alpha:1.0].CGColor;
198 | [self.view.layer insertSublayer:rightLawn above:leftLawn];
199 | }
200 |
201 |
202 | //初始化土地
203 | - (void)initLand{
204 | _landLayer = [[CALayer alloc] init];
205 | _landLayer.frame = CGRectMake(0, k_LAND_BEGIN_HEIGHT, k_SIZE.width, 20);
206 | _landLayer.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ground"]].CGColor;
207 | [self.view.layer addSublayer:_landLayer];
208 | }
209 |
210 | //初始化黄色轨道
211 | - (void)initYellowTrack{
212 | _yellowTrack = [[CAShapeLayer alloc] init];
213 | _yellowTrack.lineWidth = 5;
214 | _yellowTrack.strokeColor = [UIColor colorWithDisplayP3Red:210.0 / 255.0 green:179.0 / 255.0 blue:54.0 / 255.0 alpha:1.0].CGColor;
215 |
216 | UIBezierPath *trackPath = [[UIBezierPath alloc] init];
217 | // 画一个三次贝塞尔曲线+一个二次贝塞尔曲线
218 | // 左侧两个拐弯的三次贝塞尔曲线
219 | [trackPath moveToPoint:CGPointMake(0, k_SIZE.height - 60)];
220 | [trackPath addCurveToPoint:CGPointMake(k_SIZE.width / 1.5, k_SIZE.height / 2.0 - 20) controlPoint1:CGPointMake(k_SIZE.width / 6.0, k_SIZE.height - 200) controlPoint2:CGPointMake(k_SIZE.width / 3.0, k_SIZE.height + 50)];
221 | // 右侧一个弯度的二次贝塞尔曲线
222 | [trackPath addQuadCurveToPoint:CGPointMake(k_SIZE.width + 50, k_SIZE.height / 3.0) controlPoint:CGPointMake(k_SIZE.width - 100, 50)];
223 |
224 | [trackPath addLineToPoint:CGPointMake(k_SIZE.width + 10, k_SIZE.height + 10)];
225 | [trackPath addLineToPoint:CGPointMake(0, k_SIZE.height + 10)];
226 |
227 | _yellowTrack.fillColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"yellow"]].CGColor;
228 | _yellowTrack.path = trackPath.CGPath;
229 | [self.view.layer insertSublayer:_yellowTrack below:_landLayer];
230 |
231 | // 为了能够让弧线更好看一点,需要加入镂空的虚线
232 | CAShapeLayer *trackLine = [[CAShapeLayer alloc] init];
233 | trackLine.lineCap = kCALineCapRound;
234 | trackLine.strokeColor = [UIColor whiteColor].CGColor;
235 |
236 | trackLine.lineDashPattern = @[@1.0,@6.0];
237 | trackLine.lineWidth = 2.5;
238 | trackLine.fillColor = [UIColor clearColor].CGColor;
239 | trackLine.path = trackPath.CGPath;
240 | [_yellowTrack addSublayer:trackLine];
241 |
242 | }
243 |
244 | //初始化绿色轨道
245 | - (void)initGreenTrack{
246 | _greenTrack = [[CAShapeLayer alloc] init];
247 | _greenTrack.lineWidth = 5;
248 | _greenTrack.strokeColor = [UIColor colorWithDisplayP3Red:0.0 / 255.0 green:147.0 / 255.0 blue:163.0 /255.0 alpha:1.0].CGColor;
249 | // 绿色铁轨的火车从右侧进入,所以从右侧开始绘画。需要画三条曲线,右边一条+中间的圆圈+左边一条
250 | UIBezierPath *path = [[UIBezierPath alloc] init];
251 | [path moveToPoint:CGPointMake(k_SIZE.width + 10, k_LAND_BEGIN_HEIGHT)];
252 | [path addLineToPoint:CGPointMake(k_SIZE.width + 10, k_SIZE.height - 70)];
253 | [path addQuadCurveToPoint:CGPointMake(k_SIZE.width / 1.5, k_SIZE.height - 70) controlPoint:CGPointMake(k_SIZE.width - 150, 200)];
254 |
255 | // 画圆圈
256 | [path addArcWithCenter:CGPointMake(k_SIZE.width / 1.6, k_SIZE.height - 140) radius:70 startAngle:M_PI_2 endAngle:2.5 * M_PI clockwise:YES];
257 |
258 | [path addCurveToPoint:CGPointMake(0, k_SIZE.height - 100) controlPoint1:CGPointMake(k_SIZE.width / 1.8 - 60, k_SIZE.height - 60) controlPoint2:CGPointMake(150, k_SIZE.height / 2.3)];
259 |
260 | [path addLineToPoint:CGPointMake(- 10, k_LAND_BEGIN_HEIGHT)];
261 | _greenTrack.path = path.CGPath;
262 | _greenTrack.fillColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"green"]].CGColor;
263 | [self.view.layer addSublayer:_greenTrack];
264 |
265 | // 为了能够让弧线更好看一点,需要加入镂空的虚线
266 | CAShapeLayer *trackLine = [[CAShapeLayer alloc] init];
267 | trackLine.lineCap = kCALineCapRound;
268 | trackLine.strokeColor = [UIColor whiteColor].CGColor;
269 |
270 | trackLine.lineDashPattern = @[@1.0,@6.0];
271 | trackLine.lineWidth = 2.5;
272 | trackLine.fillColor = [UIColor clearColor].CGColor;
273 | trackLine.path = path.CGPath;
274 | [_greenTrack addSublayer:trackLine];
275 | }
276 |
277 | //添加点缀的小树
278 | - (void)initTree{
279 |
280 | [self addTreesWithNumber:7 treeFrame:CGRectMake(0, k_LAND_BEGIN_HEIGHT - 20, 13, 23)];
281 | [self addTreesWithNumber:7 treeFrame:CGRectMake(0, k_LAND_BEGIN_HEIGHT - 64, 18, 32)];
282 | [self addTreesWithNumber:5 treeFrame:CGRectMake(0, k_LAND_BEGIN_HEIGHT - 90, 13, 23)];
283 | }
284 |
285 | ////添加小树
286 | - (void)addTreesWithNumber:(NSInteger)treesNumber treeFrame:(CGRect)frame{
287 | UIImage *tree = [UIImage imageNamed:@"tree"];
288 | for (NSInteger i = 0; i < treesNumber + 1; i++) {
289 | CALayer *treeLayer = [[CALayer alloc] init];
290 | treeLayer.contents = (__bridge id _Nullable)(tree.CGImage);
291 | treeLayer.frame = CGRectMake(k_SIZE.width - 50 * i * (arc4random_uniform(4) + 1), frame.origin.y, frame.size.width, frame.size.height);
292 | [self.view.layer insertSublayer:treeLayer above:_greenTrack];
293 | }
294 | }
295 | //云彩的动画
296 | - (void)initCloudAnimation{
297 | CALayer *cloud = [[CALayer alloc]init];
298 | cloud.contents = (__bridge id _Nullable)([UIImage imageNamed:@"cloud"].CGImage);
299 | cloud.frame = CGRectMake(0, 0, 63, 20);
300 | [self.view.layer addSublayer:cloud];
301 |
302 | UIBezierPath *cloudPath = [[UIBezierPath alloc] init];
303 | [cloudPath moveToPoint:CGPointMake(k_SIZE.width + 63, 50)];
304 | [cloudPath addLineToPoint:CGPointMake(-63, 50)];
305 |
306 | CAKeyframeAnimation *ani = [CAKeyframeAnimation animationWithKeyPath:@"position"];
307 | ani.path = cloudPath.CGPath;
308 | ani.duration = 30;
309 | ani.autoreverses = NO;
310 | ani.repeatCount = CGFLOAT_MAX;
311 | ani.calculationMode = kCAAnimationPaced;
312 |
313 | [cloud addAnimation:ani forKey:@"position"];
314 | }
315 |
316 |
317 |
318 | //抽取过山车的动画
319 | - (CAKeyframeAnimation *)carAnimationWith:(NSString *)carImageName TrackLayer:(CAShapeLayer *)track AnimationDuration:(CFTimeInterval)duration BeginTime:(CFTimeInterval)beginTime{
320 | CALayer *car = [[CALayer alloc] init];
321 | car.frame = CGRectMake(0, 0, 22, 15);
322 | car.contents = (__bridge id _Nullable)([UIImage imageNamed:carImageName].CGImage);
323 |
324 | CAKeyframeAnimation *ani = [CAKeyframeAnimation animationWithKeyPath:@"position"];
325 | ani.path = track.path;
326 |
327 | ani.duration = duration;
328 | ani.beginTime = beginTime;
329 | ani.autoreverses = NO;
330 | ani.repeatCount = CGFLOAT_MAX;
331 | ani.calculationMode = kCAAnimationPaced;
332 | ani.rotationMode = kCAAnimationRotateAuto;
333 |
334 | [track addSublayer:car];
335 | [car addAnimation:ani forKey:@"carAni"];
336 |
337 | return ani;
338 | }
339 |
340 | //根据起始点,算出指定的x在这条线段上对应的y。返回这个point。知道两点,根据两点坐标,求出两点连线的斜率。y=kx+b求出点坐标。
341 | - (CGPoint)calculateWithXValue:(CGFloat)xvalue startPoint:(CGPoint)startPoint endpoint:(CGPoint)endpoint{
342 | // 求出两点连线的斜率
343 | CGFloat k = (endpoint.y - startPoint.y) / (endpoint.x - startPoint.x);
344 | CGFloat b = startPoint.y - startPoint.x * k;
345 | CGFloat yvalue = k * xvalue + b;
346 | return CGPointMake(xvalue, yvalue);
347 | }
348 |
349 | @end
350 |
--------------------------------------------------------------------------------