Script:Circular or spiral motion

From OHRRPGCE-Wiki
Jump to navigation Jump to search

Circular motion is achieved using the sin and cos functions:

 x = cos(t)
 y = sin(t)

where t is time (e.g. seconds). To control the radius r, origin (x0,y0 - the point to circle around), and speed (s - degrees per second), we have to add some more parameters:

 x = x0 + r * cos(s * t)
 y = y0 + r * sin(s * t)

sin and cos aren't builtin functions in HamsterSpeak, but there are scripts to calculate them in the 3rd Party HSI package. You only need the sine, cosine, sina, sinb, sinc, sind scripts and don't need any of the global variables or other things.

Because HamsterSpeak doesn't have floating point, the sine(angle,mult) script returns mult*sin(angle). The angle is measured in degrees (360 for a full circle).

For example, to move a slice in a circle of radius 100, making a revolution every 30 ticks, and circling the center of the screen:

script, circling slice, begin
  variable (sl, t, angle)
  sl := load walkabout sprite (1)
  # The following causes positions to be measured from the centre of the screen
  center slice (sl)

  for (t, 0, 150) do (
    angle := 360 * t / 30
    put slice (sl, cosine(angle, 100), sine(angle, 100))
    wait
  )

  free slice (sl)
end

To move in a spiral, you adjust the radius at the same time as the angle:

script, spiralling slice, begin
  variable (sl, t, angle, radius)
  sl := load walkabout sprite (1)
  center slice (sl)

  for (t, 0, 150) do (
    angle := 360 * t / 30
    radius := 100 -- t*100 / 150  # Spiral in from radius 100 to 0 in 150 ticks
    put slice (sl, cosine(angle, radius), sine(angle, radius))
    wait
  )

  free slice (sl)
end

However this will cause the movement speed to be proportional to the radius, moving fast at the beginning and slowing down to zero, as seen here: Spiral constant angular speed.gif

If we want to compensate for that to make the speed roughly uniform, it requires some significant changes, since angle is no longer proportional to t:

define constant (9, spiral speed)  # Movement speed in pixels per tick

script, spiral, begin
  variable (sl)
  create rect(320, 200)  # Hide the map
  sl := load walkabout sprite(1)
  center slice (sl)

  variable (t, radius, angle, angular speed)
  radius := 100
  angle := 0
  for (t, 0, 1000) do (
    angular speed := 360 * spiral speed * 1000 / (1 + 3142 * 2 * radius) # Degrees per tick
    if (angular speed > 60) then (angular speed := 60)
    if (angular speed < 1) then (angular speed := 1)
    angle += angular speed
    #radius := 100 -- angle * 25 / 360  # Spiral in at 25 pixels per revolution
    radius := 100 -- t*100 / 200      # Spiral in from radius 100 to 0 in 200 ticks
    if (radius < 0) then (break)

    put slice (sl, cosine(angle, radius), sine(angle, radius))
    wait
  )
end

There are two different "radius := ..." lines, which cause different spiral motions, uncomment the one you want:

The first produces an Archimedean spiral:

 radius := 100 -- angle * 25 / 360  # Spiral in at 25 pixels per revolution

Spiral Archimedean.gif

The second produces a logarithmic spiral:

 radius := 100 -- t*100 / 200      # Spiral in from radius 100 to 0 in 200 ticks

Spiral logarithmic.gif