How to make program run faster?

Started by Laskiapina, February 01, 2010, 09:15:02 AM

Previous topic - Next topic

Laskiapina

Okay, now I have everything running beautifully. Only problem is the program runs far too slowly. I can't make the player's coordinates change more dramatically (from x = x + 1 to x = x + 2), because it jumps too much even now.

Is there a simple way to get higher FPS's?

I'll show my code, although I know it's a nightmare to read, because I haven't ever been that good of a code writer. This code should run without its images. Nevermind the bugs, they aren't there when it runs with the images.

PlayBASIC Code: [Select]
centerscreen
dim maax(100)
dim maay(100)
dim omenax(10)
dim omenay(10)
dim omenaSyomatta(10)
dim maamuoto(100)
dim taiteilijax(10)
dim taiteilijay(10)
dim tiputustarkistus(100)

getimage 24,0,0,800,600
cls 50000

getimage 23,0,0,5,5
getimage 2,496,1,566,55
getimage 3,567,1,615,24
getimage 4,567,25,615,47
getimage 5,1,1,55,55
getimage 6,56,1,110,55
getimage 7,111,1,165,55
getimage 8,166,1,220,55
getimage 9,221,1,275,55
getimage 10,276,1,330,55
getimage 11,331,1,385,55
getimage 12,386,1,440,55
getimage 13,441,1,495,55
getimage 14,616,1,659,50
getimage 15,660,1,703,50
getimage 16,660,50,667,52
getimage 17,660,50,667,52
getimage 18,704,0,706,49
getimage 19,704,0,706,46
getimage 20,660,50,667,52
getimage 21,1,56,245,193
getimage 22,246,56,335,115
getimage 25,336,58,413,152
getimage 26,416,58,516,143
getimage 27,517,58,567,109
getimage 28,496,55,528,57

x = 0
y = 0
ankansuunta = 1
ankanjalkojenpaikat = 0
ankanjalat = 0
ankkax = 355: ankkay = 241
etujalkax = 363: etujalkay = 296
takajalkax = 363: takajalkay = 295
hyppy = 0
hypynmaara# = 0
voikoVasemmalleKavella = 1
voikoOikealleKavella = 1
kentta = 3

for a = 2 to 28
preparefximage a
sprite a,-100,0,a
next a

rendertoscreen

KentanValinta:
if kentta = 3 then goto Stage3maakoordinaatit

Stage3maakoordinaatit:
cls 0
x# = -40
y# = 0
maapalikoita = 19
maasetti = 1
maax(1) = 343: maay(1) = 318: maamuoto(1) = 4
maax(2) = 397: maay(2) = 318: maamuoto(2) = 1
maax(3) = 451: maay(3) = 318: maamuoto(3) = 2
maax(4) = 505: maay(4) = 318: maamuoto(4) = 5
maax(5) = 559: maay(5) = 318: maamuoto(5) = 1
maax(6) = 613: maay(6) = 318: maamuoto(6) = 1
maax(7) = 667: maay(7) = 318: maamuoto(7) = 1
maax(8) = 721: maay(8) = 318: maamuoto(8) = 1
maax(9) = 613: maay(9) = 264: maamuoto(9) = 5
maax(10) = 667: maay(10) = 264: maamuoto(10) = 1
maax(11) = 721: maay(11) = 264: maamuoto(11) = 1
maax(12) = 667: maay(12) = 210: maamuoto(12) = 5
maax(13) = 721: maay(13) = 210: maamuoto(13) = 2
maax(14) = 397: maay(14) = 372: maamuoto(14) = 4
maax(15) = 451: maay(15) = 372: maamuoto(15) = 1
maax(16) = 505: maay(16) = 372: maamuoto(16) = 3
maax(17) = 613: maay(17) = 372: maamuoto(17) = 4
maax(18) = 667: maay(18) = 372: maamuoto(18) = 1
maax(19) = 721: maay(19) = 372: maamuoto(19) = 3
taiteilijax(1) = 355: taiteilijay(1) = 269
taiteilijamaara = 1
kukkax = 995: kukkay = 170
goto Stage

Stage:
rem Background picture
cls 0

nosto = 0
valmishyppyyn = 0
voikoVasemmalleKavella = 1
voikoOikealleKavella = 1

