The numofbullets is a global variable; only the i and j variables are declared in the timer.
The numofbullets is a global variable; only the i and j variables are declared in the timer.
Then I'm afraid I can't help you out further without seeing more code. Best thing would be access to your whole game so I can try to debug it.
Yep - whatever is going wrong doesn't appear to be connected (at least entirely) with what you've posted so far - I will note however that :
is convoluted and a mess - why free the bullet at all? just fill your array with created bullet objects and just have a new boolean property of TBullet called 'active'. Then you can simply do :Code:freeandnil(bullets[i]); if i=numofbullets-1 then dec(numofbullets) else begin for j:=i+1 to numofbullets-1 do bullets[j-1]:=bullets[j]; dec(numofbullets); end;
Then go through the array and only render 'active' bullets - yes you'll be skipping over 'inactive' bullets but that's still loads faster than constantly creating/destroying objects.Code:{go through the array and create a TBullet object with 'active' set to false for all objects as part of your game initialization} if (plshoot=true) and (plcanshoot=true) then begin I := 0; while Bullet[I].active do I := I + 1; if I > high(Bullet) then exit; Bullet[I].active := true; Bullet[I].Xplace := Player.Left; Bullet[I].Yplace := Player.Top; end; for I := 0 to numofbullets-1 do if bullets[I].active then begin bullet[I].YPlace := bullet[I].YPlace-4; if bullet[I].YPlace < 10 then bullet[I].Active := false; end;
An optimization of this would to be to treat the array like a ring-buffer - then by its very nature the start index is the oldest active bullet and the end index is the newest bullet - only iterate over these - still you'll itterate over some inactive bullets but it'll be much faster than constantly keeping the array tightly packed - you could also use a linked list but really unless you've got thousands of bullets there's no need to care performance wise.
There are various reasons why you'd want to keep an array tightly packed - perhaps it needs to be kept sorted (but there are better structures such as linked lists) or perhaps you have a need to copy a continuous block of memory for some reason (uploading vertex data to a GPU) but you don't need either of these.
Also bare in mind that there's no reason you can't have two container structures - a flat array and a linked list - scan the flat array for an inactive bullet - set it to active and add a reference to a linked list. If the bullet is to be 'destroyed' set it to inactive and remove it from the linked list - this way you have a flat array for 'storage' and the linked list for optimal iteration over active elements (linked lists are slow to index but are very fast for deletions/insertions - especially in your case where you delete from anywhere in the list but only add to the end)
Even better have two linked lists - an active one and an inactive one - then you no longer have to scan for an active bullet or create one - you just remove one from the inactive list and add it to the active list and visa versa - a slow object creating, array shuffling operation becomes a case of setting a few pointers.
--
But : these are only suggestions to think about - it's overkill at this stage - as SilverWarrior suggests we'd need to see basically all of your code to tell you what's wrong.
Last edited by phibermon; 20-12-2015 at 06:01 PM.
"It's over 800 lines of code and not in english so it's difficult to read."
I have written the program in Hungarian. (Maybe it's not an easy language, and you not saw it yet in full dress: with diacritics )
The function "TFoablak.pontirany" is help to direct only the movement of the boss enemy and its bullets, which initial direction are towards the player.
The bullets of the other enemies are only goes downwards (line 533: [I]if foellvan=0 then elllovedektomb[i].yhely:=elllovedektomb.yhely+4... ).
And in line 419 happening the creating of bullets of these enemies in the coordinates of actual enemy (xhely: xplace, yhely: yplace):
[I]elllovedektomb[elllovedekdb]:=TJatekEleme.Letrehoz(ellensegtomb[i].xhely,ellensegtomb.yhely,elllovkepe);
But sometimes this coordinate totally different, and I don't know, why...
I speak Hungarian too , but even I find it difficult to read code that is not in english.
Your english is pretty good, it would help everyone here if you would develop your code in english.
I agree with Robert's suggestion.
Having your code written in English does have a great benefit that you can just simply copy and paste part of your code when you are seeking help from others.
I myself am not native English speaking person and used to write my code in Slovenian (my native language) but eventually I figured out that it is better if I write my code in English instead. Why?
When I have all of my code written in English it allows my brains to kind of switch into "English mode" where even most of my thought process is done in English. I know it sounds a bit weird.
But when I have parts of the code written in Slovenian my brain stays in "Slovenian mode" where I'm forced of constantly having to translate English parts of the code or documentation into Slovenian which I think it slows down the thought process a bit.
And sometime it might even happen that my brain would en up being in "English mode" and I would end up constantly translating my Slovenian code into English. And yes I know that this seems even weirder.
No, not so weird, SilverWarior, after all you are right: if I would like help from an English-speaking programmer community, the best is when I write my codes totally in English in order to better understand.
Therefore today I have made a small program, which is focusing the "bullet appearing" problem:
Maybe somebody can help me...Code:unit Unit1; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls; type { TForm1 } TForm1 = class(TForm) Timer1: TTimer; procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); procedure Timer1Timer(Sender: TObject); private { private declarations } public { public declarations } end; type TGameObject=class(TObject) private public xplace,yplace,celx,cely,movedir: integer; itsimage: TBitmap; canshoot: boolean; shoottimer: byte; constructor create(xplacehere,yplacehere: longint; imagehere: Tbitmap); end; var Form1: TForm1; backgroundimg,bulletimg,spaceshipimg: TBitMap; spaceship: TGameObject; bullet: array [0..100] of TGameObject; numofbullets: integer; implementation {$R *.lfm} constructor TGameObject.create(xplacehere,yplacehere: integer; imagehere: Tbitmap); begin xplace:=xplacehere; yplace:=yplacehere; itsimage:=imagehere; end; { TForm1 } procedure TForm1.FormCreate(Sender: TObject); var initialmovedir: shortint; begin backgroundimg := TBitmap.Create; backgroundimg.LoadFromFile('kepek/urhatter.bmp'); bulletimg:=TBitMap.Create; bulletimg.LoadFromFile('kepek/ell_lov.bmp'); bulletimg.transparent:=true; spaceshipimg:=TBitMap.Create; spaceshipimg.LoadFromFile('kepek/ell1.bmp'); spaceshipimg.transparent:=true; randomize; if round(random(2))=1 then initialmovedir:=-2 else initialmovedir:=2; spaceship:=TGameObject.create(Form1.ClientWidth div 2,spaceshipimg.height,spaceshipimg); spaceship.movedir:=initialmovedir; spaceship.shoottimer:=100; spaceship.canshoot:=false; numofbullets:=0; end; procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin backgroundimg.free; bulletimg.free; spaceshipimg.free; end; procedure TForm1.Timer1Timer(Sender: TObject); var i,j: integer; begin Form1.Canvas.StretchDraw(Rect(0, 0, ClientWidth, ClientHeight), backgroundimg); if spaceship.shoottimer>0 then dec(spaceship.shoottimer) else spaceship.canshoot:=true; if (spaceship.xplace+spaceship.movedir>=ClientWidth-spaceshipimg.width) or (spaceship.xplace+spaceship.movedir<=1) then begin if spaceship.yplace+spaceshipimg.height<ClientHeight then spaceship.yplace:=spaceship.yplace+spaceshipimg.height else spaceship.yplace:=spaceshipimg.height; spaceship.movedir:=-spaceship.movedir; end else begin spaceship.xplace:=spaceship.xplace+spaceship.movedir; end; Form1.Canvas.Draw(spaceship.xplace,spaceship.yplace,spaceshipimg); if (round(random(50))=1) and (spaceship.canshoot=true) then begin bullet[numofbullets]:=TGameObject.create(spaceship.xplace,spaceship.yplace,bulletimg); {!!!WRONG!!!} inc(numofbullets); spaceship.canshoot:=false; spaceship.shoottimer:=100; end; if numofbullets>0 then begin i:=0; while i<numofbullets-1 do begin if bullet[i]<>nil then begin if bullet[i].yplace>ClientHeight then begin freeandnil(bullet[i]); if i=numofbullets-1 then dec(numofbullets) else begin for j:=i+1 to numofbullets-1 do bullet[j-1]:=bullet[j]; dec(numofbullets); dec(i); end; end else begin bullet[i].yplace:=bullet[i].yplace+4; Form1.Canvas.Draw(bullet[i].xplace,bullet[i].yplace,bulletimg); end; end; inc(i); end; end; end; end.
The last loop is still bothering me, it is needlessly complicated and could make errors. Like i suggested earlier, here's how it would look:
Code:for i:=numofbullets-1 downto 0 do begin bullet[i].yplace:=bullet[i].yplace+4; if bullet[i].yplace>ClientHeight then begin bullet[i].Free; dec(numofbullets); bullet[i]:=bullet[numofbullets]; else begin Form1.Canvas.Draw(bullet[i].xplace, bullet[i].yplace, bulletimg); end; end;
Bookmarks