Information sur le package
  • Langage utilisé : C# version 4

  • Version Unity : 2017.2.0f3

  • Dispositifs testés : XXX

  • Version 0.3

Contact : f.caetta@gmail.com

Package et documentation en cours de rédaction - V0.3

Description

Le package se compose :

  • d’un fichier principal - DataMainSingleton - qui gère l’organisation et la manipulation des données

  • d’une classe Data principale (MainDataClass)

  • de 5 fichiers spécifique à chaque catégorie de données (classes fille de MainDataClass)

    • SubjectInfo

    • SeanceData

    • SessionData

    • AppData

    • GlobalData

  • un fichier qui gère la création et la modification de la base de données - BDD (SqliteData)

  • un fichier lié à la sécurité (protection) de l’application (AppSecure)

  • d’une bibliothèque pour gestion des BDD

Fichiers facultatifs

Le package contient également des fichiers facultatifs destinés à tester le bon fonctionnement des scripts :

  • FormScript

  • TestButtonScript

Le schéma ci-dessous répresente une vue générale des relations entre chaque classe du package

Tiger
Figure 1. Architecture du package / projet (S : appel à des membres statiques ; 1 : première instanciation - mot clé new - du singleton SqliteData)

Mise en place

Installation

Le package Unity est disponibles sur ce lien (un compte est nécessaire pour pouvoir télécharger les fichiers).

Pour l’installation, il suffit d’importer le package dans un projet unity puis d’attacher le script "DataMainScriptSingleton" à un GameObject.

Un prefab avec un exemple de formulaire ainsi qu’un projet complet (script + formulaire) sont également disponibles sur ce même lien .

Configuration

  • Configuration du plugin de gestion de BDD :

