I think a horizontal bar is necessary so that when the code is very wide it can be moved horizontally comfortably.
I mention this because when creating the scenarios in the platform game that I am making, the scenario is a list and I have not been able to make it very long because I had to move with the keyboard arrows from left to right and when I reached the end I returned to the beginning.
And it was very tiresome to have to move around with the keys again.
Here comes a library for creating sound effects. It's an improvement of the thing I made for that Defender-clone. You now have more advanced control over the frequency and volume of the sounds you create. You can also add echo effects and save your masterpieces as wav files.
sfx_library_example.n7
Code:
' sfx_library_example
' -------------------
#win32
' Include the sfx library.
include "sfx.n7"
' Create a window and print instructions.
set window "SFX", 640, 480
wln "1 - Play a square wave sound effect"
wln "2 - Play a sine wave sound effect"
wln "3 - Play a noise sound effect"
wln
wln "Esc - Quit"
' Create an sfx instance.
sfx = SFX()
' You can use 'SetSampleRate(value)' to change the sample rate that is used when creating sounds.
' It defaults to 16000 (so the call below is just for show). There's no point setting a higher value
' than 22050, since that is the output frequency of all audio in n7.
sfx.SetSampleRate(16000)
' Use 'SetEcho(count, delay, dropOff, panning)' to enable an echo effect for all sound effects
' created. Set the 'count' parameter to 0 to disable echo. Echo is disabled by default. 'count' is
' the number of echos and 'delay' is the delay in seconds between them. 'dropOff' decides how much
' the volume will decrase for each echo. If 'dropOff' is 0.5, the first echo will have that volume,
' the second one 0.5*0.5 = 0.26 and so on. 'panning', [-1..1] can be used to make the echo bounce
' between the left and right speakers. The 'panning' value is inverted after each echo. Set
' 'panning' to 0 to disable panning.
sfx.SetEcho(2, 0.4, 0.1, 0)
' Use 'SquareWave(duration, freq, vol)' to create a square wave sound. 'duration' is the duration in
' seconds (excluding any echo effect). 'freq' is the frequency. It can be either a number or an
' array of numbers. In the case of an array, it is evaluated as a one dimensional bezier curve. It's
' not as complicated as it may sound. To make a sound start with a frequencey of 500 and end with
' 1000, simply set the 'freq' parameter to [500, 1000]. 'vol' is the volume, and just like 'freq' it
' can be a number or an array. The 'vol' value(s) should be in the range [0..1].
crispSound = sfx.SquareWave(0.5, [50, 100, -500, 1000], [0.5, 1, 0])
' You can also use 'SaveSquareWave(filename, duration, freq, vol)' to save a sound to a wav file.
'sfx.SaveSquareWave("crisp_sound.wav", 0.5, [50, 100, -500, 1000], [0.5, 1, 0])
' Change the echo effect and use 'SineWave(duration, freq, vol)' to create a sine wave sound. The
' parameters work just as they do for 'SquareWave'.
sfx.SetEcho(2, 0.15, 0.2, 0)
blubSound = sfx.SineWave(0.2, [0, 500, 25, 500], [0, 1, 0])
' You can also use 'SaveSine'Wave(filename, duration, freq, vol)' to save a sound to a wav file.
'sfx.SaveSineWave("blub_sound.wav", 0.2, [0, 500, 25, 500], [0, 1, 0])
' This time, use panning for the echo effect. 'Noise(duration, freq, vol)' creates a noise sound,
' and the parameters work just the same way as they do for 'SquareWave' and 'SineWave'.
sfx.SetEcho(2, 0.4, 0.2, -0.5)
boomSound = sfx.Noise(0.6, [5000, 100], [1, 0, 1, 0])
' You can also use 'SaveNoise(filename, duration, freq, vol)' to save a sound to a wav file.
'sfx.SaveNoise("boom_sound.wav", 0.6, [5000, 100], [1, 0, 1, 0])
' Let the user play the sound effects.
while not keydown(KEY_ESCAPE)
if keydown(KEY_1, true) play sound crispSound
if keydown(KEY_2, true) play sound blubSound
if keydown(KEY_3, true) play sound boomSound
fwait 60
wend
sfx.n7
Code:
' SFX
' ---
' A library for creating simple sound effects.
'
' By Marcus.
' GetSampleRate
' -------------
' Return number of samples per second.
sfx.GetSampleRate = function()
return this.sr
endfunc
' SetSampleRate
' -------------
' Set number of samples per second.
sfx.SetSampleRate = function(sampleRate)
assert sampleRate >= 8000 and sampleRate <= 22050, "SFX.SetSampleRate: Invalid sample rate"
this.sr = sampleRate
endfunc
' SetEcho
' -------
' Add 'count' number of echos with a delay of 'delay' seconds. Set 'count' to 0 to disable echo.
' The volume is multiplied by 'dropOff' for each echo. 'pan', [-1..1], can be used to make the
' sound bounce between the left and right speaker. A value of -1 means that the first echo will
' be played only on the left side, and 1 means it will be played on the right side. After each
' echo the pan value is inverted. Set 'pan' to 0 to disable panning.
sfx.SetEcho = function(count, delay, dropOff, pan)
assert count >= 0, "SFX.SetEcho: Invalid count"
assert delay >= 0, "SFX.SetEcho: Invalid delay"
this.ech = count
this.echDel = delay
this.echDO = dropOff
this.echPan = pan
endfunc
' SineWaveData
' ------------
' Return sine wave data lasting for 'duration' seconds. 'freq' is the frequency and can be a
' number or an array of numbers, treated as a 1D bezier curve. 'vol' is the volume and can be a
' number or an array of numbers, treated as a 1D bezier curve. The 'vol' value(s) should be in
' the range [0..1].
sfx.SineWaveData = function(duration, freq, vol)
assert duration > 0, "SFX.SineWaveData: Invalid duration"
if typeof(freq) <> TYPE_TABLE freq = [freq]
if typeof(vol) <> TYPE_TABLE vol = [vol]
freqDegree = sizeof(freq) - 1
freqBc = BinomialCoefficients(freqDegree)
volDegree = sizeof(vol) - 1
volBc = BinomialCoefficients(volDegree)
data = []
a = 0
p = 0
dp = 1/(duration*this.sr)
for i = 0 to duration*this.sr - 1
data[i] = sin(a)*EvaluateCurve(vol, volBc, p)
a = a + 2*PI*EvaluateCurve(freq, freqBc, p)/this.sr
p = p + dp
next
if this.ech
return ApplyEcho(data, this.ech, int(this.echDel*this.sr), this.echDO, this.echPan)
else
return [data, data]
endif
endfunc
' SineWave
' --------
' Return a sine wave sound lasting for 'duration' seconds. 'freq' is the frequency and can be
' a number or an array of numbers, treated as a 1D bezier curve. 'vol' is the volume and can be
' a number or an array of numbers, treated as a 1D bezier curve. The 'vol' value(s) should be
' in the range [0..1].
sfx.SineWave = function(duration, freq, vol)
data = this.SineWaveData(duration, freq, vol)
return createsound(data[0], data[1], this.sr)
endfunc
' SaveSineWave
' ------------
' Save sine wave sound lasting for 'duration' seconds. 'freq' is the frequency and can be a
' number or an array of numbers, treated as a 1D bezier curve. 'vol' is the volume and can be a
' number or an array of numbers, treated as a 1D bezier curve. The 'vol' value(s) should be in
' the range [0..1].
sfx.SaveSineWave = function(filename, duration, freq, vol)
data = this.SineWaveData(duration, freq, vol)
return SaveWav(filename, data[0], data[1], this.sr)
endfunc
' SquareWaveData
' --------------
' Return square wave data lasting for 'duration' seconds. 'freq' is the frequency and can be a
' number or an array of numbers, treated as a 1D bezier curve. 'vol' is the volume and can be a
' number or an array of numbers, treated as a 1D bezier curve. The 'vol' value(s) should be
' in the range [0..1].
sfx.SquareWaveData = function(duration, freq, vol)
assert duration > 0, "SFX.SquareWave: Invalid duration"
if typeof(freq) <> TYPE_TABLE freq = [freq]
if typeof(vol) <> TYPE_TABLE vol = [vol]
freqDegree = sizeof(freq) - 1
freqBc = BinomialCoefficients(freqDegree)
volDegree = sizeof(vol) - 1
volBc = BinomialCoefficients(volDegree)
data = []
a = 0
p = 0
dp = 1/(duration*this.sr)
for i = 0 to duration*this.sr - 1
sa = sin(a)
if sa < 0 sa = -1
elseif sa > 0 sa = 1
data[i] = sa*EvaluateCurve(vol, volBc, p)
a = a + 2*PI*EvaluateCurve(freq, freqBc, p)/this.sr
p = p + dp
next
if this.ech
return ApplyEcho(data, this.ech, int(this.echDel*this.sr), this.echDO, this.echPan)
else
return [data, data]
endif
endfunc
' SquareWave
' ----------
' Return a square wave sound lasting for 'duration' seconds. 'freq' is the frequency and can be
' a number or an array of numbers, treated as a 1D bezier curve. 'vol' is the volume and can be
' a number or an array of numbers, treated as a 1D bezier curve. The 'vol' value(s) should be
' in the range [0..1].
sfx.SquareWave = function(duration, freq, vol)
data = this.SquareWaveData(duration, freq, vol)
return createsound(data[0], data[1], this.sr)
endfunc
' SaveSquareWave
' --------------
' Save a square wave sound lasting for 'duration' seconds. 'freq' is the frequency and can be a
' number or an array of numbers, treated as a 1D bezier curve. 'vol' is the volume and can be a
' number or an array of numbers, treated as a 1D bezier curve. The 'vol' value(s) should be
' in the range [0..1].
sfx.SaveSquareWave = function(filename, duration, freq, vol)
data = this.SquareWaveData(duration, freq, vol)
return SaveWav(filename, data[0], data[1], this.sr)
endfunc
' NoiseData
' ---------
' Return noise data lasting for 'duration' seconds. 'freq' is the frequency and can be a
' number or an array of numbers, treated as a 1D bezier curve. 'vol' is the volume and can be a
' number or an array of numbers, treated as a 1D bezier curve. The 'vol' value(s) should be
' in the range [0..1].
sfx.NoiseData = function(duration, freq, vol)
assert duration > 0, "SFX.Noise: Invalid duration"
if typeof(freq) <> TYPE_TABLE freq = [freq]
if typeof(vol) <> TYPE_TABLE vol = [vol]
freqDegree = sizeof(freq) - 1
freqBc = BinomialCoefficients(freqDegree)
volDegree = sizeof(vol) - 1
volBc = BinomialCoefficients(volDegree)
data = []
tick = 0
value = 0
deta = 0
p = 0
dp = 1/(duration*this.sr)
for i = 0 to duration*this.sr - 1
tick = tick - 1
if tick <= 0
tick = this.sr/EvaluateCurve(freq, freqBc, p)
delta = ((rnd()*2 - 1) - value)/tick
endif
value = value + delta
data[i] = value*EvaluateCurve(vol, volBc, p)
p = p + dp
next
if this.ech
return ApplyEcho(data, this.ech, int(this.echDel*this.sr), this.echDO, this.echPan)
else
return [data, data]
endif
endfunc
' Noise
' -----
' Return a noise sound lasting for 'duration' seconds. 'freq' is the frequency and can be a
' number or an array of numbers, treated as a 1D bezier curve. 'vol' is the volume and can be a
' number or an array of numbers, treated as a 1D bezier curve. The 'vol' value(s) should be
' in the range [0..1].
sfx.Noise = function(duration, freq, vol)
data = this.NoiseData(duration, freq, vol)
return createsound(data[0], data[1], this.sr)
endfunc
' SaveNoise
' ---------
' Save a noise sound lasting for 'duration' seconds. 'freq' is the frequency and can be a
' number or an array of numbers, treated as a 1D bezier curve. 'vol' is the volume and can be a
' number or an array of numbers, treated as a 1D bezier curve. The 'vol' value(s) should be
' in the range [0..1].
sfx.SaveNoise = function(filename, duration, freq, vol)
data = this.NoiseData(duration, freq, vol)
return SaveWav(filename, data[0], data[1], this.sr)
endfunc
return sfx
' BinomialCoefficients
' --------------------
function BinomialCoefficients(n)
function bc(n, k)
if n = k return 1
v = 1
i = 1
while i <= k
v = v*int((n + 1 - i)/i)
i = i + 1
wend
return v
endfunc
c = []
for i = 0 to n c[i] = bc(n, i)
return c
endfunc
' EvaluateCurve
' -------------
function EvaluateCurve(points, bcs, param)
n = sizeof(points) - 1
v = 0
for i = 0 to n v = v + bcs[i]*(1 - param)^(n - i)*param^i*points[i]
return v
endfunc
' ApplyEcho
' ---------
function ApplyEcho(data, count, offset, dropOff, pan)
pan = max(min(pan, 1), -1)
ldata = fill(0, count*offset + sizeof(data))
rdata = fill(0, count*offset + sizeof(data))
for i = 0 to sizeof(data) - 1
ldata[i] = data[i]
rdata[i] = data[i]
next
for i = 1 to count
offs = i*offset
vol = dropOff^i
lvol = vol*cos((pan + 1)*0.5*PI*0.5)
rvol = vol*sin((pan + 1)*0.5*PI*0.5)
for j = 0 to sizeof(data) - 1
ldata[offs + j] = ldata[offs + j] + data[j]*lvol
rdata[offs + j] = rdata[offs + j] + data[j]*rvol
next
pan = -pan
next
return [ldata, rdata]
endfunc
' SaveWav
' -------
function SaveWav(filename, ldata, rdata, sampleRate)
function WriteBinChars(f, txt)
for i = 0 to len(txt) - 1 write file f, asc(mid(txt, i)), 8
endfunc
f = createfile(filename, true)
if typeof(f)
if ldata = rdata channels = 1
else channels = 2
for i = 0 to sizeof(ldata) - 1 ldata[i] = max(min(ldata[i], 1), -1)
if channels = 2 for i = 0 to sizeof(rdata) - 1 rdata[i] = max(min(rdata[i], 1), -1)
WriteBinChars(f, "RIFF")
frameCount = sizeof(ldata)
bits = 16
mul = 32767
length = int(frameCount*channels*bits/8)
write file f, length + 44 - 8, 32, false
WriteBinChars(f, "WAVE")
WriteBinChars(f, "fmt ")
write file f, 16, 32, false
write file f, 1, 16, false
write file f, channels, 16, false
write file f, sampleRate, 32, false
write file f, int(sampleRate*bits*channels/8), 32, false
write file f, int(channels*bits/8), 16, false
write file f, bits, 16, false
WriteBinChars(f, "data")
write file f, length, 32, false
if channels = 1
for i = 0 to sizeof(ldata) - 1 write file f, ldata[i]*mul, 16, true
else
for i = 0 to sizeof(ldata) - 1
write file f, ldata[i]*mul, 16, true
write file f, rdata[i]*mul, 16, true
next
endif
free file f
return true
else
return false
endif
endfunc
endfunc
Objective of the game :
Touch "Q" to finish the game
Controls
Movement : Left, Right
Jump : Up
Hints :
"Q" will be displayed if you eat
the forbidden fruits "x" and reach score 20
Code:
'----------------
' INITIALIZATION
'----------------
'#win32
set window "Tiny Adventure",200,100,false,4
set redraw off
player = []
fruit = []
q = []
camera = []
'Initial Value
randomize clock()
player.x=width(primary)/2;player.y=height(primary)-15;player.img="P"
player.dx=2;player.dy=5;player.jump = 0
for i = 0 to 19; fruit[i] = [x:rnd(-80,280),y:rnd(50,80),img:"x"];next
q = [x:rnd(-80,280),y:rnd(20,50),img:"Q"]
camera.x = 0
score = 0
'--------------
' MAIN PROGRAM
'--------------
do
set color 0,0,0 ; cls 'clear screen
Say(40,1,"Tiny Adventure")
'camera's position on top left while the initial player's position in the middle
camera.x = player.x - width(primary)/2
camera.y = player.y - height(primary)/2
'update mountain's position relative to the camera.x
mountain =[-100-camera.x,90,0-camera.x,50,100-camera.x,70,200-camera.x,50,300-camera.x,90]
'player's control
if keydown(KEY_LEFT) then
player.x = player.x - player.dx
elseif keydown(KEY_RIGHT) then
player.x = player.x + player.dx
elseif keydown(KEY_UP) then
player.y = player.y - player.dy; player.jump = 1 'jump
endif
'collision detection between player and fruits
for i = 0 to 19
if (player.x>= fruit[i].x-10-camera.x and player.x <= fruit[i].x+10-camera.x) and
(player.y >= fruit[i].y-10-camera.y and player.y <= fruit[i].y+10-camera.y) then
score = score + 1
fruit[i].y = -10 'out of screen
endif
next
'collision detection between player and "Q"
if (player.x>=q.x-10-camera.x and player.x<=q.x+10-camera.x) and
(player.y>=q.y-10-camera.y and player.y<=q.y+10-camera.y) then
Say(40,24,"Completed")
q.y = -10 'out of screen
redraw
do;wait 1;until keydown(KEY_RETURN)
end
endif
'if the player jumps then goes down slowly
if player.jump and player.y<=(height(primary)-15) then
player.y = player.y + 1
if player.y <=-4 then player.y = 0 'don't fly to outer space :-)
endif
'boundaries
if player.x <5 then 'left boundary
player.x = player.x+5
Say(5,40,"Rrr")
elseif player.x >width(primary)-5 then 'right boundary
player.x = player.x-5
Say(width(primary)-35,40,"Rrr")
endif
'draw blue mountains , green fruits , white player and red "Q"
set color 255,255,255; set caret width(primary)/2,12; center "Score :"+score
set color 0,0,70 ; draw poly mountain,1
set color 0,150,0
foreach i in fruit
set caret fruit[i].x-camera.x,fruit[i].y
wln fruit[i].img
next
if score >= 20 then
set color 150,0,0;set caret q.x-camera.x,q.y; wln q.img
endif
set color 255,255,255; set caret player.x,player.y; wln player.img
redraw
fwait 30
until keydown(KEY_ESCAPE)
'-----------
' FUNCTIONS
'-----------
function Say(x,y,msg)
set color 255,0,0; set caret x,y; wln msg
endfunc
You are welcomed to try the game,
if you make some improvements on the game,
please share on this thread
so we can have fun together
function forward (dlugosc)
a = int (sin (katzolwia * pi / 180) * dlugosc)
b = int (cos (katzolwia * pi / 180) * dlugosc)
x = pozycjax + a
y = pozycjay - b
if rysowanie = 1 then
draw line pozycjax, pozycjay, x, y
endif
pozycjax = x
pozycjay = y
endfunc
function backward (dlugosc)
a = int (sin (katzolwia * pi / 180) * dlugosc)
b = int (cos (katzolwia * pi / 180) * dlugosc)
x = pozycjax - a
y = pozycjay + b
if rysowanie = 1 then
draw line pozycjax, pozycjay, x, y
endif
pozycjax = x
pozycjay = y
endfunc
function turnright (zmiana)
katzolwia = katzolwia + zmiana
sprawdz ()
endfunc
function turnleft (zmiana)
katzolwia = katzolwia - zmiana
sprawdz ()
endfunc
function gox (zmianax)
pozycjax = pozycjax + zmianax
endfunc
function goy (zmianay)
pozycjay = pozycjay + zmianay
endfunc
function reset ()
katzolwia = 0
endfunc
function sprawdz ()
if katzolwia > 360 then
katzolwia = katzolwia - 360
endif
if katzolwia < 0 then
katzolwia = katzolwia + 360
endif
endfunc
A simple example:
Code:
include "turtle.n7"
set window "Turtle Example", 900, 600
set color 0, 0, 0
cls
set color 255, 0, 0
reset ()
goxy (110, 300)
for x = 1 to 100
forward (250)
turnleft (198)
next
set color 0, 0, 255
reset ()
goxy (230, 440)
for k = 1 to 10
gox (2)
goy (2)
for x = 1 to 36
if x % 2 = 0
penup ()
endif
backward (20)
pendown ()
turnright (10)
next
next
reset ()
set color 0, 255, 0
goxy (350, 550)
k = 2
while (k < 496)
forward (500 - k)
turnright (90.5)
k = k + 2
c = c + 1
wend
wait 5000
Koch Curve:
Code:
include "turtle.n7"
set window "Koch", 520, 480
goxy (10, 300)
turnright(90)
function koch(x, t)
if t > 0 then
t = t - 1
x = x / 3
koch(x, t)
turnleft(60)
koch(x, t)
turnright(120)
koch(x, t)
turnleft(60)
koch(x, t)
else
forward(3 * x)
endif
Better make an announcement about this, in case you're wondering why I'm not very active on the forum.
At the moment I don't have a computer. The cat ate the charger cord for my laptop, which was already in a terrible state (some keys missing). But I'll buy a new one, hopefully next week.
Again, it's not the type of program NaaLaa has been designed for, but it's one from my long list of simple programs I test every single language I try with. Some the members here may remember the word count challenge we had on basicprogramming.org. N6 was pretty useless at this task, but N7 is a completely different beast. I was impressed by how easy (thanx to tables, the split function and the free val procedure) was to write this program, considering the fact that NaaLaa doesn't have sorting algorithms built-in.
The task is to read a text file, remove all non-word characters, count all words, count unique words, count how many times each word appears in the text, sort the words by occurrence an save the result to the file. And here is the code:
Code:
open file 1, "Hamlet.txt"
whole_text = ""
x = freadc(1)
while x
if x < 48 or (x > 57 and x < 65) or (x > 90 and x < 97) or x > 122
whole_text = whole_text + chr(32)
elseif x > 64 and x < 91 then
whole_text = whole_text + chr(x + 32)
else
whole_text = whole_text + chr(x)
endif
x = freadc(1)
wend
all_words = split(whole_text, " ")
words_number = 0
unique_words = []
foreach n in all_words
if len(n) > 1 or n = "a" or n ="i"
unique_words[n] = unique_words[n] + 1
words_number = words_number + 1
endif
next
create file 2, "Words.txt"
wln file 2, "All words - " + words_number
wln file 2, "Unique words - " + sizeof(unique_words)
wln file 2, ""
y = 1
while sizeof(unique_words)
foreach a, b in unique_words
if b = y then
wln file 2, a + " - " + b
endif
next
free val unique_words, y
y = y + 1
wend
OK. And now let's move to graphics and games. I won't bore you with this kind of programs, anymore.