Posted: 22nd Jun 2021 18:39
Hello all together,
i have coded a little piano game with falling tiles. The user has to press a piano key at the right time. I know it is very easy to code but i have found out everything by my self.
I am not a professionall, that?s why i want to ask what i can make better in my code. I would be happy if someone helps.

The main code is the following:

I load a different function for each song:

In this function i set the tempo and position the sprites:

+ Code Snippet
for y = 0 to 9
		for x = 0 to 12 
			setspriteposition(rectw[x,y],40+(x*140),posyw[x,y])
		next x
	next y


Then i create the arrays which have different values. Every number is for a key, for example a "c" has the value one, a "d" has the value two, it looks like:

+ Code Snippet
if flag1=1 // i am using a flag here because a bit further in the code i set the sprite position to the origin value, and the sprites belongs to the array one has to stop movement.
             
		dim array1[10] = [1,1,0,0,0,2,2,0,0,0]	// i have shorten the array for this overview, iam using 100 numbers for each array and i have 5 arrays, that?s ca. 1 min.
	endif

if flag2=1 
		dim array2[10] = [1,1,0,0,0,2,2,0,0,0]	

	endif


With this method i can work fine, but i spend many sprites, because it could be, that the song only hase one "C" for example, but i load a lot of sprites


After that comes the importatnt thing:

+ Code Snippet
for y = 0 to 9
		if time# >= (factor#)*(y+1) and time# <= (factor#*9)+(factor#)*(y+1) and array1[y] = 1 and posyw[1,y] < 656
			setspritedepth(rectw[1,y],4)
			inc posyw[1,y],1
		endif
		
		if posyw[1,y] >= 655
			posyw[1,y] = -150
			array1[y] = 0 // i set the array to 0 that the sprites belongs to array 1 do stop
			flag1=2
	 	endif
	 
next y
	 
for x = 0 to 9
	 	if time# >= (factor#*10)+(factor#)*(x+1) and time# <= (factor#*19)+(factor#)*(x+1) and array2[x] = 1 and posyw[1,x] < 656
			setspritedepth(rectw[1,x],3)
			inc posyw[1,x],1
		endif
				
		if posyw[1,x] >= 655 and time#>= (factor#*10)+(factor#)*(x+1)
			posyw[1,x] = -150
			array2[x] = 0
			flag2=2
	 	endif
next x

In the end, if the tile is in collision with a line, and the user presses the key, i play the sound.

Is this a good method to handle this?

/code tags added by mod
Posted: 23rd Jun 2021 4:01
i'm struggling to follow what you're doing but it seems you're concerned with the # of sprites that you're creating.

i have coded a little piano game with falling tiles.

short version for this: only create sprites that are (about to become) visible and remove them when they're not.

i've never written a rhythm game but here's my take on functionality & handling the sprites/falling tiles:
+ Code Snippet
// Project: Rhythm 
// Created: 2021-06-22
// By: Virtual Nomad
// show all errors
SetErrorMode(2)

// set window properties
SetWindowTitle( "Rhythm" )
SetWindowSize( 800,600, 0 )
SetWindowAllowResize( 1 )

// set display properties
SetVirtualResolution( 800,600)
SetOrientationAllowed( 1, 1, 1, 1 )
SetSyncRate( 30, 0 ) 
SetScissor( 0,0,0,0 )
UseNewDefaultFonts( 1 ) 
SetPrintSize(30)

Cyan = MakeColor(0,255,255)

For x = 1 to 8
	ThisTxt = CreateText(STR(x))
	SetTextPosition(ThisTxt, x*30+15, 320)
	SetTextSize(ThisTxt,30)
	SetTextAlignment(ThisTxt,1)
Next x

GLOBAL Song$ as String [] 
GLOBAL Notes as Integer [] 

MakeSong(20) 

CurrentRow = 0
SetRow(CurrentRow)
NextTime# = Timer() + 1.0

do
	If GetRawKeyState(27) then Exit
	
	ThisTime# = Timer()
	
	If NextTime# <= ThisTime#
		INC CurrentRow
		If CurrentRow > Song$.Length then CurrentRow = 0
		SetRow(CurrentRow)
		NextTime# = ThisTime# + 1.0
	EndIf
	
	If Notes.Length > -1 then PlaySong()
	
    DrawLine(30,300,270,300,Cyan,Cyan)

    Print(GetManagedSpriteCount())
    Sync()
loop

Function PlaySong()
	For x = Notes.Length to 0 Step -1
		ThisNote = Notes[x]
		ThisY = GetspriteY(ThisNote)
		SetSpriteY(ThisNote, ThisY + 1)

		If ThisY >= 270 and ThisY < 300
			ThisNum = GetSpriteX(ThisNote)/30
			If GetRawKeyPressed(48+ThisNum)
				SetSpriteColor(ThisNote,0,255,0,255)
			EndIf
		Endif

		If ThisY >= 300 and GetSpriteColorBlue(ThisNote) = 255 then SetSpriteColor(ThisNote,255,0,0,255)

		If ThisY > 330
			DeleteSprite(ThisNote)
			Notes.Remove(x)
		Endif
	Next x