Assets → Caetta_scripts → db → System.Data (cliquez sur le fichier puis dans l’inspector, configurer comme sur l’image ci-dessous

Tiger
Tiger
  • Compatibilité des API :

File → Build settings → Player Settings → Other Settings → API compatibility level → .NET 2.0

Tiger

Présentation des classes

Script principal

Class : DataMainScriptSingleton

Inheritance : DataMainScriptSingleton → MonoBehaviour

Instance : DataMainScriptSingleton.Instance

Il s’agit de la classe principale qui suit un patron de conception de type "singleton". Cett classe gère les instances des classes "data" et elle est accessible à partir de n’importe quel scripts

Caution
Le script DataMainScriptSingleton doit être attaché à un Gamebject pour que l’ensemble du package puisse fonctionner correctement

Propriétés (inspector) :

Les valeurs des propriétés ci-dessous sont directement modifiables via l’inspecteur de UNITY (après avoir attaché le script "DataMainScriptSingleton" à un GameObject).

Nom Type Description

ExpeName

string

Nom de l’expe

ManipName

string

Nom de la manip

DatabaseName

string

Nom de la base de données

FrequenceRec

string

Fréquence (en sec) d’enregistrement des données des séances

AppCode

string

Code à renseigner lors du lancement de l’app (laisser vide si aucun code nécessaire)

EOLDate

string

Date de fin de vie de l’application (format : "2020-01-24").

debugInfo

bool

Affichage infos Debug sur console Unity

systemInfo

bool

Affiche les infos system sur la console

BuildAndroid

bool

A cocher lors d’un build à destination d’Android

Propriétés :

Nom Type Description

currentSubject

class

Classe qui gère les informations du participant

currentSeance

class

Classe qui gère les informations de la séance

currentSession

class

Classe qui gère les informations de la session

globalData

class

Classe qui gère les informations générales(à définir)

Méthode :

Nom Type Paramètres Description

StartExpe

void

Instanciation des différences classes "data"

Trace

void

(string message, bool show=true)

Affiche un message sur la console (nécessite que debugInfo = true)

UTILISATION

L’utilisation de cette classe (pattern singleton) passe par un appel direct à son instance.

Utilisation générale
DataMainScriptSingleton.Instance.METHOD;

Exemple :

DataMainScriptSingleton.Instance.StartExpe();

DataMainScriptSingleton.Instance.trace("je suis un message sur la console");

Classes données

La manipulation des données (enregistrement, récupération, mise à jour et suppression) s’effectue en instanciant la class "DataMainScriptSingleton". Les commandes sont détaillées pour chaque catégorie de données.

Classe Data principale

Package : Caetta.Lmc2.Data

Class : MainDataClass

Inheritance : NA

Instance : NA

Cette classe les propriétes/méthodes communes à toutes les classes "Data".

Tip
Il s’agit d’une classe abstraite. Elle ne peut donc pas être directement instanciée.

Propriétés :

Nom Type Description

ID

int

ID de l’instance

DateLaunch

DateTime

Date/heure de la création de l’instance de la classe

StartTime

float

Temps écoulé (en sec) entre le lancement de l’app et l’instanciation de la classe

TimeElapsed

float

Temps écoulé (en sec) depuis l’instanciation de la classe

Propriétés (protected) :

Nom Type Description

sqliteData

SqliteData

Instance de la classe SqliteData

tableName

string

Nom de la table (spécifique à chaque classe DATA)

Méthodes (virtual) :

Nom Type Paramètres Description

insertQuery

void

string

Requête pour enregistrement des données (spécifique à chaque classe DATA)

MajUpdateByIDQuery

void

string

Requête pour mise à jour des données (spécifique à chaque classe DATA)

InsertData

void

Insertion données, avec "insertQuery" spécifique à chaque classe data

UpdateByID

void

Requête pour mise à jour des données (spécifique à chaque classe DATA)


Participant

Package : Caetta.Lmc2.Data.DataClasses

Class : SubjectInfo

Inheritance : SubjectInfo → MainDataClass

Instance : currentSubject

Propriétés :

Nom Type Description

nameSubject

string

Nom du participant

tableName

int

Age du participant

sexeSubject

string

Sexe du participant

educationLevelSubject

string

Niveau d’éducation du participant

pathologySubject

string

Groupe du participant

refSubject

string

Référence du participant

UTILISATION

Création d’un nouveau sujet
DataMainScriptSingleton.Instance.currentSubject = new SubjectInfo()

Exemple :

DataMainScriptSingleton.Instance.currentSubject = new SubjectInfo {
NameSubject = "NomSujet",
SexeSubject = "SexeSujet",
AgeSubject = 67,
EducationLevelSubject = "NiveauScolaire",
PathologySubject = "Patho",
RefSubject = "reference_du_sujet"
};

Attribution d’une valeur à une variable
DataMainScriptSingleton.Instance.currentSubject.VARIABLE = VALEUR;

Exemple :

DataMainScriptSingleton.Instance.currentSubject.AgeSubject = 56;

Récuperation de la valeur d’une variable
VALEUR = DataMainScriptSingleton.Instance.currentSubject.VARIABLE;

Exemple :

int age = DataMainScriptSingleton.Instance.currentSubject.AgeSubject;

Important
Des accesseurs [1] sont utilisés, donc ne pas oublier de mettre une majuscule pour le nom de la variable. Ex. : ageSubject ⇒ AgeSubject
Enregistrement de toutes les variables dans la base de données
DataMainScriptSingleton.Instance.currentSubject.InsertData();
Enregistrement d’une variable spécifique dans la base de données

todo


Application

Package : Caetta.Lmc2.Data.DataClasses

Class : AppData (bool insertData=true)

Inheritance : AppData → MainDataClass

Instance : appData

Propriétés (readonly) :

Nom Type Description

applicationName

string

Nom de l’app

deviceName

string

Nom du device

deviceModel

string

Modèle du device

UTILISATION

La valeur du constructeur (bool insertData ; par défaut en true) indique si le données sont enregistrées automatiquement lors de l’instanciation de cette classe WARNING: Les propriétées sont en lecture seule.

Récuperation de la valeur d’une variable
VALEUR = DataMainScriptSingleton.Instance.appData.VARIABLE;

Exemple :

string nomDuDevice = DataMainScriptSingleton.Instance.appData.deviceName;

Enregistrement de toutes les variables dans la base de données
DataMainScriptSingleton.Instance.currentSubject.InsertData();

Session

Package : Caetta.Lmc2.Data.DataClasses

Class : SessionData

Inheritance : SessionData → MainDataClass

Instance : currentSession

Propriétés :

Nom Type Description

numSession

int

Numéro de la session

expeName

string

Nom de l’expérience

manipName

string

Nom de la manip

UTILISATION

Création d’une nouvelle session
DataMainScriptSingleton.Instance.currentSession = new SessionData();

Exemple :

DataMainScriptSingleton.Instance.currentSession = new SessionData { ExpeName = "my_expe", ManipName = "my_manip" };

Attribution d’une valeur à une variable
DataMainScriptSingleton.Instance.currentSession.VARIABLE = VALEUR;

Exemple :

DataMainScriptSingleton.Instance.currentSession.expeName = "my_expe";

Récuperation de la valeur d’une variable
VALEUR = DataMainScriptSingleton.Instance.currentSession.VARIABLE;

Exemple :

string nomExpe = DataMainScriptSingleton.Instance.currentSession.expeName;

Enregistrement de toutes les variables dans la base de données
DataMainScriptSingleton.Instance.currentSession.InsertData();

Séance

Package : Caetta.Lmc2.Data.DataClasses

Class : SeanceData

Inheritance : SeanceData → MainDataClass

Instance : currentSeance

Propriétés :

Nom Type Description

CurrentObjectifs

List<string>

Liste des objectifs de la séance en cours

seanceDataIntDict

Dictionary<string, int>

Données Int de la séance en cours

seanceDataStringDict

Dictionary<string, string>

Toutes les données String de la séance en cours

Méthodes :

Nom Type Paramètres Description

AddObjectif

void

(string objectif)

Ajoute un objectif à la variable "CurrentObjectifs"

AddSeanceDataIntDict

void

(string key, int value)

Ajoute une variable (key) donnée et sa valeur associée (value)

AddSeanceDataStringDict

void

(string key, string value)

Ajoute une variable (key) donnée et sa valeur associée (value)

FeedSeanceDataIntDict

void

(list<string> listVars)

Initialise variables (list) avec valeur 0 ⇒ appel AddSeanceDataDictionary(var, 0)

FeedSeanceDataStringDict

void

(list<string> listVars)

Initialise variables (list) avec valeur "" ⇒ appel AddSeanceDataStringDict(var, "")

UTILISATION

Utilisation générale
DataMainScriptSingleton.Instance.currentSeance.PROPRIETE_METHODE;

⇒ Paramétrages des objectifs

Pour l’ajout d’objectifs, il y a deux façons de procéder :

→ en utilisant la méthode "AddObjectif()"

DataMainScriptSingleton.Instance.currentSeance.AddObjectif(string myObj);

Exemple :

DataMainScriptSingleton.Instance.currentSeance.AddObjectif("tour eiffel");

→ en modifiant la proprieté "CurrentObjectifs"

DataMainScriptSingleton.Instance.currentSeance.CurrentObjectifs = VALEUR;

Exemple :

var myObj = new List<string>() { "objectif_1", "objectif_2" } ;

Récupération du statut des objectifs :

////////////////////////////////////////
TODO :
- méthodes → récupération/statut objectifs ()
////////////////////////////////////////

⇒ Données

Un dictionnaire peut-être est utilisé pour gérer des données de la séance. Les noms des variables doivent correspondre aux noms des colonnes dans la table (base de donnée)

Ajout d’une donnée
DataMainScriptSingleton.Instance.currentSeance.AddSeanceDataIntDict(NOM_VARIABLE,VALEUR);

Exemple :

DataMainScriptSingleton.Instance.currentSeance.AddSeanceDataDictionary("nClicSurBouton1",23);

Modification d’une donnée
DataMainScriptSingleton.Instance.currentSeance.SeanceDataDictionary[NOM_VARIABLE]=VALEUR;

Exemple :

DataMainScriptSingleton.Instance.currentSeance.SeanceDataDictionary["nClicBouton1"]+=1;

Récupération d’une donnée
VALEUR = DataMainScriptSingleton.Instance.currentSeance.SeanceDataDictionary[NOM_VARIABLE];

Exemple :

int nClicMonButton1 = DataMainScriptSingleton.Instance.currentSeance.SeanceDataDictionary["nClicBouton1"];

Enregistrement des données

////////////////////////////////////////
TODO :
- méthodes → saveData ()
////////////////////////////////////////


Global Data

Package : Caetta.Lmc2.Data.DataClasses

Class : GlobalData

Inheritance : GlobalData → MainDataClass

Instance : globalData

Propriétés :

Nom Type Description

trajetPositionX

List<int>

Liste avec coordonnées X

trajetPositionY

List<int>

Liste avec coordonnées Y

trajetPositionZ

List<int>

Liste avec coordonnées Z

Méthodes :

Nom Type Paramètres Description

AddPositionXYZ

void

(int px, int py, int pz)

Ajoute positions X,Y,Z aux variables trajetPositionX,trajetPositionY,trajetPositionZ

UTILISATION

Attribution d’une valeur à une variable

Il y a deux façons de procéder :

→ en utilisant la méthode dédiée

DataMainScriptSingleton.Instance.globalData.METHOD;

Exemple :

DataMainScriptSingleton.Instance.globalData.AddPositionXYZ (256,232,312);

→ en modifiant directement la propriété

DataMainScriptSingleton.Instance.globalData.VARIABLE = VALEUR;

Exemple :

DataMainScriptSingleton.Instance.globalData.trajetPositionX = new List<int>() { 256, 257, 258, 259 };

Warning
Attention à ce que la longueur des listes trajetPositionX, trajetPositionY et trajetPositionZ soit la même
Récuperation de la valeur d’une variable
VALEUR = DataMainScriptSingleton.Instance.globalData.VARIABLE;

Exemple :

List<int>() playerPosX = DataMainScriptSingleton.Instance.globalData.trajetPositionX;

Enregistrement de toutes les variables dans la base de données
DataMainScriptSingleton.Instance.globalData.InsertData();

TODO

Classe base de données

Package : Caetta.Lmc2.Data.db

Class : SqliteData (string db_name)

Inheritance : NA

Instance : SqliteData.Instance

Il s’agit de la classe qui met en place et administre la base de données. Elle suit un patron de conception de type "singleton".

Elle nécessite d’être initialisée une seule fois avec le mot clé "new" avec comme paramètre de constructeur le nom de la base de donnée.

Elle est par défaut initialisée dans la classe "DataMainScriptSingleton" dans la fonction "Start()".

Méthodes :

Nom Type Paramètres Description

LastInsertedID

int

(string table)

Renvoi la valeur du dernier ID (max) de la table

Query

void

(string commandText)

Permet d’effectuer des requête SQLite

TODO: methode createTable

UTILISATION

Requete personnalisée
 DataMainScriptSingleton.Instance.sqliteData.Query(string commandText);

////////////////////////////////////////
TODO :
- Passer la classe en singleton → optimisation des connexions à la BDD
- Ajouter méthodes → UpdateByID(), DeleteByID(), Requêtes personnalisées à déterminer
////////////////////////////////////////

Classes additionnelles

AppSecure

Package : Caetta.Lmc2.Utils

Class : FormScript

Propriétés (static) :

Nom Type Description

appCode

string

Code de l’app (à renseigner avant compilation)

EOLDate

DateTime

Date de fin de vie de l’app (à renseigner avant compilation)

Méthodes (static)

Nom Type Paramètres Description

CheckCode

void

(string code)

Compare le code de l’app avec le code renseigné par l’utilisateur. Ferme l’app si ils ne sont pas identique

CheckEOF

void

Vérifie si l’app n’a pas dépassé sa fin de vie (se base sur la date fournie par le device). Fermme l’app si la date de fin de vie est dépassée

Note
Il n’y a pas de message d’erreur si jamais l’app se ferme (code de l’app erroné et/ou depassement de la date de fin de vie).

FormScript

Class : FormScript

Inheritance : FormScript → MonoBehaviour

Ce script doit être attaché à un canva/formulaire. Et les propriétés publiques doivent être liées à une UI (InputField,Dropdown, etc).

Propriétés (inspector) :

Nom Type Description

nomSujet

InputField

Nom du participant

sexeSujet

Dropdown

Sexe du participant

ageSujet

InputField

Age du participant

educationSujet

InputField

Niveau d’éducation du participant

groupSujet

InputField

Groupe (pathologie) du participant

referenceSujet

InputField

Référence du participant

startButton

Button

Bouton lancement de l’app (OnButtonStartClick() pour le détail)

deleteButton

Button

Bouton pour réinitialiser les informations du formulaire

Note
Les informations du formulaire en sont pas stockées dans la BDD de l’app mais avec PlayerPrefs.

Utils_FC

Package : Caetta.Lmc2.Utils

Class : Utils_FC

Méthodes (static)

Nom Type Paramètres Description

IntArrToStr

string

(int[] arr, string separator = ",")

Conversion d’un array INT en string avec séparateur, permet d’enregistrer au format TEXT dans la bdd

StrArrToStr

string

(int[] arr, string separator = ",")

Conversion d’un array string en string avec séparateur, permet d’enregistrer au format TEXT dans la bdd

StrListToStr

string

List<string> list, string separator = ",")

