Bonjour

Je cherche à "créer" mes propres types de données en javascript

Je me suis dis que j'allais passer par des objets donc je déclare :

tRGBA =     {'r': 255, 'g': 255, 'b': 255, 'a': 1};
tVector =   {'x': 0, 'y': 0};
tPoint =    {'x': 0, 'y': 0};
tRange =    {'min':0, 'max': 255};

Maintenant je déclare :

var position = tPoint,
    oldPosition = tPoint,
    direction: tVector,
    color: tRGBA;

Ca semble marcher sauf que maintenant position et oldPosition ont les mêmes valeurs. ce qui est logique puisqu'ils partagent le même objet....

Donc ma question est simple : comment je peux m'en sortir ?? ou bien comment je peux créer mes propres types de variables.

20 réponses


tleb
Réponse acceptée

Salut,

Je pense que la solution la plus propre est de faire un truc du genre :

function rgba(r, g, b, a) {
  return {r: r, g: g, b: b, a: a}
}

Ça te permet aussi de vérifier/modifier les données en entrée de la fonction.

le javascript n'est pas un langage de type "Objet" a proprement parlé.

je te conseil de ce coté la : http://underscorejs.org/#clone

ouais effectivement tleb a raison, ca te retourneras tjrs un nouvel objet, donc ca devrait correspondre a ton besoin et tu peux en instancier plusieurs

Le faire dans une fonction permet surtout de ne pas répéter des choses qu'on peut faire à l'initialisation. Ça ne sert à rien si tu ne fais rien de spécial (comme dans l'exemple au dessus).

Pas mal @tleb :) Juste que ça va m'obliger à faire près de 200 new xx():)

Je me demandais car un objet a environ 170 paramètres, et que je peux avoir des centaines d'objets simultanéments donc le code va passer plus de temps à créer des objets qu'à les dessiner.

Je me demandais au niuveau rapidité s'il vaut mieux faire :

var color = new rgba(50, 50, 50, 0.5);

ou

var color2 = {r:50, g:50, b: 50, a:05);

Qu'est-ce que tu cherches à faire, concrètement ?

C'est un système qui doit générer, modifier afficher des objets 2D ou 3D, et ce, dans un environnement.

excellent sujet !!
tu cherches à faire un moteur de rendu ?
en javascript ?
et ben....
dans mes souvenir profonds j'ai une applet java qui fait ça, si t'as t'intéresse je peux te l'a filer, je lui balançais des données type :
...
Ambient light color: Red=0.0000 Green=0.0000 Blue=0.0000

Named object: "fleg1"
Tri-mesh, Vertices: 798 Faces: 3184
Vertex list:
Vertex 0: X:5.4895 Y:-6.6340 Z:-4.5264
Vertex 1: X:5.5914 Y:-6.7309 Z:-4.5509
Vertex 2: X:5.6575 Y:-6.6030 Z:-4.6130
[...]
Face list:
Face 0: A:0 B:1 C:2 AB:1 BC:1 CA:0
Material: "Default"
Face 1: A:3 B:4 C:5 AB:1 BC:1 CA:0
Material: "Default"
Face 2: A:6 B:5 C:4 AB:1 BC:1 CA:0
Material: "Default"
Face 3: A:7 B:6 C:8 AB:1 BC:1 CA:0
Material: "Default"
[...]
Named object: "Light01"
Direct light
Position: X:-11.3306 Y:-2.0591 Z:6.2598
Light color: Red=1.0000 Green=1.0000 Blue=1.0000
Named object: "Light02"
Direct light
Position: X:10.0989 Y:4.4926 Z:4.2285
Light color: Red=1.0000 Green=1.0000 Blue=1.0000
Named object: "Light03"
Direct light
Position: X:-7.6468 Y:-4.7660 Z:-0.3282
Light color: Red=1.0000 Green=1.0000 Blue=1.0000
Named object: "Light04"
Direct light
Position: X:7.9985 Y:0.9959 Z:-0.2184
Light color: Red=1.0000 Green=1.0000 Blue=1.0000
....
donc du txt !!!
(à l'époque j'utilsais 3dstudiomax, et j'avais fait un ti script qui me convertissait les objets 3d)
ça marchait plutôt pas mal...

cela dit :
javascript est un langage '"orienté" object' mais difficilement classifiable (du moins pas encore, en emascript6 oui... donc bientôt il va falloir revoir nos classiques :)))
tu peux créer des instances d'objects par la méthode Object.create ou new avec une function comme te disait jusdicieusement tleb
je te conseille l'excellent tuto de Grafikart : [https://www.youtube.com/watch?v=-22uczx3Tb4]
tu y verras les limites et les avantages de la création d'Object ou de function...
perso je balance entre les 2....

