truc=145
Alors partout dans mon code, je pourrais utiliser le mot "truc" pour désigner le nombre 145. Pour l'instant, ça vous parait pas très utile, on est d'accord. Mais sans variable, on ne peut pas faire d'informatique.if (condition) then
liste d'instructions
else (facultatif)
autre liste d'instruction (facultatif)
end
Par exemple, si j'écris :truc=145
if (truc<150) then
truc=30
end
Voila ce qui se passe :truc=301
if (truc<150) then
truc=30
end
Comme 301 n'est pas inférieur à 150, je n'exécute pas le "truc=30". A la fin de mon code, "truc" est toujours égal à 301.truc=301
if (truc<150) then
truc=30
else
truc=456
end
Les instructions écrites entre "else" et "end" sont exécutées si et seulement si la condition du if n'est pasvraie.for truc=1,8 do
machin=truc
end
est équivalent à :machin=1
machin=2
machin=3
machin=4
machin=5
machin=6
machin=7
machin=8
Explication : "for truc=1,8 do" veut dire "pour truc allant de 1 à 8, je fais". Donc on fait les instructions pour truc=1, puis pour truc=2, et ainsi de suite jusqu'à truc=8.for truc=1,11,2 do
machin=truc
end
Vous avez remarqué le "2" ? Situé comme il est, il veut dire qu'au lieu de compter "truc" de 1 en 1, on le compte de 2 en 2. Ce code est donc équivalent à :machin=1
machin=3
machin=5
machin=7
machin=9
machin=11
Passons au while. Son utilisation est parfois plus naturelle que le for, mais leurs utilisations est globalement similaire. Syntaxe :while(condition) do
instructions
end
Veut dire : tant que la condition est vraie, j'exécute les instructions entre le do et le end.compteur=0
truc = 0
while(compteur<3) do
compteur = compteur + 1
truc = truc + 3
end
Première arrivée au while, compteur et truc sont à 0. 0 est inférieur à 3, donc on rentre dans les instructions. Deuxième passage par le while, on a donc compteur à 1 et truc à 3.for nbr=0,40,2 do
run_cmd("echo " .. nbr)
end
Code:nbr = 0
while(nbr<41) do
run_cmd("echo " .. nbr)
nbr = nbr + 2
end
chaine_resultat = ""
for i=0,40,2 do
chaine_resultat = chaine_resultat .. " " .. i
end
run_cmd("echo " .. chaine_resultat)
En gros :-- initialisation
joints_uke = { }
for i=0,19 do
joints_uke[i] = math.random(1,4)
run_cmd("echo Le joint n°" .. i .. " est a l'etat : " .. joints_uke[i])
end
On verra dans un prochain cours comment réellement faire un random ukebot... c'est facile vous verrez.function nom_de_lafonction([param1,[param2,[...]]])
....Instructions....
[return une_valeur]
end
Tout qui est entre [] est facultatif.function hw()
run_cmd("echo hello world")
end
Si vous n'écrivez que ça dans votre programme lua, il ne fera rien. Il ne s'agit que de la définition de la fonction, il faut maintenant l'appeler comme ceci, à la suite de la définition.hw()
Allez, un exemple compliqué. Une fonction qui retourne une phrase décrivant l'état d'un joint (selon notre tableau de toute à l'heure, pas encore l'état des vrais joints).joints_uke = { }
-- notre fonction
function display_joint(no_joint)
resultat = "Le joint no " .. no_joint .. " est "
if(joints_uke[no_joint] == 1) then
resultat = resultat .. "contract"
elseif(joints_uke[no_joint] == 2) then
resultat = resultat .. "extend"
elseif(joints_uke[no_joint] == 3) then
resultat = resultat .. "hold"
elseif(joints_uke[no_joint] == 4) then
resultat = resultat .. "relax"
end
return resultat
end
-- on remplit notre tableau
for i=0,19 do
joints_uke[i] = math.random(1,4)
end
--On appelle notre fonction pour les joints 0 et 4.
run_cmd("echo " .. display_joint(0))
run_cmd("echo " .. display_joint(4))
Si vous avez compris cet exemple, vous maîtrisez parfaitement les fonctions. Vous pouvez vous attaquer au TP n°2.add_hook(evenement, nom_du_groupe, votre_fonction)
-> evenement est l'évènement déclencheur du hook. C'est une chaîne de caractère (chaîne entre guillemets) parmi la liste décrite plus bas.
-> nom_du_groupe sert à préciser le groupe du hook. Cela permet de 'classer' vos hooks en plusieurs groupes distincts afin de ne retirer les hooks appartenant à un groupe tout en laissant les autres. C'est également une chaîne de caractère, définie par vos soins.
-> votre_fonction est le nom (sans guillemets, cette fois) de la fonction que vous voulez appeler quand l'évènement 'evenement' a lieu
Vous pouvez également retirer un hook ou un groupe de hook :remove_hook(evenement, nom_du_groupe, votre_fonction) -- suppression d'un hook
remove_hooks(evenement, nom_du_groupe) -- suppression d'un groupe de hooks
La liste des évènements "hookables" est décrite dans startup.lua :"new_game" (début d'une nouvelle partie)
"new_mp_game" (début d'une nouvelle partie multiplayer)
"enter_frame" (entrée dans une nouvelle frame)
"end_game" (fin d'une partie ou d'un replay)
"leave_game" (fin d'une partie ou d'un replay, pas vu de différences notables avec le précédent)
"enter_freeze" (entrée dans le mode 'edit')
"exit_freeze" (sortir du mode 'edit')
"key_up" (une touche du clavier a été relachée)
"key_down" (une touche du clavier a été pressée)
"mouse_button_up" (un bouton de la souris a été relaché)
"mouse_button_down" (un bouton de la souris a été pressé)
"mouse_move" (la souris a été bougée)
"player_select" (un joueur a été sélectionné (par clic sur son Tori, en mode SP))
"joint_select" (un joint a été sélectionné (quand la souris passe dessus))
"body_select" (pareil qu'au dessus avec les parties du corps, je crois)
"draw2d" (affichage 2D, intervient 30 à 60 fois par secondes, selon votre FPS, juste après draw3D)
"draw3d" (affichage 3D, intervient 30 à 60 fois par secondes, selon votre FPS)
"play" (passage en mode "replay")
"camera" (camera solicitée)
"console" (qq chose a été écrit dans le chat)
-- Tous les suivants sont pour la gestion de la souris sur un joueur dans la liste d'attente, en MP)
"bout_mouse_down"
"bout_mouse_up"
"bout_mouse_over"
"bout_mouse_outside"
"spec_mouse_down"
"spec_mouse_up"
"spec_mouse_over"
"spec_mouse_outside"
Allez, deux exemples concrets avant le TD afin de bien comprendre comment ça marche.local mouse_pos_x = 0
local mouse_pos_y = 0
-- on ecrira en rouge... explications au cours suivant
local function update_coord(x,y)
mouse_pos_x = x
mouse_pos_y = y
end
local function draw_coord()
set_color(1,0,0,1)
draw_text("X : " .. mouse_pos_x,20,100,2)
draw_text("Y : " .. mouse_pos_y,20,120,2)
end
add_hook("mouse_move","coord_souris", update_coord)
add_hook("draw2d","coord_souris", draw_coord)
Lancez le script, bougez la souris... c'est magique.-- les éléments de notre menu
local list_items_menu = {"Item 1","Item 2","Item 3","Item 4","Item 5"}
-- l'élément sélectionné
local selected_item = 1
-- booleen servant a savoir si on doit ou non afficher le menu
local bool_menu = true
local function menu_clavier()
--explications des fonctions 2D la semaine prochaine
--dessin du fond du menu
set_color(0.1,0.1,0.1,0.5)
draw_quad(20, 100, 320, 250)
set_color(0,0.3,0.5,1)
draw_text("Fermez et ouvrez le menu avec 'A'", 25, 105,1)
draw_text("Naviguez avec les fleches et validez avec 'L'", 25, 125,1)
set_color(0,0.1,0.3,1)
for i=1,table.getn(list_items_menu) do
if(i==selected_item) then
set_color(0.8,0,0,1)
draw_text(i .. ". " .. list_items_menu[i], 30, 150+(i*20),1)
set_color(0,0.1,0.3,1)
else
draw_text(i .. ". " .. list_items_menu[i], 30, 150+(i*20),1)
end
end
end
local function key_pressed(key)
-- les return 1 servent à 'annuler' le vrai effet des touches (les flêches ne bougeront pas la caméra si le menu est actif)
if(key == 273 and bool_menu) then
selected_item = selected_item - 1
if (selected_item < 1) then
selected_item = table.getn(list_items_menu)
end
return 1
elseif(key == 274 and bool_menu) then
selected_item = selected_item + 1
if (selected_item > table.getn(list_items_menu)) then
selected_item = 1
end
return 1
elseif(key == 108 and bool_menu) then
run_cmd("echo Item choisi : " .. list_items_menu[selected_item])
return 1
elseif(key == 113 and not bool_menu) then
add_hook("draw2d", "menu_clavier", menu_clavier)
bool_menu = true
return 1
elseif(key == 113 and bool_menu) then
remove_hook("draw2d", "menu_clavier", menu_clavier)
bool_menu = false
return 1
end
if(bool_menu) then
return 1
else
return 0
end
end
add_hook("draw2d", "menu_clavier", menu_clavier)
add_hook("key_down","menu_clavier", key_pressed)
C'est tout pour aujourd'hui. N'hésitez pas à poser des questions, je sais que ça se complique, là.Primitives :
draw_disk(number pos_x, number pos_y, number inner, number outer, integer slices, integer loops, number start, number sweep, integer blend) -> Dessine un donut ou un disque à la position voulue
draw_quad(number pos_x, number pos_y, number width, number height [, integer texture_id]) -> dessine un rectangle, texturé ou non, à la position voulue
Ecriture de texte :
draw_text(string text, number pos_x, number pos_y [, integer font_type]) -> écrit du texte à la position voulue, de la taille voulue.
draw_right_text(string text, number pos_x, number pos_y [, integer font_type]) -> écrit du texte aligné à droite à la position voulue, de la taille voulue. pos_x correspond cette fois à la distance entre la fin du texte et le bord droit de la fenêtre.
draw_centered_text(string text, number pos_y [, integer font_type]) -> Ecrit le texte centré horizontalement, à la hauteur voulue, de la taille voulue
Moins utile :
draw_chat_message(integer index, number pos_x, number pos_y) -> Ecrit le ième message du chat à la position voulue.
draw_chat_messages(number pos_x, number pos_y) -> Ecrit tous les messages du chat à la position voulue
Il existe également d'autres fonctions intéressantes pour le dessin 2D :set_color(number red, number green, number blue, number alpha) -> fixe la couleur pour le dessin de la prochaine primitive. Red, Green, Blue et Alpha (transparence) sont des valeurs décilmales comprises entre 0 et 1.
get_window_size(...) = number,number -> Pour récupérer la taille de la fenêtre (voir exemple dans l'énoncé du TD)
get_screen_pos(number x, number y, number z); = number,number -> pour récupérer les coordonnées 2D courantes d'un point 3D
J'imagine qu'il doit rester quelques points obscurs, notamment sur les disks, les quads à textures et les polices de caractères, que j'ai honteusement oublié de décrire en détail. Je vais le faire en exemple :local function hook2D_display()
set_color(0.5,0,0,1)
for i=0,3 do
draw_text("Ecriture en police " .. i, 10, 100+(60*i),i)
end
end
add_hook("draw2d", "exemple", hook2D_display)
Les quads, avec ou sans textures : copier une head texture dans votre dossier data/scripts et exécuter le code suivant :texid = load_texture("head.tga")
local function hook2D_display()
set_color(0,0,0,1)
draw_text("un rectangle noir sans texture :",10,100)
draw_quad(240, 100, 60, 45)
draw_text("un rectangle avec texture :",10,160)
set_color(1,1,1,1) -- nécessaire de remettre une couche de blanc
draw_quad(240, 160, 60, 45, texid)
end
add_hook("draw2d", "exemple", hook2D_display)
Les disks, explications des divers paramètreslocal function hook2D_display()
set_color(0,0,0.3,1)
-- Disque complet :
draw_disk(70, 100, 0, 50, 32, 1, 0, 360, 0)
-- Camembert
draw_disk(70, 230, 0, 50, 32, 1, 40, 300, 0)
-- Donut :
draw_disk(70, 360, 20, 50, 32, 1, 0, 360, 0)
-- Carre
draw_disk(170, 230, 40, 50, 4, 1, 45, 360, 0)
-- Triangle
draw_disk(170, 360, 40, 50, 3, 1, 180, 360, 0)
end
add_hook("draw2d", "exemple", hook2D_display)
Voila, voila, vous êtes prêts pour le TP.Primitives :
draw_box( number pos_x, number pos_y, number pos_z, number size_x, number size_y, number size_z, number rotation_x, rotation_y, rotation_z) -- modélisation d'un pavé
draw_capsule( number pos_x, number pos_y, number pos_z, number height, number radius, number rotation_x, rotation_y, rotation_z) -- modélisation d'une capsule (exemple : les tibias de votre tori sont des capsules)
draw_disk_3d(number pos_x, number pos_y, number pos_z, number inner, number outer, integer slices, integer loops, number start, number sweep, integer blend) -- modélisation d'un disque (cercle plein), qui pour moi bugge à mort
draw_sphere( number pos_x, number pos_y, number pos_z, number radius) -- modélisation d'une sphère
Primitives avec matrices de rotation :
draw_box_m( number pos_x, number pos_y, number pos_z, number size_x, number size_y, number size_z, table matrix_rot)
draw_capsule_m( number pos_x, number pos_y, number pos_z, number height, number radius, table matrix_rot)
draw_sphere_m( number pos_x, number pos_y, number pos_z, number radius, table matrix_rot)
Divers :
set_color(number red, number green, number blue, number alpha) -- fixe la couleur pour le dessin de la prochaine primitive. Red, Green, Blue et Alpha (transparence) sont des valeurs décilmales comprises entre 0 et 1.
draw_ground_impact(integer player_index) -- peu utile, dessine un disque creux sous le joueur indiqué.
Ok, donc la principale difficulté est d'ordre mathématique : vous devez maitriser les coordonnées spatiales (x,y,z) et surtout les rotations spatiales (pas évident du tout). Je suis pas le mieux placé pour expliquer tout ça, je m'aide pas mal des forums mathématiques quand j'ai un problème.local function draw_temple()
set_color(0.9,0.9,0.9,1)
draw_box(0, 0, 12, 65, 65, 2, 0, 0, 0)
end
add_hook("draw3d", "lua_tuto", draw_temple)
On va ajouter les colonnes à l'aide de plusieurs capsules bien réparties. On pourrait les ajouter une par une, mais comme nous sommes fainéants (et intelligents) on va plutôt utiliser des "for". Toutes nos capsules auront la même hauteur, et les mêmes dimensions. Elles auront également toutes une rotation nulle en tout angle. Seuls les paramètres correspondant aux positions et x et en y vont varier d'une colonne à l'autre, c'est ce qu'on va faire varier dans nos for.for i=0,5 do
draw_capsule( 30, (-30 + 12*i), 6, 12, 1, 0, 0, 0)
draw_capsule( -30, (-30 + 12*i), 6, 12, 1, 0, 0, 0)
end
On aurait pu modéliser aussi les 2 autres côtés du temple, en utilisant le même for, deux autres draw_capsule mais avec les coordonnées x et y inversées. L'ennui c'est que chaque angle aurait été doublé, ce qui est inutile est couteux (pas trop, mais mieux vaut prendre tout de suite de bonnes habitudes). On va donc faire un autre for, mais cette fois en supprimant les colonnes extrèmes, donc un for de 0 à 4.for i=1,4 do
draw_capsule( (-30 + 12*i), 30, 6, 12, 1, 0, 0, 0)
draw_capsule( (-30 + 12*i), -30, 6, 12, 1, 0, 0, 0)
end
Si vous n'avez pas les shaders, le sol est transparent dans un monde blanc, donc vous voyez le bas de colonnes et c'est moche. On va donc faire un sol opaque qui cache ça : un pavé très fin à altitude 0.draw_box(0, 0, 0, 70, 70, 0.001, 0, 0, 0)
Et voila notre temple !local function draw_temple()
set_color(0.9,0.9,0.9,1)
draw_box(0, 0, 12, 65, 65, 2, 0, 0, 0)
draw_box(0, 0, 0, 70, 70, 0.001, 0, 0, 0)
for i=0,5 do
draw_capsule( 30, (-30 + 12*i), 6, 12, 1, 0, 0, 0)
draw_capsule( -30, (-30 + 12*i), 6, 12, 1, 0, 0, 0)
end
for i=1,4 do
draw_capsule( (-30 + 12*i), 30, 6, 12, 1, 0, 0, 0)
draw_capsule( (-30 + 12*i), -30, 6, 12, 1, 0, 0, 0)
end
end
add_hook("draw3d", "lua_tuto", draw_temple)
Et bien, je crois qu'on peut passer au TD.http://www.toribash.com/Toribash-(Numéro de la version)-Setup.exe-Setup.exe
#!/usr/bin/toribash
#made with toribash-3.31
#SCORE 0 0
#WIN 0
VERSION 10
FIGHTNAME 0; le nom de votre replay
BOUT 0; votre pseudo (ou "Tori")
BOUT 1; uke
AUTHOR 0; le nom du créateur du replay
NEWGAME 0;500 10 0 0 0 2 100 1 0 classic 0 0 100 0 0 0 1 0 2 0 0 0 0 0 0 0.000000 0.000000 -9.820000 1 0
4) Supprimer la ligne entière de texte qui commence par "NewGame", et collez le texte suivant à sa place:ENGAGE 0; 0.000000 0.000000 0.000000 0 0 180
ENGAGE 1; 3.500000 5.000000 0.000000 0 0 0
ENGAGE 2; 0.000000 5.000000 0.000000 0 0 0
ENGAGE 3; -3.500000 5.000000 0.000000 0 0 0
NEWGAME 0;1000 10 0 0 0 2 100 1 0 classic 0 0 100 0 0 0 1 0 4 0 0 0 0 0 0
0.000000 0.000000 -9.820000 1 0
Cela devrait maintenant ressembler à ceci:#!/usr/bin/toribash
#made with toribash-3.31
#SCORE 0 0
#WIN 0
VERSION 10
FIGHTNAME 0; le nom de votre replay
BOUT 0; votre pseudo (ou "Tori")
BOUT 1; uke
AUTHOR 0; le nom du créateur du replay
ENGAGE 0; 0.000000 0.000000 0.000000 0 0 180
ENGAGE 1; 3.500000 5.000000 0.000000 0 0 0
ENGAGE 2; 0.000000 5.000000 0.000000 0 0 0
ENGAGE 3; -3.500000 5.000000 0.000000 0 0 0
NEWGAME 0;1000 10 0 0 0 2 100 1 0 classic 0 0 100 0 0 0 1 0 4 0 0 0 0 0 00.000000 0.000000 -9.820000 1 0
----en option-----BOUT 2; nom que vous voulez donner au joueur 3
BOUT 3; nom que vous voulez donner au joueur 4
l_biceps = left bicep texture
r_biceps = right bicep texture
l_triceps = left tricep texture
r_triceps = right tricep texture
l_hand = left hand texture
r_hand = right hand texture
l_foot = left foot texture
r_foot = right foot texture
l_pecs = left pec texture
r_pecs = right pec texture
l_thigh = left thigh texture
r_thigh = right thigh texture
l_leg = left leg texture
r_leg = right leg texture
chest = chest texture
breast = breast texture
groin = groin texture
head = head texture
stomach = stomach texture
ground = ground texture
dq = dq texture
trail_r_leg = right leg trail texture
trail_l_leg = left leg trail texture
trail_r_arm = right arm trail texture
trail_l_arm = left arm trail texture
(toujours suivis de .tga)
Code couleurs
Définition du mot LECTURE SEULE : Caractéristique d'une lecture d'un fichier qui n'autorise ni la modification, ni l'effacement, ni l'écrasement.