# -*- 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 # basic-4: Time management : a randomly moving caterpillar # In this lesson, we'll creates a caterpillar composed of a head (we've already done it # in the previous lesson ; now you understand why i have called it a 'head') and ten # spherish piece of body. Each piece of body follows the previous one, or the head for # first piece. # Run the tutorial if you don't understand well what is the caterpillar. # Import the Soya module. import sys, os, os.path, random, soya soya.init() soya.path.append(os.path.join(os.path.dirname(sys.argv[0]), "data")) # Creates a scene. scene = soya.World() # CaterpillarHead is the class for the head of the caterpillar. # It is identical to the Head class of lesson basic-3.py, except the class name. # So... no comment! 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.2) def begin_round(self): soya.Body.begin_round(self) self.rotate_y((random.random() - 0.5) * 50.0) def advance_time(self, proportion): soya.Body.advance_time(self, proportion) self.add_mul_vector(proportion, self.speed) # A CaterpillarPiece is a piece of the body of the caterpillar. # It follows another object -- the previous piece, or the head for the first one. class CaterpillarPiece(soya.Body): # The constructor takes two arguments: the parent and the previous piece of body that # we must follow. # Similarly to the head, we define a speed vector. 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) # We rotates the caterpillar piece so as it looks toward the previous piece. self.look_at(self.previous) # The distance_to method returns the distance between two position. # If we are too close to the previous piece of body, we set the speed's Z to 0.0, # and thus the speed is a null vector : this piece no longer moves. # Else, we reset the speed's Z to -0.2. if self.distance_to(self.previous) < 1.5: self.speed.z = 0.0 else: self.speed.z = -0.2 # advance_time is identical to the CaterpillarHead ones. def advance_time(self, proportion): soya.Body.advance_time(self, proportion) self.add_mul_vector(proportion, self.speed) # Creates a caterpillar head. caterpillar_head = CaterpillarHead(scene) caterpillar_head.rotate_y(90.0) # Creates 10 caterpillar piece of body. previous_caterpillar_piece = caterpillar_head for i in range(10): previous_caterpillar_piece = CaterpillarPiece(scene, previous_caterpillar_piece) previous_caterpillar_piece.x = i + 1 # Creates a light. light = soya.Light(scene) light.set_xyz(2.0, 5.0, 0.0) # Creates a camera. 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() # For information, the caterpillar textures were done in the Gimp, and the model were # generated with this code (see modeling-*.py to understand it) : # import soya.sphere # caterpillar_material = soya.Material(soya.Image.get("chenille.png" )) # caterpillar_head_material = soya.Material(soya.Image.get("chenille_tete.png")) # caterpillar_material .filename = "caterpillar" # caterpillar_head_material.filename = "caterpillar_head" # caterpillar_material .save() # caterpillar_head_material.save() # caterpillar = soya.sphere.Sphere(slices = 12, stacks = 12, material = caterpillar_material) # caterpillar_head = soya.sphere.Sphere(slices = 12, stacks = 12, material = caterpillar_head_material) # caterpillar_head.scale(1.2, 1.2, 1.2) # caterpillar .filename = "caterpillar" # caterpillar_head.filename = "caterpillar_head" # caterpillar .save() # caterpillar_head.save() # XXX put this elsewhere # Lots of Soya methods have also an operator : # # Position + Vector => Point # Position += Vector Position.add_vector(Vector) # Position >> Position Position.vector_to (Position) => Vector # Position %= CoordSyst Position.convert_to(CoordSyst) # Vector * float # Position + Vector => Point # Position += Vector # Position.add_vector(Vector) # Translation or vectorial addition (if the Position is a Vector). # Position >> Position => Vector # Position.vector_to (Position) => Vector # Creates a vector from a strating and an ending position. # Position %= CoordSyst Position.convert_to(CoordSyst) # Vector * float