Conversion d’un List<string> en string avec séparateur, permet d’enregistrer au format TEXT dans la bdd

IntListToStr

string

List<int> list, string separator = ",")

Conversion d’un List<int> en string avec séparateur, permet d’enregistrer au format TEXT dans la bdd

////////////////////////////////////////
TODO :
- Méthode : serialize()
////////////////////////////////////////

Base de données

Tables

Nom des tables

  • subjectinfo

  • appdata

  • sessiondata

  • seancedata

  • globaldata

Composition des tables

Composition temporaire

Table 1. subjectinfo

id

NameSubject

AgeSubject

SexeSubject

EducationLevelSubject

PathologySubject

RefSubject

Table 2. appdata

id

DateLancement

ApplicationName

DeviceName

DeviceModel

Table 3. sessiondata

id

NumSession

TempsUtilisation

SubjectID

ExpeName

ManipName

RefSubject

Table 4. seancedata

id

SeanceName

DateDebut

ListesObjectifs

DuTotObjectifs

DuBetweenObjectifs

ObjSuccess

ObjFail

ObjOrder

nClickPerSeance

nClickPerObj

nClickInterfDepl

nClickConsigneEcr

nClickConsigneOral

nEntrMetro

nEntrBus

nClickMap

trajetPosX

trajetPosY

