Une simulation de physique, grâce à l’équation de verlet. Merci à la vidéo de Pezzza’s work sur YouTube, « Writing a Physics Engine from scratch »
from math import * from kandinsky import * from time import * from ion import * from keyinput import * from random import * verletObjects = [] class VerletObject: def __init__(self,positionCurrent=(200,111),**kwargs): verletObjects.append(self) self.positionCurrent = positionCurrent self.positionOld = self.positionCurrent self.acceleration = (0,0) self.radius = 5 self.col = (255,0,0) for key,value in kwargs.items(): setattr(self,key,value) def updatePosition(self,dt): velocity = (self.positionCurrent[0]-self.positionOld[0], self.positionCurrent[1]-self.positionOld[1]) self.positionOld = self.positionCurrent self.positionCurrent = (self.positionCurrent[0] + velocity[0] + self.acceleration[0]*dt*dt, self.positionCurrent[1] + velocity[1] + self.acceleration[1]*dt*dt) self.acceleration=(0,0) def accelerate(self,vec): self.acceleration = (self.acceleration[0]+vec[0], self.acceleration[1]+vec[1]) class VerletSolver: def __init__(self): self.gravity = (0,100) self.constraintPosition = (160,111) self.constraintRadius = 100 def update(self,dt): initialPosition = [] for obj in verletObjects: initialPosition.append(obj.positionCurrent) subStep = 8 subDt = dt/subStep for i in range(subStep): self.applyGravity() self.applyConstraint() self.solveCollisions() self.updatePositions(subDt) for i in range(len(initialPosition)): fill_circle(round(initialPosition[i][0]),round(initialPosition[i][1]),verletObjects[i].radius,(255,)*3) for obj in verletObjects: fill_circle(round(obj.positionCurrent[0]),round(obj.positionCurrent[1]),obj.radius,obj.col) def updatePositions(self,dt): for obj in verletObjects: obj.updatePosition(dt) def applyGravity(self): for obj in verletObjects: obj.accelerate(self.gravity) def applyConstraint(self): for obj in verletObjects: to_obj = (obj.positionCurrent[0]-self.constraintPosition[0], obj.positionCurrent[1]-self.constraintPosition[1]) dist = sqrt((to_obj[0]**2)+(to_obj[1]**2)) if dist > self.constraintRadius-obj.radius: obj.positionCurrent = (self.constraintPosition[0]+((obj.positionCurrent[0]-self.constraintPosition[0])*(self.constraintRadius-obj.radius))/dist, self.constraintPosition[1]+((obj.positionCurrent[1]-self.constraintPosition[1])*(self.constraintRadius-obj.radius))/dist) def solveCollisions(self): objectCount = len(verletObjects) for i in range(objectCount): object1 = verletObjects[i] for k in range(i+1,objectCount): object2 = verletObjects[k] collisionAxis = (object1.positionCurrent[0]-object2.positionCurrent[0], object1.positionCurrent[1]-object2.positionCurrent[1]) dist = sqrt((collisionAxis[0]**2)+(collisionAxis[1]**2)) if dist<object1.radius+object2.radius: n = (collisionAxis[0]/dist, collisionAxis[1]/dist) delta = object1.radius+object2.radius-dist object1.positionCurrent = (object1.positionCurrent[0]+0.5*delta*n[0], object1.positionCurrent[1]+0.5*delta*n[1]) object2.positionCurrent = (object2.positionCurrent[0]-0.5*delta*n[0], object2.positionCurrent[1]-0.5*delta*n[1]) def main(): solver = VerletSolver() dt = 0 while keydown(4): pass fill_rect(0,0,320,222,(255,0,0)) fill_circle(160,111,100,(255,)*3) delay = 0 while 1: timeStart = monotonic() solver.update(dt) if keyinput(4): VerletObject(radius=randint(5,20)) if keyinput(KEY_ONOFF): verletObjects.clear() fill_rect(0,0,320,222,(255,0,0)) fill_circle(160,111,100,(255,)*3) dt = monotonic()-timeStart