# Need help moving a set of cubes from one end to the other on x-axis with python scripting

I am currently using blender 2.8 and I am trying to make a scripted animation where I move a set of cubes from one end to the other on the x-axis with delays in between animations. This isn't really a real animation because I am not using the timeline. I am trying to create a real-time demo of a personal project. If you look below I want to make the collection of cubes to travel to the right in delayed steps. My current script is like this:

import time

collection = bpy.data.collections["layer_1_filters"].objects # I grouped the 5x5 cube grid to the collection called "layer_1_filters"

for steps in range(23): #steps to the right 23 times

for cube in collection: # loop each cube

cube.location[0] = cube.location[0] + 3 # move all the cubes to the right by 3 on the x-axis

time.sleep(0.3) # pause 0.3 seconds before start moving right again.
#THIS HANGS and BREAKS BLENDER!


If I use time.sleep to delay the actions blender hangs then crashes, if I don't use some sort of delay the cubes would just immediately teleport to the end. How can I slove this?

Modal Timer operator

For the most part don't use time.sleep() in blender, as you have seen it doesn't work as expected.

Modify the template text editor > templates > python > operator modal timer

This line

self._timer = wm.event_timer_add(0.3, window=context.window)


creates a timer that fires a 'TIMER' event every 0.3 seconds.

Additionally I've added a count class property to only move the object that many times.

For example sake, only moves the context.object edit to suit

import bpy

class ModalTimerOperator(bpy.types.Operator):
"""Operator which runs its self from a timer"""
bl_idname = "wm.modal_timer_operator"
bl_label = "Modal Timer Operator"

_timer = None
count = 0

def modal(self, context, event):
if event.type in {'RIGHTMOUSE', 'ESC'}:
self.cancel(context)
return {'CANCELLED'}

if event.type == 'TIMER' and self.count < 24:
context.object.location.x += 3
self.count += 1

return {'PASS_THROUGH'}

def execute(self, context):
self.count = 0
context.object.location.x = 0
wm = context.window_manager
return {'RUNNING_MODAL'}

def cancel(self, context):
wm = context.window_manager
wm.event_timer_remove(self._timer)


Related:

Time delay when selecting objects in a python script!

How to run a python script at regular intervals?

Application Timers in 2.8

2.8 brings in a new timer class.

See my answer to Blender Python: Running multiple timers

Move an object every second

import bpy
import functools

def move_obj(ob):
ob.location.x += 0.1
return 1

bpy.app.timers.register(functools.partial(move_obj, bpy.context.object), first_interval=1)

• Thanks for the reply, I managed to do this in a different way following this docs.blender.org/api/blender2.8/bpy.app.timers.html – Inkplay_ Feb 16 '19 at 2:59
• Yes tossed up whether to go that way, added link to prior answer regarding 2.8 application timers. – batFINGER Feb 16 '19 at 3:33