trajetPosZ

trajetRotX

trajetRotY

trajetRotZ

RefSubject

Table 5. globaldata

id

DuUtilis

date

trajetPosX

trajetPosY

trajetPosZ

vidTrace

screenshotCamAre

RefSubject

Récupération du fichier

Le fichier se trouve dans le réportoire d’installation de l’app.

Sur Unity (Windows/MacOS),lorsque "system" info est coché (⇒ inspector ⇒ gameObjet auquel attaché "DataMainScriptSingleton"), le chemin du répertoire où se situe la base de données est affiché sur la console.

Lecture des données et extraction

Le plus rapide pour lire et extraire les données collectées est d’utiliser Db Browser for Sqlite (ou un logiciel équivalent).

Les données

Exemple d’implémentation

Formulaire

Attacher le script à un GameObject, puis chaque composant du formulaire à une variable public

Tiger
Figure 2. Exemple d’association entre le formulaire et le script "FormScript"

Nombre de clic sur un bouton

Dans cet exemple nous allons récuperer le nombre de clic sur un bouton en particulier. Le nombre de clics sur ce bouton correspondra à une variable de la classe "SeanceData" . Cet exemple est fourni dans dans le projet complet fourni (script button "TestButtonFor_nClick" attaché au button "TestButtonFor_nClick").

