Soya/Python base 6

# -*- indent-tabs-mode: t -*-

# Soya 3D tutorial
# Copyright (C) 2004 Jean-Baptiste LAMY
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


# base 6 : gestion des évenements, controler la chenille avec la souris

# Nous allons voir comment contrôler la chenille avec la souris.


# Importation des modules.

import sys, os, os.path, soya, soya.sdlconst

soya.init()
soya.path.append(os.path.join(os.path.dirname(sys.argv[0]), "data"))

# Création d'une scène.

scene = soya.World()

# La classe CaterpillarHead est similaire à celle du tutorial précédent.

class CaterpillarHead(soya.Body):
        def __init__(self, parent):
                soya.Body.__init__(self, parent, soya.Model.get("caterpillar_head"))
                self.speed             = soya.Vector(self, 0.0, 0.0, 0.0)
                self.rotation_y_speed  = 0.0
                self.mouse_x           = 0
                self.mouse_y           = 0
                
        def begin_round(self):
                soya.Body.begin_round(self)
                
                # Boucle pour tous les évenements Soya / SDL.
                
                for event in soya.process_event():
                        
                        # Verification des évenements de la souris, et conservation des coordonnées X et Y du curseur.
                        
                        if event[0] == soya.sdlconst.MOUSEMOTION:
                                self.mouse_x = event[1]
                                self.mouse_y = event[2]
                                
                # Le calcul des coordonnées de la souris est en 3D, Camera.coord2d_to_3d renvoie les coordonnées X et Y d'une souris en 2D
                # et une coordonnée optionnel Z (puisqu'il ne peut pas bien le gérer, la valeur de Z par défaut est -1.0).
                
                # Maintenant, nous utilisons pour Z les coordonnées Z de la chenille dans les coordonnées du système de la caméra :
                # nous considérons que le curseur est à la même hauteur que la chenille.
                # l'opérateur % est utilisé pour la conversion des coordonnées :
                #     position % coordinate_system
                # retourne la position convertie dans coordinate_system (possibly position itself if it
                # is already in the right coordinate system).
                
                mouse_pos = camera.coord2d_to_3d(self.mouse_x, self.mouse_y, (self % camera).z)
                
                # Alors ca convertit la position de la souris en système de coordonnées pour la scène, et met les 
                # coordonnées de Y à 0.0, car nous ne voulons pas d'une chenille qui vole
                # (souvenez vous que Y est l'axe de la hauteur).
                
                mouse_pos.convert_to(scene)
                mouse_pos.y = 0.0
                
                # Calcul de la vitesse de coordonnée Z ; nous ne voulons pas une vitesse constante : plus le curseur est loin
                # et plus la chenille va vite.
                # Ainsi, la vitesse de coordonnée Z est la distance entre la chenille et la souris, et doit être négative
                # (car -Z est vers le haut).
                
                self.speed.z = -self.distance_to(mouse_pos)
                
                # Rotations vers la souris.
                
                self.look_at(mouse_pos)
                
        def advance_time(self, proportion):
                soya.Body.advance_time(self, proportion)
                self.add_mul_vector(proportion, self.speed)


# Nous changeons CaterpillarPiece, afin qu'il puisse gérer la variable de vitesse du Head.

class CaterpillarPiece(soya.Body):
        def __init__(self, parent, previous):
                soya.Body.__init__(self, parent, soya.Model.get("caterpillar"))
                self.previous = previous
                self.speed = soya.Vector(self, 0.0, 0.0, -0.2)
                
        def begin_round(self):
                soya.Body.begin_round(self)
                
                # Comme la vitesse peut être très élevée, nous avons besoin de prendre en compte
                # la vitesse précédente (celle que l'on avait lors du mouvement).
                # On calcule ensuite la future position de la pièce par la translation de la piece 
                # par le vecteur vitesse de cette même pièce.
                
                previous_next_pos = self.previous + self.previous.speed
                
                # La chenille regarde vers la futur position de la pièce.
                
                self.look_at(previous_next_pos)
                
                # Calcul de la coordonnée Z de vitesse. Nous utilisons un espace entre une pièce et 
                # sa prochaine position, et nous supprimons 1.5 car nous avons besoin que chaque piece
                # soit séparé par une distance de 1.5 unités.
                
                self.speed.z = -(self.distance_to(previous_next_pos) - 1.5)
                
        def advance_time(self, proportion):
                soya.Body.advance_time(self, proportion)
                self.add_mul_vector(proportion, self.speed)
                

# Creation du Head de la chenille ainsi que 10 pièces de son corps.

caterpillar_head = CaterpillarHead(scene)
caterpillar_head.rotate_y(90.0)

previous_caterpillar_piece = caterpillar_head
for i in range(10):
        previous_caterpillar_piece = CaterpillarPiece(scene, previous_caterpillar_piece)
        previous_caterpillar_piece.x = i + 1
        
# Création d'une lampe.

light = soya.Light(scene)
light.set_xyz(2.0, 5.0, 1.0)

# Création d'une caméra.

camera = soya.Camera(scene)
camera.set_xyz(0.0, 15.0, 15.0)
camera.look_at(caterpillar_head)
soya.set_root_widget(camera)

soya.MainLoop(scene).main_loop()