Sprite

The idea behind sprites is to offer a simple way of creating something like sub-worlds within the main world. Each sprite has its own local coordinate system, mouse events, lights and materials and can in many respects be treated like the main world. Just as the main world, a sprite has an onDraw() which gets called on every frame. The convenience of using sprites is that transformations can be made in relation to the sprite and not the world. By using sprites, a moon would only need to know how to move in relation to the earth sprite and would not have to care about its orbit overlapping with the orbit of the earth.

Sprites are also a convenient way of checking whether the mouse is over a specific graphical object. Each sprite fires various mouse events that precisely reflect how the mouse is interacting with the content of the sprite.

Relevant examples: sprite.py , sprite_all.py solarsystem.py ALL

In Context

from slut import *

class Atlantis(World):
    def onSetup(self):
        self.name = "Sprite"
        self.width = 800
        self.height = 300
        
        Disc(self, 'sprite1')
        p2 = Disc(self, 'sprite2')
        p2.moveBy(-0.5, 0.0, -1.5)
        p2.enableMouseEvents()


class Disc(Sprite):
    def onDraw(self):
        disc(0, 0, 0, 1)
        
    def onMouseIn(self, event):
    	print "The mouse has been moved over the sprite"
    	print "with name: " + self.name


atlantis = Atlantis()
atlantis.run()

Sprites may also be nested in other sprites resulting in a 3D-modeler-typical scene graph (or DAG).

Sprites are added to the scene by simply instancing them. Since the first argument is a reference to the world (or another sprite) they know how to add themselves to the scene. In many cases it is customary not to manually assign the sprite instance to a variable but to use the dictionary where the world keeps track of them: self.sprites. This dictionary uses the sprite's name as the key to the sprite instance.

ASpriteClass(self, 'sprite1')
theNewSprite = self.sprites['sprite1']

On the other hand there are occasions in which it makes sense to use a separate variable to hold the reference to the new sprite:

anewsprite = ASpriteClass(self, 'sprite1')
theNewSprite = anewsprite

Sprite objects are usually instanced from a custom class (like Disc in the above example) that defines the characteristics (what it draws, how it reacts to the mouse) of that sprite. The only requirement for that custom sprite class is that it inherits from slut.sprite.Sprite. Just as shapes that are drawn directly in the world, shapes in a sprite are redrawn multiple times a second via repeated calls to onDraw(). Once a sprite has been added to the scene it can be moved, rotated and scaled as a whole.

Transformation methods come in two flavors--relative and absolute. Relative methods always operate on the sprite by adding to the current position/scale while absolute methods take the passed (x, y, z) values and make them the new position/scale. The passed arguments are units of the coordinate system where the sprite was created. This is either the world or another sprite. Arguments for rotation and orbiting methods are always in degrees (with 360 being one rotation).

spriteobject.moveBy(-2.5, 0.0, 0.0)
spriteobject.rotTo(0.0, 180.0, 0.0)
spriteobject.orbitTo(0.0, 90.0, 0.0)

The above code snippet moves the sprite (along the x-axis) -2.5 units away from the origin, then rotates the sprite around its own y-axis by 180 degrees, and finally orbits it around the origin by 90 degrees (on an ecliptic that is perpendicular to the y-axis).

Note: Orbiting always occurs around the origin of the coordinate system where the sprite was created. If the sprite was not moved away from the origin, orbiting is equivalent to rotation.

Alternatively, transformation arguments can be specified with Tween and Thrust objects.

Initiated by Stephan Hechenberger
Thanks to CADRE's 103