rem piirretään maata ja tarkastetaan onko ankan jalkojen alla maata. Jos ei ole, niin tiputetaan ankkaa pikselin verran
for mikamaa = 1 to maapalikoita
maanx = x#+maax(mikamaa): maany = y#+maay(mikamaa)

rem Check if Kumiankka's head is hit by ceiling
Createsprite 28: Positionsprite 28,374,237: spriteimage 28,28: SpriteCollisionMode 28,6
if spritehit(28,5,1) = 5 then hyppy = 0: y# = y# - 3

Createsprite 17: Positionsprite 17,387,315: spriteimage 17,17: SpriteCollisionMode 17,6
if spritehit(17,5,1) = 5 then nosto = 1
Createsprite 17: Positionsprite 17,387,313: spriteimage 17,17: SpriteCollisionMode 17,6
if spritehit(17,5,1) = 5 then nosto = 1
Createsprite 16: Positionsprite 16,387,318: spriteimage 16,16: SpriteCollisionMode 16,6
NakyykoMaa = 0
if maanx > -53 and maany > -53 and maanx < 855 and maany < 655 then NakyykoMaa = 1
if maamuoto(mikamaa) = 1 and NakyykoMaa = 1 then sprite 5,maanx,maany,5
if maamuoto(mikamaa) = 2 and NakyykoMaa = 1 then sprite 5,maanx,maany,6
if maamuoto(mikamaa) = 3 and NakyykoMaa = 1 then sprite 5,maanx,maany,7
if maamuoto(mikamaa) = 4 and NakyykoMaa = 1 then sprite 5,maanx,maany,8
if maamuoto(mikamaa) = 5 and NakyykoMaa = 1 then sprite 5,maanx,maany,9
if maamuoto(mikamaa) = 6 and NakyykoMaa = 1 then sprite 5,maanx,maany,10
if maamuoto(mikamaa) = 7 and NakyykoMaa = 1 then sprite 5,maanx,maany,11
if maamuoto(mikamaa) = 8 and NakyykoMaa = 1 then sprite 5,maanx,maany,12
if maamuoto(mikamaa) = 9 and NakyykoMaa = 1 then sprite 5,maanx,maany,13
tiputustarkistus(mikamaa) = spritehit(16,5,1)

rem Check if there is land under the Kumiankka and can it jump
Createsprite 16: Positionsprite 16,390,318: spriteimage 16,16: SpriteCollisionMode 16,6
if spritehit(16,5,1) = 5 then valmishyppyyn = 1
Createsprite 16: Positionsprite 16,384,318: spriteimage 16,16: SpriteCollisionMode 16,6
if spritehit(16,5,1) = 5 then valmishyppyyn = 1

rem Check if the Kumiankka is facing a wall
Createsprite 18: Positionsprite 18,359,240: spriteimage 18,18: SpriteCollisionMode 18,6
if spritehit(18,5,1) = 5 then voikoVasemmalleKavella = 0
Createsprite 19: Positionsprite 19,418,240: spriteimage 19,19: SpriteCollisionMode 19,6
if spritehit(19,5,1) = 5 then voikoOikealleKavella = 0
rem Check if the Kumiankka is inside the wall. If it is, push it further away
Createsprite 18: Positionsprite 18,363,240: spriteimage 18,18: SpriteCollisionMode 18,6
rem if spritehit(18,5,1) = 5 then x# = x# - 0.5
Createsprite 19: Positionsprite 19,414,240: spriteimage 19,19: SpriteCollisionMode 19,6
rem if spritehit(19,5,1) = 5 then x# = x# + 0.5
next mikamaa

rem Check if the Kumiankka is rising up the hill or falling
Login required to view complete source code
Finished projects so far: Kumiankka, Meals of the Dragon, Fisut, Draw Old, Reikäkopio, Blindage, Escape from Millmier

Homepage: Not yet named project

kevin


kevin

#2
 Using LOCKBUFFER & UNLOCKBUFFER basically doubles the frame rate here to around the 300fps.  

See -> Locking / Unlocking Buffers - Where and When


Like so,

PlayBASIC Code: [Select]
centerscreen
dim maax(100)
dim maay(100)
dim omenax(10)
dim omenay(10)
dim omenaSyomatta(10)
dim maamuoto(100)
dim taiteilijax(10)
dim taiteilijay(10)
dim tiputustarkistus(100)