donc :
je ne sais pas quel est la source de tes données (xml par exemple), mais tu peux utiliser un parser du genre DOMParser() pour généré tes 200 objets (type Object ou function...)
auxquels tu auras ajouté 2 3 méthodes pour en manipuler l'orientation, la position, l'exposition... (je te conseille le calcul matricielle)

bref :
je ne sais pas si g bien compris ton soucis et ton but...
tu parles d'environnement ? lequel ?

++
seb

Bonjour,

Oui en quelque sorte c'est un moteur qui permet de représenter et de se déplacer dans un monde 3D à la FPS (sauf que là c'est pas pour jouer :) ). Comme les lieux doivent être modélisés par tout le monde on a développé notre propre éditeur basique donc le format des données est un fichier JSON, le tout empaqueté dans un .zip avec texxtures, sprites, ... à la .pak

Pour expliquer ma problématique tout marche plus ou moins bien mais je commence la phase d'optimisation et de rendre le code plus "joli" et plus lisible. Donc je veux remplacer toutes déclarations de variables par des types compréhensibles d'où le fait que j'aimerais définir un type de variable tPoint, un autre tVector, .. Actuellement par exemple j'ai :

this.parameters = {
     position :  {x:0, y:0}
};

Je préfèrerais avoir

this.parameters = {
    position : tPoint,
};

Même si à l'arrivée cela ne change rien, je trouve que c'est plus compréhensible, car par exemple une position et un vecteur ont tous les 2 x et y mais ce n'est pas la même chose, et de bien différencier les types aide à mieux comprendre le code

ok, tu as raison, un code propre et bien commenté c important et trop souvent négligé ;)
tu as regardé le tuto de grafikart ?

si g bien compris tu veux 4 objects de base :

tRGBA =     {'r': 255, 'g': 255, 'b': 255, 'a': 1};
tVector =   {'x': 0, 'y': 0};
tPoint =    {'x': 0, 'y': 0};
tRange =    {'min':0, 'max': 255};

que tu veux assigner aux parameters d'un autre object....

objetBase = {
    position : tPoint ,
    couleur : tRGBA,
    direction : tVector,
    changementDePosition : function(x, y){
        this.position.x = x;
        this.position.y = y;
    }
}

pour pouvoir gérer ainsi :

myObject = Object.create(objetBase);
myObject2 = Object.create(objetBase);
myObject.position.x = 10; // myObject2 est modifié aussi !!!

l'énorme hic avec cette méthode, c que quand tu modifieras la propriété d'un object les autres seront modifiés aussi
dans l'exemple myObject2 à également la position.x = 10 (je sais, c difficilement compréhensible...)

pour bien faire les choses il faudrait :

myObject = Object.create(objetBase);
myObject.position = {'x': 0, 'y': 0}; // parce qu'avec myObject.position = tPoint; ça fonctionne toujours pas
myObject.position.x = 10;

c top galère !!!

avec les function, on peut faire un truc du genre :

