# Soya 3D tutorial1# Copyright (C) 2004 Jean-Baptiste LAMY2#3# This program is free software; you can redistribute it and/or modify4# it under the terms of the GNU General Public License as published by5# the Free Software Foundation; either version 2 of the License, or6# (at your option) any later version.7#8# This program is distributed in the hope that it will be useful,9# but WITHOUT ANY WARRANTY; without even the implied warranty of10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11# GNU General Public License for more details.12#13# You should have received a copy of the GNU General Public License14# along with this program; if not, write to the Free Software15# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA161718# basic-6: Event management : a mouse-controlled caterpillar1920# This time, we'll use the mouse to control the caterpillar.212223# Import the Soya module.2425import sys, os, os.path, soya, soya.sdlconst2627soya.init()28soya.path.append(os.path.join(os.path.dirname(sys.argv[0]), "data"))2930# Creates a scene.3132scene = soya.World()3334# The CaterpillarHead class is very similar to the CaterpillarHead class of the previous35# lesson.3637class CaterpillarHead(soya.Volume):38def __init__(self, parent):39soya.Volume.__init__(self, parent, soya.Shape.get("caterpillar_head"))40self.speed = soya.Vector(self, 0.0, 0.0, 0.0)41self.rotation_lateral_speed = 0.042self.mouse_x = 043self.mouse_y = 04445def begin_round(self):46soya.Volume.begin_round(self)4748# Loops over all Soya / SDL events.4950for event in soya.process_event():5152# Checks for mouse motion events, and store the mouse cursor X, Y coordinates.5354if event[0] == soya.sdlconst.MOUSEMOTION:55self.mouse_x = event[1]56self.mouse_y = event[2]5758# Computes the mouse coordinates in 3D. Camera.coord2d_to_3d takes the X and Y mouse 2D59# coordinates, and an optional Z coordinates (as it canoot guess the third coordinate ;60# Z default to -1.0).6162# Here, we use for Z the Z coordinates of the caterpillar in the camera coordinate63# system: we consider the mouse cursor to be at the same depth that the caterpillar.64# The % operator is used for coordinate system conversion:65# position % coordinate_system66# returns position converted into coordinate_system (possibly position itself if it67# is already in the right coordinate system).6869mouse_pos = camera.coord2d_to_3d(self.mouse_x, self.mouse_y, (self % camera).z)7071# Then, converts the mouse position into the scene coordinate system, and set its Y72# coordinate to 0.0, because we don't want the caterpillar to start flying !73# (remember, Y is the upper direction).7475mouse_pos.convert_to(scene)76mouse_pos.y = 0.07778# Computes the speed Z coordinate ; we don't want a constant speed: the farther the79# mouse cursor is, the faster the caterpillar moves.80# Thus the speed Z coordinate is the distance from the caterpillar to the mouse,81# and it must be negative (cause -Z is front).8283self.speed.z = -self.distance_to(mouse_pos)8485# Rotations toward the mouse.8687self.look_at(mouse_pos)8889def advance_time(self, proportion):90soya.Volume.advance_time(self, proportion)91self.add_mul_vector(proportion, self.speed)929394# We change CaterpillarPiece, so it can deal with the variable-speed head.9596class CaterpillarPiece(soya.Volume):97def __init__(self, parent, previous):98soya.Volume.__init__(self, parent, soya.Shape.get("caterpillar"))99self.previous = previous100self.speed = soya.Vector(self, 0.0, 0.0, -0.2)101102def begin_round(self):103soya.Volume.begin_round(self)104105# As the speed can be very high, we need to take into account the speed of the previous106# piece (the one we are moving toward).107# Computes the next position of the previous piece, by translating the piece by the108# piece's speed vector.109110previous_next_pos = self.previous + self.previous.speed111112# Looks toward the previous piece's next position.113114self.look_at(previous_next_pos)115116# Computes the speed's Z coordinate. We use the distance between this piece and the117# next position of the previous one, and we remove 1.5 because we want each piece118# to be sepaarated by 1.5 distance units.119120self.speed.z = -(self.distance_to(previous_next_pos) - 1.5)121122def advance_time(self, proportion):123soya.Volume.advance_time(self, proportion)124self.add_mul_vector(proportion, self.speed)125126127# Creates a caterpillar head and 10 caterpillar piece of body.128129caterpillar_head = CaterpillarHead(scene)130caterpillar_head.rotate_lateral(90.0)131132previous_caterpillar_piece = caterpillar_head133for i in range(10):134previous_caterpillar_piece = CaterpillarPiece(scene, previous_caterpillar_piece)135previous_caterpillar_piece.x = i + 1136137# Creates a light.138139light = soya.Light(scene)140light.set_xyz(2.0, 5.0, 1.0)141142# Creates a camera.143144camera = soya.Camera(scene)145camera.set_xyz(0.0, 15.0, 15.0)146camera.look_at(caterpillar_head)147soya.set_root_widget(camera)148149soya.Idler(scene).idle()150151