getimage 24,0,0,800,600
cls 50000

getimage 23,0,0,5,5
getimage 2,496,1,566,55
getimage 3,567,1,615,24
getimage 4,567,25,615,47
getimage 5,1,1,55,55
getimage 6,56,1,110,55
getimage 7,111,1,165,55
getimage 8,166,1,220,55
getimage 9,221,1,275,55
getimage 10,276,1,330,55
getimage 11,331,1,385,55
getimage 12,386,1,440,55
getimage 13,441,1,495,55
getimage 14,616,1,659,50
getimage 15,660,1,703,50
getimage 16,660,50,667,52
getimage 17,660,50,667,52
getimage 18,704,0,706,49
getimage 19,704,0,706,46
getimage 20,660,50,667,52
getimage 21,1,56,245,193
getimage 22,246,56,335,115
getimage 25,336,58,413,152
getimage 26,416,58,516,143
getimage 27,517,58,567,109
getimage 28,496,55,528,57

x = 0
y = 0
ankansuunta = 1
ankanjalkojenpaikat = 0
ankanjalat = 0
ankkax = 355: ankkay = 241
etujalkax = 363: etujalkay = 296
takajalkax = 363: takajalkay = 295
hyppy = 0
hypynmaara# = 0
voikoVasemmalleKavella = 1
voikoOikealleKavella = 1
kentta = 3

for a = 2 to 28
preparefximage a
sprite a,-100,0,a
next a

rendertoscreen

KentanValinta:
if kentta = 3 then goto Stage3maakoordinaatit

Stage3maakoordinaatit:
cls 0
x# = -40
y# = 0
maapalikoita = 19
maasetti = 1
maax(1) = 343: maay(1) = 318: maamuoto(1) = 4
maax(2) = 397: maay(2) = 318: maamuoto(2) = 1
maax(3) = 451: maay(3) = 318: maamuoto(3) = 2
maax(4) = 505: maay(4) = 318: maamuoto(4) = 5
maax(5) = 559: maay(5) = 318: maamuoto(5) = 1
maax(6) = 613: maay(6) = 318: maamuoto(6) = 1
maax(7) = 667: maay(7) = 318: maamuoto(7) = 1
maax(8) = 721: maay(8) = 318: maamuoto(8) = 1
maax(9) = 613: maay(9) = 264: maamuoto(9) = 5
maax(10) = 667: maay(10) = 264: maamuoto(10) = 1
maax(11) = 721: maay(11) = 264: maamuoto(11) = 1
maax(12) = 667: maay(12) = 210: maamuoto(12) = 5
maax(13) = 721: maay(13) = 210: maamuoto(13) = 2
maax(14) = 397: maay(14) = 372: maamuoto(14) = 4
maax(15) = 451: maay(15) = 372: maamuoto(15) = 1
maax(16) = 505: maay(16) = 372: maamuoto(16) = 3
maax(17) = 613: maay(17) = 372: maamuoto(17) = 4
maax(18) = 667: maay(18) = 372: maamuoto(18) = 1
maax(19) = 721: maay(19) = 372: maamuoto(19) = 3
taiteilijax(1) = 355: taiteilijay(1) = 269
taiteilijamaara = 1
kukkax = 995: kukkay = 170
goto Stage

Stage:
rem Background picture
cls 0

nosto = 0
valmishyppyyn = 0
voikoVasemmalleKavella = 1
voikoOikealleKavella = 1

lockbuffer

rem piirretään maata ja tarkastetaan onko ankan jalkojen alla maata. Jos ei ole, niin tiputetaan ankkaa pikselin verran
for mikamaa = 1 to maapalikoita
maanx = x#+maax(mikamaa): maany = y#+maay(mikamaa)

rem Check if Kumiankka's head is hit by ceiling
Createsprite 28: Positionsprite 28,374,237: spriteimage 28,28: SpriteCollisionMode 28,6
if spritehit(28,5,1) = 5 then hyppy = 0: y# = y# - 3

Createsprite 17: Positionsprite 17,387,315: spriteimage 17,17: SpriteCollisionMode 17,6
if spritehit(17,5,1) = 5 then nosto = 1
Createsprite 17: Positionsprite 17,387,313: spriteimage 17,17: SpriteCollisionMode 17,6
if spritehit(17,5,1) = 5 then nosto = 1
Createsprite 16: Positionsprite 16,387,318: spriteimage 16,16: SpriteCollisionMode 16,6
NakyykoMaa = 0
if maanx > -53 and maany > -53 and maanx < 855 and maany < 655 then NakyykoMaa = 1

