StarBlender
|
StarBlender
tut4
GAME BLENDER & PYTHON
1/2
Ce tutorial va décrire les étapes du script permettant de
faire déplacer un objet vers un lieu précis défini par un
empty déplaçable à la souris ( comme dans tous les jeux de
stratégie ). Mais c'est surtout un bon moyen de se familiariser
avec Python dans Game Blender. Les parties du script seront
ecrites en bleue.
commandes utiles pour l'editeur de textes :
copier : alt-C
coller : alt-V
caractère " [ " : touche " ^ " en clavier
QWERTY ( configurez une option pour passer du clavier AZERTY au
QWERTY )
caractère " ] " : touche " $ " en QWERTY
caractère " # " : touche " * " en QWERTY (
ce caractère en début de ligne signifie que c'est un comentaire
et elle n'est donc pas pris en compte dans le script )
1°) Bon, commençons tout de suite par le plus dur : le
script. Créez donc un nouveau fichier texte dans la fenêtre
appropriée ( shift-F11 puis cliquez sur et add new
). Au début de chaque script, on doit importer les modules que l'on
va utiliser. Ici on aura besoin de celui de Game Blender ( normal
) et du Rasterizer ( qui comprend tout ce qui attrait à
la fenêtre 3D ). Pour cela, tapez :
import Rasterizer
import GameLogic (
ou from GameLogic
import *, au choix )
Veillez à bien respecter les majuscules et miniscules si vous ne
voulez pas retrouver des erreurs dans le script. La syntaxe est
très importante dans les scripts.
Le script fonctionne avec la souris il faut donc tenir compte
de la taille de la fenêtre 3D pour les calcul de la position du
curseur. Le module Rasterizer a des fonctions de capture
de dimensions de la fenêtre, d'où son utilité. En trez donc
ces fonctions :
l = Rasterizer.getWindowWidth()
L = Rasterizer.getWindowHeight()
Vous l'aurez compris, la première ligne est pour la largeur et
la seconde, la hauteur. On le voit ici, pour affecter une valeur
à une variable, il suffit d'un "=". Il faut toujours
une variable ou un mudule avant une fonction. Ici c'est Rasterizer
qui a été mis avant la fonction get(...). ( Il faut séparer
la fonction de la variable avec un point )
Faîtes un test : ajoutez en dessous :
print l, L ( la
fonction print doit être suivie d'une variable, plusieurs
variables peuvent être appelées en étant intercalées d'une
virgule )
Créez un objet quelconque et ajoutez-lui un sensor "always"
lié à un contrôleur "Python : "nom du script
" ".
Démarrez le jeu avec P, quittez ( échap ) et regardez la fenêtre
DOS. Normalement, les dimensions de la fenêtre 3D doivent être
affichées. S'il est affiché "PYTHON SCRIPT ERROR", vérifiez
le script, normalement l'erreur est affichées juste en dessous.
Ca marche ? Bon effacez la dernière ligne.
2°) On va maintenant accéder à la logique du jeu. Il faut déjà
déclarer le contrôleur Python avec une variable ( ex : cont )
cont = GameLogic.getCurrentController() ( si vous avez rentré from GameLogic import * au début, ne tapez pas le Gamelogic. )
Nous allons maintenant ouvrir l'accès aux données de l'objet :
ow = cont.getOwner() (
comme tout à l'heure, vous pouvez donner n'importe quel nom à
la variable. On doit également utiliser la précédente variable
"cont" ).
On doit maintenant créer une liste de tous les actuators
et sensors liés au contrôleur, que l'on va utiliser dans
le script.
senslist = cont.getSensors()
actlist = cont.getActuators() ( ici encore, la variable "cont" est utilisée
car on fait appel au contrôleur )
Dans la logique, il y aura un sensor ( la position de la
souris ) et un actuator ( la position de l'empty )
liés au contrôleur Python.
mousesensor = senslist[0] ( le chiffre entre crochet définis la position du
sensor, attention ça commence par 0 )
newloc = actlist[0] (
plus généralement, lorsque une liste est affecté à une
variable, on accède à une donnée de la liste en indicant avec
des crochet la position de la donnée. Si vous démarrez le
script vous aurez un message d'erreur "LIST INDEX OUT OF
RANGE". C'est normal, aucun actuator n'est lié au contrôleur,
donc créez un empty avec un actuator ( n'importe lequel ) lié
au contrôleur )
3°) Maintenant que l'on a posé les bases, on va commencer le
coeur du script. Voici son principe : on demande la position du
curseur à partir du centre de l'écran ( donc de la caméra ) et
on calcule ensuite sa position dans la scène en général en
ajoutant les coordonnées de la caméra. Et lorsque l'on clique
sur le bouton gauche de la souris, l'empty viendra se
positionner sur ces coordonnées, donc sur le curseur. Voilà,
rien de pluss simple. Donc commençons par obtenir les coordonnées
de la camera :
campos = ow.getPosition() ( On a utilisé ici, la variable "ow" définie
plus haut qui donne accès aux informations de l'objet, la
fonction getPosition crée une liste de 3 élément, les coordonnées
x, y, et z )
A présent, les coordonnées de la souris à l'écran :
x = mousesensor.getXPosition()
y = mousesensor.getYPosition()
Vous pouvez tester cette fonction en remplaçant le sensor "always"
par un "mouse" avec l'option "trigger on
movement" enclenchée.
Target est bien sur le nom de l'empty et
globLoc, celui du script
Et en ajoutant bien sûr au script :
print x, y
4°) Vous remarquez que l'origine des coordonnées de la
position de la souris est le coin en haut à gauche, or on
aimerai bien que ce soit le centre de l'écran. De plus, pour
faciliter les calculs sui vont suivre, il faudrait avoir les
coordonnées entre -1 et 1. Ex :
centre : 0 ; 0
coin en bas à gauche : -1 ; -1
coin en bas à droite : 1 ; -1
coin en haut à droite : 1 ; 1
coin en haut à gauche : -1 ; 1
Juste un peu de réflexion et on trouve le truc :
screenposx = 2.0 * ( x - l/2 ) / l
screenposy = 2.0 * ( ( L - y ) - L/2 ) / L ( bon c'est des maths, je vais pas vous décrire le
truc ; la seule chose à remarquer est le "2.0". Et oui
pourquoi pas 2 ? Et ben parceque à la base, x et y sont déclaré
comme entier or des entiers entre 0 et 1 y'en a pas des masses,
on est donc obligé de forcer la virgule avec un " .0 "
( merci Olivier pour ce petit truc ) )
Comme d'habitude, pour vérifier :
print screenposx, screenposy
5°) A présent, il faut convertir cette position à l'écran
en position dans la scène. Le problème c'est que quand la caméra
change de hauteur, la souris ne couvre plus la même zone donc :
problème. On va donc introduire une petite variable en fonction
de la hauteur. La postion de l'écran pour l'instant correspond
avec celle de la scène si la caméra ne couvre que 4 carré (
donc des coordonnées de -1 à 1, comme la souris ). Donc on
place la caméra à cette hauteur et on note sa position sur l'axe
z. A présent il suffit de diviser n'importe quelle hauteur de la
caméra par ce nombre pour savoir le facteur d'agrandissement (
visuel ) de la scène et multiplier la position de la souris en
conséquence. Ex :
_scène visible : de -1 à 1
_hauteur de la caméra : X
_scène visible : de -2 à 2
_hauteur caméra : 2X
facteur d'agrandissement : 2 donc on multiplie les coordonnées
de la souris par 2 ( bon je sais c'est pas très clair... ;) )
Ce fameux X, vous pouvez le trouver tous seul mais je vous le
donne ( je suis gentil :) ) : 1.265 pour la largeur et 1.84 pour
la hauteur ( hé oui la caméra n'est pas carré ; attention, c'est
avec un lens de 35 ). Donc :
deltax = campos[2] / 1.265
deltay = campos[2] / 1.84 ( le 2 correspond au troisième élément de la liste
"campos" c'est-à-dire la hauteur de la caméra )
On convertit maintenant les coordonnées de la souris en coordonnées
globales en ajoutant la position de la caméra et on crée une
liste de coordonnées :
newposx = campos[0] + screenposx * deltax
newposy = campos[1] + screenposy * deltay
newposz = 0
newpos = [newposx, newposy, newposz]
Vérification :
print newpos ( déplacez
la caméra, normalement la position de la souris donne les
coordonées globales... )
6°) Maintenant il ne reste plus qu'a fournir ces coordonnées
à l'empty pour qu'il se place à l'endroit voulu.
Seulement si on le fait directement, comme çà, l'empty se
positionnera toujours sous la souris. Nous allons donc mettre une
condition qui implique que le bouton gauche soit pressé. Bon en
fait je n'ai pas trouvé cette fonction, on va donc utiliser une
propriété "clic" qui ne se met sur "on" dès
qu'on appuie sur le bouton gauche. On va commencer par finir le
script puis on verra la logique dans la 2ème partie. Il font
donc commencer par déclarer la propriété "clic" :
clic = ow.clic (
et çà fonctionne de même pour toutes les propriétés, ainsi
la variable "clic" a la même valeur que la propriété
)
Là on va devoir ouvrir l'accès aux données de l'empty pour
lui donner ces coordonnées, seulement l'empty n'est pas
le porteur duscript. Mais si vous regardez haut début du script,
on a définit l'actuator ( porté par l'empty ) par
la variable newloc. Donc il faut passer par cet actuator pour
arriver à l'objet lui même :
ow2 = newloc.getOwner()
Maintenant on peut écrire la condition et son effet :
if clic == "on": ( attention pour une condition, il faut 2
"=" ; remarquez que les valeurs avec des chaînes de
caractères sont entre guillemets )
ow2.setPosition(newpos) ( ne surtout pas oublié la tabulation, elle indique
la hiérarchie, dans le cas contraire, elle serait ignorée ).
7°) Ca y est le script est fini mais tel quel, il ne marchera
pas, il manque un petit peu de logique ( pour la condition "clic"
). mais le plus dur est passé. Voici le script complet :
import Rasterizer
import GameLogic
l = Rasterizer.getWindowWidth()
L = Rasterizer.getWindowHeight()
cont = GameLogic.getCurrentController()
ow = cont.getOwner()
senslist = cont.getSensors()
actlist = cont.getActuators()
mousesensor = senslist[0]
newloc = actlist[0]
campos = ow.getPosition()
x = mousesensor.getXPosition()
y = mousesensor.getYPosition()
screenposx = 2.0 * ( x - l/2 ) / l
screenposy = 2.0 * ( ( L - y ) - L/2 ) / L
deltax = campos[2] / 1.265
deltay = campos[2] / 1.84
newposx = campos[0] + screenposx *
deltax
newposy = campos[1] + screenposy * deltay
newposz = 0
newpos = [newposx, newposy, newposz]
clic = ow.clic
ow2 = newloc.getOwner()
if clic == "on":
ow2.setPosition(newpos)
( les interlignes ne définissent
rien, c'est juste pour rendre le script plus clair )
SUITE
|
StarBlender
Aujourd'hui :
mercredi 24 avril 2024 Dernière modification : 2001
Version de Blender : 2.12
©copyright Abjedi 2001
|