objectBase = function(params){
    if(typeof(params)=='undefined')params = {};
    this.position =     (params.position)?params.position:{'x': 0, 'y': 0};
    this.couleur =      (params.couleur)?params.couleur:{'r': 255, 'g': 255, 'b': 255, 'a': 1};
    this.direction =    (params.direction)?params.direction:{'x': 0, 'y': 0};

    this.changementDePosition = function(x,y){ // ou bien avec les prototype...
        this.position.x = x;
        this.position.y = y;
    }
}

myObject3 = new objectBase();
myObject4 = new objectBase({
    position : {'x': 10, 'y': 10}
});

là c ok myObject3 et 4 ont des positions différentes mais on s'éloigne de ton envie de départ....

bref, c po simple :)))

je rajoute, car tu disais :

Pas mal @tleb :) Juste que ça va m'obliger à faire près de 200 new xx():)

mais si tu récupères un json tu n'as plus qu'à le parser et faire une boucle pour créer tes objects :

json = JSON.parse(json);
objects = [];
for(var i in json){
    objects[i] = new objectBase(json[i]);
}

en gros.... :)

oui saibe comme tu le dis ce n'est pas simple :))
Ton idée de parser le json pour avoir créer un tableau ne me plait pas car au lieu d'avoir position.x = 99 je vais avoir objects[12].x = 99 . De plus on ne sait jamais à quelle ligne du json sont définies les variables :)

Je sens que je vais laisser la façon actuelle mais je vais passer le type de variable dans le nom donc : position devient pointPosition

tu aurais un extrait de ton json ?
et un bout de code qui le lit, car je comprends po tout....

J'ai essayé d'extraire des choses qui peuvent t'aider à comprendre :)

un bout du json:

{
"id": 1,
"name" : "Pièce 1",
"details": "Pièce principale de la maison",
"position": {"x": 250, "y": 250, "z": 0},
"positionRange": {"x": 100, "y": 100, "z": 0},
"gravityMove": 9.807,
"angle": 10,
"angleRange": 10,
"speed": 1,
"speedRange": 0.5,
"radialAccel": 0,
"radialAccelRange": 0,
"tangentialAccel": 0,
"tangentialAccelRange": 0,
"textureEnabled": true,
"textureAdditive": true,
"radius": 120,
"radiusRange": 2,
"scale": {"min":1, "max":0},
"alpha": {"min":1, "max":0},
"ambiantColor": {"r":251, "g":102, "b":178.5, "a":1},
"ambiantColorRange": {"r": 150, "g":150, "b":51, "a":0.1},
"ambiantColorPosition": {"x": 200, "y": 450, "z": 1024},
"active": true,
}

un bout de la fonction d'init

 // PUBLIC
this.init = function () {
    this.parameters = {
        'id':                   1,
        name :                  '',
        details:                '',
        active :                true,
        duration:               {min:0, max:0},
        position:               this.parameters.position || {x:0, y:0, z:0},
        positionRange:          this.parameters.positionRange || {x:0, y:0, z:0},
        scale:                  {min:1, max: 0},
        opacity:                {min:1, max: 0},
        gravityMove:            0,
        velocity :              {x:0, y:0, z:0}, 
        spread:                 Math.PI / 32,
        ambiantColor:           {r:0, g:0, b:0, a:0},
        ambiantColorRange:      {r:0, g:0, b:0, a:0},
        ambiantColorPosition:   {x:0, y:0, z:0},
        radialAccel:            0,
        radialAccelRange :      0,
        tangentialAccel:        0,
        tangentialAccelRange:   0,
    };

    utils.extend(this.parameters, this.parametersLoaded);  // Load default parameters from last this.load()
};

extend: function(obj, config) {
    for (var prop in config) {
        obj[prop] = config[prop];
    }
},    

this._loadConfigurationFile = function(filename) {
    this.parametersLoaded = utils.loadJson(filename);
    if (this.parametersLoaded)  {
        utils.extend(this.parameters, this.parametersLoaded);
    }
};

loadJson: function(filename) {
    var xobj = new XMLHttpRequest();
    xobj.overrideMimeType("application/json");
    xobj.open('GET', filename, false);
    xobj.send(null);
    if(xobj.status == 200) {
        return JSON.parse(xobj.responseText);
    }
    return false;
},