if maamuoto(mikamaa) = 1 and NakyykoMaa = 1 then sprite 5,maanx,maany,5
if maamuoto(mikamaa) = 2 and NakyykoMaa = 1 then sprite 5,maanx,maany,6
if maamuoto(mikamaa) = 3 and NakyykoMaa = 1 then sprite 5,maanx,maany,7
if maamuoto(mikamaa) = 4 and NakyykoMaa = 1 then sprite 5,maanx,maany,8
if maamuoto(mikamaa) = 5 and NakyykoMaa = 1 then sprite 5,maanx,maany,9
if maamuoto(mikamaa) = 6 and NakyykoMaa = 1 then sprite 5,maanx,maany,10
if maamuoto(mikamaa) = 7 and NakyykoMaa = 1 then sprite 5,maanx,maany,11
if maamuoto(mikamaa) = 8 and NakyykoMaa = 1 then sprite 5,maanx,maany,12
if maamuoto(mikamaa) = 9 and NakyykoMaa = 1 then sprite 5,maanx,maany,13
tiputustarkistus(mikamaa) = spritehit(16,5,1)

rem Check if there is land under the Kumiankka and can it jump
Createsprite 16: Positionsprite 16,390,318: spriteimage 16,16: SpriteCollisionMode 16,6
if spritehit(16,5,1) = 5 then valmishyppyyn = 1
Createsprite 16: Positionsprite 16,384,318: spriteimage 16,16: SpriteCollisionMode 16,6
if spritehit(16,5,1) = 5 then valmishyppyyn = 1

rem Check if the Kumiankka is facing a wall
Createsprite 18: Positionsprite 18,359,240: spriteimage 18,18: SpriteCollisionMode 18,6
if spritehit(18,5,1) = 5 then voikoVasemmalleKavella = 0
Createsprite 19: Positionsprite 19,418,240: spriteimage 19,19: SpriteCollisionMode 19,6
if spritehit(19,5,1) = 5 then voikoOikealleKavella = 0
rem Check if the Kumiankka is inside the wall. If it is, push it further away
Createsprite 18: Positionsprite 18,363,240: spriteimage 18,18: SpriteCollisionMode 18,6
rem if spritehit(18,5,1) = 5 then x# = x# - 0.5
Login required to view complete source code



 You really should be drawn the all the sprites batched, via either DrawALLSprites, or DRawOrderedSprite.  

 There's lots of redundancy in the code also.  

 eg,

PlayBASIC Code: [Select]
Createsprite 17: Positionsprite 17,387,315: spriteimage 17,17: SpriteCollisionMode 17,6
if spritehit(17,5,1) = 5 then nosto = 1
Createsprite 17: Positionsprite 17,387,313: spriteimage 17,17: SpriteCollisionMode 17,6
if spritehit(17,5,1) = 5 then nosto = 1




Really should something like this,

PlayBASIC Code: [Select]
// These really don't need to be inside the loop, once it's created, it's going to exist until it's deleted.  So you certainly shouldn't be creating the sprite constantly  
Createsprite 17
spriteimage 17,17: SpriteCollisionMode 17,6
;
Positionsprite 17,387,315
if spritesoverlap(17,5) then nosto = 1
Positionsprite 17,387,313
if spritesoverlap(17,5) then nosto = 1





If all you want to do is detect if 2 sprites overlap, then use SpritesOverlap,  SpriteHit is for batch detection.

 
Code like the following,

PlayBASIC Code: [Select]
if maamuoto(mikamaa) = 1 and NakyykoMaa = 1 then sprite 5,maanx,maany,5
if maamuoto(mikamaa) = 2 and NakyykoMaa = 1 then sprite 5,maanx,maany,6
if maamuoto(mikamaa) = 3 and NakyykoMaa = 1 then sprite 5,maanx,maany,7
if maamuoto(mikamaa) = 4 and NakyykoMaa = 1 then sprite 5,maanx,maany,8
if maamuoto(mikamaa) = 5 and NakyykoMaa = 1 then sprite 5,maanx,maany,9
if maamuoto(mikamaa) = 6 and NakyykoMaa = 1 then sprite 5,maanx,maany,10
if maamuoto(mikamaa) = 7 and NakyykoMaa = 1 then sprite 5,maanx,maany,11
if maamuoto(mikamaa) = 8 and NakyykoMaa = 1 then sprite 5,maanx,maany,12
if maamuoto(mikamaa) = 9 and NakyykoMaa = 1 then sprite 5,maanx,maany,13