Il y a ici deux façons de proceder :

  • utiliser un des dictionnaires de la classe SeanceData (ce dictionnaire pourra aussi contenir d’autres variables)

  • créer une variable dédiée dans la classe SeanceData

Utilisation du dictionnaire

Une instance de la classe "SeanceData" doit tout d’abord être disponible afin de pouvoir y stocker la variable désirée. Dans le cas contraire elle peut être instanciée avec cette ligne de commande :

 DataMainScriptSingleton.Instance.currentSeance = new SeanceData();

Dans la classe "SeanceData" il y a deux dictionnaires :

  • private Dictionary<string, string> seanceDataStringDict;

  • private Dictionary<string, int> seanceDataIntDict;

Comme nous voulons enregistrer le nombre de clic et qu’il s’agit d’un entier, nous allons utiliser le dictionnaire seanceDataIntDict. Nous allons créer une variable "nClicMyButton" et lui donner une valeur de 0 (pour l’instant il y a 0 clic sur ce bouton) :

DataMainScriptSingleton.Instance.currentSeance.AddSeanceDataIntDict("nClicMyButton", 0);

Il faut ensuite incrémenter la valeur "nClic" à chaque fois que le bouton est cliqué :

DataMainScriptSingleton.Instance.currentSeance.SeanceDataIntDict["nClicMyButton"] += 1;
Warning
Ne pas oublier la majuscule même si la variable est "seanceDataIntDict" (pour rappel des accesseurs/mutateurs sont utilisés)