J'espère que cela pourra t'aider :)

sinon plutot que de créer ton propre moteur JS en 3D, il existe des libs comme Three.js (https://threejs.org/)

voila un boilerplate de mise en place pour une intégration facile:
https://github.com/jeromeetienne/threejsboilerplate

ahlalalala... papervision remonte à si loin (sick flash tu me manques...)

Oui je sais qu'il existe des moteurs 3D (on a testé threejs, unity, unreal engine, ...) mais ils sont beaucoup trop lourds pour nos besoins assez simples, le temps de bien les assimimer on a aussi vite fait d'en écrire un, puis ca va aussi sembler con mais on aime bien avec le contrôle sur ce que l'on fait :)

je comprends tout à fait :)
et comme j'ai rien à faire....
je suis parti de tes infos :

// ton helper
var utils = {
    loadJson: function(filename) {
        var xobj = new XMLHttpRequest();
        xobj.overrideMimeType("application/json");
        xobj.open('GET', filename, false);
        xobj.send(null);
        if(xobj.status == 200) {
            return JSON.parse(xobj.responseText);
        }
        return false;
    },
    extend: function merge(def, params){
        for(var k in def){
            if(typeof(params[k])==='undefined') params[k] = def[k];
        }
        return params;
    }
};

// ton object parent
myObj = function(json){
    this.parameters = utils.extend({
        id :                    1,
        name :                  '',
        details:                '',
        active :                true,
        duration:               {min:0, max:0},
        position:               {x:0, y:0, z:0},
        positionRange:          {x:0, y:0, z:0},
        scale:                  {min:1, max: 0},
        opacity:                {min:1, max: 0},
        gravityMove:            0,
        velocity :              {x:0, y:0, z:0}, 
        spread:                 Math.PI / 32,
        ambiantColor:           {r:0, g:0, b:0, a:0},
        ambiantColorRange:      {r:0, g:0, b:0, a:0},
        ambiantColorPosition:   {x:0, y:0, z:0},
        radialAccel:            0,
        radialAccelRange :      0,
        tangentialAccel:        0,
        tangentialAccelRange:   0,
    }, json || {});

    // je préfère enlevé la couche parameters ;)
    for(var i in this.parameters){
        this[i] = this.parameters[i];
    }
    delete this.parameters;
}

// une methode qui sert à rien ;)
myObj.prototype.getParams = function(){
    p = {};
    for(var k in this){
        if(typeof(this[k]) != 'function')
            p[k] = this[k];
    }
    return p;
};

// on récupère le json
json = utils.loadJson('objs.json');

// on fabrique les 200 instances
objs = {};
for(var i in json){
    objs[json[i].id] = new myObj(json[i]);
}

// on en fait ce qu'on veut
objs[1].position.x = 30;
console.log(objs[1].getParams());

je vois pas mieux pour l'instant....

Merci beaucoup saibe pour ce code, je vais reprendre quelques briques qui vont m'aider à améliorer le code. Mais autant ton code est très intéressant et instructif autant il ne répond pas à ma question initiale qui était de savoir si on pouvait définir des types de variables personnalisées un peu comme le struct du C :))

ok ;) ben tanpis... j'aurai essayé...
juste un truc, ds la méthode extend du utils (que j'avais repris un poil) le merge sert à rien...
tu utilises aucunes lib, genre jquery ?
ds tous les cas, bonne continuation, et si t'as un truc en ligne à partager, je serais curieux de voir ça :)
++

coucou saibe désolé du retard. Oui j'ai vu après avoir postéque j'avais doublonné :)) Pour le moment on évite jQuery ou du moins pour la partie moteur, dans le modeleur on l'utilise

Pour le moment il n'y a rien en ligne désolé mais cela viendra et je posterai un lien :)

Je te remercie pour ton temps et bonne continuation à toi aussi