can be simplified as bellow..    

PlayBASIC Code: [Select]
if NakyykoMaa = 1
if maamuoto(mikamaa)>=1 and maamuoto(mikamaa)<=9
sprite 5,maanx,maany,5+(maamuoto(mikamaa)-1)
endif
endif



So we've reduced 10 IF/THEN's decisions into 2.    This stuff really add's up the b igger your game gets


IN this section you use MirrorImage,  
PlayBASIC Code: [Select]
    if leftkey() = 1 and rightkey() = 0 and ankansuunta = 2 then mirrorimage 2,1,0: ankansuunta = 1: mirrorimage 3,1,0: mirrorimage 4,1,0





 MirrorImage  flips the actual image pixel data.    Another way of doing the same thing is by scaling the sprite (when in rotation mode) by -1, this has the same effect and doesn't alter the original image..  So if more than one sprite is using the same image, they won't all get mirrored.




Laskiapina

#3
That helped a lot.  :) I removed those CREATESPRITEs earlier, but those other remarks were very helpful.
Now I came across a very strange bug. The program doesn't allow the player to jump from one groundblock (maamuoto(31). If I take that block off of the coordinates, the groundblock next to it starts bugging. I've no idea why this is.

Here's the code:
PlayBASIC Code: [Select]
setfps 100
dim maax(100)
dim maay(100)
dim omenax(10)
dim omenay(10)
dim omenaSyomatta(10)
dim maamuoto(100)
dim taiteilijax(10)
dim taiteilijay(10)
dim tiputustarkistus(100)

boxc 0,0,800,600,1,50000

getimage 23,496,1,566,55
getimage 24,496,1,566,55
rem Kumiankka
getimage 2,496,1,566,55
rem jalat
getimage 3,567,1,615,24
getimage 4,567,25,615,47
rem laatikot
getimage 5,1,1,55,55
getimage 6,56,1,110,55
getimage 7,111,1,165,55
getimage 8,166,1,220,55
getimage 9,221,1,275,55
getimage 10,276,1,330,55
getimage 11,331,1,385,55
getimage 12,386,1,440,55
getimage 13,441,1,495,55
rem an artist
getimage 14,616,1,659,50
getimage 15,660,1,703,50
rem collision detection lines
getimage 16,660,50,667,52
getimage 17,660,50,667,52
getimage 18,704,0,706,49
getimage 19,704,0,706,46
getimage 20,660,50,667,52
rem speech bubble and arrow keys
getimage 21,1,56,245,193
getimage 22,246,56,335,115
rem exit-flowers
getimage 25,336,58,413,152
getimage 26,416,58,516,143
rem collectable thing
getimage 27,517,58,567,109
rem collision detection lines for head
getimage 28,496,55,528,57
rem jumping and falling feet
getimage 29,571,58,613,103
getimage 30,571,104,615,140

rem Annetaan muuttujat
versio# = 0.001
rem Maan koordinaatit ovat nyt nollassa
x = 0
y = 0
rem Ankka osoittaa nyt vasempaan ja ankan jalkojen paikat on nyt seisonta-asennossa
ankansuunta = 1
ankanjalkojenpaikat = 0
ankanjalat = 0
ankkax = 355: ankkay = 241
etujalkax = 363: etujalkay = 296
takajalkax = 363: takajalkay = 295
hyppy = 0
hypynmaara# = 0
voikoVasemmalleKavella = 1
voikoOikealleKavella = 1
kentta = 1
ink rgb(255,255,255)
ikkunanLeveys = 800: ikkunanKorkeus = 600
openscreen ikkunanLeveys,ikkunanKorkeus,24,1: titlescreen "Kumiankka kehitysvaiheessa"

for a = 2 to 30
preparefximage a
createsprite a
SpriteCollisionMode a,6
sprite a,-100,0,a
next a

