Animated Spinners
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
Create and display five spinners. One spinner in the middle and four spinners surrounding it. Each spinner is created by drawing radius lines around a center axis and then looping through the drawing to simulate a moving clock hand. When the loop is sped up, the illusion of a spinner is created. NOTE: The animated GIF example is actually slower than what you should be able to create. A fast animation will fill in more radial lines with a pleasing appearance.
- Stretch goal
Extra credit for offsetting the spinners with mouse movement.
EasyLang
spRadius = 10
angle = 90
background 000
# define the spinners, each element is x, y, color
spData[][] = [ [ 50 50 955 ] [ 25 50 369 ] [ 75 50 309 ] [ 50 25 390 ] [ 50 75 930 ] ]
spCount = len spData[][]
#
on timer
clear
for sp = 1 to spCount
x = spData[sp][1]
y = spData[sp][2]
color spData[sp][3]
move x y
line x + spRadius * cos angle y + spRadius * sin angle
angle -= 1
if angle < 0
angle += 360
.
.
timer 0.001
.
timer 0
FreeBASIC
Const SIZE = 380
Const RADIUS = 60
Const SPINNERS = 5
Const SENSITIVITY = 0.5
Type SpinnerType
x As Single
y As Single
angle As Single
kolor As Integer
End Type
Dim s(0 To SPINNERS-1) As SpinnerType
Screenres SIZE, SIZE, 32
Windowtitle "Move the mouse to offset the spinners"
' Setup spinners with different positions and kolors
s(0).x = SIZE\2 : s(0).y = SIZE\2 : s(0).kolor = Rgb( 0,255, 0) 'lime
s(1).x = SIZE\2 + 50 : s(1).y = SIZE\2 + 50 : s(1).kolor = Rgb(255,128, 0) 'orange
s(2).x = SIZE\2 - 50 : s(2).y = SIZE\2 - 50 : s(2).kolor = Rgb(255, 0, 0) 'red
s(3).x = SIZE\2 + 50 : s(3).y = SIZE\2 - 50 : s(3).kolor = Rgb(255,255, 0) 'yellow
s(4).x = SIZE\2 - 50 : s(4).y = SIZE\2 + 50 : s(4).kolor = Rgb(255,255,255) 'white
Dim As Integer mx, my, i
For i = 0 To SPINNERS-1: s(i).angle = 0: Next
Do
Getmouse mx, my
Color , Rgb(44,45,42)
Cls
' Draw background circle
Circle (SIZE\2, SIZE\2), SIZE\2-25, Rgb(0,0,0), , , , F
Circle (SIZE\2, SIZE\2), SIZE\2-25, Rgb(128,128,128)
' Update and draw each spinner
For i = 0 To SPINNERS-1
' Mouse interaction with smoother movement
If mx > s(i).x-RADIUS And mx < s(i).x+RADIUS Then
If my > s(i).y-RADIUS And my < s(i).y+RADIUS Then
s(i).x += Sgn(s(i).x - mx) * SENSITIVITY
s(i).y += Sgn(s(i).y - my) * SENSITIVITY
End If
End If
' Draw new line
Line (s(i).x, s(i).y)-(s(i).x + RADIUS * Cos(s(i).angle), _
s(i).y + RADIUS * Sin(s(i).angle)), s(i).kolor
' Update angle
s(i).angle += 0.25
Next i
Sleep 1
Loop Until Inkey = Chr(27) 'ESC
FutureBasic
Created with FutureBasic
_Window = 1
_WindowSize = 350
begin globals
CAShapeLayerRef gShapeLayer1
CALayerRef gLayer1
short gLoopCounter1
short gAngle1 = 1
CAShapeLayerRef gShapeLayer2
CALayerRef gLayer2
short gLoopCounter2
short gAngle2 = 1
CAShapeLayerRef gShapeLayer3
CALayerRef gLayer3
short gLoopCounter3
short gAngle3 = 1
CAShapeLayerRef gShapeLayer4
CALayerRef gLayer4
short gLoopCounter4
short gAngle4 = 1
CAShapeLayerRef gShapeLayer5
CALayerRef gLayer5
short gLoopCounter5
short gAngle5 = 1
float gMouseX,gMouseY
end globals
local fn DrawSpinner(x as int,x1 as int,Angle as short, LoopCounter as short, ShapeLayer as CAShapeLayerRef) as short
BezierPathRef path
path = fn BezierPathInit
short EndX,EndY
short RadiusLength = 60
short CenterX = _WindowSize/2 + x
short CenterY = _WindowSize/2 + x1
// Move the spinner left or right with the horizontal mouse position
if (gMouseY > CenterY - RadiusLength & gMouseY < CenterY + RadiusLength )
if (gMouseX > CenterX && gMouseX < CenterX + RadiusLength) then CenterX = CenterX - 10
if gMouseX < CenterX && gMouseX > CenterX - RadiusLength then CenterX = CenterX + 10
end if
// Move the spinner up or down with the vertical mouse position
if (gMouseX > CenterX - RadiusLength & gMouseX < CenterX + RadiusLength )
if (gMouseY > CenterY && gMouseY < CenterY + RadiusLength ) then CenterY = CenterY - 10
if gMouseY < CenterY && gMouseY > CenterY - RadiusLength then CenterY = CenterY + 10
end if
LoopCounter++
EndX = CenterX
EndY = CenterY
BezierPathMoveToPoint( path, fn CGPointMake(CenterX ,CenterY))
select
case Angle > 0 && Angle <= RadiusLength // top to 90 degrees
EndX = CenterX + LoopCounter
EndY = CenterY - RadiusLength + LoopCounter
case Angle > 0 && Angle > RadiusLength && Angle <= RadiusLength * 2 // 90 degrees to bottom
EndX = CenterX + RadiusLength - LoopCounter
EndY = (CenterY + LoopCounter)
case Angle > 0 && Angle > RadiusLength * 2 && Angle <= RadiusLength * 3 // bottom to 270 degrees
EndX = CenterX - LoopCounter
EndY = (CenterY + RadiusLength - LoopCounter )
case Angle > 0 && Angle > RadiusLength * 3 && Angle <= RadiusLength * 4 // 270 degrees to top
EndX = CenterX - RadiusLength + LoopCounter
EndY = (CenterY -LoopCounter)
end select
BezierPathLineToPoint( path, fn CGPointMake(EndX , EndY ))
CAShapeLayerSetPath( ShapeLayer, path )
CAShapeLayerSetLineWidth( ShapeLayer, 2 )
if LoopCounter => RadiusLength then LoopCounter = 0
AppSetProperty( @"Loop", (CFTypeRef) fn StringWithFormat(@"%d",LoopCounter ))
if Angle > RadiusLength * 4 then Angle = 1
Angle++
end fn = Angle
local fn DoMouse
CGPoint pt = fn EventLocationInView( _windowContentViewTag )
gMouseX = pt.x
gMouseY = pt.y
end fn
local fn BuildWindow
CGRect r
SInt32 style
style = NSWindowStyleMaskTitled
r = fn CGRectMake(0,0,_WindowSize,_WindowSize)
window _window, @"Move the mouse to offset the spinners", r, style
viewsetflipped(_windowContentViewTag,_true)
WindowSetAcceptsMouseMovedEvents(_window,_true)
WindowSubclassContentView(_Window) // need this to detect mouse movement
ViewSetWantsLayer( _windowContentViewTag, _true )
// Draw an circle around the spinners
CAShapeLayerRef shapeLayer
CALayerRef layer
layer = fn ViewLayer( _windowContentViewTag )
shapeLayer = fn CAShapeLayerInit
CALayerAddSublayer( layer, shapeLayer )
CAShapeLayerSetStrokeColor( shapeLayer, fn ColorGray )
BezierPathRef path
r = fn CGRectMake(25,25,_WindowSize - 50,_WindowSize - 50)
path = fn BezierPathWithRoundedRect(r,_WindowSize - 50,_WindowSize + 150)
CAShapeLayerSetPath( shapeLayer, path )
CAShapeLayerSetLineWidth( shapeLayer, 1 )
// Initialize drawing layers for the five spinners
gLayer1 = fn ViewLayer( _windowContentViewTag )
gShapeLayer1 = fn CAShapeLayerInit
CALayerAddSublayer( gLayer1, gShapeLayer1)
CAShapeLayerSetStrokeColor( gShapeLayer1, fn ColorGreen )
gAngle1 = fn DrawSpinner( 0, 0, gAngle1, gLoopCounter1, gShapeLayer1)
gLoopCounter1 = fn StringIntValue(fn AppProperty( @"Loop" ))
gLayer2 = fn ViewLayer( _windowContentViewTag )
gShapeLayer2 = fn CAShapeLayerInit
CALayerAddSublayer( gLayer2, gShapeLayer2 )
CAShapeLayerSetStrokeColor( gShapeLayer2, fn ColorOrange )
gAngle2 = fn DrawSpinner( 50, 50, gAngle2, gLoopCounter2, gShapeLayer2 )
gLoopCounter2 = fn StringIntValue(fn AppProperty( @"Loop" ))
gLayer3 = fn ViewLayer( _windowContentViewTag )
gShapeLayer3 = fn CAShapeLayerInit
CALayerAddSublayer( gLayer3, gShapeLayer3 )
CAShapeLayerSetStrokeColor( gShapeLayer3, fn ColorRed )
gAngle3 = fn DrawSpinner( -50, -50, gAngle3, gLoopCounter3, gShapeLayer3 )
gLoopCounter3 = fn StringIntValue(fn AppProperty( @"Loop" ))
gLayer4 = fn ViewLayer( _windowContentViewTag )
gShapeLayer4 = fn CAShapeLayerInit
CALayerAddSublayer( gLayer4, gShapeLayer4 )
CAShapeLayerSetStrokeColor( gShapeLayer4, fn ColorYellow )
gAngle4 = fn DrawSpinner( 50, -50, gAngle4, gLoopCounter4, gShapeLayer4 )
gLoopCounter4 = fn StringIntValue(fn AppProperty( @"Loop" ))
gLayer5 = fn ViewLayer( _windowContentViewTag )
gShapeLayer5 = fn CAShapeLayerInit
CALayerAddSublayer( gLayer5, gShapeLayer5 )
CAShapeLayerSetStrokeColor( gShapeLayer5, fn ColorWhite )
gAngle5 = fn DrawSpinner( -50, 50, gAngle5, gLoopCounter5, gShapeLayer5)
gLoopCounter5= fn StringIntValue(fn AppProperty( @"Loop" ))
end fn
void local fn DoDialog( ev as long )
select ( ev )
case _viewMouseMoved
fn DoMouse
end select
end fn
fn BuildWindow
on dialog fn DoDialog
local fn DrawLayers
gAngle1 = fn DrawSpinner( 0, 0, gAngle1, gLoopCounter1, gShapeLayer1)
gLoopCounter1 = fn StringIntValue(fn AppProperty( @"Loop" ))
gAngle2 = fn DrawSpinner( 50, 50, gAngle2, gLoopCounter2, gShapeLayer2 )
gLoopCounter2 = fn StringIntValue(fn AppProperty( @"Loop" ))
gAngle3 = fn DrawSpinner( -50, -50, gAngle3, gLoopCounter3, gShapeLayer3 )
gLoopCounter3 = fn StringIntValue(fn AppProperty( @"Loop" ))
gAngle4 = fn DrawSpinner( 50, -50, gAngle4, gLoopCounter4, gShapeLayer4 )
gLoopCounter4 = fn StringIntValue(fn AppProperty( @"Loop" ))
gAngle5 = fn DrawSpinner( -50, 50, gAngle5, gLoopCounter5, gShapeLayer5)
gLoopCounter5= fn StringIntValue(fn AppProperty( @"Loop" ))
end fn
fn AppSetTimer( .0001, @fn DrawLayers, _true ) // Determines the spinner speed
// Set the value to .01 to see that the spinners are actually lines rotating around a center axis.
// Set the value to .0001 to see the spinning illusion.
HandleEvents
- Output:
Java
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.JPanel;
public final class AnimatedSpinners extends JPanel implements Runnable {
public static void main(String[] args) {
EventQueue.invokeLater( () -> {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("Animated Spinners");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new AnimatedSpinners() );
frame.setLocationByPlatform(true);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
} );
}
@Override
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics2D graphics2D = (Graphics2D) graphics;
graphics2D.setColor(Color.BLACK);
graphics2D.fillOval(24, 24, SIZE - 48, SIZE - 48);
spinners.forEach( s -> s.draw(graphics2D) );
}
@Override
public void run() {
repaint();
}
private AnimatedSpinners() {
setPreferredSize( new Dimension(SIZE, SIZE) );
setBackground(Color.DARK_GRAY);
setDoubleBuffered(true);
addMouseMotionListener(Spinner.listener);
spinners = List.of( new Spinner(0, 0, Color.GREEN), new Spinner(-120, -120, Color.RED),
new Spinner(120, -120, Color.YELLOW), new Spinner(-120, 120, Color.WHITE),
new Spinner(120, 120, Color.ORANGE) );
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(this, 0, 20, TimeUnit.MILLISECONDS);
}
private static final class Spinner {
public Spinner(int aOffsetX, int aOffsetY, Color aColour) {
centreX = SIZE / 2 + aOffsetX;
centreY = SIZE / 2 + aOffsetY;
colour = aColour;
}
public void draw(Graphics2D graphics2D) {
Point delta = mouseMovement();
centreX += delta.x;
centreY += delta.y;
angle = ( angle + ANGLE_INCREMENT ) % TAU;
final int endX = centreX + (int) ( RADIUS * Math.cos(angle) );
final int endY = centreY + (int) ( RADIUS * Math.sin(angle) );
graphics2D.setColor(colour);
graphics2D.setStroke( new BasicStroke(2.0F) );
graphics2D.drawLine(centreX, centreY, endX, endY);
}
private Point mouseMovement() {
Point delta = new Point(0, 0);
// Move the spinner left or right with the horizontal mouse position
if ( mouseY > centreY - RADIUS && mouseY < centreY + RADIUS ) {
if ( mouseX > centreX && mouseX < centreX + RADIUS ) { delta.x= -10; }
if ( mouseX < centreX && mouseX > centreX - RADIUS ) { delta.x = +10; }
}
// Move the spinner up or down with the vertical mouse position
if ( mouseX > centreX - RADIUS && mouseX < centreX + RADIUS ) {
if ( mouseY < centreY && mouseY > centreY - RADIUS ) { delta.y = +10; }
if ( mouseY > centreY && mouseY < centreY + RADIUS ) { delta.y = -10; }
}
// Ensure that the spinner remains in the black background circle
return ( Math.hypot(SIZE / 2 - centreX, SIZE / 2 - centreY) < SIZE / 2 - RADIUS - 24 - 10) ?
delta : new Point(0, 0);
}
private int centreX, centreY;
private final Color colour;
private static double angle;
private static int mouseX, mouseY;
private static final int RADIUS = 60;
private static final double ANGLE_INCREMENT = Math.PI / 6.0;
private static final double TAU = 2 * Math.PI;
private static final MouseAdapter listener = new MouseAdapter() {
public void mouseMoved(MouseEvent event) {
mouseX = event.getX();
mouseY = event.getY();
}
};
}
private List<Spinner> spinners;
private static final int SIZE = 600;
}
Julia
Luxor's backend under Windows for movie creation has trouble with higher frame rates, so the frame rate of the output (nothing else) is modified with Clipchamp for the viewable gif file below.
""" https://rosettacode.org/wiki/Animated_Spinners """
using Luxor
const movie = Movie(600, 600, "lux_spinners")
function frame(scene::Scene, frame_num)
rulers()
sethue("grey40")
rect(Point(-300, -300), 595, 595, action = :fill)
sethue("black")
circle(Point(0, 0), 296, action = :fill)
colors = ["green", "orange", "red", "white", "yellow"]
xs, ys = [0.0, 120.0, -120.0, 120.0, -120.0], [0.0, 120.0, -120.0, -120.0, 120.0]
centers = [Point(xs[i], ys[i]) for i in eachindex(xs)]
angle, r = mod1(frame_num * 7, 360), 84.0
xs .= getindex.(centers, 1) .+ r * cospi(angle / 180)
ys .= getindex.(centers, 2) .+ r * sinpi(angle / 180)
for (i, c) in enumerate(centers)
sethue(colors[i])
setline(8)
line(c, Point(xs[i], ys[i]), action = :stroke)
end
end
animate(movie, [Scene(movie, frame, 1:720)], framerate = 1000, creategif = true, pathname = "lux_spinners.gif")
- Output:
prior version
Sorry, it seems I somehow deleted this when moving Python into the right place...
""" https://rosettacode.org/wiki/Animated_Spinners """
using Gtk, Colors, Graphics, Cairo
""" Parameters for drawing the Gtk spinners app. """
struct Draw5Parameters
dim::Vector{Int}
xs::Vector{Float64}
ys::Vector{Float64}
deltas::Vector{Float64}
previous::Vector{Float64}
fps::Int
colors::Vector{Colorant}
Draw5Parameters() = new([800, 800], zeros(5), zeros(5), zeros(2), zeros(2), 150,
[colorant"lightgreen", colorant"orange", colorant"red", colorant"white", colorant"yellow"])
end
const DP = Draw5Parameters()
const WIN = GtkWindow("Spinners", DP.dim[1], DP.dim[2])
const CANVAS = GtkCanvas()
push!(WIN, CANVAS)
@guarded Gtk.draw(CANVAS) do _
""" Draw the spinners as a single line position. """
ctx = getgc(CANVAS)
h = height(ctx)
w = width(ctx)
if all(iszero, DP.xs) || w != DP.dim[1] || h != DP.dim[2]
DP.dim .= w, h
DP.xs .= [0.0, 50.0, -50.0, 50.0, -50.0] .* (w / 200) .+ (w / 2)
DP.ys .= [0, 50, -50, -50, 50] .* (h / 200) .+ (h / 2)
set_coordinates(ctx, BoundingBox(0, w, 0, h))
set_source(ctx, colorant"gray")
rectangle(ctx, 0, 0, w, h)
fill(ctx)
set_source(ctx, colorant"black")
arc(ctx, h / 2, w / 2, w / 2, 0, 2π)
fill(ctx)
end
r = w / 10
for i in eachindex(DP.xs)
set_line_width(ctx, 4.0)
set_source(ctx, colorant"black")
move_to(ctx, DP.xs[i], DP.ys[i])
line_to(ctx, DP.xs[i] + r * DP.previous[1] * 1.1, DP.ys[i] + r * DP.previous[2] * 1.1)
stroke(ctx)
set_line_width(ctx, 2.0)
set_source(ctx, DP.colors[i])
move_to(ctx, DP.xs[i], DP.ys[i])
line_to(ctx, DP.xs[i] + r * DP.deltas[1], DP.ys[i] + r * DP.deltas[2])
stroke(ctx)
end
DP.previous .= DP.deltas
end
""" Run the spinners by drawing serial rotations in the angle of the lines. """
function spin()
angle = 0.0
while true
angle = mod1(angle + 100 * rand(), 360)
DP.deltas .= cospi(angle / 180), sinpi(angle / 180)
draw(CANVAS)
show(CANVAS)
sleep(1 / DP.fps)
end
end
@async spin()
- Output:
M2000 Interpreter
We handle refresh rate to animate without flickering. Mouse move when we press mouse.
Module Animated_Spinners {
Cls #222222, 0
move scale.x div 2, scale.y div 2
R=min.data(scale.x, scale.y) *1/10
Circle Fill 0, R*3
Z=0
z1=pi/180*random(1,9)
p2=2*pi
' hold statement save the screen - as our background (including circle)
' release statement write back the background
X=scale.x div 2
Y=scale.y div 2
hold
' 60 hz = 1000ms/60 cycles
every 1000/60 {
release
Pen 15 {
move X, Y
draw angle Z, R
}
Pen 11 {
move X+R, Y-R
draw angle Z, R
}
Pen 12 {
move X-R, Y+R
draw angle Z, R
}
Pen 14 {
move X+R, Y+R
draw angle Z, R
}
move X-R, Y-R
draw angle Z, R, 13 ' specific color
Z-=z1*random(1, 10)
Z|mod p2
Refresh 200
if inkey$<>"" then exit
if mouse then x=mouse.x : y=mouse.y
}
refresh 25
}
Animated_Spinners
Phix
-- demo\rosetta\Animated_Spinners.exw
with javascript_semantics
requires("1.0.6") -- (not yet shipped)
include xpGUI.e
constant title = "Animated Spinners"
atom angle = 0,
dpt = 1 -- degrees per tick
procedure redraw(gdx canvas, integer w,h)
integer r = floor(min(w,h)*0.45),
cx = floor(w/2),
cy = floor(h/2)
gCanvasCircle(canvas, cx, cy, r, true, colour:=XPG_BLACK)
atom ar = angle*XPG_DEG2RAD,
ds = r*sqrt(2)/4,
dx = r/2.5*cos(ar),
dy = r/2.5*sin(ar)
for s in {{ 0, 0,XPG_GREEN},
{-ds,-ds,XPG_RED},
{+ds,-ds,XPG_YELLOW},
{+ds,+ds,XPG_ORANGE},
{-ds,+ds,XPG_WHITE}} do
atom {ax,ay,c} = s
gCanvasLine(canvas,cx+ax,cy+ay,cx+ax+dx,cy+ay+dy,colour:=c)
end for
end procedure
procedure timer_action(gdx timer)
angle += dpt
gdx canvas = gGetAttribute(timer,"USER_DATA")
gRedraw(canvas)
end procedure
function key_handler(gdx dlg, integer c)
switch c
case '+','=': dpt = min(dpt+1,160)
case '-','_': dpt = max(dpt-1,1)
end switch
gSetAttribute(dlg,"TITLE","%s [%g dpt]",{title,dpt})
gRedraw(dlg)
return XPG_DEFAULT
end function
gdx canvas = gCanvas(redraw,"BGCLR=DARK_GREY"),
dialog = gDialog(canvas,title,"SIZE=510x540, MINSIZE=273x58"),
timer = gTimer(timer_action, 10, true, canvas)
gSetHandler(dialog, `KEY`, key_handler)
gShow(dialog)
gMainLoop()
Python
This was inspired by the Java solution.
import pygame
WIDTH, HEIGHT = 350, 400
RADIUS = 50
FPS = 20
def calculate_angle_line_pos(
start: tuple[int | float, int | float], radius: int | float, angle: int | float
):
vec = pygame.math.Vector2(0, -radius).rotate((angle) % 360)
return start[0] + vec.x, start[1] + vec.y
class Spinner:
def __init__(
self,
pos: tuple[int, int],
color: tuple[int, int, int],
radius=10,
speed=110,
starting_angle=360,
line_width=2,
):
self.__pos = pos
self.__radius = radius
self.__angle = starting_angle
self.__color = color
self.__speed = speed
self.__line_width = line_width
def draw(self, surface: pygame.Surface):
pygame.draw.line(
surface,
self.__color,
self.__pos,
calculate_angle_line_pos(self.__pos, self.__radius, self.__angle),
self.__line_width,
)
self.__angle = (self.__angle - self.__speed) % 361
def main():
pygame.init()
pygame.display.set_caption("Spinners")
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
cx, cy = WIDTH // 2, HEIGHT // 2
spinner = Spinner((cx - RADIUS, cy - RADIUS), (255, 0, 0), RADIUS)
spinner2 = Spinner((cx, cy), (0, 0, 255), RADIUS)
spinner3 = Spinner((cx + RADIUS, cy - RADIUS), (255, 255, 0), RADIUS)
spinner4 = Spinner((cx - RADIUS, cy + RADIUS), (255, 255, 255), RADIUS)
spinner5 = Spinner((cx + RADIUS, cy + RADIUS), (255, 175, 0), RADIUS)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((44, 45, 44))
pygame.draw.circle(screen, (100, 100, 100), (cx, cy), 100 + RADIUS + 2)
pygame.draw.circle(screen, (0, 0, 0), (cx, cy), 100 + RADIUS)
spinner.draw(screen)
spinner2.draw(screen)
spinner3.draw(screen)
spinner4.draw(screen)
spinner5.draw(screen)
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
if __name__ == "__main__":
main()
- Output:
Wren
import "dome" for Window, Process
import "graphics" for Canvas, Color
import "math" for Math
import "input" for Mouse
var Degrees3 = Num.pi / 60
var Rate = 1
class AnimatedSpinners {
construct new(width, height) {
Window.title = "Animated spinners"
Window.resize(width, height)
Canvas.resize(width, height)
Canvas.cls(Color.darkgray)
_w = width
_h = height
_r = 60
_dx = [0, -180, 180, -180, 180]
_dy = [0, -180, -180, 180, 180]
_cols = [Color.green, Color.red, Color.white, Color.yellow, Color.brown]
}
drawHand(cx, cy, angle, color) {
var x = cx + (_r * Math.cos(angle)).truncate
var y = cy + (_r * Math.sin(angle)).truncate
Canvas.line(cx, cy, x, y, color, 2)
}
init() {
_frame = 0
_cx = _w / 2
_cy = _h / 2
Canvas.circlefill(_cx, _cy, _cx - 20, Color.black)
for (i in 0..4) drawHand(_cx + _dx[i], _cy + _dy[i], 0, _cols[i])
}
update() {
_frame = _frame + 1
if (_frame == 120) _frame = 0
}
draw(dt) {
var angle = Degrees3 * _frame * Rate
Canvas.cls(Color.darkgray)
Canvas.circlefill(_w/2, _h/2, _w/2 - 20, Color.black)
// Move the spinner left or right with the horizontal mouse position
if (Mouse.y > _cy - _r && Mouse.y < _cy + _r) {
if (Mouse.x > _cx && Mouse.x < _cx + _r) _cx = _cx - 10
if (Mouse.x < _cx && Mouse.x > _cx - _r) _cx = _cx + 10
}
// Move the spinner up or down with the vertical mouse position
if (Mouse.x > _cx - _r && Mouse.x < _cx + _r) {
if (Mouse.y > _cy && Mouse.y < _cy + _r) _cy = _cy - 10
if (Mouse.y < _cy && Mouse.y > _cy - _r) _cy = _cy + 10
}
// Ensure the center spinner is always visible
if (_cx < _r) _cx = _cx + _r
if (_cx > _w - _r)_cx = _cx - _r
if (_cy < _r) _cy = _cy + _r
if (_cy > _h - _r) _cy = _cy - _r
for (i in 0..4) drawHand(_cx + _dx[i], _cy + _dy[i], angle, _cols[i])
}
}
// Pass Rate as a command line argument to speed up the spinner, otherwise 1 is used
if (Process.args.count == 3) Rate = Num.fromString(Process.args[2])
var Game = AnimatedSpinners.new(800, 800)
XPL0
def R = 50.;
real X, Y, A;
int X0, Y0, C, N;
[SetVid($13); \320x200
X0:= [50, 150, 100, 50, 150];
Y0:= [50, 50, 100, 150, 150];
A:= 0.;
repeat X:= R*Cos(A);
Y:= R*Sin(A);
for N:= 0 to 4 do
[Move(X0(N), Y0(N));
Line(fix(X)+X0(N), fix(Y)+Y0(N), 9+N);
];
WaitForVSync;
for N:= 0 to 4 do
[Move(X0(N), Y0(N));
Line(fix(X)+X0(N), fix(Y)+Y0(N), 0);
];
A:= A + 0.05;
until KeyHit;
]