❄ Snow!

from random import randint

class flake:
    def __init__ (self,x,y):
        self.vec = PVector(x,y)        
        self.z = random(0,3)
        self.velY = map(self.z,0,3,0.5,1)
        self.velX = 0
        
    def show(self):
        ellipse(self.vec.x,self.vec.y,map(self.z,0,3,2,5),map(self.z,0,3,2,5))
        
    def update(self):
        self.vec.y += self.velY
        self.vec.x += self.velX
        self.velY += 0.01 
        if self.velX > 0:
            self.velX -= 0.01
        elif self.velX < 0:
            self.velX += 0.01
        
        if self.vec.y > height:
            self.vec.x = randint(0,width)
            self.vec.y = randint(-500,-50)
            self.velY = map(self.z,0,3,0.5,1.5)
        if self.vec.x < 0: 
            self.vec.x = randint(350,width)
        if self.vec.x > width: 
            self.vec.x = randint(0,100)
            
        

width = 700
height = 500
snow = []
total = 1001 #num of snowflakes

for i in range(0,total):
    snow.append(flake(randint(0,width),randint(-500,50)))
    

def setup():
    size(width,height)
    noStroke()
    fill(178,32,201)

def draw():
    background(150)
    for i in range(0,total):
        snow[i].show()
        snow[i].update()
    if keyPressed:
        if key == "w":
            for i in range(0,total):
                    a = map(snow[i].z,0,3,0.01,0.03)
                    snow[i].velY -= a
        if key == "s":
            for i in range(0,total):
                    a = map(snow[i].z,0,3,0.01,0.03)
                    snow[i].velY += a
        if key == "d":
            for i in range(0,total):
                    a = map(snow[i].z,0,3,0.01,0.03)
                    snow[i].velX += a
        if key == "a":
            for i in range(0,total):
                    a = map(snow[i].z,0,3,0.01,0.03)
                    snow[i].velX -= a
        if key == "r":
            del snow [:]
            for i in range(0,total):
                    snow.append(flake(randint(0,width),randint(-500,50)))
       

(I know that with rain I have less gravity acceleration limitations, but in my city snowed :snowman_with_snow: )

Use wasd to control snow, r to reset
(If I add more :snowflake: i lag :slightly_frowning_face: )

What can I improve?

In draw loop you have this operations:

a = map(snow[i].z,0,3,0.01,0.03)
map(self.z,0,3,2,5)
self.velY = map(self.z,0,3,0.5,1.5)

They depends on z that isn’t changing. By counting this values before drawing you can win some processing time.

1 Like

I’ve refactored the original code in order to cache all pre-calculated values. :heavy_plus_sign:
However, it didn’t speed anything. Alas, I guess it’s got slightly slower! :no_mouth:
Regardless, using FX2D instead of default JAVA2D is what actually makes the sketch race! :racing_car:

"""
 Snow! (v1.1)
 by Sky (2019-Jan-04)
 mod GoToLoop (2019-Jan-07)
 https://Discourse.Processing.org/t/snow/7156/3
"""

from math import copysign

FLAKES, YMIN, YMAX = 1001, -500, 50
RANGE = tuple(range(FLAKES))

def setup():
    size(700, 500, FX2D)
    noStroke()
    fill(178, 32, 201)

    global flakes
    flakes = tuple(Flake(random(width), random(YMIN, YMAX)) for i in RANGE)


def draw():
    background(150)
    for f in flakes: f.show().update()
    changeAllFlakesSpeed()
    this.surface.title = 'FPS: ' + `this.round(frameRate)`


def keyPressed():
    k = chr(keyCode) if key != CODED else keyCode

    if k == 'R' or k == ENTER or k == RETURN:
        for f in flakes: f.reset(random(width), random(YMIN, YMAX))


def changeAllFlakesSpeed():
    if not keyPressed: return

    k = key.upper() if key != CODED else keyCode

    if k == 'W' or k == UP:
        for f in flakes: f.vel.y -= f.maps[2]

    elif k == 'S' or k == DOWN:
        for f in flakes: f.vel.y += f.maps[2]

    elif k == 'A' or k == LEFT:
        for f in flakes: f.vel.x -= f.maps[2]

    elif k == 'D' or k == RIGHT:
        for f in flakes: f.vel.x += f.maps[2]


class Flake:
    Z, INC = 3.0, .01

    def __init__(f, x, y):
        f.vec = __pvector__()
        f.vel = __pvector__()
        f.reset(x, y)


    def __str__(f):
        return 'vec: %s\tvel: %s' % (f.vec, f.vel)


    def reset(f, x, y):
        z = random(f.Z)

        f.maps = (
            map(z, 0, f.Z, .5, 1.5),
            map(z, 0, f.Z, 2, 5),
            map(z, 0, f.Z, .01, .03)
        )

        f.vec.set(x, y)
        f.vel.set(0, f.maps[0])

        return f


    def show(f):
        ellipse(f.vec.x, f.vec.y, f.maps[1], f.maps[1])
        return f


    def update(f):
        f.vec.add(f.vel)
        f.vel.add(copysign(f.INC, -f.vel.x), f.INC)

        if f.vec.y > height:
            f.vec.set(random(width), random(YMIN, -YMAX))
            f.vel.y = f.maps[0]

        if   f.vec.x < 0:     f.vec.x = random(width>>1, width)
        elif f.vec.x > width: f.vec.x = random(100)

        return f
1 Like