Pamiętasz efekt sinus scroll z 8-bitowych demo i intro w latach 90-tych?
Były one tworzone w setkach linii assemblera, z przerwaniami sprzętowymi i obliczanymi z góry tablicami sinusa. A oto przykład w około 30 liniach czystego JavaScript.
Potrzebujemy obrazu bitmapowego z czcionką o stałej czerokości (inaczej mono-spaced lub nieproporcjonalnej). To oznacza, że każda litera ma tę samą szerokość w pikselach, co znacznie uprości nasze obliczenia. Ten paragraf używa fontu proporcjonalnego, więc 'w' jest szersze niż 'i'. Przykładowy kod w tabelce używa fontu nieproporcjonalnego.
Powyższa czcionka została zrippowana z jakiegoś intro na legendarny Commodore 64 (jest na stronie
C-64 logo generator, ale możesz też po prostu wpisać alfabet w edytorze grafiki w innej czcionce i nagrać to jako bitmapę).
Teraz jesteśmy gotowi na kod:
<html> |
<body style='background-color:black'> |
<canvas id='myCanvas' width='600' height='800'></canvas> |
<script> |
const text = ' old school sine scroller another cool javascript tutorial'; |
const fontWidth = 54; |
const fontHeight = 71; |
const letters = 12; |
let x = []; |
let char = []; |
let wiggle = 0; |
let counter = 0; |
let position = letters; |
let bitmap = new Image(); |
bitmap.src = 'font.png'; |
let canvas = document.getElementById('myCanvas'); |
let context = canvas.getContext('2d'); |
for (let n = 0; n < letters; n++) { |
char[n] = text.charCodeAt(n) - 97; |
x[n] = n * fontWidth; |
} |
window.requestAnimationFrame(scroll); |
|
function scroll() { |
context.clearRect(0, 0, canvas.width, canvas.height); |
for (let n = 0; n < letters; n++) { |
let y = 100 + wiggle * Math.sin(n + counter / 6.28); |
context.drawImage(bitmap, char[n] * fontWidth, 0, fontWidth, fontHeight, x[n], y, fontWidth, fontHeight); |
x[n]--; |
if (x[n] < -fontWidth) { |
x[n] = (letters - 1) * fontWidth; |
char[n] = text.charCodeAt(position) - 97; |
position++; |
if (position > text.length) position = 0; |
} |
} |
if (counter > 200 && wiggle < 30) wiggle = wiggle + .1; |
counter++; |
window.requestAnimationFrame(scroll); |
} |
</script> |
</body></html> |
Główny program tylko inicjalizuje zmienne:
Linie 1-3: ustawienie HTML5
5: Tekst naszego scrolla. Kilka spacji na przodzie, by wychodził z prawej strony ekranu.
6-7: szerokość i wysykość fontu, w pikselach
8: liczba liter do scrollowania
9: tablica współrzędnych x liter
10: znak na danej pozycji
11: współczynnik amplitudy - zaczynamy od płaskiej linii
12: licznik czasu
13: bieżąca pozycja w tekście
14-15: obraz źródłowy (niewidoczny na ekranie)
16-17: docelowy canvas
18-21: ustawiamy pierwszy zestaw znaków i ich współrzędne x
22: rozpoczynamy animację scrolla
Cała prawdziwa akcja dzieje się w funkcji scroll:
25: wyczyść poprzednią klatkę
26: dla każdej litery:
27: oblicz współrzędną y używając funkcji sinus
28: skopiuj odpowiedni znak z bitmapy na canvas
Ta linia jest nieco skomplikowana, przyjrzymy się więc dokładnie argumentom:
bitmap - źródłowa bitmapa
char[n] * fontWidth, 0 - współrzędne lewego górnego rogu źródłowego obrazu n-tego znaku
fontWidth, fontHeight - rozmiar źródłowego obrazu (jeden znak)
x[n], y - współrzędne docelowe na canvas
fontWidth, fontHeight - rozmiar kopii (także jeden znak)
29: przesuń literę w lewo
30-33: jeżeli litera wyszła za ekran z lewej strony, ustaw ją z powrotem po prawej stronie i przypisz następny znak z tekstu
32: zamień znak JavaScript (ASCII) na zakres 0 do 23 : a to 0, b to 1 itd.
34: jeżeli dotarliśmy do końca tekstu, zaczynamy od nowa
37: ten współczynnik określa amplitudę sinusoidy. Zaczęliśmy od zera - płaskiej linii. Kiedy licznik osiąga 200, zacznamy zwiększać amplitudę, aż osiągniemy maksymalną wartość 30.
38: zwiększamy licznik w każdej klatce animacji
39: żądanie kolejnej klatki
Jest mnóstwo rzeczy, które możesz dodać do tego kodu:
- obsługa znaków nieliterowych (liczb, przecinka, kropki itd.)
- obsługa polskich liter
- kontrolowanie prędkości scrolla tekstem (np. przyspieszamy, gdy kolejny znak to '@', a zwalniamy, jeżeli to '#')
- kontrolowanie amplitudy tekstem
- obliczanie indywidualnej współrzędnej y dla każdej pionowej linii pikseli (zamiast dla każdej litery)
Powodzenia!
Inne samouczki:
Fraktale - 25 linii JavaScript
Złudzenie optyczne - 18 linii JavaScript
Rozbiajanie muru kulą - 14 linii kodu Python/Blender 3d
Efekt domino - 10 linii kodu Python/Blender 3d