Détecter nombre de doigts sur l'écran (IOS)

Bonjour à tous,

Je suis en train de developper une petite application pas très compliqué mais je bloque sur un point :

Je n’arrive pas a trouver le moyen de détecter le nombre de doigts présents sur l’écran et lancer une action à partir de ça…
Je vous explique plus en détail :

J’aimerais que plusieurs utilisateurs posent leur doigts sur l’écran que ça forme un cercle autour pour bien montrer qu’ils sont détectes, ensuite générer un nombrer aléatoire entre 0 et le nombre de doigts présents,

Merci pour votre aide :pray:
Pierre.

Euh … iOS ou robot vert ? Le forum traite des deux. Il faut préciser la cible, avant de poser une question.

C’est sur IOS je bosse sur Xcode 11 pardon j’ai zappé de le préciser, je modifie ça tout de suite

Chaque fois qu’un doigt touche l’écran, iOS génère un événement touchesBegan, contenant les informations de contact, notamment la position. Tu peux aussi passer par les gestures.

Question subsidiaire : application UIKit ou SwiftUI ?

C’est une app SwiftUI,

Je ne suis que tout nouveau dans le dev IOS j’ai commencé les tutos et le Dev de mon app en début de semaine

Je code un petit exemple, demain ou après-demain, dés que j’ai un peu de temps libre.

Au top, Merci @Draken :pray:

Bonjour @Draken,
J’ai réussi (via le site d’Apple dev) à coder la fonctionnalité qui permet de détecter les doigts, par contre impossible de trouver comment je pourrais compter le nombre de doigts sur l’écran et ainsi déterminer un nombre aléatoire entre 0 et le nombre de doigt sur l’écran.

Auriez vous une idée ?

Merci d’avance

Je vous met le code ci dessous si jamais :

import UIKit

class TESTtouchViewController: UIViewController {

override func loadView() {
        view = TouchableView()
        view.backgroundColor = .black
    }
}

class TouchableView: UIView {
    var touchViews = [UITouch:TouchSpotView]()

    
    override init(frame: CGRect) {
        super.init(frame: frame)
        isMultipleTouchEnabled = true
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        isMultipleTouchEnabled = true
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            createViewForTouch(touch: touch)
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let view = viewForTouch(touch: touch)
            // Move the view to the new location.
            let newLocation = touch.location(in: self)
            view?.center = newLocation
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            removeViewForTouch(touch: touch)
        }
    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            removeViewForTouch(touch: touch)
        }
    }

    func createViewForTouch( touch : UITouch ) {
        let newView = TouchSpotView()
        newView.bounds = CGRect(x: 0, y: 0, width: 1, height: 1)
        newView.center = touch.location(in: self)

        // Add the view and animate it to a new size.
        addSubview(newView)
        UIView.animate(withDuration: 0.2) {
            newView.bounds.size = CGSize(width: 100, height: 100)
        }

        // Save the views internally
        touchViews[touch] = newView
    }

    func viewForTouch (touch : UITouch) -> TouchSpotView? {
        return touchViews[touch]
    }

    func removeViewForTouch (touch : UITouch ) {
        if let view = touchViews[touch] {
            view.removeFromSuperview()
            touchViews.removeValue(forKey: touch)
        }
    }
}

class TouchSpotView : UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor.lightGray
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // Update the corner radius when the bounds change.
    override var bounds: CGRect {
        get { return super.bounds }
        set(newBounds) {
            super.bounds = newBounds
            layer.cornerRadius = newBounds.size.width / 2.0
            
        }
    }
}

Je n’ai pas eu beaucoup de temps pour penser à toi. Désolé, je suis complément surbooké en ces moments de crise.

Ton problème est plus compliqué qu’il n’y parait, à cause de l’imperfection des êtres humains. iOS ne permet pas de connaître à un moment donné le nombre de doigts touchant l’écran. La seule chose qu’il sache faire c’est d’avertir l’application qu’un contact vient d’avoir lieu.

Prenons un cas simple avec deux utilisateurs. Il est QUASI-IMPOSSIBLE qu’ils touchent l’écran au même moment, même avec des réflexes de-la-mort-qui-tue. Il y aura toujours un petit décalage, de quelques fractions de secondes.

Lorsque l’utilisateur A touche l’écran, iOS détecte l’événement et prévient l’application en appelant la fonction movesBegan (UIKIT ou SwiftUI).

