As promised in the last post, here's some old LISP code I used to demo the original circle linking application. I've changed it slightly to not only move the snake in 2D, now the Z-value of the lead object is set to be a fraction of the object's Y-value. This won't actually change what's seen in a standard overhead view... if you want to revert to 2D-only movement of the snake, simply remove "zval" from the two calls to the MOVE command.
I should also add that while the snake will move through 3D by default, I didn't change the code that prompts the user to select the screen area: as you drag across to the second point, it "rubber-bands" in screen coordinates, even if the point that gets selected is returned in the coordinates of the current UCS. As this is primarily a test-bed, I didn't see the point in devoting time to address this quirk - the snake still moves, which is the main thing.
The performance will, of course, depend on your system and on the length and composition of the snake (whether the snake is made up of circles or spheres with materials being display realistically, for instance).
The LISP code depends on getting the circle's centre point (getting the value of group-code 10), so while it will work on all sorts of objects, it won't work on 3D solids. So you should create a chain with a circle at the head for this to work properly.
The file is available here for download.
Here's the LISP code:
1 ; Create a chain of linked circles, by either using LINK
2 ; on a number of CIRCLEs or AUTOLINK.
3 ; Type SNAKE, select the head of the chain, and then enter
4 ; a distance for the simulation to run over (this version
5 ; also assumes that 0,0 is at the bottom left of the screen)
6 ;
7 ; The function plotted is just a sine wave,
8 ; using the full height of the screen
9 ;
10 ; Written by Kean Walmsley 26/03/96, for messing about
11 ; purposes only
12 ;
13 ; Updated 1/12/06, adding support for 3D, and formatting
14 ; text to fit the width of the Through_the_Interface blog
15
16 (defun asdk_snake (en pt1 pt2 screens moves waves
17 / ocmd oblp undoctl undoon undoone
18 undoall screenno maxdeg distance vhgt en
19 xval yvalybase xinc xmax xbot pt1 pt2
20 )
21 (setq ocmd (getvar "CMDECHO")
22 oblp (getvar "BLIPMODE")
23 undoctl (getvar "UNDOCTL")
24 undoon (= 1 (logand 1 undoctl))
25 undoone (= 2 (logand 2 undoctl))
26 undoall (= 4 (logand 4 undoctl))
27 )
28 (setvar "CMDECHO" 0)
29 (setvar "BLIPMODE" 0)
30 (if undoon
31 (command "_.UNDO" "_CONTROL" "_NONE")
32 )
33 (setq screenno 0
34 maxdeg (* pi waves)
35 distance (abs (- (car pt1) (car pt2)))
36 vhgt (abs (- (cadr pt1) (cadr pt2)))
37 ybase (/ (+ (cadr pt1) (cadr pt2)) 2)
38 xbot (if (< (car pt1) (car pt2))
39 (car pt1)
40 (car pt2)
41 )
42 xmax (+ distance xbot)
43 xinc (/ distance moves)
44 xval xbot
45 yval (+ ybase (* (sin (* maxdeg
46 (/ (- xval xbot)
47 (- xmax xbot)
48 )
49 )
50 )
51 (/ vhgt 2.0)
52 )
53 )
54 zval (/ yval 4)
55 )
56 (while (< screenno screens)
57 (while (< xval xmax)
58 (command "_.MOVE" en ""
59 (cdr (assoc 10 (entget en)))
60 (list xval yval zval)
61 )
62 (setq xval (+ xval xinc)
63 yval (+ ybase (* (sin (* maxdeg
64 (/ (- xval xbot)
65 (- xmax xbot)
66 )
67 )
68 )
69 (/ vhgt 2.0)
70 )
71 )
72 zval (/ yval 4)
73 )
74 )
75 (setq screenno (1+ screenno))
76 (while (and (>= xval xbot) (< screenno screens))
77 (command "_.MOVE" en ""
78 (cdr (assoc 10 (entget en)))
79 (list xval yval zval)
80 )
81 (setq xval (- xval xinc)
82 yval (- ybase (* (sin (* maxdeg
83 (/ (- xval xbot)
84 (- xmax xbot)
85 )
86 )
87 )
88 (/ vhgt 2.0)
89 )
90 )
91 zval (/ yval 4)
92 )
93 )
94 (setq screenno (1+ screenno))
95 )
96 (if undoone
97 (command "_.UNDO" "_ONE")
98 (if undoall
99 (command "_.UNDO" "_ALL")
100 )
101 )
102 (setvar "CMDECHO" ocmd)
103 (setvar "BLIPMODE" oblp)
104 (terpri)
105 )
106
107 (defun C:SNAKE (/ es pt1 pt2 screens moves waves)
108 (if (setq es (entsel "\nSelect the snake's head: "))
109 (if
110 (setq pt1
111 (getpoint "\nSelect first corner of screen area: ")
112 )
113 (if
114 (setq pt2
115 (getcorner
116 pt1
117 "\nSelect second corner of screen area: "
118 )
119 )
120 (progn
121 (if (not asdk_screens) (setq asdk_screens 2))
122 (if (not asdk_moves) (setq asdk_moves 100))
123 (if (not asdk_waves) (setq asdk_waves 4))
124 (if
125 (not
126 (setq screens
127 (getint
128 (strcat
129 "\nEnter number of times"
130 " to cross screen <"
131 (itoa asdk_screens)
132 ">: "
133 )
134 )
135 )
136 )
137 (setq screens asdk_screens)
138 (setq asdk_screens screens)
139 )
140 (if
141 (not
142 (setq moves
143 (getint
144 (strcat
145 "\nEnter number of moves"
146 " to cross screen <"
147 (itoa asdk_moves)
148 ">: "
149 )
150 )
151 )
152 )
153 (setq moves asdk_moves)
154 (setq asdk_moves moves)
155 )
156 (if
157 (not
158 (setq waves
159 (getint
160 (strcat
161 "\nEnter number of waves for snake <"
162 (itoa asdk_waves)
163 ">: "
164 )
165 )
166 )
167 )
168 (setq waves asdk_waves)
169 (setq asdk_waves waves)
170 )
171 (asdk_snake (car es) pt1 pt2 screens moves waves)
172 )
173 )
174 )
175 )
176 (princ)
177 )