Skip to content

Instantly share code, notes, and snippets.

@nutti
Created December 31, 2017 08:37
Show Gist options
  • Save nutti/cebd59f490e5c82ab9f773d83a784dd3 to your computer and use it in GitHub Desktop.
Save nutti/cebd59f490e5c82ab9f773d83a784dd3 to your computer and use it in GitHub Desktop.
Turtle Graphcs with Suzanne
# MIT License
#
# Copyright (c) 2017 Nutti
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import bpy
from bpy.props import (
EnumProperty,
BoolProperty,
IntProperty,
FloatVectorProperty
)
from mathutils import Vector, Euler
import math
bl_info = {
"name": "Suzanne Walk",
"author": "Nutti",
"version": (1, 0),
"blender": (2, 79, 0),
"location": "View 3D > Tool Shelf",
"description": "Turtle Graphics on Blender with Suzanne",
"warning": "",
"support": "TESTING",
"wiki_url": "",
"tracker_url": "",
"category": "Object"
}
class SuzanneWalkOp(bpy.types.Operator):
bl_idname = "object.suzanne_walk_op"
bl_label = "Exec"
bl_description = "Turtle Walk simulated by Suzanne"
def __init__(self):
self.__timer = None
self.__op = ''
self.__val = 0
self.__color = None
def __handle_add(self, context):
if self.__timer is None:
self.__timer = context.window_manager.event_timer_add(0.1, context.window)
context.window_manager.modal_handler_add(self)
def __handle_remove(self, context):
if self.__timer is not None:
context.window_manager.event_timer_remove(self.__timer)
self.__timer = None
def __move(self, obj, scene, foward=True):
q = obj.rotation_quaternion.copy()
q.rotate(Euler((0.0, 0.0, -math.pi / 2), 'XYZ'))
dir = Vector((0.5, 0.0, 0.0)) if foward else Vector((-0.5, 0.0, 0.0))
delta = q * dir
obj.location = obj.location + delta
self.__val = self.__val - 1
bpy.ops.mesh.primitive_cube_add(location=obj.location, radius=0.1)
new_obj = bpy.context.active_object
mtrl = bpy.data.materials.new('Mat')
mtrl.diffuse_color = (self.__color[0], self.__color[1], self.__color[2])
new_obj.data.materials.append(mtrl)
scene.sw_cube_total = scene.sw_cube_total + 1
def __rotate(self, obj, left=True):
q = obj.rotation_quaternion
angle = (math.pi * self.__val) if left else (-math.pi * self.__val)
q.rotate(Euler((0.0, 0.0, angle / 180.0), 'XYZ'))
self.__val = 0
def __update(self, scene):
obj = bpy.data.objects["Suzanne"]
obj.rotation_mode = 'QUATERNION'
if self.__op == 'FORWARD':
self.__move(obj, scene)
elif self.__op == 'BACKWARD':
self.__move(obj, scene, False)
elif self.__op == 'LEFT':
self.__rotate(obj)
elif self.__op == 'RIGHT':
self.__rotate(obj, False)
def modal(self, context, event):
sc = context.scene
if event.type != 'TIMER':
return {'RUNNING_MODAL'}
if context.area:
context.area.tag_redraw()
self.__update(sc)
if self.__val <= 0:
sc.sw_running = False
self.__handle_remove(context)
return {'FINISHED'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
context = bpy.context
sc = context.scene
if sc.sw_running:
return {'CANCELLED'}
sc.sw_running = True
self.__op = sc.sw_op
self.__val = sc.sw_val
self.__color = sc.sw_color
self.__handle_add(context)
return {'RUNNING_MODAL'}
class SuzanneWalkReset(bpy.types.Operator):
bl_idname = "object.suzanne_walk_reset"
bl_label = "Reset"
bl_description = "Reset"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
sc = context.scene
for obj in bpy.data.objects:
if obj.type == 'MESH':
bpy.data.objects.remove(obj)
for mtrl in bpy.data.materials:
bpy.data.materials.remove(mtrl)
bpy.ops.mesh.primitive_monkey_add()
sc.sw_cube_total = 0
return {'FINISHED'}
class OBJECT_PT_SW(bpy.types.Panel):
bl_label = "Suzanne Walk"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_category = "Suzanne Walk"
bl_context = "objectmode"
def draw(self, context):
sc = context.scene
layout = self.layout
row = layout.row()
row.operator(SuzanneWalkOp.bl_idname)
row.operator(SuzanneWalkReset.bl_idname)
layout.prop(sc, "sw_op")
layout.prop(sc, "sw_val")
layout.prop(sc, "sw_color")
layout.separator()
layout.label("Cube: {0}".format(sc.sw_cube_total))
if sc.sw_running:
layout.enabled = False
def init_props(scene):
scene.sw_running = BoolProperty(
name="Running",
description="Running",
default=False
)
scene.sw_op = EnumProperty(
name="Operation",
description="Operation",
items=[
('FORWARD', "Forward", "Move forward"),
('BACKWARD', "Backward", "Move backward"),
('LEFT', "Left", "Rotate Left"),
('RIGHT', "Right", "Rotate Right")
],
default='FORWARD'
)
scene.sw_val = IntProperty(
name="Value",
description="Value",
min=1,
max=100,
default=10
)
scene.sw_color = FloatVectorProperty(
name="Color",
description="Color",
default=(0.0, 0.0, 0.0),
min=0.0,
max=1.0,
subtype='COLOR'
)
scene.sw_cube_total = IntProperty(
name="Cube Total",
description="Cube Total",
)
def clear_props(scene):
del scene.sw_op
def register():
bpy.utils.register_module(__name__)
init_props(bpy.types.Scene)
def unregister():
bpy.utils.unregister_module(__name__)
clear_props(bpy.types.Scene)
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment