您的工作是使这种圈子错觉动起来。看起来像点在圆内旋转,但实际上它们只是沿直线移动。
标准
- 结果必须是动画的。制作动画的方式无关紧要,它可以生成
.gif
,可以绘制到窗口,某些设备屏幕或其他任何内容。 - 这是一次人气竞赛,因此您可能需要向程序中添加一些其他功能,以获得更多的赞誉,例如改变分数。
- 获胜者是上次提交有效作品后7天获得最高评价的有效答案。
- 实际将实现点沿直线而不是其他方式移动的答案受到更多欢迎
您的工作是使这种圈子错觉动起来。看起来像点在圆内旋转,但实际上它们只是沿直线移动。
.gif
,可以绘制到窗口,某些设备屏幕或其他任何内容。Answers:
使用乌龟模块。乌龟的颜色不同,它们始终面对相同的方向,因此只要关注其中一只就可以很容易看出它们沿直线运动。尽管如此,圈子的幻想仍然很强烈。
即使只有3或4只乌龟,这种错觉仍然显得很强烈:
对于所有这些GIF示例,帧速率都已大大降低,但似乎并没有降低这种错觉。在本地运行代码可以使动画更流畅。
import turtle
import time
from math import sin, pi
from random import random
def circle_dance(population=11, resolution=480, loops=1, flip=0, lines=0):
population = int(population)
resolution = int(resolution)
radius = 250
screen = turtle.Screen()
screen.tracer(0)
if lines:
arrange_lines(population, radius)
turtles = [turtle.Turtle() for i in range(population)]
for i in range(population):
dancer = turtles[i]
make_dancer(dancer, i, population)
animate(turtles, resolution, screen, loops, flip, radius)
def arrange_lines(population, radius):
artist = turtle.Turtle()
for n in range(population):
artist.penup()
artist.setposition(0, 0)
artist.setheading(n / population * 180)
artist.forward(-radius)
artist.pendown()
artist.forward(radius * 2)
artist.hideturtle()
def make_dancer(dancer, i, population):
dancer.setheading(i / population * 180)
dancer.color(random_turtle_colour())
dancer.penup()
dancer.shape('turtle')
dancer.turtlesize(2)
def random_turtle_colour():
return random() * 0.9, 0.5 + random() * 0.5, random() * 0.7
def animate(turtles, resolution, screen, loops, flip, radius):
delay = 4 / resolution # 4 seconds per repetition
while True:
for step in range(resolution):
timer = time.perf_counter()
phase = step / resolution * 2 * pi
draw_dancers(turtles, phase, screen, loops, flip, radius)
elapsed = time.perf_counter() - timer
adjusted_delay = max(0, delay - elapsed)
time.sleep(adjusted_delay)
def draw_dancers(turtles, phase, screen, loops, flip, radius):
population = len(turtles)
for i in range(population):
individual_phase = (phase + i / population * loops * pi) % (2*pi)
dancer = turtles[i]
if flip:
if pi / 2 < individual_phase <= 3 * pi / 2:
dancer.settiltangle(180)
else:
dancer.settiltangle(0)
distance = radius * sin(individual_phase)
dancer.setposition(0, 0)
dancer.forward(distance)
screen.update()
if __name__ == '__main__':
import sys
circle_dance(*(float(n) for n in sys.argv[1:]))
该代码可以使用5个可选参数运行:填充,分辨率,循环,翻转和线条。
population
是海龟的数量resolution
是时间分辨率(每个重复的动画帧数)loops
确定海龟向自身循环的次数。默认值1给出一个标准的圆,其他奇数给出该串乌龟中的循环数,而偶数给出一连串乌龟在末端断开,但仍带有弯曲运动的错觉。flip
如果非零,则导致海龟在回程时翻转方向(如庇护所建议的那样,以便它们从不向后移动)。默认情况下,它们保持固定方向,以避免端点产生视觉干扰。lines
如果非零,则显示海龟移动的线,以与问题中的示例图像保持一致。带flip
set的示例(带有和不带有)lines
。我将上面的主要示例保留为没有翻转,因为我不希望有零星的跳跃,但是在所有海龟对齐的情况下,圆的边缘看起来确实更平滑,因此人们可以选择运行时喜欢的哪种样式编码。
上面的图像是如何用相同的代码生成的,可能不会立即显而易见。尤其是进一步向上的图像,它具有较慢的外循环和较快的内循环(看起来像是有人意外掉下的心形)。如果有人想延迟尝试/思考的时间,我在下面隐藏了对此的解释。
通过将循环数设置为15并将乌龟数设置为23(太低而无法表示15个循环)来创建具有不同大小的内部和外部循环的动画。使用大量乌龟会导致15个清晰定义的循环。使用过多的海龟会导致锯齿(与图像处理和渲染相同的原因)。试图代表过高的频率会导致显示较低的频率,并产生失真。
尝试使用不同的数字,我发现其中一些失真比对称的原件更有趣,因此我想在此处包括一个...
结果:
#include <stdio.h>
#include <Windows.h>
#include <Math.h>
int round (double r) { return (r > 0.0) ? (r + 0.5) : (r - 0.5); }
void print (int x, int y, char c) {
COORD p = { x, y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), p);
printf("%c", c);
}
int main ()
{
float pi = 3.14159265358979323846;
float circle = pi * 2;
int len = 12;
int hlen = len / 2;
int cx = 13;
int cy = 8;
float w = 11.0;
float h = 8.0;
float step = 0.0;
while (1)
{
system("cls"); // xD
for (int i = 0; i < len; i++)
{
float a = (i / (float)len) * circle;
int x = cx + round(cos(a) * w);
int y = cy + round(sin(a) * h);
print(x, y, 'O');
if (i < hlen) continue;
step -= 0.05;
float range = cos(a + step);
x = cx + round(cos(a) * (w - 1) * range);
y = cy + round(sin(a) * (h - 1) * range);
print(x, y, 'O');
}
Sleep(100);
}
return 0;
}
system("cls"); // xD
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 380 380" width="380" height="380" version="1.0">
<g transform="translate(190 190)">
<circle cx="0" cy="0" r="190" fill="#000"/>
<line x1="0" y1="-190" x2="0" y2="190" stroke="#fff" stroke-width="1.5"/>
<line x1="72.71" y1="175.54" x2="-72.71" y2="-175.54" stroke="#fff" stroke-width="1.5"/>
<line x1="134.35" y1="134.35" x2="-134.35" y2="-134.35" stroke="#fff" stroke-width="1.5"/>
<line x1="175.54" y1="72.71" x2="-175.54" y2="-72.71" stroke="#fff" stroke-width="1.5"/>
<line x1="190" y1="0" x2="-190" y2="0" stroke="#fff" stroke-width="1.5"/>
<line x1="175.54" y1="-72.71" x2="-175.54" y2="72.71" stroke="#fff" stroke-width="1.5"/>
<line x1="134.35" y1="-134.35" x2="-134.35" y2="134.35" stroke="#fff" stroke-width="1.5"/>
<line x1="72.71" y1="-175.54" x2="-72.71" y2="175.54" stroke="#fff" stroke-width="1.5"/>
<g transform="rotate(0)">
<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0" to="360" begin="0" dur="8s" repeatCount="indefinite"/>
<g transform="translate(0 90)">
<g transform="rotate(0)">
<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0" to="-360" begin="0" dur="4s" repeatCount="indefinite"/>
<circle cx="0" cy="90" r="10" fill="#fff"/>
<circle cx="63.64" cy="63.64" r="10" fill="#fff"/>
<circle cx="90" cy="0" r="10" fill="#fff"/>
<circle cx="63.64" cy="-63.64" r="10" fill="#fff"/>
<circle cx="0" cy="-90" r="10" fill="#fff"/>
<circle cx="-63.64" cy="-63.64" r="10" fill="#fff"/>
<circle cx="-90" cy="0" r="10" fill="#fff"/>
<circle cx="-63.64" cy="63.64" r="10" fill="#fff"/>
</g>
</g>
</g>
</g>
</svg>
intervaltime
更改FPS(FPS = 1000 /间隔时间)。
balls
更改#个球。
maxstep
调整循环中的#步,则“平滑”越大。64应该足够大,使其看起来平滑。
建模为圆周移动,而不是沿直线移动球,但是视觉效果(应该是?)相同。有些代码很冗长,但这不是高尔夫代码,所以...
var intervalTime = 40;
var balls = 8;
var maxstep = 64;
var canvas = $('#c').get(0); // 100% necessary jquery
var ctx = canvas.getContext('2d');
var step = 0;
animateWorld = function() {
createBase();
step = step % maxstep;
var centerX = canvas.width/2 + 115 * Math.cos(step * 2 / maxstep * Math.PI);
var centerY = canvas.height/2 + 115 * Math.sin(step * 2 / maxstep * Math.PI);
for (var i=0; i<balls; i++) {
drawCircle(ctx, (centerX + 115 * Math.cos((i * 2 / balls - step * 2 / maxstep) * Math.PI)), (centerY + 115 * Math.sin((i * 2 / balls - step * 2 / maxstep) * Math.PI)), 10, '#FFFFFF');
}
step++;
}
function createBase() {
drawCircle(ctx, canvas.width/2, canvas.height/2, 240, '#000000');
for(var i=0; i<balls*2; i++) {
drawLine(ctx, canvas.width/2, canvas.height/2, canvas.width/2 + 240 * Math.cos(i / balls * Math.PI), canvas.height/2 + 240 * Math.sin(i / balls * Math.PI), '#FFFFFF');
}
}
function drawLine(context, x1, y1, x2, y2, c) {
context.beginPath();
context.moveTo(x1,y1);
context.lineTo(x2,y2);
context.lineWidth = 3;
context.strokeStyle = c;
context.stroke();
}
function drawCircle(context, x, y, r, c) {
context.beginPath();
context.arc(x, y, r, 0, 2*Math.PI);
context.fillStyle = c;
context.fill();
}
function drawRect(context, x, y, w, h, c) {
context.fillStyle = c;
context.fillRect(x, y, w, h);
}
$(document).ready(function() {
intervalID = window.setInterval(animateWorld, intervalTime);
});
仅使用css动画的解决方案(请参阅JSFiddle上的动画-请注意,我在小提琴中添加了特定于浏览器的前缀,以便它可以在最新版本中使用)。
<body>
<div id="w1"></div>
<div id="w2"></div>
<div id="w3"></div>
<div id="w4"></div>
<div id="w5"></div>
<div id="w6"></div>
<div id="w7"></div>
<div id="w8"></div>
</body>
div {
position: absolute;
width: 20px;
height: 20px;
border-radius: 20px;
background: red;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-timing-function: ease-in-out;
}
#w1 { animation-name: s1; animation-delay: 0.0s }
#w2 { animation-name: s2; animation-delay: 0.5s }
#w3 { animation-name: s3; animation-delay: 1.0s }
#w4 { animation-name: s4; animation-delay: 1.5s }
#w5 { animation-name: s5; animation-delay: 2.0s }
#w6 { animation-name: s6; animation-delay: 2.5s }
#w7 { animation-name: s7; animation-delay: 3.0s }
#w8 { animation-name: s8; animation-delay: 3.5s }
@keyframes s1 { from {top: 100px; left: 0px;} to {top: 100px; left: 200px;} }
@keyframes s2 { from {top: 62px; left: 8px;} to {top: 138px; left: 192px;} }
@keyframes s3 { from {top: 29px; left: 29px;} to {top: 171px; left: 171px;} }
@keyframes s4 { from {top: 8px; left: 62px;} to {top: 192px; left: 138px;} }
@keyframes s5 { from {top: 0px; left: 100px;} to {top: 200px; left: 100px;} }
@keyframes s6 { from {top: 8px; left: 138px;} to {top: 192px; left: 62px;} }
@keyframes s7 { from {top: 29px; left: 171px;} to {top: 171px; left: 29px;} }
@keyframes s8 { from {top: 62px; left: 192px;} to {top: 138px; left: 8px;} }
-webkit-
对于基于Webkit的和基于-moz-
Mozilla的)这是相同的小提琴,带有更新的前缀:jsfiddle.net/nBCxz/3
这是一个非常简单的提交。
animateCircle[n_] := Animate[Graphics[
Flatten@{
Disk[],
White,
Map[
(
phase = #*2 \[Pi]/n;
line = {Cos[phase], Sin[phase]};
{Line[{-line, line}],
Disk[Sin[t + phase]*line, 0.05]}
) &,
Range[n]
]
},
PlotRange -> {{-1.1, 1.1}, {-1.1, 1.1}}
],
{t, 0, 2 \[Pi]}
]
如果您致电,animateCircle[32]
您将获得包含32条直线和圆的整洁动画。
在Mathematica中它是完全平滑的,但我不得不对GIF的帧数进行一些限制。
现在,如果每行放两张光盘会发生什么?(即,添加Disk[-Sin[t + phase]*line, 0.05]
到中的列表Map
。)
您也可以将它们异相90度(使用Cos
代替-Sin
):
{t, 0, 2 \[Pi]}
为,{t, 0, 2 \[Pi] - 2 \[Pi]/60, 2 \[Pi]/60}
以便不会有两个相同的帧并更改Animate
为Table
。然后,您将能够导出GIF。
Animate
)。我会尝试Table
再次使用。
这会使您的处理器略微哭泣,但看起来很漂亮,我相信它可以按照规格工作。我使用@Fabricio的答案作为实现圆运动算法的指南。
编辑:进行了一些调整,以提高渲染速度。
编码:
'Open Excel
Set objX = CreateObject("Excel.Application")
objX.Visible = True
objX.Workbooks.Add
'Populate values
objX.Cells(1, 1).Value = "Lbl"
objX.Cells(1, 2).Value = "Amt"
For fillX = 2 to 17
objX.Cells(fillX, 1).Value = "V"+Cstr(fillX-1)
objX.Cells(fillX, 2).Value = "1"
Next
'Create pie
objX.Range("A2:B17").Select
objX.ActiveSheet.Shapes.AddChart.Select
With objX.ActiveChart
.ChartType = 5 'pieChart
.SetSourceData objX.Range("$A$2:$B$17")
.SeriesCollection(1).Select
End with
'Format pie
With objX.Selection.Format
.Fill.ForeColor.RGB = 0 'black
.Fill.Solid
.Line.Weight = 2
.Line.Visible = 1
.Line.ForeColor.RGB = 16777215 'white
End With
'animation variables
pi = 3.14159265358979323846
circle = pi * 2 : l = 16.0
hlen = l / 2 : cx = 152.0
cy = 99.0 : w = 90.0
h = 90.0 : s = 0.0
Dim posArry(7,1)
'Animate
While 1
For i = 0 to hlen-1
a = (i / l) * circle
range = cos(a + s)
x = cx + cos(a) * w * range
y = cy + sin(a) * h * range
If whileInx = 1 Then
createOval x, y
ElseIf whileInx = 2 Then
objX.ActiveChart.Legend.Select
ElseIf whileInx > 2 Then
ovalName = "Oval "+ Cstr(i+1)
dx = x - posArry(i,0)
dy = y - posArry(i,1)
moveOval ovalName, dx, dy
End if
posArry(i,0) = x
posArry(i,1) = y
Next
s=s-0.05
wscript.Sleep 1000/60 '60fps
whileInx = 1 + whileInx
Wend
'create circles
sub createOval(posX, posY)
objX.ActiveChart.Shapes.AddShape(9, posX, posY, 10, 10).Select '9=oval
objX.Selection.ShapeRange.Line.Visible = 0
with objX.Selection.ShapeRange.Fill
.Visible = 1
.ForeColor.RGB = 16777215 'white
.solid
end with
end sub
'move circles
sub moveOval(ovalName, dx, dy)
with objX.ActiveChart.Shapes(ovalName)
.IncrementLeft dx
.IncrementTop dy
end with
end sub
=2*PI()*(NOW()*24*60*60/A2-FLOOR(NOW()*24*60*60/A2,1))
=ROUND(7*SIN(A1),0)
=ROUND(5*SIN(A1+1*PI()/4),0)
=ROUND(7*SIN(A1+2*PI()/4),0)
=ROUND(5*SIN(A1+3*PI()/4),0)
A2(周期)确定完整“革命”的时间(秒)。
行中的每个单元格都是与相应行的值有关的基本条件。例如,K2为:
=1*(A5=7)
中央单元格(K9)为:
=1*OR(A5=0,A6=0,A7=0,A8=0)
通过在随机单元格上按住“删除”来强制动画以不断触发刷新。
我知道这是一个古老的话题,但是最近的活动使它达到了顶峰,并且出于某种原因似乎很有吸引力。长时间的pcg侦听器,首次呼叫者。要温柔。
只是为了与PSTricks一起玩。
\documentclass[preview,border=12pt,multi]{standalone}
\usepackage{pstricks}
\psset{unit=.3}
% static point
% #1 : half of the number of points
% #2 : ith point
\def\x[#1,#2]{(3*cos(Pi/#1*#2))}
\def\y[#1,#2]{(3*sin(Pi/#1*#2))}
% oscillated point
% #1 : half of the number of points
% #2 : ith point
% #3 : time parameter
\def\X[#1,#2]#3{(\x[#1,#2]*cos(#3+Pi/#1*#2))}
\def\Y[#1,#2]#3{(\y[#1,#2]*cos(#3+Pi/#1*#2))}
% single frame
% #1 : half of the number of points
% #2 : time parameter
\def\Frame#1#2{%
\begin{pspicture}(-3,-3)(3,3)
\pstVerb{/I2P {AlgParser cvx exec} bind def}%
\pscircle*{\dimexpr3\psunit+2pt\relax}
\foreach \i in {1,...,#1}{\psline[linecolor=yellow](!\x[#1,\i] I2P \y[#1,\i] I2P)(!\x[#1,\i] I2P neg \y[#1,\i] I2P neg)}
\foreach \i in {1,...,#1}{\pscircle*[linecolor=white](!\X[#1,\i]{#2} I2P \Y[#1,\i]{#2} I2P){2pt}}
\end{pspicture}}
\begin{document}
\foreach \t in {0,...,24}
{
\preview
\Frame{1}{2*Pi*\t/25} \quad \Frame{2}{2*Pi*\t/25} \quad \Frame{3}{2*Pi*\t/25} \quad \Frame{5}{2*Pi*\t/25} \quad \Frame{10}{2*Pi*\t/25}
\endpreview
}
\end{document}
Fortran
使用以下位置的Fortran gif模块将每个帧创建为单独的gif文件:http : //fortranwiki.org/fortran/show/writegif
然后,我通过使用ImageMagick将单独的gifs合并为一个动画gif进行了一点欺骗。
更新:设置新= .true。得到以下内容:
program circle_illusion
use, intrinsic :: iso_fortran_env, only: wp=>real64
use gif_util !gif writing module from http://fortranwiki.org/fortran/show/writegif
implicit none
logical,parameter :: new = .false.
integer,parameter :: n = 500 !550 !size of image (square)
real(wp),parameter :: rcircle = n/2 !250 !radius of the big circle
integer,parameter :: time_sep = 5 !deg
real(wp),parameter :: deg2rad = acos(-1.0_wp)/180.0_wp
integer,dimension(0:n,0:n):: pixel ! pixel values
integer,dimension(3,0:3) :: colormap ! RGB 0:255 for colors 0:ncol
real(wp),dimension(2) :: xy
integer,dimension(2) :: ixy
real(wp) :: r,t
integer :: i,j,k,row,col,m,n_cases,ang_sep
character(len=10) :: istr
integer,parameter :: black = 0
integer,parameter :: white = 1
integer,parameter :: red = 2
integer,parameter :: gray = 3
colormap(:,0) = [0,0,0] !black
colormap(:,1) = [255,255,255] !white
colormap(:,2) = [255,0,0] !red
colormap(:,3) = [200,200,200] !gray
if (new) then
ang_sep = 5
n_cases = 3
else
ang_sep = 20
n_cases = 0
end if
do k=0,355,time_sep
!clear entire image:
pixel = white
if (new) call draw_circle(n/2,n/2,black,n/2)
!draw polar grid:
do j=0,180-ang_sep,ang_sep
do i=-n/2, n/2
call spherical_to_cartesian(dble(i),dble(j)*deg2rad,xy)
call convert(xy,row,col)
if (new) then
pixel(row,col) = gray
else
pixel(row,col) = black
end if
end do
end do
!draw dots:
do m=0,n_cases
do j=0,360-ang_sep,ang_sep
r = sin(m*90.0_wp*deg2rad + (k + j)*deg2rad)*rcircle
t = dble(j)*deg2rad
call spherical_to_cartesian(r,t,xy)
call convert(xy,row,col)
if (new) then
!call draw_circle(row,col,black,10) !v2
!call draw_circle(row,col,m,5) !v2
call draw_circle(row,col,white,10) !v3
else
call draw_square(row,col,red) !v1
end if
end do
end do
!write the gif file for this frame:
write(istr,'(I5.3)') k
call writegif('gifs/test'//trim(adjustl(istr))//'.gif',pixel,colormap)
end do
!use imagemagick to make animated gif from all the frames:
! from: http://thanosk.net/content/create-animated-gif-linux
if (new) then
call system('convert -delay 5 gifs/test*.gif -loop 0 animated.gif')
else
call system('convert -delay 10 gifs/test*.gif -loop 0 animated.gif')
end if
!delete individual files:
call system('rm gifs/test*.gif')
contains
subroutine draw_square(r,c,icolor)
implicit none
integer,intent(in) :: r,c !row,col of center
integer,intent(in) :: icolor
integer,parameter :: d = 10 !square size
pixel(max(0,r-d):min(n,r+d),max(0,c-d):min(n,c+d)) = icolor
end subroutine draw_square
subroutine draw_circle(r,c,icolor,d)
implicit none
integer,intent(in) :: r,c !row,col of center
integer,intent(in) :: icolor
integer,intent(in) :: d !diameter
integer :: i,j
do i=max(0,r-d),min(n,r+d)
do j=max(0,c-d),min(n,c+d)
if (sqrt(dble(i-r)**2 + dble(j-c)**2)<=d) &
pixel(i,j) = icolor
end do
end do
end subroutine draw_circle
subroutine convert(xy,row,col)
implicit none
real(wp),dimension(2),intent(in) :: xy !coordinates
integer,intent(out) :: row,col
row = int(-xy(2) + n/2.0_wp)
col = int( xy(1) + n/2.0_wp)
end subroutine convert
subroutine spherical_to_cartesian(r,theta,xy)
implicit none
real(wp),intent(in) :: r,theta
real(wp),dimension(2),intent(out) :: xy
xy(1) = r * cos(theta)
xy(2) = r * sin(theta)
end subroutine spherical_to_cartesian
end program circle_illusion
强制性C64版本。
在您喜欢的模拟器中复制并粘贴:
1 print chr$(147)
2 poke 53281,0
3 for p=0 to 7
5 x=int(11+(cos(p*0.78)*10)):y=int(12+(sin(p*0.78)*10))
6 poke 1024+x+(y*40),15
9 next p
10 for sp=2040 to 2047:poke sp,13:next sp
20 for i=0 to 62:read a:poke 832+i,a:next i
30 for i=0 to 7:poke 53287+i,i+1:next i
40 rem activate sprites
50 poke 53269,255
60 an=0.0
70 rem maincycle
75 teta=0.0:k=an
80 for i=0 to 7
90 px=cos(k)*64
92 s=i:x=px*cos(teta): y=px*sin(teta): x=x+100: y=y+137: gosub 210
94 teta=teta+0.392699
95 k=k+0.392699
96 next i
130 an=an+0.1
140 goto 70
150 end
200 rem setspritepos
210 poke 53248+s*2,int(x): poke 53249+s*2,int(y)
220 return
5000 data 0,254,0
5010 data 3,199,128
5020 data 7,0,64
5030 data 12,126,96
5040 data 25,255,48
5050 data 59,7,152
5060 data 52,1,200
5070 data 116,0,204
5080 data 120,0,100
5090 data 120,0,100
5100 data 120,0,100
5110 data 120,0,36
5120 data 104,0,36
5130 data 100,0,108
5140 data 54,0,72
5150 data 51,0,152
5160 data 25,131,16
5170 data 12,124,96
5180 data 4,0,64
5190 data 3,1,128
5200 data 0,254,0
紧凑的javascript版本,将默认设置更改为其他设置
HTML:
<canvas id="c" width="400" height="400" />
JavaScript:
var v= document.getElementById('c');
var c= v.getContext('2d');
var w= v.width, w2= w/2;
var num= 28, M2= Math.PI*2, da= M2/num;
draw();
var bw= 10;
var time= 0;
function draw()
{
v.width= w;
c.beginPath();
c.fillStyle= 'black';
circle(w2,w2,w2);
c.lineWidth= 1.5;
c.strokeStyle= c.fillStyle= 'white';
var a= 0;
for (var i=0; i< num*2; i++){
c.moveTo(w2,w2);
c.lineTo(w2+Math.cos(a)*w2, w2+Math.sin(a)*w2);
a+= da/2;
}
c.stroke();
a= 0;
for (var i=0; i< num; i++){
circle(w2+Math.cos(a)*Math.sin(time+i*Math.PI/num)*(w2-bw),
w2+Math.sin(a)*Math.sin(time+i*Math.PI/num)*(w2-bw), bw);
a+= da/2;
}
time+=0.03;
requestAnimationFrame(draw);
}
function circle(x,y,r)
{
c.beginPath();
c.arc(x, y, r, 0, M2);
c.fill();
}
bw=10
)。请编辑您的答案以显示您的代码。哦,要解决这个问题,您应该修复一个错误:在Trig计算中替换time+i*0.39*0.29
为time+i*Math.PI/num
,以便对于的任何值正确计算坐标num
。(PS 在此更新了JSFiddle。欢迎访问codegolf.stackexchange.com)
我对榆树的看法。我是一个初学者,很乐意接受PR来改进此解决方案(GitHub):
请注意,此提交实际上是直线上的移动点:
import Color exposing (..)
import Graphics.Collage exposing (..)
import Graphics.Element exposing (..)
import Time exposing (..)
import Window
import List exposing (..)
import AnimationFrame -- "jwmerrill/elm-animation-frame"
import Debug
-- CONFIG
size = 600
circleSize = 240
dotCount = 12
dotSize = 10
velocity = 0.01
-- MODEL
type alias Dot =
{ x : Float
, angle : Float
}
type alias State = List Dot
createDots : State
createDots = map createDot [ 0 .. dotCount - 1 ]
createDot : Int -> Dot
createDot index =
let angle = toFloat index * pi / dotCount
in { x = 0
, angle = angle
}
-- UPDATE
update : Time -> State -> State
update time dots = map (moveDot time) dots |> Debug.watch "Dots"
moveDot : Time -> Dot -> Dot
moveDot time dot =
let t = velocity * time / pi
newX = (-circleSize + dotSize) * cos(t + dot.angle)
in { dot | x <- newX }
-- VIEW
view : State -> Element
view dots =
let background = filled black (circle circleSize)
dotLinePairs = map viewDotWithLine dots
in collage size size (background :: dotLinePairs)
viewDotWithLine : Dot -> Form
viewDotWithLine dot =
let dotView = viewDot dot
lineView = createLineView
in group [dotView , lineView] |> rotate dot.angle
viewDot : Dot -> Form
viewDot d = alpha 0.8 (filled lightOrange (circle dotSize)) |> move (d.x, 0)
createLineView : Form
createLineView = traced (solid white) (path [ (-size / 2.0, 0) , (size / 2.0, 0) ])
-- SIGNALS
main = Signal.map view (animate createDots)
animate : State -> Signal State
animate dots = Signal.foldp update dots time
time = Signal.foldp (+) 0 AnimationFrame.frame
第二人生LSL
乌龟alpha图像的起点(右键单击下方以保存图像)
乌龟alpha图像的起点(右键单击上方以保存图像)
构建对象:
生成根基本圆柱体大小<1、1、0.01>切片0.49、0.51,颜色< 0,0,0>
对该圆柱的描述不带引号(非常重要)为“ 8,1,1,1”(非常重要),
将其命名为“ cyl”,颜色< 0.25、0.25、0.25 > alpha 0.5
复制cyl 48次
创建一个框,将其命名为“ sphere”,颜色< 1、1、1 >透明度100,但顶部透明度0
将乌龟纹理放置在该框的表面0上,乌龟应该面对+ x
复制该框48次
选择所有框和圆柱体,确保最后选择根圆柱体,链接(控件L)
将以下两个脚本放在根目录中:
//script named "dialog"
default
{
state_entry()
{
}
link_message(integer link, integer num, string msg, key id)
{
list msgs = llCSV2List(msg);
key agent = (key)llList2String(msgs, 0);
string prompt = llList2String(msgs, 1);
integer chan = (integer)llList2String(msgs, 2);
msgs = llDeleteSubList(msgs, 0, 2);
llDialog(agent, prompt, msgs, chan);
}
}
//script named "radial animation"
float interval = 0.1;
float originalsize = 1.0;
float rate = 5;
integer maxpoints = 48;
integer points = 23; //1 to 48
integer multiplier = 15;
integer lines;
string url = "https://codegolf.stackexchange.com/questions/34887/make-a-circle-illusion-animation/34891";
list cylinders;
list spheres;
float angle;
integer running;
integer chan;
integer lh;
desc(integer on)
{
if(on)
{
string desc =
(string)points + "," +
(string)multiplier + "," +
(string)running + "," +
(string)lines
;
llSetLinkPrimitiveParamsFast(1, [PRIM_DESC, desc]);
}
else
{
list params = llCSV2List(llList2String(llGetLinkPrimitiveParams(1, [PRIM_DESC]), 0));
points = (integer)llList2String(params, 0);
multiplier = (integer)llList2String(params, 1);
running = (integer)llList2String(params, 2);
lines = (integer)llList2String(params, 3);
}
}
init()
{
llSetLinkPrimitiveParamsFast(LINK_ALL_OTHERS, [PRIM_POS_LOCAL, ZERO_VECTOR,
PRIM_COLOR, ALL_SIDES, <1, 1, 1>, 0]);
integer num = llGetNumberOfPrims();
integer i;
for(i = 2; i <= num; i++)
{
string name = llGetLinkName(i);
if(name == "cyl")
cylinders += [i];
else if(name == "sphere")
spheres += [i];
}
vector size = llGetScale();
float scale = size.x/originalsize;
float r = size.x/4;
vector cylindersize = <0.01*scale, 0.01*scale, r*4>;
float arc = 180.0/points;
for(i = 0; i < points; i++)
{
float angle = i*arc;
rotation rot = llEuler2Rot(<0, 90, 0>*DEG_TO_RAD)*llEuler2Rot(<0, 0, angle>*DEG_TO_RAD);
integer cyl = llList2Integer(cylinders, i);
integer sphere = llList2Integer(spheres, i);
llSetLinkPrimitiveParamsFast(1, [PRIM_LINK_TARGET, cyl, PRIM_POS_LOCAL, ZERO_VECTOR, PRIM_ROT_LOCAL, rot, PRIM_SIZE, cylindersize, PRIM_COLOR, ALL_SIDES, <0.25, 0.25, 0.25>, 0.5*lines,
PRIM_LINK_TARGET, sphere, PRIM_COLOR, ALL_SIDES, <0.25 + llFrand(0.75), 0.25 + llFrand(0.75), 0.25 + llFrand(0.75)>, 1
]);
}
}
run()
{
vector size = llGetScale();
float scale = size.x/originalsize;
float r = size.x/2;
vector spheresize = <0.06, 0.06, 0.02>*scale;
float arc = 180.0/points;
list params;
integer i;
for(i = 0; i < points; i++)
{
float x = r*llCos((angle + i*arc*multiplier)*DEG_TO_RAD);
vector pos = <x, 0, 0>*llEuler2Rot(<0, 0, i*arc>*DEG_TO_RAD);
rotation rot = llEuler2Rot(<0, 0, i*arc>*DEG_TO_RAD);
integer link = llList2Integer(spheres, i);
params += [PRIM_LINK_TARGET, link, PRIM_POS_LOCAL, pos,
PRIM_ROT_LOCAL, rot,
PRIM_SIZE, spheresize
//PRIM_COLOR, ALL_SIDES, <1, 1, 1>, 1
];
}
llSetLinkPrimitiveParamsFast(1, params);
}
dialog(key id)
{
string runningstring;
if(running)
runningstring = "notrunning";
else
runningstring = "running";
string linesstring;
if(lines)
linesstring = "nolines";
else
linesstring = "lines";
string prompt = "\npoints: " + (string)points + "\nmultiplier: " + (string)multiplier;
string buttons = runningstring + ",points+,points-,reset,multiplier+,multiplier-," + linesstring + ",www";
llMessageLinked(1, 0, (string)id + "," + prompt + "," + (string)chan + "," + buttons, "");
//llDialog(id, prompt, llCSV2List(buttons), chan);
}
default
{
state_entry()
{
chan = (integer)("0x" + llGetSubString((string)llGetKey(), -8, -1));
lh = llListen(chan, "", "", "");
desc(FALSE);
init();
run();
llSetTimerEvent(interval);
}
on_rez(integer param)
{
llListenRemove(lh);
chan = (integer)("0x" + llGetSubString((string)llGetKey(), -8, -1));
lh = llListen(chan, "", "", "");
}
touch_start(integer total_number)
{
key id = llDetectedKey(0);
dialog(id);
}
timer()
{
if(!running)
return;
angle += rate;
if(angle > 360)
angle -= 360;
else if(angle < 0)
angle += 360;
run();
}
listen(integer channel, string name, key id, string msg)
{
if(msg == "points+")
{
if(points < maxpoints)
{
points++;
desc(TRUE);
llResetScript();
}
}
else if(msg == "points-")
{
if(points > 0)
{
points--;
desc(TRUE);
llResetScript();
}
}
else if(msg == "multiplier+")
{
multiplier++;
desc(TRUE);
}
else if(msg == "multiplier-")
{
multiplier--;
desc(TRUE);
}
else if(msg == "running")
{
running = TRUE;
desc(TRUE);
}
else if(msg == "notrunning")
{
running = FALSE;
desc(TRUE);
}
else if(msg == "lines")
{
lines = TRUE;
desc(TRUE);
llResetScript();
}
else if(msg == "nolines")
{
lines = FALSE;
desc(TRUE);
llResetScript();
}
else if(msg == "reset")
llResetScript();
else if(msg == "www")
llRegionSayTo(id, 0, url);
dialog(id);
}
}