rendertoscreen
kentta = 2

KentanValinta:
if kentta = 2 then goto Stage2maakoordinaatit
if kentta = 3 then end
if kentta = 4 then end

Stage2maakoordinaatit:
cls 0
x# = -130: y# = 1000
missaYKoordinaatissaKuolee = -1300
maapalikoita = 66
maasetti = 1
maax(1) = 323: maay(1) = 318: maamuoto(1) = 4
maax(2) = 377: maay(2) = 318: maamuoto(2) = 1
maax(3) = 431: maay(3) = 318: maamuoto(3) = 1
maax(4) = 485: maay(4) = 318: maamuoto(4) = 3
maax(5) = 377: maay(5) = 372: maamuoto(5) = 7
maax(6) = 600: maay(6) = 230: maamuoto(6) = 4
maax(7) = 654: maay(7) = 230: maamuoto(7) = 1
maax(8) = 708: maay(8) = 230: maamuoto(8) = 1
maax(9) = 762: maay(9) = 230: maamuoto(9) = 3
maax(10) = 870: maay(10) = 95: maamuoto(10) = 5
maax(11) = 924: maay(11) = 95: maamuoto(11) = 2
maax(12) = 592: maay(12) = 0: maamuoto(12) = 1
maax(13) = 646: maay(13) = 0: maamuoto(13) = 1
maax(14) = 700: maay(14) = 0: maamuoto(14) = 2
maax(15) = 410: maay(15) = -90: maamuoto(15) = 1
maax(16) = 560: maay(16) = -224: maamuoto(16) = 5
maax(17) = 614: maay(17) = -224: maamuoto(17) = 1
maax(18) = 668: maay(18) = -224: maamuoto(18) = 1
maax(19) = 722: maay(19) = -224: maamuoto(19) = 1
maax(20) = 776: maay(20) = -224: maamuoto(20) = 1
maax(21) = 614: maay(21) = -278: maamuoto(21) = 5
maax(22) = 668: maay(22) = -278: maamuoto(22) = 1
maax(23) = 722: maay(23) = -278: maamuoto(23) = 2
maax(24) = 450: maay(24) = -410: maamuoto(24) = 1
maax(25) = 504: maay(25) = -410: maamuoto(25) = 2
maax(26) = 600: maay(26) = -505: maamuoto(26) = 4
maax(27) = 654: maay(27) = -505: maamuoto(27) = 1
maax(28) = 708: maay(28) = -505: maamuoto(28) = 1
maax(29) = 762: maay(29) = -505: maamuoto(29) = 3



maax(30) = 410: maay(30) = -600: maamuoto(30) = 4
maax(31) = 464: maay(31) = -600: maamuoto(31) = 3



maax(32) = 600: maay(32) = 410: maamuoto(32) = 4
maax(33) = 654: maay(33) = 410: maamuoto(33) = 1
maax(34) = 708: maay(34) = 410: maamuoto(34) = 1
maax(35) = 762: maay(35) = 410: maamuoto(35) = 2
maax(36) = 762: maay(36) = 464: maamuoto(36) = 4
maax(37) = 950: maay(37) = 550: maamuoto(37) = 5
maax(38) = 1004: maay(38) = 550: maamuoto(38) = 1
maax(39) = 1058: maay(39) = 550: maamuoto(39) = 3
maax(40) = 1220: maay(40) = 700: maamuoto(40) = 1
maax(41) = 1274: maay(41) = 700: maamuoto(41) = 1
maax(42) = 1400: maay(42) = 900: maamuoto(42) = 4
maax(43) = 1454: maay(43) = 900: maamuoto(43) = 3
maax(44) = 1088: maay(44) = 1100: maamuoto(44) = 5
maax(45) = 1142: maay(45) = 1100: maamuoto(45) = 1
maax(46) = 1196: maay(46) = 1100: maamuoto(46) = 1
maax(47) = 1250: maay(47) = 1100: maamuoto(47) = 1
maax(48) = 772: maay(48) = 1100: maamuoto(48) = 1
maax(49) = 826: maay(49) = 1100: maamuoto(49) = 1
Login required to view complete source code
Finished projects so far: Kumiankka, Meals of the Dragon, Fisut, Draw Old, Reikäkopio, Blindage, Escape from Millmier

Homepage: Not yet named project