{"id":1980,"date":"2014-10-07T19:15:16","date_gmt":"2014-10-07T23:15:16","guid":{"rendered":"http:\/\/tim.cstj.qc.ca\/cours\/xcode\/wp\/?page_id=1980"},"modified":"2014-10-07T19:15:16","modified_gmt":"2014-10-07T23:15:16","slug":"tim-briques-spritekit","status":"publish","type":"page","link":"https:\/\/ve2cuy.com\/xcode\/tim-briques-spritekit\/","title":{"rendered":"TIM.Briques &#8211; SpriteKit"},"content":{"rendered":"<h1>Construction d&rsquo;un jeu vid\u00e9o avec SpriteKit<\/h1>\n<h4><\/h4>\n<h3>\u00c9l\u00e9ments de contenu<\/h3>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignleft wp-image-2106\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/d8ll3.gif\" alt=\"d8ll3\" width=\"215\" height=\"395\" \/><br \/>\n&nbsp;<\/p>\n<ul>\n<li>SpriteKit<\/li>\n<li>Physique<\/li>\n<li>D\u00e9tection de collisions<\/li>\n<li>Effets sonores<\/li>\n<li>Particules<\/li>\n<li>Gestion de niveaux<\/li>\n<\/ul>\n<p>&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1><\/h1>\n<h1>Description<\/h1>\n<p>Dans ce laboratoire nous verrons, \u00a0grace au framework spriteKit, \u00e0 l&rsquo;engin de physique, aux particules et au frameWork AVPlayer, comment construire une application de type casse briques.<br \/>\nAu lieu d&rsquo;utiliser la m\u00e9thode classique de v\u00e9rification- \u00e0 chaque cadre (enterFrame) &#8211; d&rsquo;une intersection entre\u00a0deux \u00e9l\u00e9ments, nous utiliserons plut\u00f4t une m\u00e9thode de d\u00e9l\u00e9gation de l&rsquo;engin de physique pour d\u00e9tecter une collision.<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>Sprite Kit<\/h1>\n<p>Sprite Kit propose une infrastructure de d\u00e9veloppement de jeux vid\u00e9os 2D en offrant des fonctions d&rsquo;animations et de rendu. \u00a0Cette librairie a \u00e9t\u00e9 introduite \u00e0 la version 5 de Xcode.<br \/>\nAvant l&rsquo;arriv\u00e9e de Sprite Kit, les d\u00e9veloppeurs de jeux IOS devaient utiliser des libraires tierces parties comme par exemple, le populaire framework <a href=\"http:\/\/www.cocos2d-x.org\">Cocos2d<\/a>.<br \/>\nSprite Kit utilise\u00a0une boucle standard d&rsquo;animation (enterFrame) pour produire et afficher les rendus.<br \/>\nVoici le cycle de vie d&rsquo;un cadre &#8211; frame &#8211; \u00a0d&rsquo;animation:<br \/>\n<div id=\"attachment_2333\" style=\"width: 1186px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2333\" class=\"wp-image-2333 size-full\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/update_loop_2x.png\" alt=\"update_loop_2x\" width=\"1176\" height=\"744\" \/><p id=\"caption-attachment-2333\" class=\"wp-caption-text\">Source: Apple<\/p><\/div><br \/>\n&nbsp;<br \/>\nLe framework propose aussi d&rsquo;autres m\u00e9thodes permettant d&rsquo;enrichir l&rsquo;exp\u00e9rience du jeu: possibilit\u00e9 de jouer des trames sonores, un engin de simulation de physique, \u00a0effets sp\u00e9ciaux complexes, utilisation d&rsquo;atlas de textures et support de particules.<br \/>\nApple propose deux autres frameworks pour le d\u00e9veloppement de jeux videos 3D: Metal et Sc\u00e8ne Kit. \u00a0Il est aussi possible de cr\u00e9er des projets de type OpenGL.<br \/>\nCe laboratoire couvrira les fonctions de\u00a0base de Sprite Kit.<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>\u00c9tape 1 &#8211;\u00a0Une nouvelle application de type &lsquo;Game&rsquo;<\/h1>\n<p>Dans l&rsquo;univers de Xcode, b\u00e2tir\u00a0un jeu implique la cr\u00e9ation d&rsquo;un nouveau projet Xcode.<br \/>\n<span style=\"color: #ff0000;\"><strong><br \/>\nAction 1.1<\/strong> <\/span>&#8211; \u00a0Cr\u00e9ons un nouveau projet et s\u00e9lectionnons &lsquo;Game&rsquo; comme gabarit de d\u00e9part:<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2014\/10\/TIM.Briques.01.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1981\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/TIM.Briques.01.png\" alt=\"TIM.Briques.01\" width=\"734\" height=\"433\" \/><\/a><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.2<\/strong>\u00a0<\/span>&#8211; \u00a0 Nommons le projet et \u00a0s\u00e9lectionnons &lsquo;SpriteKit&rsquo; sous &lsquo;Game Technologie&rsquo;:<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2014\/10\/TIM.Briques.02.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-1982\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/TIM.Briques.02.png\" alt=\"TIM.Briques.02\" width=\"736\" height=\"434\" \/><\/a><br \/>\n<span style=\"color: #ff0000;\"><strong>Note:<\/strong> <\/span>sceneKit et Metal permettent le d\u00e9veloppement de jeux 3D.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.3<\/strong>\u00a0<\/span>&#8211; \u00a0Testons l&rsquo;application (Touchez \u00e0 l&rsquo;\u00e9cran pendant l&rsquo;ex\u00e9cution)<br \/>\n<a href=\"\/xcode\/wp-content\/uploads\/2014\/10\/TIM.Briques.03.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-1983\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/TIM.Briques.03.png\" alt=\"TIM.Briques.03\" width=\"669\" height=\"399\" \/><\/a><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.4<\/strong>\u00a0<\/span>&#8211; \u00a0Analysons le code de d\u00e9part:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/  GameScene.swift\n\/\/  TIM.Briques\n\/\/\n\/\/  Created by Alain on 2014-10-07.\n\/\/  Copyright (c) 2014 Alain. All rights reserved.\nimport SpriteKit\nclass GameScene: SKScene {\n    override func didMoveToView(view: SKView) {\n        \/* Setup your scene here *\/\n        let myLabel = SKLabelNode(fontNamed:\"Chalkduster\")\n        myLabel.text = \"Hello, World!\";\n        myLabel.fontSize = 65;\n        myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));\n        self.addChild(myLabel)\n    }\n    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {\n        \/* Called when a touch begins *\/\n        for touch: AnyObject in touches {\n            let location = touch.locationInNode(self)\n            let sprite = SKSpriteNode(imageNamed:\"Spaceship\")\n            sprite.xScale = 0.5\n            sprite.yScale = 0.5\n            sprite.position = location\n            let action = SKAction.rotateByAngle(CGFloat(M_PI), duration:1)\n            sprite.runAction(SKAction.repeatActionForever(action))\n            self.addChild(sprite)\n        }\n    }\n    override func update(currentTime: CFTimeInterval) {\n        \/* Called before each frame is rendered *\/\n        println(\"update\")\n    }\n}<\/pre>\n<p>&nbsp;<\/p>\n<hr \/>\n<h1><\/h1>\n<h1>D\u00e9buter avec une sc\u00e8ne vide<\/h1>\n<p><span style=\"color: #ff0000;\"><strong>Action 1.6<\/strong>\u00a0<\/span>&#8211; Rempla\u00e7ons le code du fichier GameScene.swift\u00a0par:<\/p>\n<pre class=\"lang:swift decode:true\">import SpriteKit\nclass GameScene: SKScene {\n    override func didMoveToView(view: SKView) {\n        \/* Setup your scene here *\/\n    } \/\/ didMoveToView()\n    override func update(currentTime: CFTimeInterval) {\n        \/* Called before each frame is rendered *\/\n    } \/\/ update()\n} \/\/ class GameScene<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.7<\/strong>\u00a0<\/span>&#8211; Ajoutons la ligne suivante \u00e0 la classe\u00a0GameViewController.<\/p>\n<pre class=\"lang:swift mark:7 decode:true\" title=\"Seulement la ligne: scene.size = skView.bounds.size\">\/\/class GameViewController: UIViewController {\n\/\/    override func viewDidLoad() {\n\/\/ ...\n            \/* Set the scale mode to scale to fit the window *\/\n            scene.scaleMode = .AspectFill\n            scene.size = skView.bounds.size\n            skView.presentScene(scene)\n<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note:<\/strong><\/span> \u00a0la ligne:\u00a0\u00a0&lsquo;scene.size = skView.bounds.size&rsquo; indique que nous d\u00e9sirons une sc\u00e8ne de taille \u00e9gale \u00e0 l&rsquo;appareil sur lequel nous ex\u00e9cuterons l&rsquo;application.<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.8<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons les ressources suivantes au projet:\u00a0<a href=\"\/xcode\/wp-content\/uploads\/2014\/10\/TIM.Briques.Ressources.zip\">TIM.Briques.Ressources<\/a><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>Tout est question de &lsquo;Noeuds&rsquo;<\/h1>\n<p>Pour ajouter des \u00e9l\u00e9ments sur la sc\u00e8ne, il suffit de cr\u00e9er des instances de classes \u00e9tendant la classe SKNode.<br \/>\nVoici une liste des classes propos\u00e9es:<\/p>\n<ul class=\"Objective-C\" style=\"color: #000000;\">\n<li class=\"depth7 subclass\" style=\"color: #0088cc;\"><code class=\"code-voice\" style=\"color: #808080;\"><a style=\"color: #0088cc;\" href=\"https:\/\/developer.apple.com\/Library\/ios\/documentation\/SpriteKit\/Reference\/SK3DNode\/index.html#\/\/apple_ref\/occ\/cl\/SK3DNode\">SK3DNode<\/a><\/code><\/li>\n<li class=\"depth7 subclass\" style=\"color: #0088cc;\"><code class=\"code-voice\" style=\"color: #808080;\"><a style=\"color: #0088cc;\" href=\"https:\/\/developer.apple.com\/Library\/ios\/documentation\/SpriteKit\/Reference\/SKCropNode_Ref\/index.html#\/\/apple_ref\/occ\/cl\/SKCropNode\">SKCropNode<\/a><\/code><\/li>\n<li class=\"depth7 subclass\" style=\"color: #0088cc;\"><code class=\"code-voice\" style=\"color: #808080;\"><a style=\"color: #0088cc;\" href=\"https:\/\/developer.apple.com\/Library\/ios\/documentation\/SpriteKit\/Reference\/SKEffectNode_Ref\/index.html#\/\/apple_ref\/occ\/cl\/SKEffectNode\">SKEffectNode<\/a><\/code><\/li>\n<li class=\"depth7 subclass\" style=\"color: #0088cc;\"><code class=\"code-voice\" style=\"color: #808080;\"><a style=\"color: #0088cc;\" href=\"https:\/\/developer.apple.com\/Library\/ios\/documentation\/SpriteKit\/Reference\/SKEmitterNode_Ref\/index.html#\/\/apple_ref\/occ\/cl\/SKEmitterNode\">SKEmitterNode<\/a>\u00a0- Pour des particules<\/code><\/li>\n<li class=\"depth7 subclass\" style=\"color: #0088cc;\"><code class=\"code-voice\" style=\"color: #808080;\"><a style=\"color: #0088cc;\" href=\"https:\/\/developer.apple.com\/Library\/ios\/documentation\/SpriteKit\/Reference\/SKFieldNode_Ref\/index.html#\/\/apple_ref\/occ\/cl\/SKFieldNode\">SKFieldNode<\/a><\/code><\/li>\n<li class=\"depth7 subclass\" style=\"color: #0088cc;\"><code class=\"code-voice\" style=\"color: #808080;\"><a style=\"color: #0088cc;\" href=\"https:\/\/developer.apple.com\/Library\/ios\/documentation\/SpriteKit\/Reference\/SKLabelNode_Ref\/index.html#\/\/apple_ref\/occ\/cl\/SKLabelNode\">SKLabelNode<\/a>\u00a0 \u00a0- Pour du texte<\/code><\/li>\n<li class=\"depth7 subclass\" style=\"color: #0088cc;\"><code class=\"code-voice\" style=\"color: #808080;\"><a style=\"color: #0088cc;\" href=\"https:\/\/developer.apple.com\/Library\/ios\/documentation\/SpriteKit\/Reference\/SKLightNode_Ref\/index.html#\/\/apple_ref\/occ\/cl\/SKLightNode\">SKLightNode<\/a><\/code><\/li>\n<li class=\"depth7 subclass\" style=\"color: #0088cc;\"><code class=\"code-voice\" style=\"color: #808080;\"><a style=\"color: #0088cc;\" href=\"https:\/\/developer.apple.com\/Library\/ios\/documentation\/SpriteKit\/Reference\/SKShapeNode_Ref\/index.html#\/\/apple_ref\/occ\/cl\/SKShapeNode\">SKShapeNode<\/a><\/code><\/li>\n<li class=\"depth7 subclass\" style=\"color: #0088cc;\"><code class=\"code-voice\" style=\"color: #808080;\"><a style=\"color: #0088cc;\" href=\"https:\/\/developer.apple.com\/Library\/ios\/documentation\/SpriteKit\/Reference\/SKSpriteNode_Ref\/index.html#\/\/apple_ref\/occ\/cl\/SKSpriteNode\">SKSpriteNode<\/a>\u00a0 - Pour un sprite (une image, un personnage anim\u00e9)<\/code><\/li>\n<li class=\"depth7 subclass\" style=\"color: #0088cc;\"><code class=\"code-voice\" style=\"color: #808080;\"><a style=\"color: #0088cc;\" href=\"https:\/\/developer.apple.com\/Library\/ios\/documentation\/SpriteKit\/Reference\/SKVideoNode\/index.html#\/\/apple_ref\/occ\/cl\/SKVideoNode\">SKVideoNode<\/a><\/code><\/li>\n<\/ul>\n<hr \/>\n<h3>Ajouter du texte &#8211; SKLabelNode<\/h3>\n<p><span style=\"color: #ff0000;\"><strong>Action 1.9<\/strong>\u00a0<\/span>&#8211; Ajoutons un titre (SKLabelNode) sur la sc\u00e8ne :<\/p>\n<pre class=\"lang:swift decode:true\">    \/\/ Point de d\u00e9part du code de la sc\u00e8ne\n    override func didMoveToView(view: SKView) {\n        \/* Construire la sc\u00e8ne du jeu ici *\/\n        \/\/ Note: self est sous entendu ici: self.backgroundColor =\n        backgroundColor = UIColor(red: 0, green: 0, blue: 140\/255, alpha: 1)\n        let unTitre = SKLabelNode(fontNamed:\"Arial\")\n        \/\/let unTitre = SKLabelNode(fontNamed:\"Hoefler Text\")\n        unTitre.text = \"TIM.Briques\";\n        unTitre.fontSize = 35;\n        \/\/unTitre.fontColor = UIColor.redColor()\n        self.addChild(unTitre)\n    }<\/pre>\n<p>&nbsp;<br \/>\n<strong>R\u00e9sultat obtenu:\u00a0<\/strong><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2110\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/tim.briques.04.png\" alt=\"tim.briques.04\" width=\"322\" height=\"592\" \/><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>Le syst\u00e8me de coordonn\u00e9es de SKScene<\/h1>\n<p>Extrait de la documentation d&rsquo;Apple:<br \/>\nBuilding Your Scene<\/p>\n<article id=\"contents\" class=\"isShowingTOC\" tabindex=\"0\">You have already learned many things about working with scenes. Here\u2019s a quick recap of the important facts:<\/p>\n<ul class=\"ul\">\n<li class=\"li\">Scenes (<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKScene_Ref\/index.html#\/\/apple_ref\/occ\/cl\/SKScene\" target=\"_self\" rel=\"noopener\">SKScene<\/a><\/code>\u00a0objects) are used to provide content to be rendered by an\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKView\/index.html#\/\/apple_ref\/occ\/cl\/SKView\" target=\"_self\" rel=\"noopener\">SKView<\/a><\/code>\u00a0object.<\/li>\n<li class=\"li\">A scene\u2019s content is created as a tree of node objects. The scene is the root node.<\/li>\n<li class=\"li\">When presented by a view, a scene runs actions and simulates physics, then renders the node tree.<\/li>\n<li class=\"li\">You create custom scenes by subclassing the\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKScene_Ref\/index.html#\/\/apple_ref\/occ\/cl\/SKScene\" target=\"_self\" rel=\"noopener\">SKScene<\/a><\/code>\u00a0class.<\/li>\n<\/ul>\n<p>With those basic concepts in mind, it is time to learn more about the node tree and building your scenes.<\/p>\n<section><a style=\"color: #3366cc;\" title=\"A Node Provides a Coordinate System to Its Children\" name=\"\/\/apple_ref\/doc\/uid\/TP40013043-CH3-SW8\"><\/a><\/p>\n<h2 class=\"jump\" style=\"font-weight: 400; color: #3c4c6c;\">A Node Provides a Coordinate System to Its Children<\/h2>\n<p>When a node is placed in the node tree, its\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKNode_Ref\/index.html#\/\/apple_ref\/occ\/instm\/SKNode\/position\" target=\"_self\" rel=\"noopener\">position<\/a><\/code>\u00a0property places it within a coordinate system provided by its parent. Sprite Kit uses the same coordinate system on both iOS and OS X.\u00a0<span class=\"content_text\">Figure 4-1<\/span>\u00a0shows the Sprite Kit coordinate system. Coordinate values are measured in points, as in UIKit or AppKit; where necessary, points are converted to pixels when the scene is rendered. A positive x coordinate goes to the right and a positive y coordinate goes up the screen.<\/p>\n<figure class=\"figure\"><a style=\"color: #3366cc;\" title=\"Figure 4-1Sprite Kit coordinate system\" name=\"\/\/apple_ref\/doc\/uid\/TP40013043-CH3-SW9\"><\/a><figcaption><span class=\"caption_number\" style=\"font-weight: bold;\">Figure 4-1<\/span>\u00a0\u00a0Sprite Kit coordinate system<\/figcaption><img decoding=\"async\" src=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/GraphicsAnimation\/Conceptual\/SpriteKit_PG\/Art\/cartesian_coords_2x.png\" alt=\"\" width=\"198\" height=\"191.5\" \/><\/figure>\n<p>Sprite Kit also has a standard rotation convention.\u00a0<span class=\"content_text\">Figure 4-2<\/span>\u00a0shows the polar coordinate convention. An angle of\u00a0<code style=\"color: #666666;\">0<\/code>\u00a0radians specifies the positive x axis. A positive angle is in the counterclockwise direction.<br \/>\n&nbsp;<\/p>\n<figure class=\"figure\"><a style=\"color: #3366cc;\" title=\"Figure 4-2Polar coordinate conventions (rotation)\" name=\"\/\/apple_ref\/doc\/uid\/TP40013043-CH3-SW2\"><\/a><figcaption><span class=\"caption_number\" style=\"font-weight: bold;\">Figure 4-2<\/span>\u00a0\u00a0Polar coordinate conventions (rotation)<\/figcaption><img decoding=\"async\" src=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/GraphicsAnimation\/Conceptual\/SpriteKit_PG\/Art\/polar_coords_2x.png\" alt=\"\" width=\"190.5\" height=\"193.5\" \/><\/figure>\n<p>When you are working only with Sprite Kit code, a consistent coordinate system means that you can easily share code between an iOS and OS X version of your game. However, it does mean that when you write OS-specific user interface code, you may need to convert between the operating system\u2019s view coordinate conventions and Sprite Kit\u2019s coordinate system. This is most often the case when working with iOS views, which use a different coordinate convention.<br \/>\n&nbsp;<br \/>\n<\/section>\n<section><a style=\"color: #3366cc;\" title=\"Only Some Nodes Contain Content\" name=\"\/\/apple_ref\/doc\/uid\/TP40013043-CH3-SW10\"><\/a><\/p>\n<h2 class=\"jump\" style=\"font-weight: 400; color: #3c4c6c;\">Only Some Nodes Contain Content<\/h2>\n<p>Not all nodes draw content. For example, the\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKSpriteNode_Ref\/index.html#\/\/apple_ref\/occ\/cl\/SKSpriteNode\" target=\"_self\" rel=\"noopener\">SKSpriteNode<\/a><\/code>\u00a0class draws a sprite, but the\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKNode_Ref\/index.html#\/\/apple_ref\/occ\/cl\/SKNode\" target=\"_self\" rel=\"noopener\">SKNode<\/a><\/code>\u00a0class doesn\u2019t draw anything. You can tell whether a particular node object draws content by reading its\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKNode_Ref\/index.html#\/\/apple_ref\/occ\/instp\/SKNode\/frame\" target=\"_self\" rel=\"noopener\">frame<\/a><\/code>\u00a0property. The frame is the visible area of the parent\u2019s coordinate system that the node draws into. If the node draws content, this frame has a nonzero size. For a scene, the frame always reflects the visible portion of the scene\u2019s coordinate space.<br \/>\nIf a node has descendants that draw content, it is possible for a node\u2019s subtree to provide content even though it doesn\u2019t provide any content itself. You can call a node\u2019s\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKNode_Ref\/index.html#\/\/apple_ref\/occ\/instm\/SKNode\/calculateAccumulatedFrame\" target=\"_self\" rel=\"noopener\">calculateAccumulatedFrame<\/a><\/code>\u00a0method to retrieve a rectangle that includes the entire area that a node and all of its descendants draw into.<br \/>\n<\/section>\n<section><a style=\"color: #3366cc;\" title=\"Creating a Scene\" name=\"\/\/apple_ref\/doc\/uid\/TP40013043-CH3-SW14\"><\/a><\/p>\n<h2 class=\"jump\" style=\"font-weight: 400; color: #3c4c6c;\">Creating a Scene<\/h2>\n<p>A scene is presented by a view. The scene includes properties that define where the scene\u2019s origin is positioned and the size of the scene. If the scene does not match the view\u2019s size, you can also define how the scene is scaled to fit in the view.<\/p>\n<section><a style=\"color: #3366cc;\" title=\"A Scene\u2019s Size Defines Its Visible Area\" name=\"\/\/apple_ref\/doc\/uid\/TP40013043-CH3-SW15\"><\/a><\/p>\n<h3 class=\"jump\" style=\"font-weight: 400; color: #000000;\">A Scene\u2019s Size Defines Its Visible Area<\/h3>\n<p>When a scene is first initialized, its\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKScene_Ref\/index.html#\/\/apple_ref\/occ\/instp\/SKScene\/size\" target=\"_self\" rel=\"noopener\">size<\/a><\/code>\u00a0property is configured by the designated initializer. The size of the scene specifies the size of the visible portion of the scene in points. This is only used to specify the visible portion of the scene. Nodes in the tree can be positioned outside of this area; those nodes are still processed by the scene, but are ignored by the renderer.<br \/>\n<\/section>\n<section><a style=\"color: #3366cc;\" title=\"Using the Anchor Point to Position the Scene\u2019s Coordinate System in the View\" name=\"\/\/apple_ref\/doc\/uid\/TP40013043-CH3-SW19\"><\/a><\/p>\n<h3 class=\"jump\" style=\"font-weight: 400; color: #000000;\">Using the Anchor Point to Position the Scene\u2019s Coordinate System in the View<\/h3>\n<p>By default, a scene\u2019s origin is placed in the lower-left corner of the view, as shown in\u00a0<span class=\"content_text\">Figure 4-3<\/span>. So, a scene is initialized with a height of\u00a0<code style=\"color: #666666;\">1024<\/code>\u00a0and a width of\u00a0<code style=\"color: #666666;\">768<\/code>, has the origin\u00a0<code style=\"color: #666666;\">(0,0)<\/code>\u00a0in the lower-left corner, and the\u00a0<code style=\"color: #666666;\">(1024,768)<\/code>\u00a0coordinate in the upper-right corner. The\u00a0<code style=\"color: #666666;\">frame<\/code>\u00a0property holds\u00a0<code style=\"color: #666666;\">(0,0)-(1024,768)<\/code>.<br \/>\nA scene\u2019s\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKNode_Ref\/index.html#\/\/apple_ref\/occ\/instp\/SKNode\/position\" target=\"_self\" rel=\"noopener\">position<\/a><\/code>\u00a0property is ignored by Scene Kit because the scene is always the root node for a node tree. Its default value is\u00a0<code style=\"color: #666666;\">CGPointZero<\/code>\u00a0and you can\u2019t change it. However, you can move the scene\u2019s origin by setting its\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKScene_Ref\/index.html#\/\/apple_ref\/occ\/instp\/SKScene\/anchorPoint\" target=\"_self\" rel=\"noopener\">anchorPoint<\/a><\/code>\u00a0property. The anchor point is specified in the unit coordinate space and chooses a point in the enclosing view.<\/p>\n<figure class=\"figure\"><a style=\"color: #3366cc;\" title=\"Figure 4-3Default anchor for a scene is in the lower-left corner of the view\" name=\"\/\/apple_ref\/doc\/uid\/TP40013043-CH3-SW24\"><\/a><figcaption><span class=\"caption_number\" style=\"font-weight: bold;\">Figure 4-3<\/span>\u00a0\u00a0Default anchor for a scene is in the lower-left corner of the view<\/figcaption><img decoding=\"async\" src=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/GraphicsAnimation\/Conceptual\/SpriteKit_PG\/Art\/unit_coords_2x.png\" alt=\"\" width=\"215.5\" height=\"205\" \/><\/figure>\n<p>The default value for the anchor point is\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/GraphicsImaging\/Reference\/CGGeometry\/index.html#\/\/apple_ref\/c\/data\/CGPointZero\" target=\"_self\" rel=\"noopener\">CGPointZero<\/a><\/code>, which places it at the lower-left corner. The scene\u2019s visible coordinate space is\u00a0<code style=\"color: #666666;\">(0,0)<\/code>\u00a0to\u00a0<code style=\"color: #666666;\">(width,height)<\/code>. The default anchor point is most useful for games that do not scroll a scene\u2019s content.<br \/>\nThe second-most common anchor point value is\u00a0<code style=\"color: #666666;\">(0.5,0.5)<\/code>, which centers the scene\u2019s origin in the middle of the view as shown in\u00a0<span class=\"content_text\">Figure 4-4<\/span>. The scene\u2019s visible coordinate space is\u00a0<code style=\"color: #666666;\">(-width\/2,-height\/2)<\/code>\u00a0to\u00a0<code style=\"color: #666666;\">(width\/2, height\/2)<\/code>. Centering the scene on its anchor point is most useful when you want to easily position nodes relative to the center of the screen, such as in a scrolling game.<\/p>\n<figure class=\"figure\"><a style=\"color: #3366cc;\" title=\"Figure 4-4Moving the anchor point to the center of the view\" name=\"\/\/apple_ref\/doc\/uid\/TP40013043-CH3-SW11\"><\/a><figcaption><span class=\"caption_number\" style=\"font-weight: bold;\">Figure 4-4<\/span>\u00a0\u00a0Moving the anchor point to the center of the view<\/figcaption><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/GraphicsAnimation\/Conceptual\/SpriteKit_PG\/Art\/unit_coords_new_anchor_2x.png\" alt=\"\" width=\"213\" height=\"205\" \/><\/figure>\n<p>So, to summarize, the\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKScene_Ref\/index.html#\/\/apple_ref\/occ\/instp\/SKScene\/anchorPoint\" target=\"_self\" rel=\"noopener\">anchorPoint<\/a><\/code>\u00a0and\u00a0<code style=\"color: #666666;\"><a style=\"color: #3366cc;\" href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/SpriteKit\/Reference\/SKScene_Ref\/index.html#\/\/apple_ref\/occ\/instp\/SKScene\/size\" target=\"_self\" rel=\"noopener\">size<\/a><\/code>\u00a0properties are used to compute the scene\u2019s frame, which holds the visible portion of the scene.<br \/>\n&nbsp;<br \/>\n<\/section>\n<section><a style=\"color: #3366cc;\" title=\"A Scene\u2019s Contents Are Scaled to Fit the View\" name=\"\/\/apple_ref\/doc\/uid\/TP40013043-CH3-SW12\"><\/a><\/section>\n<\/section>\n<\/article>\n<hr \/>\n<h1>Expressions utiles sous SpriteKit<\/h1>\n<p>[table delimiter=\u00a0\u00bb|\u00a0\u00bb]<br \/>\nExpression|Description|Construire\/Utilisation<br \/>\nCGFloat|Valeur r\u00e9elle|let x:CGFloat = 3.141592<br \/>\nCGPoint|Repr\u00e9sente une coordonn\u00e9e (x,y)|CGPointMake(2, 3.14)<br \/>\nCGRect|Repr\u00e9sente un rectangle sous la forme x,y, largeur, hauteur|CGRectMake(0,0,640,1024)<br \/>\nCGPointZero|Un CGPoint \u00e9gal \u00e0 (0,0)|CGPointZero<br \/>\nCGRectGetMidX|Obtenir le centre horizontal d&rsquo;un cadre|CGRectGetMidX(self.frame)<br \/>\nCGRectGetMidY|Obtenir le centre vertical d&rsquo;un cadre|CGRectGetMidY(self.frame)<br \/>\nobjet.position|De type CGPoint &#8211; Obtenir ou modifier la position d&rsquo;un objet|unObjet.position = CGPointMake(0, 0)<br \/>\nobjet.frame|De type CGRect &#8211; Obtenir ou modifier la cadre d&rsquo;un objet|unObjet.frame = CGRectMake(0, 0, 50, 50)<br \/>\n[\/table]<br \/>\n&nbsp;<\/p>\n<hr \/>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.10<\/strong>\u00a0<\/span>&#8211; Pla\u00e7ons le titre au centre de la sc\u00e8ne.<\/p>\n<pre class=\"lang:swift decode:true \">        unTitre.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));\n<\/pre>\n<p><strong>R\u00e9sultat obtenu:\u00a0<\/strong><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2116\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/tim.briques.05.png\" alt=\"tim.briques.05\" width=\"320\" height=\"592\" \/><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Il est\u00a0possible de modifier le point d&rsquo;encrage de la sc\u00e8ne:<\/p>\n<pre class=\"lang:swift decode:true\">self.anchorPoint = CGPointMake(0.5, 0.5)  \/\/ placer au centre\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.11<\/strong>\u00a0<\/span>&#8211;\u00a0Pla\u00e7ons le titre au haut\u00a0de la sc\u00e8ne.<\/p>\n<pre class=\"lang:swift decode:true\">        unTitre.position = CGPoint(x:CGRectGetMidX(frame), y:frame.height - unTitre.frame.height \/ 2)<\/pre>\n<p><strong>R\u00e9sultat obtenu:\u00a0<\/strong><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2117\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/tim.briques.06.png\" alt=\"tim.briques.06\" width=\"324\" height=\"128\" \/><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Remarquez que le texte sort un peu de l&rsquo;\u00e9cran. \u00a0Le rectangle du &lsquo;label&rsquo; est plus haut que la zone visible &#8211; espace pour souligner (simple et double).<br \/>\n<span style=\"color: #ff0000;\"><strong><br \/>\nAction 1.12<\/strong>\u00a0<\/span>&#8211; Ajustons le titre.<\/p>\n<pre class=\"lang:swift decode:true\">        unTitre.position = CGPoint(x:CGRectGetMidX(frame), y:frame.height - unTitre.frame.height);\n<\/pre>\n<p><strong>R\u00e9sultat obtenu:\u00a0<\/strong><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2119\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/tim.briques.07.png\" alt=\"tim.briques.07\" width=\"322\" height=\"109\" \/><br \/>\n&nbsp;<br \/>\nNote \u00e0 l&rsquo;auteur: gestion de la rotation.<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h3>Ajouter une image &#8211; SKSPriteNode<\/h3>\n<p><span style=\"color: #ff0000;\"><strong>Action 1.13<\/strong>\u00a0<\/span>&#8211; Ajoutons un\u00a0ballon (fourni dans le fichier des ressources du projet) au centre la sc\u00e8ne.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-746\" src=\"\/xcode\/wp-content\/uploads\/2013\/10\/balle@2x.png\" alt=\"balle@2x\" width=\"128\" height=\"128\" \/><br \/>\n&nbsp;<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Dans la zone des propri\u00e9t\u00e9s\n    var ballon:SKSpriteNode!\n\/\/ Dans didMoveToView()\n        ballon = SKSpriteNode(imageNamed: \"balle\")\n        ballon.position = CGPoint(x:CGRectGetMidX(frame), y:CGRectGetMidY(frame))\n        self.addChild(ballon)<\/pre>\n<p><strong>R\u00e9sultat obtenu:\u00a0<\/strong><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2120\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/tim.briques.08.png\" alt=\"tim.briques.08\" width=\"321\" height=\"591\" \/><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1><\/h1>\n<h1>La m\u00e9thode update() &#8211; onEnterFrame<\/h1>\n<p>La m\u00e9thode <strong>update<\/strong> est ex\u00e9cut\u00e9e &#8211; si possible &#8211; 60 fois par seconde. \u00a0C&rsquo;est une des m\u00e9thodes de la classe <span style=\"color: #800080;\">SKScene<\/span>\u00a0et elle peut-\u00eatre\u00a0surcharg\u00e9e.<br \/>\nPour\u00a0changer le nombre d&rsquo;images par seconde il faut\u00a0renseigner la propri\u00e9t\u00e9\u00a0<a href=\"https:\/\/developer.apple.com\/library\/mac\/documentation\/SpriteKit\/Reference\/SKView\/index.html#\/\/apple_ref\/occ\/instp\/SKView\/frameInterval\u00a0\">frameInterval<\/a>.<br \/>\nPar exemple, pour diviser\u00a0\u00a0la cadence par 2 (30fps):<\/p>\n<blockquote><p><span style=\"color: #c32275;\">override<\/span> <span style=\"color: #c32275;\">func<\/span> didMoveToView(view: <span style=\"color: #6122ae;\">SKView<\/span>) {<br \/>\nview.<span style=\"color: #703daa;\">frameInterval<\/span> = <span style=\"color: #0435ff;\">2<\/span><\/p><\/blockquote>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.14<\/strong>\u00a0<\/span>&#8211; Ajoutons le code suivant \u00e0 la m\u00e9thode &lsquo;update&rsquo; de la classe de la sc\u00e8ne .<\/p>\n<pre class=\"lang:swift decode:true \">    override func update(currentTime: CFTimeInterval) {\n        \/* Called before each frame is rendered *\/\n        let nouvellePosition = CGPointMake(ballon.position.x + 1, ballon.position.y)\n        if nouvellePosition.x &gt; frame.width \/* + ballon.frame.width \/ 2 *\/\n        {\n            ballon.position = CGPointMake( 0 \/* -ballon.frame.width *\/, ballon.position.y)\n        } else {\n        ballon.position = nouvellePosition\n        } \/\/ if nouvellePosition.x &gt; frame.width\n    } \/\/ update()<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.14b<\/strong>\u00a0<\/span>&#8211; Testons l&rsquo;application.<br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Remarquez que le ballon entre sur la sc\u00e8ne sur la moiti\u00e9 de sa largeur.<br \/>\n<span style=\"color: #ff0000;\"><strong><br \/>\nAction 1.15<\/strong>\u00a0<\/span>&#8211; Supprimons les commentaires pour tenir compte de la taille du ballon dans le calcul de la position.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2121\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/d8r6j.gif\" alt=\"d8r6j\" width=\"260\" height=\"479\" \/><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 1.16<\/strong>\u00a0<\/span>&#8211; Pla\u00e7ons en commentaire le code dans la m\u00e9thode <strong>update<\/strong>().<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>\u00c9tape 2 &#8211; Physique<\/h1>\n<p>Le framework <strong>SpriteKit<\/strong> propose des propri\u00e9t\u00e9s dans\u00a0les sprites: physicsBody,\u00a0categoryBitMask,&#8230;, \u00a0et des classes:\u00a0SKPhysicsBody, &#8230;, permettant de d\u00e9finir un univers physique.<br \/>\nNous allons utiliser ces propri\u00e9t\u00e9s et ces m\u00e9thodes pour soumettre les sprites aux forces gravitationnelles et pour d\u00e9tecter une collision entre eux.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.1<\/strong>\u00a0<\/span>&#8211;\u00a0Organisons un peu notre du code &#8211; Ajouter\u00a0le ballon avec une m\u00e9thode:<\/p>\n<pre class=\"lang:swift decode:true\">   func ajouterBallon(){\n        ballon = SKSpriteNode(imageNamed: \"balle\")\n        ballon.position = CGPoint(x:CGRectGetMidX(frame), y:frame.height - ballon.frame.height)\n        \/\/ ballon.physicsBody = SKPhysicsBody(circleOfRadius: ballon.frame.size.width\/2)\n        self.addChild(ballon)\n    }  \/\/ ajouterBallon<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.2<\/strong>\u00a0<\/span>&#8211; Ajoutons le code suivant dans la m\u00e9thode ajouterBallon pour ajouter un corps physique au ballon:<\/p>\n<pre class=\"lang:swift decode:true\">        ballon.physicsBody = SKPhysicsBody(circleOfRadius: ballon.frame.size.width\/2)\n<\/pre>\n<p>Documentation Apple pour\u00a0<a href=\"https:\/\/developer.apple.com\/library\/IOs\/documentation\/SpriteKit\/Reference\/SKPhysicsBody_Ref\/index.html\">SKPhysicsBody<\/a><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.3<\/strong>\u00a0<\/span>&#8211; Testons l&rsquo;application.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2123\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/d8s0e.gif\" alt=\"d8s0e\" width=\"260\" height=\"479\" \/><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Maintenant que le ballon a un corps physique, il sera\u00a0soumis \u00e0 une force gravitationnelle de\u00a0<span style=\"color: #222222;\">9,78 m\/s\u00b2. \u00a0Pour ce que cela repr\u00e9sente dans un univers de 6 pouces. \u00a0<\/span><br \/>\nIl est possible de modifier\u00a0la gravit\u00e9 par programmation.<br \/>\n&nbsp;<\/p>\n<hr \/>\n<p>Voici une liste des constructeurs disponibles pour cr\u00e9er un corps physique:<\/p>\n<h3>\u00c0 partir d&rsquo;un sprite<\/h3>\n<ul>\n<li>bodyWithCircleOfRadius:<\/li>\n<li>bodyWithCircleOfRadius:center:<\/li>\n<li>bodyWithRectangleOfSize:<\/li>\n<li>bodyWithRectangleOfSize:center:<\/li>\n<li>bodyWithBodies:<\/li>\n<li>bodyWithPolygonFromPath:<\/li>\n<li>bodyWithTexture:size:<\/li>\n<li>bodyWithTexture:alphaThreshold:size:<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h3>\u00c0 partir d&rsquo;une forme vide<\/h3>\n<ul>\n<li>bodyWithEdgeLoopFromRect:<\/li>\n<li>bodyWithEdgeFromPoint:toPoint:<\/li>\n<li>bodyWithEdgeLoopFromPath:<\/li>\n<li>bodyWithEdgeChainFromPath:<\/li>\n<\/ul>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.4<\/strong>\u00a0<\/span>&#8211; \u00a0Ajoutons, au bas de la sc\u00e8ne, une palette de jeu:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/  Zone des propri\u00e9t\u00e9s de la classe de la sc\u00e8ne\n    var palette:SKSpriteNode!\n    func ajouterPalette(\/*size:CGSize*\/)\n    {\n    \/\/ Cr\u00e9er une palette\n    palette = SKSpriteNode(imageNamed:\"rectangle\")\n    \/\/ La positionner\n    palette.position = CGPointMake(size.width\/2, palette.size.height * 2);\n    \/\/ Lui ajouter un corps physique\n    palette.physicsBody = SKPhysicsBody(rectangleOfSize: palette.frame.size)\n    \/\/ \u00c0 Faire: Soustraire l'objet \u00e0 la gravit\u00e9 de la sc\u00e8ne\n    \/\/ palette.physicsBody!.dynamic = false\n    \/\/ Ajouter \u00e0 ;a sc\u00e8ne\n    self.addChild(palette)\n    } \/\/ ajouterPalette<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: \u00a0En ex\u00e9cutant le projet, nous allons remarquer que les deux objets vont tomber hors de la sc\u00e8ne.<br \/>\n<span style=\"color: #008000;\"><strong>Solution<\/strong><\/span>: Il faut soustraire la palette \u00e0 la gravit\u00e9.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.5<\/strong>\u00a0<\/span>&#8211; \u00a0Enlevons le commentaire devant la ligne suivante:<\/p>\n<pre class=\"lang:swift decode:true\">    palette.physicsBody!.dynamic = false<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: &lsquo;physicsBody&rsquo; est une optionnelle.<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.6<\/strong>\u00a0<\/span>&#8211; Testons l&rsquo;application.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2267\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/dyvap.gif\" alt=\"dyvap\" width=\"260\" height=\"479\" \/><br \/>\n&nbsp;<br \/>\nRemarquez que tr\u00e8s peu \u00e9nergie est retourn\u00e9 \u00e0 la balle suite \u00e0 l&rsquo;impact avec la palette.<br \/>\nLa classe SKPhysicsBody propose les propri\u00e9t\u00e9s suivantes pour le contr\u00f4le des diff\u00e9rentes r\u00e8gles du corps physique.<\/p>\n<ul>\n<li>mass<\/li>\n<li>density<\/li>\n<li>area<\/li>\n<li>friction<\/li>\n<li>restitution<\/li>\n<li>linearDamping<\/li>\n<li>angularDamping<\/li>\n<\/ul>\n<p>Note: Voir la <a href=\"https:\/\/developer.apple.com\/library\/IOs\/documentation\/SpriteKit\/Reference\/SKPhysicsBody_Ref\/index.html\">documentation<\/a> d&rsquo;Apple.<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.7<\/strong>\u00a0<\/span>&#8211; Modifions les propri\u00e9t\u00e9s\u00a0physiques de la balle<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Dans ajouterBalle(), avant l'ajout \u00e0 la sc\u00e8ne.\n        \/\/ physicsBody est une optionnelle\n        if let physique = ballon.physicsBody {\n            physique.restitution = 1.0      \/\/ L'objet va rebondir avec la m\u00eame force qu'\u00e0 l'impact.\n            physique.friction =  0.5        \/\/ Simule de la friction au contact.\n            physique.linearDamping = 0.1    \/\/ Simule de la friction (dans l'air, l'eau, ...) en diminuant la v\u00e9locit\u00e9 de l'objet.\n            physique.allowsRotation = false\n        }\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.8<\/strong>\u00a0<\/span>&#8211; Testons l&rsquo;application.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2268\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/dyvwr.gif\" alt=\"dyvwr\" width=\"260\" height=\"479\" \/><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>D\u00e9placement de la palette de jeu<\/h1>\n<p><span style=\"color: #ff0000;\"><strong>Action 2.9<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons la m\u00e9thode suivante \u00e0 la classe de la sc\u00e8ne:<\/p>\n<pre class=\"lang:swift decode:true\">    override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {\n        for touch: AnyObject in touches {\n            var localisation:CGPoint = touch.locationInNode(self)\n            palette.position = localisation\n        } \/\/ for touch\n    } \/\/ touchesMoved()<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>:\u00a0Le point centre de la palette sera renseign\u00e9 par le point de contact de l&rsquo;\u00e9cran.<br \/>\n<span style=\"color: #ff0000;\"><strong><br \/>\nAction 2.10<\/strong>\u00a0<\/span>&#8211; Testons l&rsquo;application.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2269\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/dyweo.gif\" alt=\"dyweo\" width=\"260\" height=\"479\" \/><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: un &lsquo;d\u00e9placement&rsquo;, sur n&rsquo;importe lequel des objets de la sc\u00e8ne, provoquera le d\u00e9placement de la palette.<br \/>\nLimitons le d\u00e9placement, sur l&rsquo;axe des &lsquo;y&rsquo;, \u00e0 la valeur de d\u00e9part de la palette.<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.11<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons le code suivant \u00e0 la classe <strong>touchesMoved<\/strong>:<\/p>\n<pre class=\"lang:swift mark:2 decode:true\" title=\"Ajouter seulement la ligne 2\">            var localisation:CGPoint = touch.locationInNode(self)\n            localisation.y = palette.position.y\n            palette.position = localisation\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.12<\/strong>\u00a0<strong>&#8211;\u00a0\u00c0 r\u00e9aliser en laboratoire: \u00a0<\/strong><\/span>Modifier le code pour que la palette ne sorte pas, en partie, de la sc\u00e8ne (axe de &lsquo;x&rsquo;)<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2271\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/dywvx.gif\" alt=\"dywvx\" width=\"260\" height=\"479\" \/><br \/>\n&nbsp;<br \/>\n<span style=\"color: #000000;\">[expand title=\u00a0\u00bbAfficher la solution\u00a0\u00bb]<\/span><\/p>\n<pre class=\"lang:swift decode:true\">            \/\/ G\u00e9rer le d\u00e9bordement de l'axe des x.\n            if (localisation.x &lt; palette.size.width \/ 2) {\n                localisation.x = palette.size.width \/ 2;\n            }  \/\/ Trop \u00e0 gauche.\n            if (localisation.x &gt; size.width - (palette.size.width\/2)) {\n                localisation.x = size.width - (palette.size.width\/2);\n            }  \/\/ Trop \u00e0 droite.\n            palette.position = localisation\n<\/pre>\n<p><span style=\"color: #000000;\">[\/expand]<\/span><\/p>\n<hr \/>\n<h1>Emprisonner la balle dans un univers ferm\u00e9<\/h1>\n<p>Pr\u00e9sentement, il n&rsquo;y a pas de fronti\u00e8re, \u00e0 laquelle la balle peut se butter. \u00a0Nous adressons cette situation, en ajoutant un corps physique \u00a0\u00e0 la sc\u00e8ne.<br \/>\n<span style=\"color: #ff0000;\"><strong><br \/>\nAction 2.13<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons la m\u00e9thode suivante \u00e0 la classe de la sc\u00e8ne:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Lancer cette m\u00e9thode dans didMoveToView()\n    func preparerLaScene(){\n        \/\/ Changer la couleur de la sc\u00e8ne\n        backgroundColor = UIColor(red: 0, green: 0, blue: 140\/255, alpha: 1)\n        \/\/ Donner un corps physique \u00e0 la sc\u00e8ne\n        physicsBody = SKPhysicsBody(edgeLoopFromRect: frame)\n        \/\/ println(frame)\n    } \/\/ preparerLaScene\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.14<\/strong>\u00a0<\/span>&#8211; Testons l&rsquo;application.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2272\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/dyxen.gif\" alt=\"dyxen\" width=\"260\" height=\"479\" \/><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: La balle perd beaucoup d&rsquo;\u00e9nergie \u00e0 chaque collision. \u00a0Nous pourrions modifier la &lsquo;restitution&rsquo; mais nous allons plut\u00f4t utiliser une autre approche, faire \u00e9voluer nos objets dans un univers \u00e0 gravit\u00e9 zero.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.15<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons le code suivant \u00e0 la m\u00e9thode preparerLaScene():<\/p>\n<pre class=\"lang:swift decode:true\">        physicsBody!.friction = 0.0\n        physicsWorld.gravity = CGVectorMake(0.0, 0.0)  \/\/ valeur par d\u00e9faut (0.0, -9.8)\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.16<\/strong>\u00a0<\/span>&#8211; Testons l&rsquo;application.<br \/>\n<strong><span style=\"color: #ff0000;\">Note:<\/span> <\/strong>Remarquez que la balle ne tombe plus.<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>Appliquons une direction\u00a0et une force &#8211; un vecteur &#8211; \u00a0\u00e0 la balle<\/h1>\n<p>Explication<br \/>\nPour appliquer une force \u00e0 un sprite, il faut utiliser sa m\u00e9thode <strong>applyImpulse<\/strong><span style=\"color: #000000;\">(unVecteur) et lui passer une direction et une force sous la forme d&rsquo;un vecteur d\u00e9crivant deltaX et deltaY.<\/span><br \/>\nLe vecteur est cr\u00e9\u00e9 avec la fonction\u00a0<strong>CGVectorMake<\/strong><span style=\"color: #000000;\">(<span style=\"color: #808000;\">deltaX<\/span><\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #808000;\">deltaY<\/span><span style=\"color: #000000;\">)<\/span><br \/>\n&nbsp;<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2312\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/physique01.png\" alt=\"physique01\" width=\"481\" height=\"743\" \/><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.17<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons le code suivant \u00e0 la m\u00e9thode ajouterBalle():<\/p>\n<pre class=\"lang:swift decode:true\">        \/\/ Attention: Il faut appliquer l'impulsion lorsque l'objet est dans un univers physique.\n        \/\/ Apr\u00e8s cette ligne:\n        \/\/ self.addChild(ballon)\n        let unVecteur = CGVectorMake(50, -20)\n        ballon.physicsBody!.applyImpulse(unVecteur)\n        println(\"Propuls\u00e9 sur un angle de : \\(atan2(unVecteur.dy,unVecteur.dx) * 180 \/ 3.141592)\")\n        \/\/ Ou bien:\n        println(\"Propuls\u00e9 sur un angle de : \\( Double(atan2(unVecteur.dy,unVecteur.dx) * 180) \/ M_PI)\")\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.18<\/strong>\u00a0<\/span>&#8211;\u00a0Testons l&rsquo;application.<br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: La balle perd de l&rsquo;\u00e9nergie sur impact des murs et lors d&rsquo;un contact avec la palette.<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.19<\/strong>\u00a0<\/span>&#8211;\u00a0Corrigeons la situation:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Dans la m\u00e9thode: ajouterBallon\n        if let physique = personnage.physicsBody {\n            physique.restitution    = 1.0\n            physique.friction       =  0\n            physique.linearDamping  = 0\n            physique.allowsRotation = false\n        }\n\/\/\n\/\/ Dans la m\u00e9thode: ajouterPalette\n       if let physique = palette.physicsBody {\n            physique.restitution    = 0.1\n            physique.friction       = 0.4\n         }\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 2.20<\/strong>\u00a0<\/span>&#8211;\u00a0Testons l&rsquo;application.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2273\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/dyziy.gif\" alt=\"dyziy\" width=\"260\" height=\"479\" \/><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: La balle peut se coincer avec\u00a0un angle de zero ou de 90. \u00a0Nous verrons plus loin comment r\u00e9gler ce probl\u00e8me.<\/p>\n<hr \/>\n<h1><\/h1>\n<h1>3\u00a0&#8211; D\u00e9tection de collisions<\/h1>\n<p>Le syst\u00e8me de physique de spriteKit propose des m\u00e9thodes et des propri\u00e9t\u00e9s pour la d\u00e9tection de collisions.<br \/>\nVoici la marche \u00e0 suivre pour mettre en place une d\u00e9tection de collision entre deux sprites:<\/p>\n<h3>Les \u00e9tapes de d\u00e9tection de collisions:<\/h3>\n<p><strong><span style=\"color: #808000;\">1 &#8211; D\u00e9finir des masques de bits des corps physiques:\u00a0categoryBitMask<\/span><\/strong><br \/>\n<span style=\"color: #ff0000;\"><strong>Action 3.1<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons, dans la section des propri\u00e9t\u00e9s de\u00a0la\u00a0classe de la sc\u00e8ne,\u00a0la d\u00e9claration suivante:<\/p>\n<pre class=\"lang:swift decode:true\">    \/\/ 32 cat\u00e9gories\n    struct categoriesPhysiquesDuJeu {\n        static let aucun        : UInt32 = 0\n        static let tous         : UInt32 = UInt32.max\n        static let balle        : UInt32 = 0b1       \/\/ 1\n        static let palette      : UInt32 = 0b10      \/\/ 2\n    } \/\/ categoriesPhysiquesDuJeu<\/pre>\n<p>&nbsp;<br \/>\n<strong><span style=\"color: #808000;\">2 &#8211; Renseigner les masques:\u00a0\u00a0&lsquo;<strong>categoryBitMask<\/strong><strong>&lsquo; et\u00a0<\/strong>&lsquo;contactTestBitMask&rsquo;\u00a0<\/span><\/strong><br \/>\n<span style=\"color: #ff0000;\"><strong>Action 3.2a<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons le code suivant \u00e0 la m\u00e9thode ajouterBallon:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Dans ajouterBallon:\n            physique.categoryBitMask    = categoriesPhysiquesDuJeu.balle\n            physique.contactTestBitMask = categoriesPhysiquesDuJeu.palette \/\/ | categoriesPhysiquesDuJeu.autre | categoriesPhysiquesDuJeu.autre\n<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Action 3.2b<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons le code suivant \u00e0 la m\u00e9thode ajouterPalette:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Dans ajouterPalette:\n            physique.categoryBitMask    = categoriesPhysiquesDuJeu.palette\n<\/pre>\n<p>&nbsp;<br \/>\n<strong><span style=\"color: #808000;\">3 &#8211; Mise en place et programmation du &lsquo;contactDelegate&rsquo;:<\/span><\/strong><\/p>\n<ul>\n<li>souscrire au protocole <strong>SKPhysicsContactDelegate<\/strong><\/li>\n<li>renseigner le <strong>delegate<\/strong><\/li>\n<li>impl\u00e9menter la m\u00e9thode\u00a0<strong>didBeginContact<\/strong><\/li>\n<\/ul>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 3.3<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons le code suivant \u00e0 la\u00a0classe de la sc\u00e8ne (attention aux\u00a03\u00a0\u00e9tapes):<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ 1 - Abonner la sc\u00e8ne au protocole\nclass GameScene: SKScene, SKPhysicsContactDelegate\n\/\/ 2 - renseigner le delegate\n   func preparerLaScene(){\n        ...\n        physicsWorld.contactDelegate = self\n    } \/\/ preparerLaScene\n\/\/ 3 - Programmer la m\u00e9thode didBeginContact\n    func didBeginContact(contact: SKPhysicsContact) {\n        println(\"Il y a eu contact entre deux objets\")\n        \/\/println(\"Il y a eu contact entre: \\(contact.bodyA) et \\(contact.bodyB)\")\n        \/\/println(\"Il y a eu contact entre: \\(contact.bodyA.node!.name!) et \\(contact.bodyB.node!.name!)\")\n    }\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 3.4<\/strong>\u00a0<\/span>&#8211;\u00a0Testons l&rsquo;application.<br \/>\nR\u00e9sultat dans la console:<\/p>\n<blockquote><p>Il y a eu contact entre deux objets<br \/>\nIl y a eu contact entre deux objets<br \/>\nIl y a eu contact entre deux objets<br \/>\nIl y a eu contact entre deux objets<\/p><\/blockquote>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Exercice<\/strong><\/span>: Nommez le ballon, la palette et la sc\u00e8ne pour obtenir:<\/p>\n<blockquote><p>Il y a eu contact entre: La sc\u00e8ne et Le ballon<br \/>\nIl y a eu contact entre: La palette et Le ballon<br \/>\nIl y a eu contact entre: La sc\u00e8ne et Le ballon<br \/>\nIl y a eu contact entre: La palette et Le ballon<br \/>\nIl y a eu contact entre: La sc\u00e8ne et Le ballon<br \/>\n&#8230;<br \/>\n<b>\u00a0<\/b><\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<hr \/>\n<h1>D\u00e9terminer les objets impliqu\u00e9s dans une\u00a0collision<\/h1>\n<p>La m\u00e9thode <strong>didBeginContact<\/strong> va recevoir une r\u00e9f\u00e9rence aux deux objets impliqu\u00e9s dans la collision: \u00a0<strong>contact.bodyA<\/strong> et\u00a0<strong>contact.bodyB<\/strong>.<br \/>\nEn testant la valeur de\u00a0<strong>.categoryBitMask<\/strong> il sera possible de d\u00e9terminer les objets re\u00e7us.<br \/>\nNous avons donn\u00e9 au personnage (ballon) la plus petite valeur pour son\u00a0masque de \u00a0cat\u00e9gorie. \u00a0En testant la taille du masque des deux objets re\u00e7us, il sera possible de d\u00e9terminer quel objet entre bodyA et bodyB est le personnage; celui avec la plus petite valeur de masque.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 3.5<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons le code suivant \u00e0 la m\u00e9thode <strong>didBeginContact<\/strong>:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Dans la m\u00e9thode: didBeginContact()\n        var pasLaBalle:SKPhysicsBody\n        var laBalle:SKPhysicsBody\n        \/\/ La balle a la plus petite valeur de masque.\n        \/\/ D\u00e9terminons quel objet est la balle\n        if (contact.bodyA.categoryBitMask &lt; contact.bodyB.categoryBitMask) {\n            pasLaBalle = contact.bodyB;\n            laBalle = contact.bodyA;\n        } else {\n            pasLaBalle = contact.bodyA;\n            laBalle = contact.bodyB;\n        }  \/\/ D\u00e9terminer quel objet est la balle\n        \/\/ La balle a touch\u00e9 la palette\n        if pasLaBalle.categoryBitMask == categoriesPhysiquesDuJeu.palette {\n            println(\"La balle a touch\u00e9 la palette\")\n            \/\/println(\"La balle a touch\u00e9 la palette \u00e0 la position: \\(laBalle.node?.position)\")\n        } \/\/ if pasLaBalle.categoryBitMask\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a03.6<\/strong>\u00a0<\/span>&#8211;\u00a0Testons l&rsquo;application.<br \/>\nR\u00e9sultat dans la console:<\/p>\n<blockquote><p>La balle a touch\u00e9 la palette<br \/>\nLa balle a touch\u00e9 la palette<br \/>\nLa balle a touch\u00e9 la palette<br \/>\nLa balle a touch\u00e9 la palette<\/p><\/blockquote>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Pour indiquer qu&rsquo;un sprite peut entrer en collision avec plusieurs autres sprites, il faut fusionner les bits de masque avec l&rsquo;op\u00e9rateur &lsquo;|\u00a0\u00bb &#8211; OR bitWise &#8211; et placer le r\u00e9sultat dans <strong>unSpriteATester.contactTestBitMask<\/strong>.<br \/>\nPar exemple,<\/p>\n<blockquote>\n<p style=\"color: #539aa4;\"><span style=\"color: #000000;\">corpsPhysiqueDuBallon.<\/span><span style=\"color: #703daa;\">contactTestBitMask<\/span><span style=\"color: #000000;\"> = <\/span>categoriesPhysiquesDuJeu<span style=\"color: #000000;\">.palette | <\/span>categoriesPhysiquesDuJeu<span style=\"color: #000000;\">.insecte | <\/span>categoriesPhysiquesDuJeu<span style=\"color: #000000;\">.bordure_ecran\u00a0|<\/span><span style=\"color: #1d9421;\">\u00a0<span style=\"color: #008080;\">categoriesPhysiquesDuJeu.bas_ecran<\/span>\u00a0<\/span><\/p>\n<p style=\"color: #539aa4;\">\n<\/blockquote>\n<h1 style=\"color: #539aa4;\"><\/h1>\n<hr \/>\n<h1 style=\"color: #539aa4;\"><span style=\"color: #000000;\">Les actions &#8211; SKAction<\/span><\/h1>\n<p>Il est possible, avec\u00a0<strong>spriteKit<\/strong>, de programmer des actions.<br \/>\nPar exemple,<\/p>\n<ul>\n<li>d\u00e9placer un sprite,<\/li>\n<li>appliquer un effet de fondu,<\/li>\n<li>jouer un effet sonore,<\/li>\n<li>&#8230;<\/li>\n<\/ul>\n<p>Les actions sont programm\u00e9es grace \u00e0 la classe &lsquo;<strong>SKAction<\/strong>&lsquo;.<br \/>\n&nbsp;<\/p>\n<h3>Ajouter un effet sonore suite \u00e0 la collision<\/h3>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 3.7<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons le code suivant \u00e0 la m\u00e9thode\u00a0<strong>didBeginContact<\/strong>:<\/p>\n<pre class=\"lang:swift mark:4-5 decode:true\">        \/\/ La balle a touch\u00e9 la palette\n        if pasLaBalle.categoryBitMask == categoriesPhysiquesDuJeu.palette {\n            println(\"La balle a touch\u00e9 la palette\")\n            let playSFX = SKAction.playSoundFileNamed(\"jump.wav\", waitForCompletion:false)\n            runAction(playSFX)\n         } \/\/ if pasLaBalle.categoryBitMask\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a03.8<\/strong>\u00a0<\/span>&#8211;\u00a0Testons l&rsquo;application.<br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Vous devriez entendre un son \u00e0 chaque fois que le personnage entre en collision avec la palette de jeu.<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>4\u00a0&#8211; Ajoutons les insectes<\/h1>\n<p>\u00c0 cette \u00e9tape du projet, nous devrions \u00eatre en mesure d&rsquo;ajouter des insectes au haut de la sc\u00e8ne.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a04.1<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons un nouveau masque physique de bits, permettant de d\u00e9tecter une collision entre la balle et un insecte :<\/p>\n<pre class=\"lang:swift mark:6 decode:true\">   struct categoriesPhysiquesDuJeu {\n        static let aucun        : UInt32 = 0\n        static let tous         : UInt32 = UInt32.max\n        static let balle        : UInt32 = 0b1       \/\/ 1\n        static let palette      : UInt32 = 0b10      \/\/ 2\n        static let insecte      : UInt32 = 0b100     \/\/ 4\n    } \/\/ categoriesPhysiquesDuJeu\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action\u00a04.2<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons la m\u00e9thode suivante, pour la cr\u00e9ation\u00a0d&rsquo;insectes au haut de l&rsquo;\u00e9cran;<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Note: Lancer la m\u00e9thode dans didMoveToView()\n\/\/ \u00c0 ajouter dans les propri\u00e9t\u00e9s de la sc\u00e8ne\n        let MARGE_HAUT:CGFloat = 70\n        let NB_INSECTES_PAR_LIGNE = 6\n        var nbNiveau = 2\n        var nbPoints = 0\n        var nbVies = 3\n    func ajouterInsectes(){\n        let nbInsectesSurEcran = nbNiveau * NB_INSECTES_PAR_LIGNE\n        let fichierInsect = \"bug0\\(nbNiveau)\"\n        for ligne in 0..&lt;nbNiveau {\n            for indiceInsect in 1...NB_INSECTES_PAR_LIGNE {\n                let insecte = SKSpriteNode(imageNamed:fichierInsect)\n                insecte.physicsBody = SKPhysicsBody(rectangleOfSize: insecte.frame.size)\n                if let physique = insecte.physicsBody {\n                    physique.dynamic            = false\n                    physique.categoryBitMask    = categoriesPhysiquesDuJeu.insecte\n                }\n                let xPos = insecte.size.width * CGFloat(indiceInsect) - 15;\n                let yPos = size.height - insecte.size.height * CGFloat(ligne) - MARGE_HAUT + 4;\n                insecte.position = CGPointMake(xPos, yPos);\n                addChild(insecte)\n            } \/\/ for indiceInsect\n        } \/\/ ligne\n    }  \/\/ ajouterInsectes()<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Le nombre de lignes d&rsquo;insectes est fonction de la valeur de la variable nbNiveau. \u00a0Par exemple, au niveau 3, il y aura trois lignes d&rsquo;insectes.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 4.3<\/strong>\u00a0<\/span>&#8211;\u00a0Testons l&rsquo;application.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2277\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/tim.briques.2.01.png\" alt=\"tim.briques.2.01\" width=\"321\" height=\"591\" \/><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: La balle est coinc\u00e9e entre les insectes.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 4.4<\/strong>\u00a0<\/span>&#8211;\u00a0Modifions la position de d\u00e9part de la balle &#8211; ainsi que son image:<\/p>\n<pre class=\"lang:swift decode:true\">        ballon = SKSpriteNode(imageNamed: \"lezard50px\")\n        ballon.position = CGPoint(x:ballon.frame.size.width, y:frame.height - 300)  \/\/ Id\u00e9alement, placer le ballon sous les insectes...\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 4.5<\/strong>\u00a0<\/span>&#8211;\u00a0Testons l&rsquo;application avec des valeurs entre 1 et 6 pour la variable\u00a0<strong>nbNiveau<\/strong>.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong><strong>Action 4.6<\/strong>\u00a0&#8211;\u00a0\u00c0 faire en laboratoire: \u00a0<\/strong><\/span>Vous devez programmer la d\u00e9tection de collisions entre le ballon\u00a0et un insecte puis,\u00a0retirer l&rsquo;insecte de la sc\u00e8ne. \u00a0Indice: \u00a0&lsquo;pasLaBalle.<span style=\"color: #703daa;\">node!.removeFromParent()&rsquo;<\/span><br \/>\nR\u00e9sultat:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2280\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/dz50a.gif\" alt=\"dz50a\" width=\"260\" height=\"479\" \/><br \/>\n<span style=\"color: #000000;\">[expand title=\u00a0\u00bbAfficher la solution\u00a0\u00bb]<\/span><\/p>\n<pre class=\"lang:swift decode:true\">         \/\/ dans ajouterBallon\n            physique.contactTestBitMask = categoriesPhysiquesDuJeu.palette | categoriesPhysiquesDuJeu.insecte\n        \/\/ dans didBeginContact\n        \/\/ La balle a touch\u00e9 un insecte\n        if pasLaBalle.categoryBitMask == categoriesPhysiquesDuJeu.insecte {\n            println(\"La balle a touch\u00e9 un insecte \u00e0 la position: \\(laBalle.node?.position)\")\n            let playSFX = SKAction.playSoundFileNamed(\"jump.wav\", waitForCompletion:false)\n            runAction(playSFX)\n            pasLaBalle.node?.removeFromParent()\n        } \/\/ if pasLaBalle.categoryBitMask == insecte\n<\/pre>\n<p><span style=\"color: #000000;\">[\/expand]<\/span><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>Ligne de statut pour l&rsquo;application &#8211; vies et niveau<\/h1>\n<p>&nbsp;<br \/>\nNous allons ajouter, au haut de l&rsquo;\u00e9cran, une zone d&rsquo;affichage permettant de connaitre la valeur des variables nbPoints, nbVies et nbNiveau.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 4.7<\/strong>\u00a0<\/span>&#8211; Ajoutons la propri\u00e9t\u00e9s suivante \u00e0 la classe de la sc\u00e8ne principale:<\/p>\n<pre class=\"lang:swift decode:true\">    var labelStatut:SKLabelNode!\n<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 4.8<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons les m\u00e9thodes suivantes \u00e0 la classe de la sc\u00e8ne principale:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ 1 - Ajouter\n    \/**\n        Ajoutera une instance de labelStatut \u00e0 la sc\u00e8ne: Voir actualiserStatut()\n        @param aucun\n    *\/\n    func ajouterStatut()\n    {\n        labelStatut = SKLabelNode(fontNamed:\"Chalkduster\") \/\/ [SKLabelNode labelNodeWithFontNamed:@\"Chalkduster\"];\n        labelStatut.fontSize = 14;\n        labelStatut.position = CGPointMake(CGRectGetWidth(self.frame)\/2, CGRectGetHeight(self.frame) - 20);\n        addChild(labelStatut)\n        actualiserStatut()\n    }  \/\/ ajouterStatut()\n    \/**\n        Affiche, sur la sc\u00e8ne, des informations sur le niveau, les vies restantes et le nombre de points accumul\u00e9s.\n    @param aucun\n    *\/\n    func actualiserStatut()\n    {\n        labelStatut.text = NSString(format:\"Points: %06d  Niveau: %d  Vies: %d\", nbPoints, nbNiveau, nbVies)\n    } \/\/ actualiserStatut\n\/\/ 2 - dans : didMoveToView(view: SKView), remplacer ajouterTitre() par:\n        ajouterStatut()<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: J&rsquo;ai utilis\u00e9 NSString(format:) pour pouvoir contr\u00f4ler\u00a0le nombre de &lsquo;0&rsquo; dans le pointage. \u00a0%06d assure que les points seront affich\u00e9s avec 6 caract\u00e8res. \u00a0Si le nombre est petit, alors des z\u00e9ros seront ins\u00e9r\u00e9s \u00e0 gauche du nombre.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 4.9<\/strong>\u00a0<\/span>&#8211;\u00a0Testons l&rsquo;application:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2284\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/tim.briques.2.02.png\" alt=\"tim.briques.2.02\" width=\"376\" height=\"691\" \/><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong><strong>Action 4.10<\/strong>\u00a0&#8211; \u00c0 faire en laboratoire: \u00c0 chaque collision avec un insecte, ajouter 5 points au total.<\/strong><\/span><br \/>\n<span style=\"color: #000000;\">[expand title=\u00a0\u00bbAfficher la solution\u00a0\u00bb]<\/span><\/p>\n<pre class=\"lang:swift decode:true\">\/\/ dans:    if pasLaBalle.categoryBitMask == categoriesPhysiquesDuJeu.insecte {\n               nbPoints+=5\n               actualiserStatut()\n<\/pre>\n<p><span style=\"color: #000000;\">[\/expand]<\/span><br \/>\n<span style=\"color: #000000;\">\u00a0<\/span><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>Tester la collision au sol<\/h1>\n<p>Nous allons maintenant ajouter une mince rectangle, avec un corps physique, au bas de l&rsquo;\u00e9cran pour pouvoir d\u00e9terminer que le personnage (ballon) a manqu\u00e9 la palette.<br \/>\nDans ce cas, il faudra retrancher un point de vie du total.<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 4.11<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons la m\u00e9thode suivante \u00e0 la classe de la sc\u00e8ne principale:<\/p>\n<pre class=\"lang:swift decode:true\">    \/\/ 1 - dans : struct categoriesPhysiquesDuJeu {\n        static let bas_ecran    : UInt32 = 0b1000    \/\/ 8\n    \/\/ 2 - dans : didMoveToView(view: SKView)\n        ajouterBasEcran()\n    \/\/ 3 - Ajouter\n    \/**\n        Tracer un rectangle (0,1,largeurEcran, 3) au bas de l'\u00e9cran.\n        Sert \u00e0 d\u00e9tecter, via le 'bitMask', si le personnage manque la palette.\n    *\/\n    func ajouterBasEcran()\n    {\n        let basEcran = SKNode.node()\n        basEcran.physicsBody = SKPhysicsBody(edgeFromPoint: CGPointMake(0, 1), toPoint:CGPointMake(size.width, 3))\n        basEcran.physicsBody!.categoryBitMask = categoriesPhysiquesDuJeu.bas_ecran  \/\/ \u00e0 ajouter \u00e0 la struct des 'categoriesPhysiques'\n        addChild(basEcran)\n    } \/\/ ajouterBasEcran<\/pre>\n<p>&nbsp;<br \/>\n<strong><span style=\"color: #ff0000;\"><strong>Action 4.12<\/strong>\u00a0<\/span><span style=\"color: #ff0000;\">&#8211;\u00a0\u00c0 faire en laboratoire: \u00c0 chaque collision avec le bas de l&rsquo;\u00e9cran, soustraire 1 \u00e0\u00a0nbVies et r\u00e9afficher le statut.<\/span><\/strong><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Pensez; \u00e0 ajuster le masque de collisions du personnage, \u00e0 retirer le ballon, \u00e0 ajouter le ballon.<br \/>\n<strong>R\u00e9sultat d\u00e9sir\u00e9<\/strong>:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2288\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/e1bpu.gif\" alt=\"e1bpu\" width=\"260\" height=\"478\" \/><br \/>\n<span style=\"color: #000000;\">[expand title=\u00a0\u00bbAfficher la solution\u00a0\u00bb]<\/span><\/p>\n<pre class=\"lang:swift decode:true\">\/\/ 1 - dans: ajouterBallon\n            physique.contactTestBitMask = categoriesPhysiquesDuJeu.palette | categoriesPhysiquesDuJeu.insecte  | categoriesPhysiquesDuJeu.bas_ecran\n\/\/ 2 - dans: didBeginContact()\n       \/\/ La balle a touch\u00e9 le bas de l'\u00e9cran\n        if pasLaBalle.categoryBitMask == categoriesPhysiquesDuJeu.bas_ecran {\n            laBalle.node?.removeFromParent()\n            let playSFX = SKAction.playSoundFileNamed(\"jump.wav\", waitForCompletion:false)\n            runAction(playSFX)\n            nbVies--\n            actualiserStatut()\n            ajouterBallon()\n        } \/\/ if pasLaBalle.categoryBitMask == bas_ecran\n<\/pre>\n<p><span style=\"color: #000000;\">[\/expand]<\/span><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>5 &#8211; Passer \u00e0 une autre sc\u00e8ne<\/h1>\n<p>Un jeu peut proposer plusieurs sc\u00e8nes.<br \/>\nLa m\u00e9thode <strong>presentScene<\/strong> de l&rsquo;optionnelle &lsquo;<strong>view<\/strong>&lsquo; permet de passer \u00e0 une autre sc\u00e8ne du jeu.<br \/>\nSi pr\u00e9sente, la m\u00e9thode &lsquo;<strong>didMoveToView<\/strong>&lsquo; de la destination sera ex\u00e9cut\u00e9e.<br \/>\n<span style=\"color: #ff0000;\"><strong><br \/>\nNote<\/strong><\/span>: La valeur des variables n&rsquo;est pas pr\u00e9serv\u00e9e lors du passage d&rsquo;une sc\u00e8ne \u00e0 l&rsquo;autre.<br \/>\nPour\u00a0conserver l&rsquo;\u00e9tat des certaines variables, il faut utiliser des variables statiques ou bien passer des param\u00e8tres entre les sc\u00e8nes.<\/p>\n<h3><\/h3>\n<h3>La sc\u00e8ne \u00ab\u00a0Fin de la partie\u00a0\u00bb<\/h3>\n<p><span style=\"color: #ff0000;\"><strong>Action 5.1<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons une nouvelle classe au projet:<\/p>\n<pre class=\"lang:swift mark:8 decode:true\">\/\/  FinPartie.swift\nimport SpriteKit\nclass FinPartie: SKScene {\n    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {\n        \/\/ retour \u00e0 la sc\u00e8ne pr\u00e9c\u00e9dente\n        let debut = GameScene(size: self.size)\n        view?.presentScene(debut, transition: SKTransition.doorsOpenHorizontalWithDuration(0.5))\n    }  \/\/ touchesBegan\n} \/\/ class FinPartie<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: \u00a0Il est important de passer la taille de la sc\u00e8ne de d\u00e9part (\u00e0 la ligne 8) entre les diff\u00e9rentes sc\u00e8nes sans quoi nous nous retrouverons avec une sc\u00e8ne de taille (0.1,0.1).<br \/>\n&nbsp;<\/p>\n<h3>Passer \u00e0 la sc\u00e8ne finDePartie<\/h3>\n<p><span style=\"color: #ff0000;\"><strong>Action 5.2<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons le m\u00e9thode suivante \u00e0 la classe de \u00a0la sc\u00e8ne principale:<\/p>\n<pre class=\"lang:swift decode:true\">\u001b    \/**\n      Permet de passer \u00e0 la sc\u00e8ne de fin de partie.\n      \u00c0 lancer, lorsque nbVies == 0.\n    *\/\n    func finDeLaPartie(){\n        \/\/ Passer \u00e0 une autre sc\u00e8ne\n        let uneScene = FinPartie(size: self.size)  \/\/ Cr\u00e9er une sc\u00e8ne taille == courante.\n        view?.presentScene(uneScene, transition: SKTransition.doorsOpenHorizontalWithDuration(0.5))\n    }  \/\/ finDeLaPartie()\n<\/pre>\n<p>&nbsp;<br \/>\n<strong style=\"color: #ff0000;\"><strong>Action 5.3<\/strong>\u00a0&#8211;\u00a0\u00c0 faire en laboratoire: Afficher la sc\u00e8ne &lsquo;FinPartie&rsquo;, lorsque nbVies == 0.<\/strong><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Il faut ajouter le texte suivant \u00e0 la sc\u00e8ne:<\/p>\n<blockquote><p>Fin de la partie<br \/>\nTouchez\u00a0l&rsquo;\u00e9cran pour recommencer.<\/p><\/blockquote>\n<p>&nbsp;<br \/>\n<strong>R\u00e9sultat d\u00e9sir\u00e9:<\/strong><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2290\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/e1eb0.gif\" alt=\"e1eb0\" width=\"260\" height=\"478\" \/><br \/>\n<span style=\"color: #000000;\">[expand title=\u00a0\u00bbAfficher la solution sur le test de nbVies\u00a0\u00bb]<\/span><\/p>\n<pre class=\"lang:swift decode:true\">\/\/ dans:    if pasLaBalle.categoryBitMask == categoriesPhysiquesDuJeu.bas_ecran {\n            \/\/ nbVies--\n             if nbVies == 0 {\n                finDeLaPartie()\n            }<\/pre>\n<p><span style=\"color: #000000;\">[\/expand]<\/span><br \/>\n<span style=\"color: #000000;\">\u00a0<\/span><br \/>\n<span style=\"color: #000000;\">[expand title=\u00a0\u00bbAfficher la solution pour le texte de la sc\u00e8ne FinPartie\u00a0\u00bb]<\/span><\/p>\n<pre class=\"lang:swift decode:true \">    func ajouterLeTexte(){\n        let unTitre = SKLabelNode(fontNamed:\"Arial\")\n        unTitre.text = \"Fin de la partie\";\n        unTitre.fontSize = 32;\n        unTitre.position = CGPoint(x:CGRectGetMidX(frame), y:CGRectGetMidY(frame) + unTitre.frame.height);\n        self.addChild(unTitre)\n        let unTitre2 = SKLabelNode(fontNamed:\"Arial\")\n        unTitre2.fontSize = 20;\n        unTitre2.text = \"Touchez l'\u00e9cran pour recommencer.\";\n        unTitre2.position = CGPoint(x:CGRectGetMidX(frame), y:CGRectGetMidY(frame) - unTitre.frame.height);\n        self.addChild(unTitre2)\n    }  \/\/ ajouterLeTexte()\n<\/pre>\n<p>&nbsp;<br \/>\n[\/expand]<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>\u00c0 faire en laboratoire<\/h1>\n<p><strong style=\"color: #ff0000;\">Afficher la sc\u00e8ne &lsquo;NiveauSuivant&rsquo;, pendant 2 sec., lorsque nbInsectes == 0.<\/strong><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Il faut ajouter et programmer la sc\u00e8ne &lsquo;NiveauSuivant&rsquo;.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #000000;\">[expand title=\u00a0\u00bbAfficher la solution pour la sc\u00e8ne ProchainNiveau\u00a0\u00bb]<\/span><\/p>\n<pre class=\"lang:swift decode:true\">import SpriteKit\nclass ProchainNiveau: SKScene {\n    override func didMoveToView(view: SKView) {\n        ajouterLeTexte()\n        NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: \"retour\", userInfo: nil, repeats: false)\n    } \/\/ didMoveToView()\n    func ajouterLeTexte(){\n        let unTitre = SKLabelNode(fontNamed:\"Arial\")\n        unTitre.text = \"Prochain niveau\";\n        unTitre.fontSize = 32;\n        unTitre.position = CGPoint(x:CGRectGetMidX(frame), y:CGRectGetMidY(frame) + unTitre.frame.height);\n        self.addChild(unTitre)\n    }  \/\/ ajouterLeTitre()\n    func retour(){\n        \/\/ retour \u00e0 la sc\u00e8ne pr\u00e9c\u00e9dente\n        let debut = GameScene(size: self.size)\n        view?.presentScene(debut, transition: SKTransition.doorsOpenHorizontalWithDuration(0.5))\n    } \/\/ retour()\n} \/\/ class ProchainNiveau<\/pre>\n<p><span style=\"color: #000000;\">[\/expand]<\/span><br \/>\n&nbsp;<br \/>\n<span style=\"color: #008000;\"><strong>Astuce<\/strong>: <span style=\"color: #000000;\">Pensez \u00e0 d\u00e9sactiver le test de collision avec le bas de l&rsquo;\u00e9cran pendant l&rsquo;\u00e9laboration de cette \u00e9tape.<\/span><\/span><br \/>\nIl faut g\u00e9rer le compteur d&rsquo;insectes lors d&rsquo;une collision avec le personnage:<\/p>\n<ul>\n<li>ajouter une propri\u00e9t\u00e9<\/li>\n<li>renseigner la propri\u00e9t\u00e9 dans la m\u00e9thode ajouterInsectes<\/li>\n<li>d\u00e9cr\u00e9menter la propri\u00e9t\u00e9 lors d&rsquo;une collision avec le personnage<\/li>\n<li>suite \u00e0 une collision, si == 0 alors augmenter la valeur de nbNiveau puis afficher &lsquo;NiveauSuivant&rsquo;<\/li>\n<\/ul>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Pour pr\u00e9server les points et le niveau, il faut utiliser des variables statiques.<br \/>\n<strong style=\"color: #008000;\">Astuce<\/strong><span style=\"color: #008000;\">: \u00a0<\/span>En swift, une variable statique doit-\u00eatre d\u00e9finie dans une structure &lsquo;<strong>struct<\/strong>&lsquo;:<\/p>\n<blockquote><p><span style=\"color: #c32275;\">struct<\/span> lesStatiques {<br \/>\n<span style=\"color: #c32275;\">\u00a0 \u00a0static<\/span> <span style=\"color: #c32275;\">var<\/span> nbNiveau = <span style=\"color: #0435ff;\">1<br \/>\n<\/span>\u00a0 \u00a0<span style=\"color: #c32275;\">static<\/span> <span style=\"color: #c32275;\">var<\/span> nbPoints = <span style=\"color: #0435ff;\">0<br \/>\n<\/span><span style=\"color: #000000;\">} <\/span>\/\/ lesStatiques<\/p><\/blockquote>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Pensez \u00e0 corriger les r\u00e9f\u00e9rences \u00e0 <strong>nbNiveau<\/strong> et <strong>nbPoints<\/strong><br \/>\n&nbsp;<br \/>\n<strong>R\u00e9sultat d\u00e9sir\u00e9:<\/strong><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2292\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/e1g0d.gif\" alt=\"e1g0d\" width=\"260\" height=\"478\" \/><br \/>\n&nbsp;<br \/>\n<span style=\"color: #000000;\">[expand title=\u00a0\u00bbAfficher la solution\u00a0\u00bb]<\/span><\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Effacer les propri\u00e9t\u00e9s:\n    var nbNiveau = 1\n    var nbPoints = 0\n\/\/ 1 - Ajouter les variables statiques\n    struct lesStatiques {\n        static var nbNiveau = 1\n        static var nbPoints = 0\n    } \/\/ lesStatiques\nNote: Corriger les references (6 erreurs) \u00e0 nbNiveau et nbPoints\n\/\/ 2 - Ajouter dans les propri\u00e9t\u00e9s\n   var nbInsectesSurEcran = 0\n\/\/ 3 - dans: ajouterInsectes\n  nbInsectesSurEcran = lesStatiques.nbNiveau * NB_INSECTES_PAR_LIGNE\n\/\/ 4 - Ajouter:\n     \/**\n    Permet de passer \u00e0 la sc\u00e8ne NiveauSuivant.\n    \u00c0 lancer, lorsque nbInsectesSurEcran == 0.\n    *\/\n    func prochainNiveau(){\n        \/\/ Passer \u00e0 une autre sc\u00e8ne\n        let uneScene = ProchainNiveau(size: self.size)  \/\/ Cr\u00e9er une sc\u00e8ne taille == courante.\n        view?.presentScene(uneScene, transition: SKTransition.doorsOpenHorizontalWithDuration(0.5))\n    }  \/\/ finDeLaPartie()\n\/\/ 5 - dans: La balle a touch\u00e9 un insecte\n   nbInsectesSurEcran--\n   if nbInsectesSurEcran == 0 {\n      lesStatiques.nbNiveau++\n      prochainNiveau()\n    }<\/pre>\n<p><span style=\"color: #000000;\">[\/expand]<\/span><br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>6 &#8211; Fonds d&rsquo;\u00e9cran et musique d&rsquo;ambiance<\/h1>\n<p>Nous allons ajouter de la musique d&rsquo;ambiance et un fond d&rsquo;\u00e9cran.<br \/>\nCes deux \u00e9l\u00e9ments seront fonction de <strong>nbNiveau<\/strong>.<br \/>\n<span style=\"color: #ff0000;\"><strong><br \/>\nAction 6.1<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons la m\u00e9thode suivante \u00e0 la classe de la sc\u00e8ne principale:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ **** NOTE: \u00c0 ajouter: import AVFoundation\n\/\/ **** NOTE: \u00c0 ajouter aux propri\u00e9t\u00e9s de la classe: var playerTrameSonore = AVAudioPlayer()\n\/\/ **** NOTE: \u00c0 ajouter \u00e0 didMoveToView() : ajouterFondEcran()\n    func ajouterFondEcran()\n        \/\/ *******************************************************************************\n    {\n        let fichierFondEcran = \"bg0\\(lesStatiques.nbNiveau)\"\n        let fichierMusiqueAmbiance = \"ambiance0\\(lesStatiques.nbNiveau)\"\n        \/\/ Cr\u00e9er un sprite \u00e0 partir du fichier image correspondant au niveau du jeu.\n        let background = SKSpriteNode(imageNamed: fichierFondEcran)\n        background.size = frame.size\n        background.position = CGPoint(x:CGRectGetMidX(frame), y:CGRectGetMidY(frame))\n        addChild(background)\n        \/\/ Ajouter une trame sonore - voir Labo Aquarium 7.6 pour le d\u00e9tail.\n        let URLTrameSonore = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(fichierMusiqueAmbiance, ofType: \"mp3\")!)\n        var error:NSError?\n        playerTrameSonore = AVAudioPlayer(contentsOfURL: URLTrameSonore, error: &amp;error)\n        playerTrameSonore.prepareToPlay()     \/\/ Charger le fichier son en m\u00e9moire\n        playerTrameSonore.numberOfLoops = -1  \/\/ Boucle \u00e0 l'infini avec une valeur n\u00e9gative\n        playerTrameSonore.volume = 0.2\n        playerTrameSonore.play()\n    } \/\/ ajouterFondEcran()<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 6.2<\/strong>\u00a0<\/span>&#8211;\u00a0Testons l&rsquo;application<br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Pour constater un changement\u00a0de trame sonore et d&rsquo;image de fond, il faut passez d&rsquo;un niveau \u00e0 l&rsquo;autre.<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>7 &#8211; Gestion de la d\u00e9t\u00e9rioration du vecteur du personnage<\/h1>\n<p>Vous avez peut-\u00eatre remarqu\u00e9, qu&rsquo;\u00e0 l&rsquo;occasion, l&rsquo;angle de d\u00e9placement du personnage est bloqu\u00e9 \u00e0 l&rsquo;horizontal ou \u00e0 la vertical.<br \/>\nPour corriger ce probl\u00e8me nous pourrions, lors d&rsquo;une collision, mesurer\u00a0l&rsquo;angle du personnage &#8211; unObjet.velocity.dy, et dx \u00a0&#8211; et le corriger au besoin.<br \/>\n<span style=\"color: #ff0000;\"><strong><br \/>\nAction 7.1<\/strong>\u00a0<\/span>&#8211; Ajoutons le code suivant dans didBeginContact:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ 1 - NOTE: ajouter le masque de bits suivant \u00e0:\n\/\/ struct categoriesPhysiquesDuJeu {\n   static let bordure_ecran: UInt32 = 0b10000   \/\/ 16\n\/\/ 2 - NOTE: modifier le masque de contact du ballon:\n       physique.contactTestBitMask = categoriesPhysiquesDuJeu.palette | categoriesPhysiquesDuJeu.insecte  | categoriesPhysiquesDuJeu.bas_ecran | categoriesPhysiquesDuJeu.bordure_ecran\n\/\/ 3 - NOTE: ajouter le test suivant dans didBeginContact()\n        \/\/ Le personnage a touch\u00e9 la bordure\n        if pasLaBalle.categoryBitMask == categoriesPhysiquesDuJeu.bordure_ecran {\n            let anglePersonnage = Double(atan2(laBalle.velocity.dy, laBalle.velocity.dx) * 180) \/ M_PI\n            println(\"Touch\u00e9 la bordure velo.dx = \\(laBalle.velocity.dx), velo.dy= \\(laBalle.velocity.dy) - angle = \\(anglePersonnage)\")\n            \/\/ Tester si l'angle de la trajectoire s'approche trop de la ligne horizontale.\n            \/\/ velocity.dY entre -30 et 30 retourne un angle trop droit qui risque de coincer le personnage\n            if (laBalle.velocity.dy &gt; -30 &amp;&amp; laBalle.velocity.dy &lt; 30) {\n                NSLog(\"Angle trop bas, r\u00e9ajustement...\");\n                laBalle.velocity = CGVectorMake(laBalle.velocity.dx, laBalle.velocity.dy + 400);\n            }  \/\/ Angle trop bas\n            \/\/ Tester si l'angle de la trajectoire s'approche trop de la ligne verticale.\n            \/\/ velocity.dx entre -5 et 5 retourne un angle trop droit qui risque de coincer le personnage\n            if (laBalle.velocity.dx &gt; -5 &amp;&amp; laBalle.velocity.dx &lt; 5) {\n                NSLog(\"Angle trop droit, r\u00e9ajustement...\");\n                laBalle.velocity = CGVectorMake(laBalle.velocity.dx + 100 , laBalle.velocity.dy);\n            }  \/\/ Angle trop droit\n        }  \/\/ Le personnage a touch\u00e9 la bordure de la sc\u00e8ne<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: \u00a0 \u00c0 vous d&rsquo;am\u00e9liorer le code pr\u00e9c\u00e9dent!<br \/>\nSi le personnage sort du cadre de la sc\u00e8ne, il peut \u00eatre replac\u00e9\u00a0de la fa\u00e7on suivante:<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 7.2<\/strong>\u00a0<\/span>&#8211; Ajoutons le code suivant \u00e0 la m\u00e9thode <strong>update<\/strong>:<\/p>\n<pre class=\"lang:swift decode:true\">    override func update(currentTime: CFTimeInterval) {\n        \/* Called before each frame is rendered *\/\n        if  ballon.position.x &lt; 0 ||\n            ballon.position.y &lt; 0 ||\n            ballon.position.x &gt; self.size.width ||\n            ballon.position.y &gt; self.size.height\n        {\n            ballon.removeFromParent()\n            ajouterBallon()\n        }\n     } \/\/ update()<\/pre>\n<p>&nbsp;<br \/>\n&nbsp;<\/p>\n<hr \/>\n<h1>8 &#8211; Ajoutons des particules<\/h1>\n<p>Xcode permet de cr\u00e9er et de configurer des particules en mode GUI.<br \/>\nCes particules pourront par la suite \u00eatre ajout\u00e9es \u00e0 une des sc\u00e8nes.<br \/>\n<span style=\"color: #ff0000;\"><strong>NOTE: \u00a0Ne pas faire cette \u00e9tape avec la version 6.0x de Xcode. \u00a0Un bug connu va corrompre votre projet.<\/strong><\/span><br \/>\n<span style=\"color: #ff0000;\"><strong>Utiliser\u00a0<\/strong><\/span><span style=\"color: #ff0000;\"><b>plut\u00f4t la version 6.1+ de Xcode.<\/b><\/span><br \/>\n<span style=\"color: #ff0000;\"><strong>Action 8.0.a<\/strong><\/span> &#8211; Ouvrir le projet, \u00e9tape 7 compl\u00e9t\u00e9e, et remplacer le contenu du fichier &lsquo;GameViewController.swift&rsquo; \u00a0par:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/  GameViewController.swift\n\/\/  TIM.Briques\nimport UIKit\nimport SpriteKit\nextension SKNode {\n    class func unarchiveFromFile(file : NSString) -&gt; SKNode? {\n        if let path = NSBundle.mainBundle().pathForResource(file, ofType: \"sks\") {\n            var sceneData = NSData(contentsOfFile: path, options: .DataReadingMappedIfSafe, error: nil)!\n            var archiver = NSKeyedUnarchiver(forReadingWithData: sceneData)\n            archiver.setClass(self.classForKeyedUnarchiver(), forClassName: \"SKScene\")\n            let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as GameScene\n            archiver.finishDecoding()\n            return scene\n        } else {\n            return nil\n        }\n    }\n}\nclass GameViewController: UIViewController {\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        println(\"viewDidLoad\")\n        if let scene = GameScene.unarchiveFromFile(\"GameScene\") as? GameScene {\n            println(\"GameScene.unarchiveFromFile('GameScene')\")\n            \/\/ Configure the view.\n            let skView = self.view as SKView\n            skView.showsFPS = true\n            skView.showsNodeCount = true\n            \/* Sprite Kit applies additional optimizations to improve rendering performance *\/\n            skView.ignoresSiblingOrder = true\n            \/* Set the scale mode to scale to fit the window *\/\n            scene.scaleMode = .AspectFill\n            scene.size = skView.bounds.size\n            skView.presentScene(scene)\n        } else\n        {\n            println(\"Erreur sur: GameScene.unarchiveFromFile('GameScene')\")\n        }\n    }\n    override func shouldAutorotate() -&gt; Bool {\n        return true\n    }\n    override func supportedInterfaceOrientations() -&gt; Int {\n        if UIDevice.currentDevice().userInterfaceIdiom == .Phone {\n            return Int(UIInterfaceOrientationMask.AllButUpsideDown.rawValue)\n        } else {\n            return Int(UIInterfaceOrientationMask.All.rawValue)\n        }\n    }\n    override func didReceiveMemoryWarning() {\n        super.didReceiveMemoryWarning()\n        \/\/ Release any cached data, images, etc that aren't in use.\n    }\n    override func prefersStatusBarHidden() -&gt; Bool {\n        return true\n    }\n}<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Une syntaxe diff\u00e9rente entre 6.01 et 6.1 provoque des erreurs lorsque nous ouvrons notre projet avec la version 6.1 de Xcode<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 8.0.b<\/strong><\/span>\u00a0&#8211;\u00a0Rempla\u00e7ons la ligne suivante:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ dans: func ajouterBasEcran() {\n       \/\/ REMPLACER: let basEcran = SKNode.node()  par,\n        let basEcran = SKNode()<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: Il ne devrait plus y avoir d&rsquo;erreurs dans le projet.<br \/>\n&nbsp;<\/p>\n<hr \/>\n<p><span style=\"color: #ff0000;\"><strong><br \/>\nAction 8.1<\/strong>\u00a0<\/span>&#8211;\u00a0Ajoutons un fichier de particules au projet:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2299\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/particules.01.png\" alt=\"particules.01\" width=\"733\" height=\"433\" \/><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 8.2<\/strong>\u00a0<\/span>&#8211; Renseignons le type de particule \u00e0 cr\u00e9er:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2300\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/particules.02.png\" alt=\"particules.02\" width=\"347\" height=\"172\" \/><br \/>\n<span style=\"color: #ff0000;\"><strong>Action 8.2b<\/strong> <\/span>&#8211; Nommons le fichier \u00a0\u00bb\u00a0&lsquo;etoiles.sks'\u00a0\u00bb.<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 8.3<\/strong>\u00a0<\/span>&#8211; Observons le r\u00e9sultat pr\u00e9sent\u00e9 dans l&rsquo;\u00e9diteur de Xcode.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2296\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/e1k33.gif\" alt=\"e1k33\" width=\"260\" height=\"260\" \/><br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: \u00a0Si vous ne voyez pas ce qui pr\u00e9c\u00e8de, assurez-vous que le fichier &lsquo;etoiles.sks&rsquo; est s\u00e9lectionn\u00e9 dans l&rsquo;explorateur du projet.<br \/>\n&nbsp;<br \/>\nIl y a de nombreuses propri\u00e9t\u00e9s permettant de changer l&rsquo;apparence et le comportement des particules.<br \/>\nLa fa\u00e7on la plus simple pour les modifier est d&rsquo;utiliser le panneau \u00a0&lsquo;inspecteur SKNode&rsquo;.<br \/>\n<span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: R\u00e9f\u00e9rez-vous \u00e0 la <a href=\"https:\/\/developer.apple.com\/library\/mac\/documentation\/IDEs\/Conceptual\/xcode_guide-particle_emitter\/ManipulatingtheParticleEmitter\/ManipulatingtheParticleEmitter.html\">documentation<\/a> d&rsquo;Apple \u00a0pour le d\u00e9tail de l&rsquo;\u00e9diteur de particules.<br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 8.4<\/strong>\u00a0<\/span>&#8211;\u00a0Ajustons les propri\u00e9t\u00e9s de notre particule:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2298\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/particules.03.png\" alt=\"particules.03\" width=\"375\" height=\"708\" \/><br \/>\n&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 8.5<\/strong>\u00a0<\/span>&#8211;\u00a0Programmons l&rsquo;affichage des particules suite \u00e0 une collision du personnage avec un insecte. \u00a0Ajoutons le m\u00e9thode suivante:<\/p>\n<pre class=\"lang:swift decode:true\">    \/**\n        Afficher des particules \u00e0 la position 'coordonnees'\n    *\/\n    func etincelles(var coordonnees:CGPoint)\n    {\n        let _etincelles = SKEmitterNode(fileNamed:\"etoiles.sks\")\n        _etincelles.position = coordonnees;\n        addChild(_etincelles)\n    }  \/\/ etincelles()<\/pre>\n<p>&nbsp;<br \/>\n<span style=\"color: #ff0000;\"><strong>Action 8.6<\/strong>\u00a0<\/span>&#8211; Ajoutons le code suivant \u00e0 la m\u00e9thode <strong>didBeginContact<\/strong>:<\/p>\n<pre class=\"lang:swift mark:4 decode:true\">       \/\/ La balle a touch\u00e9 un insecte\n        if pasLaBalle.categoryBitMask == categoriesPhysiquesDuJeu.insecte {\n            println(\"La balle a touch\u00e9 un insecte\")\n            \/\/ Attention:  Placer avant le removeFromParent!\n            etincelles(pasLaBalle.node!.position)\n            ...\n        }<\/pre>\n<p><strong><span style=\"color: #ff0000;\">Note<\/span><\/strong>: &lsquo;<strong>pasLaballe.node!.position&rsquo;<\/strong> permet de connaitre la position de l&rsquo;insecte. \u00a0Nous voulons afficher les particules \u00e0 cette position.<br \/>\nVoila, il ne reste plus qu&rsquo;\u00e0 tester l&rsquo;application finale!<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"wp-image-2106\" src=\"\/xcode\/wp-content\/uploads\/2014\/10\/d8ll3.gif\" alt=\"d8ll3\" width=\"215\" height=\"395\" \/><br \/>\nT\u00e9l\u00e9charger le projet termin\u00e9:\u00a0<a title=\"TIM.Briques.Solution.Xcode 6.1\" href=\"\/xcode\/wp-content\/uploads\/2014\/10\/TIM.Briques.solution.zip\">TIM.Briques.solution<\/a><br \/>\n&nbsp;<\/p>\n<hr \/>\n<p style=\"text-align: right;\">Fin du document &#8211; (c) Alain Boudreault &#8211; R\u00e9vision 2014.12.02<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Construction d&rsquo;un jeu vid\u00e9o avec SpriteKit \u00c9l\u00e9ments de contenu &nbsp; SpriteKit Physique D\u00e9tection de collisions Effets sonores Particules Gestion de niveaux &nbsp; &nbsp; &nbsp; Description Dans ce laboratoire nous verrons, \u00a0grace au framework spriteKit, \u00e0 l&rsquo;engin de physique, aux particules et au frameWork AVPlayer, comment construire une application de type casse briques. Au lieu d&rsquo;utiliser [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-1980","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages\/1980","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/comments?post=1980"}],"version-history":[{"count":0,"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/pages\/1980\/revisions"}],"wp:attachment":[{"href":"https:\/\/ve2cuy.com\/xcode\/wp-json\/wp\/v2\/media?parent=1980"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}