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
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
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
-
Compatibilité des API :
File → Build settings → Player Settings → Other Settings → API compatibility level → .NET 2.0
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.
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
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"
};
DataMainScriptSingleton.Instance.currentSubject.VARIABLE = VALEUR;
Exemple :
DataMainScriptSingleton.Instance.currentSubject.AgeSubject = 56;
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 |
DataMainScriptSingleton.Instance.currentSubject.InsertData();
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.
VALEUR = DataMainScriptSingleton.Instance.appData.VARIABLE;
Exemple :
string nomDuDevice = DataMainScriptSingleton.Instance.appData.deviceName;
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
DataMainScriptSingleton.Instance.currentSession = new SessionData();
Exemple :
DataMainScriptSingleton.Instance.currentSession = new SessionData { ExpeName = "my_expe", ManipName = "my_manip" };
DataMainScriptSingleton.Instance.currentSession.VARIABLE = VALEUR;
Exemple :
DataMainScriptSingleton.Instance.currentSession.expeName = "my_expe";
VALEUR = DataMainScriptSingleton.Instance.currentSession.VARIABLE;
Exemple :
string nomExpe = DataMainScriptSingleton.Instance.currentSession.expeName;
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
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" } ;
////////////////////////////////////////
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)
DataMainScriptSingleton.Instance.currentSeance.AddSeanceDataIntDict(NOM_VARIABLE,VALEUR);
Exemple :
DataMainScriptSingleton.Instance.currentSeance.AddSeanceDataDictionary("nClicSurBouton1",23);
DataMainScriptSingleton.Instance.currentSeance.SeanceDataDictionary[NOM_VARIABLE]=VALEUR;
Exemple :
DataMainScriptSingleton.Instance.currentSeance.SeanceDataDictionary["nClicBouton1"]+=1;
VALEUR = DataMainScriptSingleton.Instance.currentSeance.SeanceDataDictionary[NOM_VARIABLE];
Exemple :
int nClicMonButton1 = DataMainScriptSingleton.Instance.currentSeance.SeanceDataDictionary["nClicBouton1"];
////////////////////////////////////////
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
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 |
VALEUR = DataMainScriptSingleton.Instance.globalData.VARIABLE;
Exemple :
List<int>() playerPosX = DataMainScriptSingleton.Instance.globalData.trajetPositionX;
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
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
id |
NameSubject |
AgeSubject |
SexeSubject |
EducationLevelSubject |
PathologySubject |
RefSubject |
id |
DateLancement |
ApplicationName |
DeviceName |
DeviceModel |
id |
NumSession |
TempsUtilisation |
SubjectID |
ExpeName |
ManipName |
RefSubject |
id |
SeanceName |
DateDebut |
ListesObjectifs |
DuTotObjectifs |
DuBetweenObjectifs |
ObjSuccess |
ObjFail |
ObjOrder |
nClickPerSeance |
nClickPerObj |
nClickInterfDepl |
nClickConsigneEcr |
nClickConsigneOral |
nEntrMetro |
nEntrBus |
nClickMap |
trajetPosX |
trajetPosY |
trajetPosZ |
trajetRotX |
trajetRotY |
trajetRotZ |
RefSubject |
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
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
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. |
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); } }