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

By default

Untitled Untitled

Pour vous, GameBlender est :
sans avenir.
d�cevant.
int�ressant.
prometteur.
g�nial.
 

resultats

©copyright Abjedi 2001