Open menu
Evénements et méthodes

Exercice 1, 2 & 3 - 

1°/ model.js
  • Il suffit de suivre les indications du TP, en remplaçant la méthode buy().
  • contenu de model.js :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
function getRandomInt(max) {
  return Math.floor(Math.random() * Math.floor(max));
}
 
var itemCats = [ 'helmet', 'crown', 'armor', 'clothes', 'weapon', 'lighter', 'purse', 'potion', 'spell', 'food'];
 
var itemLimits = [
  {slot:'head', limit:1, types: [ 'helmet' , 'crown' ]},
  {slot:'body', limit:1, types: [ 'armor', 'clothes' ]},
  {slot:'hands', limit:2, types: [ 'weapon', 'lighter']},
  {slot:'belt', limit:3, types: [ 'weapon', 'purse']},
  {slot:'bag', limit:10, types: [ 'helmet', 'crown', 'clothes', 'lighter', 'potion', 'spell', 'food', 'purse' ]}
];
 
class Item {
  constructor(id, name, type, price, effect) {
    this.id = id;
    this.name = name;
    //let idx = itemCats.findIndex(e => e == type);
    //var testType = function(el) {return el == type};
    function testType(el) { return el == type;}
    let idx = itemCats.findIndex(testType);
    if (idx != -1) {
      this.type = type;
    }
    else {
      this.type = '';
    }
    if (price>=0) {
      this.price = price;
    }
    else {
      this.price = 0;
    }
    this.effect = effect;
  }
}
 
var items = [
  new Item(0, 'conic helmet', 'helmet', 200, 'A+10'),
  new Item(1, 'great crown of apologia', 'crown', 200, 'A+20'),
  new Item(2, 'band of joy', 'crown', 100, 'L+10'),
  new Item(3, 'leather armor', 'armor', 100, 'A+10'),
  new Item(4, 'broigne', 'armor', 200, 'A+20'),
  new Item(5, 'hauberk', 'armor', 500, 'A+40'),
  new Item(6, 'plate armor', 'armor', 1000, 'A+60'),
  new Item(7, 'tuxedo', 'clothes', 600, 'L+1'),
  new Item(8, 'cursed swimsuit', 'clothes', 10, 'A-10'),
  new Item(9, 'unicorn cosplay', 'clothes', 200, 'L+10'),
  new Item(10, 'dagger', 'weapon', 100, 'S+5'),
  new Item(11, 'cursed dagger', 'weapon', 100, 'S-5'),
  new Item(12, 'short sword', 'weapon', 200, 'S+10'),
  new Item(13, 'cursed short sword', 'weapon', 200, 'S-10'),
  new Item(14, 'long sword', 'weapon', 300, 'S+20'),
  new Item(15, 'cursed long sword', 'weapon', 300, 'S-20'),
  new Item(16, 'axe', 'weapon', 100, 'S+10'),
  new Item(17, 'cursed axe', 'weapon', 100, 'S-10'),
  new Item(18, 'great axe', 'weapon', 200, 'S+20'),
  new Item(19, 'cursed great axe', 'weapon', 200, 'S-20'),
  new Item(20, 'torch', 'lighter', 2, ''),
  new Item(21, 'oil lamp', 'lighter', 10, ''),
  new Item(22, 'leather purse', 'purse', 10, ''),
  new Item(23, 'protection potion', 'potion', 100, 'a+10'),
  new Item(24, 'health potion', 'potion', 100, 'l+10'),
  new Item(25, 'strength potion', 'potion', 100, 's+10'),
  new Item(26, 'fireball', 'spell', 1000, ''),
  new Item(27, 'ice cone', 'spell', 1000, ''),
  new Item(28, 'total healing', 'spell', 1000, ''),
  new Item(29, 'invisibility', 'spell', 1000, ''),
  new Item(30, 'levitation', 'spell', 1000, ''),
  new Item(31, 'apple', 'food', 1, 'l+1'),
  new Item(32, 'chicken', 'food', 10, 'l+5'),
  new Item(33, 'beef', 'food', 15, 'l+10'),
  new Item(34, 'wine', 'food', 2, 'l+2')
];
 
class Perso {
 
  constructor(name, level) {
    this.name = name;
    this.level = level;
    this.slots = [
      {name:'head', id:1, items:[]},
      {name:'body', id:2, items:[]},
      {name:'hands', id:3, items:[]},
      {name:'belt', id:4, items:[]},
      {name:'bag', id:5, items:[]}
    ];
    this.boughtItems = []; // list of item bought but not yet assigned
    this.life = 50*this.level; // the actual level of life
    this.gold=500;
    this.updateCaracs();
  }
 
  updateCaracs() {
    this.vitaliy = this.level*50;
    this.armor = 0;
    this.strength = this.level*20;
    for(let i=0;i<this.slots.length;i++) {
      let slot = this.slots[i];
      for(let j=0;j<slot.items.length;j++) {
        let item = slot.items[j];
        // search for armor effects
        if (item.effect[0] == 'A') {
          let val = item.effect.substring(2,item.effect.length);
          if (item.effect[1] == '+') this.armor += eval(val);
          else if (item.effect[1] == '-') this.armor -= eval(val);
        }
        // search for vitality effects
        if (item.effect[0] == 'L') {
          let val = item.effect.substring(2,item.effect.length);
          if (item.effect[1] == '+') this.vitality += eval(val);
          else if (item.effect[1] == '-') this.vitality -= eval(val);
        }
        // search for strength effects
        if (item.effect[0] == 'S') {
          let val = item.effect.substring(2,item.effect.length);
          if (item.effect[1] == '+') this.strength += eval(val);
          else if (item.effect[1] == '-') this.strength -= eval(val);
        }
      }
    }
    if (this.life > this.vitality) this.life = this.vitality;
  }
 