La valeur de "nClicMyButton" peut être ensuite récuperée et affichée sur la console

int nClic;
DataMainScriptSingleton.Instance.currentSeance.SeanceDataIntDict.TryGetValue("nClicMyButton", out nClic);
Debug.Log ("Nombre de clic => "+ nClic);

Ci-dessous le script complet avec les imports et fonctions (ce script doit être attaché au bouton du test)

using UnityEngine;
using UnityEngine.UI;
using Caetta.Lmc2.Data.DataClasses;

public class TestButtonNclic : MonoBehaviour {

    public Button myButton;
    void Start ()
    {
        // Vérifie qu'une instance SeanceData est bien disponible
        if (DataMainScriptSingleton.Instance.currentSeance==null)
		    {
			       DataMainScriptSingleton.Instance.currentSeance = new SeanceData();
		    }
        /* Ajoute une variable "nombre de clic sur ce bouton" avec 0
         * comme valeur au dictionnaire de seanceDataIntDict la classe SeanceData*/
         DataMainScriptSingleton.Instance.currentSeance.AddSeanceDataIntDict("nClicMyButton", 0);
		    // Ecoute un évenement clic sur le bouton
		    myButton.onClick.AddListener(OnMyButtonClick);
	 }
	 private void OnMyButtonClick()
   {
        // Incrémente la valeur de nClicMyButton
        DataMainScriptSingleton.Instance.currentSeance.SeanceDataIntDict["nClicMyButton"] += 1;
        // récupération et affichage du nombre de clic sur la console
        int nClic;
        DataMainScriptSingleton.Instance.currentSeance.SeanceDataIntDict.TryGetValue("nClicMyButton", out nClic);
        Debug.Log("Nombre de clic => " + nClic);
   }
}
Note
Attention, la valeur ici est stockée en mémoire vive et non de façon persistente. Il faut ensuite faire la correspondance avec une colonne dans une des tables de la base de données et faire une requête.
Utilisation d’une variable dédiée

Cette façon de proceder nécessite qu’une variable soit directement créée dans la classe "SeanceData". Appelons cette variable "nClicMyButtonEx" et associons lui un getter/setter :

private int nClicMyButtonEx;
// Get/set variable Exemple
        public int NClicMyButtonEx
        {
            get
            {
                return nClicMyButtonEx;
            }
            set
            {
                nClicMyButtonEx = value;
            }
        }

Dans le script attaché au bouton, il suffit ensuite d’accéder à la propriété "nClicMyButton" lorsque l’on veut incrémenter la valeur :

DataMainScriptSingleton.Instance.currentSeance.NClicMyButtonEx += 1;

Nous pouvons ensuite récuperer la valeur de NClicMyButtonEx :

Debug.Log("NClicMyButtonEx = " + DataMainScriptSingleton.Instance.currentSeance.NClicMyButtonEx);

Ci-dessous le script complet qui est attaché au bouton :

using UnityEngine;
using UnityEngine.UI;
using Caetta.Lmc2.Data.DataClasses;

public class TestButtonNclic : MonoBehaviour {

    public Button myButton;
    void Start () {
        // Vérifie qu'une instance SeanceData est bien disponible
        if (DataMainScriptSingleton.Instance.currentSeance==null)
		    {
			     DataMainScriptSingleton.Instance.currentSeance = new SeanceData();
		     }
		    // Ecoute un évenement clic sur le bouton
		    myButton.onClick.AddListener(OnMyButtonClick);
	}
	private void OnMyButtonClick()
  {
       // Incrémenter la valeur de nClicMyButtonEx
       DataMainScriptSingleton.Instance.currentSeance.NClicMyButtonEx += 1;
       // récupération et affichage de nClicMyButtonEx sur la console
       Debug.Log("NClicMyButtonEx = " + DataMainScriptSingleton.Instance.currentSeance.NClicMyButtonEx);
  }
}

1. Les accesseurs sont souvent utilisés en POO pour récupérer la valeur de membres privés