Une fraction de seconde plus tard, quand l’utilisateur B touche l’écran, iOS appelle de nouveau la fonction movesBegan pour prévenir l’application. C’est un AUTRE événement de contact.

Le code que tu as trouvé est assez complexe, à ton niveau d’apprentissage. Je doute que tu comprennes grand chose sur son fonctionnement (mais ça viendra !).

En gros, chaque fois qu’un utilisateur pose le doigt sur l’écran, l’information est mémorisée dans un système de stockage de données que l’on appelle un dictionnaire. Si le doigt quitte l’écran, iOS prévient l’application par l’intermédiaire de la fonction touchesEnded, qui fait disparaître l’image de l’écran, et efface l’information du dictionnaire.

Avec ce code, pour connaître le nombre de doigts sur l’écran, à un moment donné, il suffit de consulter le dictionnaire pour lui demander combien d’éléments il contient. Un truc du genre :

let nbDoigtsActifs = touchView.count

Simple, non ? Sauf que tout ceci est en UIKIT et pas en SwiftUI.

Je te porte ça en SwiftUI ce WE, si j’ai le courage (semaine très chargée, vraiment …).


Autre problème, la gestion du temps. Dans la mesure où les actions des utilisateurs ne sont pas simultanées, il faut prévoir un court délai d’attente avant de valider le nombre de doigts en contact. Et un signal de démarrage (visuel ou sonore) pour donner le top départ aux utilisateurs. Genre « Vous avez une seconde pour poser vos doigts sur l’écran ».

Ton application doit donc activer et désactiver la détection des contacts et gérer le temps. Le mot clé pour ça est : Timer !! Encore quelque chose de nouveau à apprendre …

Aucun problème, je te suis très reconnaissant de prendre autant de ton temps pour m’aider, ce qui me permet de beaucoup avancer dans mon app et dans mon apprentissage.

Je ne pensais vraiment pas que cette appli était aussi compliquée à réaliser, en fait j’essaie de porter un petit jeu qui se joue en soirée sur iPhone, il s’appelle le jeu du doigt (je te met les règles ci joint pour que tu vois ce que j’essaie de faire dans mon app).

Pour ce qui est de la présentation et du fonctionnement j’ai essayé de me baser sur une application qui existe déjà mais qui n’as pas le même but : elle permet de voir quel joueur enlève son doigt en dernier de l’écran (après de changement de couleur de celui-ci) Je te met la capture que j’ai faite en PJ.

https://mega.nz/#!ZrQw0SSQ!8HedEgFN9swf7pVqGBzm_v42KlX2-OAn8ZCGFaIiu6Y
Étant donné que je suis nouvel utilisateur je ne peux pas envoyer de fichier du coups je l’ai Upload sur MEGA

En réfléchissant à ce problème de timer, il serait possible de rajouter un pickerView sur la page d’accueil pour que l’utilisateur puisse choisir le nombre de joueurs avant même de lancer le jeu.
Ce qui permettrais de simplement attendre qu’il y ait : touchView.count = « à la donnée renvoyée par le pickerView ».

Je vais essayer d’en apprendre plus de mon coté sur UITouch ainsi qu’avec toutes les précieuses infos que tu m’as donné.

Je te remercie encore du temps et de l’énergie que tu me consacre,

Les règles du jeu du doigt :

Placez le verre rempli au mileu de la table pour que tout le monde puisse le voir.

Chaque joueur pose ensuite son doigt sur le verre.

Un décompte de 3 secondes est fait par un des participants et à « 0 », le 1er joueur doit dire un chiffre entre 0 et le nombre de participants (ex « 6 » pour 6 participants). Au même moment, chaque joueur doit soit laisser son doigt sur le verre, soit le retirer. Cela vaut aussi pour celui qui énonce le chiffre.

Une fois cette étape franchie, 2 cas de figures sont possibles :

Le joueur 1 a réussi à deviner le nombre de doigts restant sur le verre

Le joueur 1 est autorisé à quitter le jeu car il a trouvé le bon nombre de doigt restants. C’est donc au joueur 2 de pronostiquer à son tour. S’il réussi, ce sera au joueur 3 et ainsi de suite.

  • Le joueur 1 n’a pas réussi à deviner le nombre de doigts restants sur le verre

C’est au joueur 2 de deviner.

Fin de partie : le dernier joueur restant perd la partie et doit boire le verre