  /* modified version for TP 4:
       - called from buy() in vue instance, where checks/confirmation are done.
       - item parameter is an item object
  */
  buy(item) {
    this.boughtItems.push(item);
    this.gold -= item.price;
  }
 
  /* assign(): try to assign an item to a slot
  - itemId is the index of item in boughtItem
  - slot is the name of the slot (see attribute name in slots)
  return true if it's possible (i.e. limits and type of item respected)
  else return false.
  */
  assign(itemId, to) {
    let item = this.boughtItems[itemId];
    if (item == undefined) return false;
    let slot = this.slots.find(e => e.name == to);
    let slotLim = itemLimits.find(e => e.slot == to);
    // if to exists in player's slots and itemLimits
    if ((slot != undefined) && (slotLim != undefined)) {
      // check if limits/type is ok or not
      if (slot.items.length == slotLim.limit) {
        alert('limit for '+to+' alreay reached');
        return false;
      }
      let t = slotLim.types.find(e => e == item.type);
      if (t == undefined) {
        alert(to+' cannot be assigned with '+item.type);
        return false;
      }
      console.log("assign "+item.name+" to "+slot.name);
      slot.items.push(item);
      this.boughtItems.splice(itemId,1);
      this.updateCaracs();
      return true;
    }
    return false;
  }
}
 
var players = [
  new Perso("toto",1), new Perso("tutu",2)
];
 
// create the shop, filling with items taken at random
var shop = [];
for(let i=0;i<10;i++) {
  let idx = getRandomInt(items.length);
  shop.push(items[idx]);
}

 


2°/ index.js

  • Tout ce qui concerne l'affichage dynamique ET les événements est maintenant géré grâce à vuejs.
  • La propriété calculée player consiste juste à faire un return d'un élément de players. NB : si on sort de ce tableau, la porirété calculée prend comme valeur undefined, ce qui peut être testé.
  • La méthode buy() contient en gros les mêmes choses que celle de model.js du TP 3.
  • contenu de index.js :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
var app = new Vue({
  el: '#mydiv',
  data: {
    idPlayer:'',
    players,  // to observe and have an access to players array
    shop, // to observe the shop
    idToBuy:'',
    idDrag : -1 // the id in boughtItems of the item currently dragged
  },
  computed : {
    player : function() {
      return players[this.idPlayer];
    }
  },
  methods: {
    /* NB : since shop defined in data observes shop defined in model.js
    any modification of the latter will be observed. Thus, we can
    use directly shop instead of this.shop in the following code.
    */
    buy : function() {
      if (shop[this.idToBuy].price > this.player.gold) {
        alert("Not enough gold");
      }
      else {
        let r = confirm("want to buy " + shop[this.idToBuy].name+" for "+shop[this.idToBuy].price+"gp ?");
        if (r == true) {
          this.player.buy(shop[this.idToBuy]);
          shop.splice(this.idToBuy,1);
          this.idToBuy='';
        }
      }
    },
    dragStart(index) {
      console.log("start dragging "+this.player.boughtItems[this.idDrag].name);
      this.idDrag = index;
    },
    dragEnd() {
      console.log("stop dragging");
      this.idDrag = -1;
    },
    drop(slot) {
      console.log("item dropped on "+slot);
      this.player.assign(this.idDrag,slot);
    }
  }
})

 


4°/ shop.html
  • Grâce à l'ajout de la propriété claculée player, toutes les occurences de players[idPlayer] ont été remplacées par player.
  • Pour que l'événement dragstart appelle dragStart(index), il suffit d'assigner la valeur index grâce à v-for. En effet, v-for permet de récupérer l'indice des éléments parcourus, par ex v-for="(el,index) in ...".
  • Par rapport au TP 3, la gestion de la boutique a un peu changé : on n'ajoute/retranche plus 1 à index. En fait, ce n'était utile que pour le TP 3 où 2 versions de la boutique cohabitent et doivent appeler la même fonction buy().
  • contenu de shop.html :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="model.js"></script>
</head>
<body>
  <div id="mydiv">
    <label for="idperso">#player:</label><input id="idperso" v-model="idPlayer"><br>
    <div v-if="player != undefined">
      <h1>{{player.name}}, level {{player.level}}, life = {{player.life}}, strength =  {{player.strength}}</h1>
      <table border="1">
        <tr v-for="sl in player.slots">
          <td @dragover.prevent @drop="drop(sl.name)">{{sl.name}}</td>
          <td v-for="it in sl.items">{{it.name}}</td>
        </tr>
      </table>
      <p>Bought items :<button draggable="true" v-for="(it,index) in player.boughtItems" @dragstart="dragStart(index)" @dragend="dragEnd()">{{it.name}}</button></p>
      <label for="gold">Gold:</label>
      <input type="text" readonly id="gold" :value="player.gold"><br>
 
      <p v-for="(it,index) in shop">
        <input type="radio" name="itemsToBuy" :id="'ittobuy'+index" :value="index" v-model="idToBuy">
        <label :for="'ittobuy'+index">{{it.name}} : {{it.price}} gp</label>
      </p>
      <button @click="buy()" v-if="shop[idToBuy]!=undefined">Buy {{shop[idToBuy].name}}</button>
 
    </div>
  </div>
  <script src="index.js"></script>
</body>
</html>

 



4°/ Archive globale

  • Vous pouvez télécharger une archive avec tous les fichiers [ ici ]