EndFunction

Function SetRow(Row)
	ThisRow$ = Song$[Row]
	For x = 1 to 8
		If MID(ThisRow$,x,1) <> "0"
			ThisSprite = CreateSprite(0)
			SetSpriteColor(ThisSprite,0,0,255,255)
			SetSpriteSize(Thissprite,30,30)
			SetSpritePosition(ThisSprite,x*30,-30)
			Notes.Insert(ThisSprite)
		Endif
	Next x
EndFunction

Function MakeSong(Length)
	For x = 1 to Length
		This = Random(1,8)
		Row$ = ""
		For y = 1 to 8
			If y = This then Row$ = Row$ + STR(This) else Row$ = Row$ + "0"
		Next y
		Song$.Insert(Row$)
	Next x
EndFunction


i'm "creating" a "song" which consists of 20 rows of strings 8 characters long. Ie, MakeSong(20).
for this, only 1 note is played at a time but later code accounts for multiple notes being played at once.

then initializing the current row of notes to 0, the corresponding Note/Sprite is generated and placed just above the visible area in its corresponding column (1-8) and added to an array (Notes) for later handling.

the sprite begins falling and then the new row/note/sprite is generated and placed once per second. IE, SetRow(CurrentRow), over and over (the "song" will loop).

as the notes fall (via the PlaySong() function which references the Notes array), i check the y position and corresponding keypress (1-8) as it passes over the line.

if "success", i turn the sprite green. if it passes without being "pressed", turn it red.

when it passes a final threshold, it's deleted and removed from Notes.

note the # in the top left (GetManagedSpriteCount()):


you could have thousands of rows/notes but only those that are visible matter if "handled" similarly.

hope that helps?

fixed 1 flaw. note, to remove "more than 1 note" from the array, you'll need to handle the Notes array better than i have here.

@ NextTime# = ThisTime# + 0.8 and my fingers knot up
Posted: 24th Jun 2021 17:21
Thanks for your answer, this is what the game has to do. Instead of the numbers i a have piano keys of course. My code works, but it?s completely different to your code, so i will work with it at the weekend.

To your answer (i'm struggling to follow what you're doing but it seems you're concerned with the # of sprites that you're creating):

At first i started to make everything manually:

factor is the value of bpm for a sixteenth

if time >= factor*1 and sprite 1 <= 656
inc sprite 1,1
endif
if time >= factor*2 and sprite 2 <= 656
inc sprite 2,1
endif

if getspritecollision sprite 1 with line and key 1 = pressed
playsound 1
endif

if getspritecollision sprite 2 with line and key 1 = pressed
playsound 1
endif


After that, i decided to use arrays and for loops to handel that:

dim rectw[13,10]
dim posyw[13,10]

for y = 0 to 9
for x = 0 to 12
rectw[x,y] = createsprite(201)
next x
next y

for y = 0 to 9
for x = 0 to 12
setspriteposition(rectw[x,y],40+(x*140),posyw[x,y]) // x for the 13 keys and the nine for the following sprites
next x
next y


This for 13 keys i need.

for y = 0 to 9
if time# >= (factor#)*(y+1) and time# <= (factor#*9)+(factor#)*(y+1) and array1[y] = 1 and posyw[1,y] < 656 // it?s the same idea but with loop to set the time factor, i have added the <= that the following rows don?t get true at the same time
setspritedepth(rectw[1,y],4)
inc posyw[1,y],1
endif

if posyw[1,y] >= 655 // to save sprites i set the sprites from the first array back to the start position
posyw[1,y] = -150
array1[y] = 0 // i set the array to 0 that the sprites belongs to array 1 do stop
flag1=2
endif
next y


After the timer has reached the 10, the code goes on with array2

for x = 0 to 9
if time# >= (factor#*10)+(factor#)*(x+1) and time# <= (factor#*19)+(factor#)*(x+1) and array2[x] = 1 and posyw[1,x] < 656
setspritedepth(rectw[1,x],3)
inc posyw[1,x],1
endif

if posyw[1,x] >= 655 and time#>= (factor#*10)+(factor#)*(x+1)
posyw[1,x] = -150
array2[x] = 0
flag2=2
endif
next x


i work with 5 arrays with a dimension each of 100, but for this overview of 10

if flag1 = 1
dim array1[10] = [1,1,0,0,0,2,2,0,0,0] i am setting a flag to each array that the array only runs one time because every value of each array could be different
endif
dim array2[10] = [1,1,0,0,0,2,2,0,0,0]
dim array3[10] = [1,1,0,0,0,2,2,0,0,0]
dim array4[10] = [1,1,0,0,0,2,2,0,0,0]
dim array5[10] = [1,1,0,0,0,2,2,0,0,0]

That?s it. I don?t found my method bad, because i only have to change these 5 array for each song, The framerate is ok, but as i said i spend many sprites

Thanks for your posting.
Posted: 24th Jun 2021 18:02
no problem.

also, i'd sent you a PM. note the Bell Icon at the top-right of the screen which notifies us of unread personal messages.

click that or go here to view.