
рд╕рднреА рдХреЛ рдирдорд╕реНрдХрд╛рд░! рдкрд╛рдареНрдпрдХреНрд░рдо рдХреЗ рд╢реБрднрд╛рд░рдВрдн рдХреА рдкреНрд░рддреНрдпрд╛рд╢рд╛ рдореЗрдВ
"рдЖрдИрдУрдПрд╕-рдбреЗрд╡рд▓рдкрд░ред рдмреБрдирд┐рдпрд╛рджреА рдкрд╛рдареНрдпрдХреНрд░рдо тАЭ рд╣рдордиреЗ рдПрдХ рдФрд░
рдЦреБрд▓рд╛ рд╕рдмрдХ рдЖрдпреЛрдЬрд┐рдд рдХрд┐рдпрд╛ред рдпрд╣ рд╡реЗрдмрд┐рдирд╛рд░ рдРрд╕реЗ рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЬрд┐рдиреНрд╣реЗрдВ рдХрд┐рд╕реА рднреА рднрд╛рд╖рд╛ рдФрд░ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдореЗрдВ рд╡рд┐рдХрд╕рд┐рдд рд╣реЛрдиреЗ рдХрд╛ рдЕрдиреБрднрд╡ рд╣реИ, рд▓реЗрдХрд┐рди рд╕реНрд╡рд┐рдлреНрдЯ рднрд╛рд╖рд╛ рд╕реАрдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдФрд░ iOS рдХреЗ рд▓рд┐рдП рд╡рд┐рдХрд╛рд╕ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдкрд╛рда рдореЗрдВ, рд╣рдордиреЗ
рд╕реНрд╡рд┐рдлреНрдЯ рднрд╛рд╖рд╛ рдХреЗ
рд╡рд╛рдХреНрдп рд░рдЪрдирд╛ рдФрд░ рдкреНрд░рдореБрдЦ рдирд┐рд░реНрдорд╛рдгреЛрдВ рдХреА рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рдЬрд╛рдВрдЪ рдХреА, рдореБрдЦреНрдп рд╡рд┐рдХрд╛рд╕ рд╕рд╛рдзрдиреЛрдВ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реБрдПред
рд╡реЗрдмрд┐рдирд╛рд░ рдкреНрд░рддрд┐рднрд╛рдЧрд┐рдпреЛрдВ рдиреЗ рд╕реАрдЦрд╛:
- рд╕реНрд╡рд┐рдлреНрдЯ рднрд╛рд╖рд╛ рдХреНрдпрд╛ рд╣реИ, рдЗрд╕рдХреА рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ рдХреНрдпрд╛ рд╣реИрдВ;
- Xcode рд╡рд┐рдХрд╛рд╕ рдХрд╛ рд╡рд╛рддрд╛рд╡рд░рдг рдЖрдкрдХреЛ рдЖрд░рдВрдн рдХрд░рдиреЗ рдореЗрдВ рдХреИрд╕реЗ рдорджрдж рдХрд░рддрд╛ рд╣реИ
- iOS рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд░рд▓ рдЧреЗрдо рдХреИрд╕реЗ рдмрдирд╛рдПрдВред
рд╡реЗрдмрд┐рдирд╛рд░ рдХрд╛ рд╕рдВрдЪрд╛рд▓рди
рдПрд▓реЗрдХреНрд╕реА рд╕реЛрдмреЛрд▓реЗрд╡рд╕реНрдХреА рдиреЗ рдХрд┐рдпрд╛, рдЬреЛ
рдпреИрдВрдбреЗрдХреНрд╕ рдХреЗ рдПрдХ рдЖрдИрдУрдПрд╕ рдбреЗрд╡рд▓рдкрд░ рдереЗред
рдЗрд╕реЗ рд╕реНрд╡рдпрдВ рдХрд░реЗрдВ рд╕рд╛рдВрдк
рдХрд╛рдо рдХреЗ рд▓рд┐рдП, рд╣рдордиреЗ рдПрдХреАрдХреГрдд рд╡рд┐рдХрд╛рд╕
рдкрд░реНрдпрд╛рд╡рд░рдг Xcode рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рдпрд╣ Apple рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдПрдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ, рдореБрдХреНрдд рдФрд░ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рд╡рд╛рддрд╛рд╡рд░рдг рд╣реИред
рдмрд╣реБрдд рд╢реБрд░реБрдЖрдд рдореЗрдВ, рд╣рдордиреЗ рдПрдХ рдирдИ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдмрдирд╛рдИ рдФрд░ "рдЧреЗрдо" рдлрд╛рдЗрд▓реЛрдВ рдХреЗ рдореВрд▓ рд╕реЗрдЯ рдХрд╛ рдЪрдпрди рдХрд┐рдпрд╛:

рдЖрдЧреЗ рдХреА рд╣рд▓рдЪрд▓ рдХреЗ рдмрд┐рдирд╛, рдЙрдиреНрд╣реЛрдВрдиреЗ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЛ "рд╕реНрдиреЗрдХ" рдХрд╣рд╛ред рд╕рднреА рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдЫреЛрдбрд╝ рджреА рдЧрдИрдВ, рдЬрд┐рд╕рд╕реЗ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рд╣реЛ рдЧрдпрд╛ рдХрд┐ рд╕реНрдкреНрд░рд╛рдЗрдЯрд┐рдЯ рдЧреЗрдо рдЯреЗрдХреНрдиреЛрд▓реЙрдЬреА рд▓рд╛рдЗрди рдореЗрдВ рдерд╛ред
рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХрд╛ рд╡рд┐рд╡рд░рдгредрдЙрдкрд░реЛрдХреНрдд рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдорд╛рд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдмрдирд╛рдИ рдЧрдИ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рд╡рд┐рдВрдбреЛ рдХреЗ рдмрд╛рдПрдВ рднрд╛рдЧ рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХреА рдЬрд╛рдПрдЧреАред рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдлрд╛рдЗрд▓реЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ
AppDelegate.swift рд╣реИ , рдЬреЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдШрдЯрдирд╛ (рд▓реЙрдиреНрдЪ, рдзрдХреНрдХрд╛, рд▓рд┐рдВрдХ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ, рдЖрджрд┐) рдХреЗ рд╕рд╛рде рд╕рд┐рд╕реНрдЯрдо рдХреЛ рд╣рдорд╛рд░реЗ рдХреЛрдб рдХреЗ рд╕рд╛рде рд╕рдВрд╡рд╛рдж рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдХреЛрдб:
рд╕рдорд╛рди рд░реВрдк рд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдлрд╛рдЗрд▓реЗрдВ
GameScene.swift рдФрд░
GameViewController.swift рд╣реИрдВ ред GameScene рд╡рд░реНрдЧ рджреГрд╢реНрдп рдмрдирд╛рддрд╛ рд╣реИ, рдФрд░ GameViewController рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреЗ рдПрдХ рд╕реНрдХреНрд░реАрди рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ (рдПрдХ рд╕реНрдХреНрд░реАрди - рдПрдХ GameViewController)ред рдмреЗрд╢рдХ, рдпрд╣ рдирд┐рдпрдо рд╣рдореЗрд╢рд╛ рд╕рдорд░реНрдерд┐рдд рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░ рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рд╣рдорд╛рд░рд╛ рдЖрд╡реЗрджрди рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреЗрд╡рд▓ рдПрдХ GameViewController рд╣реЛрдЧрд╛ред рдЪрд▓реЛ рдЙрд╕рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред
рдПрдХ GameViewController рд▓реЗрдЦрди
рд╣рдо рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХреЛрдб рдХреЛ рд╣рдЯрд╛ рджреЗрдВрдЧреЗред рд╡реНрдпреВ рдХрдВрдЯреНрд░реЛрд▓рд░ рдореЗрдВ рдХрдИ рддрд░реАрдХреЗ рд╣реЛрддреЗ рд╣реИрдВ рдЬреЛ рд╕реНрдХреНрд░реАрди рдХреА рд╕реНрдерд┐рддрд┐ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬрдм рд╕рднреА рд╕реНрдХреНрд░реАрди рддрддреНрд╡ рдкрд╣рд▓реЗ рд╣реА рд▓реЛрдб рд╣реЛ рдЪреБрдХреЗ рд╣реИрдВ, рддреЛ
viewDidLoad()
рдЪрд╛рд▓реВ рд╣реЛ
viewDidLoad()
, рдФрд░ рд╕реНрдХреНрд░реАрди рд╕реНрдорд╛рд░реНрдЯрдлреЛрди рдкрд░ рджрд┐рдЦрд╛рдИ рджреЗрдиреЗ рд╡рд╛рд▓реА рд╣реИред рдЪреВрдБрдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдЦреЗрд▓ рд╣реИ, рд╣рдореЗрдВ рдЦреЗрд▓ рджреГрд╢реНрдп рдХреЛ рдЕрдкрдиреЗ рджреГрд╢реНрдп рдирд┐рдпрдВрддреНрд░рдХ рдореЗрдВ рд░рдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рдпрд╣ рд╡рд╣ рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдБ рд╕рд╛рдБрдк рдЪрд▓реЗрдЧрд╛ рдФрд░ рдЦреЗрд▓ рдХреА рдЕрдиреНрдп рд╕рднреА рдШрдЯрдирд╛рдПрдВ рдШрдЯрд┐рдд рд╣реЛрдВрдЧреА)ред
рдПрдХ рджреГрд╢реНрдп рдмрдирд╛рдПрдБ:
let scene = GameScene(size: view.bounds.size)
рдЖрдЬреНрдЮрд╛ рджреЗрдирд╛ рдПрдХ рд╕реНрдерд┐рд░ рдФрд░ рдПрдХ рдЦреЛрдЬрд╢рдмреНрдж рд╣реИред рд╕реНрд╡рд┐рдлреНрдЯ рднреА var рдХреАрд╡рд░реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рдПрдХ рд╡реИрд░рд┐рдПрдмрд▓ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред
рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рдкреНрд░реЛрдЧреНрд░рд╛рдо рдЪрд▓рд╛рдиреЗ рдХреЗ рджреМрд░рд╛рди рдХрдИ рдмрд╛рд░ рдЪрд░ рдХрд╛ рдорд╛рди рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВред рдЪрд▓реЛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рдЖрд░рдВрднреАрдХрд░рдг рдХреЗ рдмрд╛рдж рдЪрд░ рдХрд╛ рдорд╛рди рдирд╣реАрдВ рдмрджрд▓ рд╕рдХрддреЗ
рдЕрдм рд╣рдореЗрдВ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдЬрд┐рд╕ рджреГрд╢реНрдп рдореЗрдВ рд╣рдо рдмрдирд╛рдП рдЧрдП рджреГрд╢реНрдп рдХреЛ рд░рдЦреЗрдВрдЧреЗ, рд╡рд╣ рд╡рд╛рдВрдЫрд┐рдд рдкреНрд░рдХрд╛рд░ рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП,
рдЧрд╛рд░реНрдб рдирд┐рд░реНрдорд╛рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ - рдпрд╣ рд╡реИрд╕рд╛ рд╣реА рд╣реИ рдЬреИрд╕реЗ, рдХреЗрд╡рд▓ рдЕрдиреНрдп рддрд░реАрдХреЗ рд╕реЗ (рдпрджрд┐ рдирд╣реАрдВ):
guard let skView = view as? SKView else { return }
рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдХрд┐ рд╕реНрдХреНрд░реАрди рддрддреНрд╡ рд╡рд╛рдВрдЫрд┐рдд рдкреНрд░рдХрд╛рд░ рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ, рд╣рдо рдЗрд╕рдореЗрдВ рдЕрдкрдирд╛ рджреГрд╢реНрдп рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ:
skView.presentScene(scene)
рдЖрдкрдХреЛ рдкреНрд░рддрд┐ рд╕реЗрдХрдВрдб рдлрд╝реНрд░реЗрдо рдХреА рд╕рдВрдЦреНрдпрд╛ (FPS) рджрд┐рдЦрд╛рдиреЗ рдХреА рднреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
skView.showsFPS = true
рдлрд┐рд░ рджреГрд╢реНрдп рдкрд░ рд╕рднреА рдкреНрд░рдХрд╛рд░ рдХреЗ рддрддреНрд╡реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдВ:
skView.showsNodeCount = true
рдФрд░ рддрддреНрд╡реЛрдВ рдХреА рдкрджрд╛рдиреБрдХреНрд░рдо рдореЗрдВ рдЙрдирдХреЗ рдЖрджреЗрд╢ рдХреА рдкрд░рд╡рд╛рд╣ рдХрд┐рдП рдмрд┐рдирд╛ рддрддреНрд╡реЛрдВ рдХреЛ рд╕реНрдХреНрд░реАрди рдкрд░ рджрд┐рдЦрд╛рдИ рджреЗрддреЗ рд╣реИрдВ:
skView.ignoresSiblingOrder = true
рдФрд░ рдпрд╣ рдордд рднреВрд▓реЛ рдХрд┐ рд╣рдорд╛рд░рд╛ рджреГрд╢реНрдп рд╕реНрдХреНрд░реАрди рдХреА рдкреВрд░реА рдЪреМрдбрд╝рд╛рдИ рддрдХ рдлреИрд▓рд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП:
scene.scaleMode = .resizeFill
рдпрд╣рд╛рдБ
GameViewController.swift рдлрд╝рд╛рдЗрд▓ рдХреЗ рд▓рд┐рдП рдЕрдВрддрд┐рдо рдХреЛрдб рд╣реИ:
import UIKit import SpriteKit import GameplayKit class GameViewController: UIViewController { override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() setup() } private func setup() { guard let skView = view as? SKView else { return } let scene = GameScene(size: view.bounds.size) skView.showsFPS = true skView.showsNodeCount = true skView.ignoresSiblingOrder = true scene.scaleMode = .resizeFill skView.presentScene(scene) } }
GameViewController.swift рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдиреЗ рдХрд╛ рд╡рд┐рд╡рд░рдгредрдЗрд╕рд▓рд┐рдП, рд╣рдордиреЗ рджреГрд╢реНрдп рдмрдирд╛рдпрд╛, рд▓реЗрдХрд┐рди рдпрд╣ рдЦрд╛рд▓реА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рд╣рдо рдЕрдм рдПрдореБрд▓реЗрдЯрд░ рдЪрд▓рд╛рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдХреЗрд╡рд▓ рдПрдХ рдХрд╛рд▓реА рд╕реНрдХреНрд░реАрди рджреЗрдЦреЗрдВрдЧреЗред
рдПрдХ GameScene рд▓реЗрдЦрди
рдкрд┐рдЫрд▓реА рдмрд╛рд░ рдХреА рддрд░рд╣, рд╣рдо рдЕрдзрд┐рдХрд╛рдВрд╢ рдХреЛрдб рд╣рдЯрд╛рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░
рджреГрд╢реНрдп рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХрд░рддреЗ рд╣реИрдВ ред рдЗрд╕рдХреЗ рднреА рдЕрдкрдиреЗ рддрд░реАрдХреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЪреВрдВрдХрд┐ рд╣рдордиреЗ ViewController рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ рджреГрд╢реНрдп рдЬреЛрдбрд╝рд╛, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ
didMove()
рд╡рд┐рдзрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
override func didMove(to view: SKView) { setup(in: view) }
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЬрдм рдЦреЗрд▓ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ, рддреЛ
Update()
рдкрджреНрдзрддрд┐ рдХреЛ рдкреНрд░рддреНрдпреЗрдХ рдлреНрд░реЗрдо рдХреЗ рд▓рд┐рдП рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ:
override func update(_ currentTime: TimeInterval) { snake?.move() }
рдФрд░ рд╣рдореЗрдВ рд╕реНрдХреНрд░реАрди рдХреЛ рдЯреИрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╣реИрдВрдбрд▓рд░ рдХреА рднреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return }
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return }
рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдЬрд╛рдирддреЗ рд╣реИрдВ, рд╕реНрд╡рд┐рдлреНрдЯ
рд╕рд┐рдВрдЯреИрдХреНрдЯрд┐рдХ рд╢реБрдЧрд░ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рдкреНрд░рд╕рд┐рджреНрдз рд╣реИред рд╕рд┐рдВрдереЗрдЯрд┐рдХ рдЪреАрдиреА - рдпреЗ рддрдХрдиреАрдХреА рдкрд╣рд▓реВ рд╣реИрдВ рдЬреЛ рдбреЗрд╡рд▓рдкрд░ рдХреЗ рдЬреАрд╡рди рдХреЛ рд╕рд░рд▓ рдмрдирд╛рддреЗ рд╣реИрдВ, рдХреЛрдб рдХреЗ рд▓реЗрдЦрди рдХреЛ рдЧрддрд┐ рджреЗрддреЗ рд╣реИрдВред рдпрд╣ рд╕рдм рджреГрд╢реНрдп рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдореЗрдВ рдмрд╣реБрдд рдорджрдж рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдо рдЕрдм рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд░рдВрдЧ рд╕реЗрдЯ рдХрд░реЗрдВ:
backgroundColor = SKColor.white
рдЪреВрдВрдХрд┐ рд╕рд╛рдВрдк рдПрдХ рд╡рд┐рдорд╛рди рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рднреМрддрд┐рдХреА рдХреА рдЬрд░реВрд░рдд рдирд╣реАрдВ рд╣реИ, рдФрд░ рдЖрдк рдЗрд╕реЗ рдмрдВрдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рд╕рд╛рдВрдк рдЧреБрд░реБрддреНрд╡рд╛рдХрд░реНрд╖рдг рдХреЗ рдХрд╛рд░рдг рдиреАрдЪреЗ рди рдЧрд┐рд░реЗред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдореЗрдВ рдЦреЗрд▓ рдХреЛ рд╕реНрдкрд┐рди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдЖрджрд┐ ред:
physicsWorld.gravity = .zero physicsWorld.contactDelegate = self physicsBody = SKPhysicsBody(edgeLoopFrom: frame) physicsBody?.allowsRotation = false physicsBody?.categoryBitMask = CollisionCategories.edgeBody physicsBody?.collisionBitMask = CollisionCategories.snake | CollisionCategories.snakeHead view.showsPhysics = true
рдЕрдм рдмрдЯрди рдмрдирд╛рдПрдВ:
let counterClockwiseButton = ControlsFactory.makeButton(at: CGPoint(x: scene.frame.minX + 30, y: scene.frame.minY + 50), name: .counterClockwiseButtonName) addChild(counterClockwiseButton) let clockwiseButton = ControlsFactory.makeButton(at: CGPoint(x: scene.frame.maxX - 90, y: scene.frame.minY + 50), name: .clockwiseButtonName) addChild(clockwiseButton)
рдЬрдм рдЖрдкрдиреЗ рдХреЛрдб рдХрд╛ рдПрдХ рдЯреБрдХрдбрд╝рд╛ рд▓рд┐рдЦрд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдпрд╣ рд╡рд┐рдЪрд╛рд░ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдХреНрдпрд╛ рдХреЛрдб рдореЗрдВ рд╕реБрдзрд╛рд░ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдпрд╛ рдЗрд╕реЗ
рдлрд┐рд░ рд╕реЗ рд╕рдХреНрд░рд┐рдп
рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рддрд╛рдХрд┐ рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдЗрд╕рдХрд╛
рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред рджреЗрдЦреЛ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдореВрд▓ рд░реВрдк рд╕реЗ рд╕реНрдХреНрд░реАрди рдкрд░ рджреЛ рдмрдЯрди рд╣реИрдВ, рдЬрд┐рд╕рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рд▓рд┐рдП рдПрдХ рд╣реА рдХреЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рддреЛ, рдЗрд╕ рдХреЛрдб рдХреЛ рдПрдХ рдЕрд▓рдЧ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдирд┐рдХрд╛рд▓рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП,
рдПрдХ рдирдпрд╛ рд╡рд░реНрдЧ
рдмрдирд╛рдПрдВ рдФрд░, рддрджрдиреБрд╕рд╛рд░,
ControlsFactory.swift рдлрд╝рд╛рдЗрд▓ рдирд┐рдореНрди рдХреЛрдб рдХреЗ рд╕рд╛рде:
import SpriteKit final class ControlsFactory { static func makeButton(at position: CGPoint, name: String) -> SKShapeNode { let button = SKShapeNode() button.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 45, height: 45)).cgPath button.position = position button.fillColor = .gray button.strokeColor = UIColor.lightGray.withAlphaComponent(0.7) button.lineWidth = 10 button.name = name return button } }
рдПрдХ рдмреЗрддрд░рддреАрдм рд╕реЗрдм рдЦреАрдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рд╣рдорд╛рд░рд╛ рд╕рд╛рдБрдк "рдЦрд╛рдПрдЧрд╛",
Apple рд╡рд░реНрдЧ рдФрд░
Apple.swift рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ:
import SpriteKit final class Apple: SKShapeNode { let diameter: CGFloat = 10 convenience init(at point: CGPoint) { self.init() path = UIBezierPath(ovalIn: CGRect(x: -diameter/2, y: -diameter/2, width: diameter, height: diameter)).cgPath fillColor = .red strokeColor = UIColor.red.withAlphaComponent(0.7) lineWidth = 5 position = point physicsBody = SKPhysicsBody(circleOfRadius: diameter / 2, center: .zero) physicsBody?.categoryBitMask = CollisionCategories.apple } }
рдФрд░ рд╣рдо
createApple()
рдореЗрдВ
createApple()
рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕рд╛рде рд╣рдорд╛рд░реЗ рд╕реЗрдм рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ:
private func createApple() { let padding: UInt32 = 15 let randX = CGFloat(arc4random_uniform(UInt32(gameFrameRect.maxX) - padding) + padding) let randY = CGFloat(arc4random_uniform(UInt32(gameFrameRect.maxY) - padding) + padding) let apple = Apple(at: CGPoint(x: randX, y: randY).relative(to: gameFrameRect)) gameFrameView.addChild(apple) }
рдЦреИрд░, рд╕рд╛рдВрдк рдХреЗ рд▓рд┐рдП рдмрд╛рд░реА рдЖрдИ рд╣реИред рдпрд╣ рджреЛ рднрд╛рдЧреЛрдВ рд╕реЗ рдорд┐рд▓рдХрд░
рдмрдиреЗрдЧрд╛ : рд╢рд░реАрд░ (
SnakeBodyPart.swift ) рдФрд░ рд╕рд┐рд░ (
SnHead.swift )ред
рд╕реНрдиреЗрдХрдмреЙрдбреАрдкрд╛рд░реНрдЯ.рд╕реНрд╡рдлрд╝реНрдЯ рдХреЛрдб:
import SpriteKit class SnakeBodyPart: SKShapeNode { init(at point: CGPoint, diameter: CGFloat = 10.0) { super.init() path = UIBezierPath(ovalIn: CGRect(x: -diameter/2, y: -diameter/2, width: diameter, height: diameter)).cgPath fillColor = .green strokeColor = UIColor.green.withAlphaComponent(0.7) lineWidth = 5 position = point physicsBody = SKPhysicsBody(circleOfRadius: diameter - 4, center: .zero) physicsBody?.isDynamic = true physicsBody?.categoryBitMask = CollisionCategories.snake physicsBody?.contactTestBitMask = CollisionCategories.edgeBody | CollisionCategories.apple } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
рд╕реНрдиреЗрд╣рд╛рд╣реЗрдб.рд╡рд┐рдлреНрдЯ рдХреЛрдб:
import SpriteKit final class SnakeHead: SnakeBodyPart { init(at point: CGPoint) { super.init(at: point, diameter: 20) physicsBody?.categoryBitMask = CollisionCategories.snakeHead physicsBody?.contactTestBitMask = CollisionCategories.edgeBody | CollisionCategories.apple } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
рд╣рд╛рд▓рд╛рдБрдХрд┐, рд╣рдо рдЖрдкрдХреЛ рдкреНрд░рддреНрдпреЗрдХ рдкрдВрдХреНрддрд┐ рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЗ рд╕рд╛рде рдмреЛрд░ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ,
рдХреНрдпреЛрдВрдХрд┐ рд╡реАрдбрд┐рдпреЛ рдореЗрдВ
GameScene.swift рдлрд╝рд╛рдЗрд▓ рдФрд░ рдЕрдиреНрдп рдХрдХреНрд╖рд╛рдУрдВ рдХреЛ
рдмрдирд╛рдиреЗ рдХрд╛ рд╡рд┐рд╡рд░рдг рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╣рдо рдХреЗрд╡рд▓
GameScene.swift рдХрд╛ рдЕрдВрддрд┐рдо рдХреЛрдб рджреЗрдЦрдиреЗ рдХреА рдкреЗрд╢рдХрд╢ рдХрд░рддреЗ рд╣реИрдВ:
import SpriteKit import GameplayKit class GameScene: SKScene { var gameFrameRect: CGRect = .zero var gameFrameView: SKShapeNode! var startButton: SKLabelNode! var stopButton: SKLabelNode! var snake: Snake? override func didMove(to view: SKView) { setup(in: view) } override func update(_ currentTime: TimeInterval) { snake?.move() } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return } if let shapeNode = touchedNode as? SKShapeNode, touchedNode.name == .counterClockwiseButtonName || touchedNode.name == .clockwiseButtonName { shapeNode.fillColor = .green if touchedNode.name == .counterClockwiseButtonName { snake?.moveCounterClockwise() } else if touchedNode.name == .clockwiseButtonName { snake?.moveClockwise() } } else if touchedNode.name == .startButtonName { start() } else if touchedNode.name == .stopButtonName { stop() } } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return } if let shapeNode = touchedNode as? SKShapeNode, touchedNode.name == .counterClockwiseButtonName || touchedNode.name == .clockwiseButtonName { shapeNode.fillColor = .gray } } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return } if let shapeNode = touchedNode as? SKShapeNode, touchedNode.name == .counterClockwiseButtonName || touchedNode.name == .clockwiseButtonName { shapeNode.fillColor = .gray } }
рдкрд░рд┐рдгрд╛рдо рд╕рдмрд╕реЗ рд╕рд░рд▓ рд╕рд╛рдБрдк рдХрд╛ рдЦреЗрд▓ рдерд╛:

рдЦреЗрд▓ рд▓рд┐рдЦрдиреЗ рдореЗрдВ рд╣рдореЗрдВ рд▓рдЧрднрдЧ рдбреЗрдврд╝ рдШрдВрдЯрд╛ рд▓рдЧрд╛ред рдпрджрд┐ рдЖрдк рд╕реНрд╡рд┐рдлреНрдЯ рдореЗрдВ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреМрд╢рд▓ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рд╕рднреА рдЪрд░рдгреЛрдВ рдХреЛ рд╕реНрд╡рдпрдВ рджреЛрд╣рд░рд╛рдПрдВред рд╡реИрд╕реЗ,
рдпрд╣рд╛рдВ рдЖрдкрдХреЛ рдЙрди рд╕рднреА рдХреЛрдб рдлрд╝рд╛рдЗрд▓реЛрдВ рдХрд╛ рдкреВрд░рд╛ рдЙрдкрдпреЛрдЧ рдорд┐рд▓реЗрдЧрд╛ рдЬреЛ рдЗрд╕ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рдереЗред