Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2002-09

GPF

6 messages · 4 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Unknown author

Hi,
I am currently working on a loderunner clone using FPC and SDL. The game uses high-resolution graphics and a lot of code. Right now it is over 1000 lines of code (and I haven't even added sound support yet) - while this may seem a bit much for a lode runner clone I have added many features to the orriginal idea: Levels are plain text files with characters representing what should be on screen etc.

The overall game was written in a largely object oriented fashion (e.g. only when it made sense to do so) and it is incredibly optimized. For example where-ever possible I used global rather than private variables as this means less memory.

Quite wonderfully the program shows up at only 1.7% ram usage on my system Not so lovely is that it uses 100% of CPU - when the player is standing still, which inexplicably drops down to between 20 and 50 percent the moment you start moving.

For starters I am writing it turn based, e.g. the player moves and then the enemies move one by one. Obviously it would be ridiculous to post all the code here, but it is an open-source project so if anybody would like the current code they can e-mail me - I would really appreciate any help.

The core code however is something like this (I left out the grit and these are split over severall units)

Type visuals = object
             what : byte;
             constructor init (location: SDL_Rect,isWhat :Byte);
             procedure draw;
        end;
Type levelobj = object
           block : Array[1..20,1..20] of visuals
           constructor init
           procedure draw;
     end;
type characters = object
           isEnemy : Boolean;
           Status : Byte;
           procedure setStatus (newStatus :Byte);
           constructor init (x,y :byte);
           procedure draw;
    end;
Var player : Characters;
    enemy : Array [1..5] of Characters.

{Both the player and the enemies are handled by the characters object - this makes sense as the exact same physics applies to all of them - the isEnemy boolean comes in for the few minor differences}

Characters.Draw has the task of looking at the character's status and then moving him according to it, e.g. status=0 - character stands still, status=1 character moves left etc.} in doing so it also checks the characters location on the map and applies appropriate physics first. In order to do so some things apply: The characters can only move one full tile at a time - thus player.X and player.Y will be the block on the level he currently ocupies etc. This means that it is easy to determine what the level will do to the player (does he fall, run into a brick etc.) The actuall screen positions are only calculated during drawing.

The main program calls procedure mainloop after initialization which has the task of loading the consecutive levels as they are reached. Mainloop itself calls gameloop which checks for keys and addjusts the players status accordingly. Then it calls updateGame; UpdateGame checks the timers on any holes dug and fills them up after 10 secconds, then it runs the following for each enemy (pseudocode)

If we are higher than the player - find a way down and head towards it. If we are lower than the player find a way up and head towards it. If we are on the same height as the player head towards him.

Once that is done gameloop runs draw for each character in turn (including the player). This part will obviously need to be adjusted later for more realistic play.

The game works perfectly if there is one enemy (e.g. enemy : Array [1..1] of enemies;
{Level.init reads the initial enemy and player positions from the level file but ignores enemies above the limit}

Changing the upperlimit of the enemy array to two the program still runs, but it GPF's directly after executing enemy[2].draw the first time. Raising said upper limit any higher (there are supposed to be 5 enemies) causes and instant and most ungracious GPF (Guess your Program's F*cked) before it even finishes loading the level.

Right now I haven't finished the graphics for the enemies yet so they are loading the same bitmaps as the player (setStatus determines the correct bitmap to show for the different animations) but I cannot Imagine this to be the problem as: 1: A single enemy works
2: The bitmaps are being stored in sepperate variables.

I have compiled the code with maximum optimization and with none at all -this did not affect the result. Does anybody know what could be wrong ?

PS. The code is written for maximum portabillity and at this stage contains no threads whatsoever.

I appreciate any help very much, and If anybody wants to look at the code just say the word, I'll stick it on a public CVS server as soon as I have something that runs at least, and do the whole website etc. thing there-after.

Obviously I will credit any contributers in the AUTHORS file.

Ciao
A.J.

------------------------------------------------------ Sent with Penguin WebMail (http://linux-directory.com)

Reply by email

Jonas Maebe
to Unknown author
Show quoted text 8 lines
Changing the upperlimit of the enemy array to two the program still runs, but it GPF's directly after executing enemy[2].draw the first time. Raising said upper limit any higher (there are supposed to be 5 enemies) causes and instant and most ungracious GPF (Guess your Program's F*cked) before it even finishes loading the level.

Have you tried compiling it with -ghl already?

Jonas

Reply by email

Sebastian Günther
to Unknown author: I am currently working on a loderunner clone using FPC and SDL. The game uses…
I appreciate any help very much, and If anybody wants to look at the code just say the word, I'll stick it on a public CVS server as soon as I have something that runs at least, and do the whole website etc. thing there-after.

you might consider using fpAsync (or libAsync at least) for handling keyboard input and timers. This way you could for example process enemies e.g. 10 times per seconds, without having to wait for keyboard input forever or running silly idle loops which will lead to 100% CPU usage...
(I think timers are ideal for this kind of games. For more complex games, especially 3D games, you'll normally try to render as much pictures per second as possible; for this you would render everything within an idle handler - which are yet to be implemented in *Async, but this will be done soon)

- Sebastian

Reply by email

A.J. Venter
to Jonas Maebe: Have you tried compiling it with -ghl already? Jonas
Jonas Maebe wrote
Have you tried compiling it with -ghl already? Jonas

I have now :-)
(That option is not in the manpage nor have I ever found it in the docs - I
wish I knew about it before)

Here is the output:
General protection fault.
No heap dump by heaptrc unit
Exitcode = 216
Runtime error 216 at 0x0804B8B4
0x0804B8B4 CHARACTERS__SETIMAGE, line 212 of levelobj.pas 0x0804B913 CHARACTERS__SETSTATUS, line 221 of levelobj.pas 0x0804BBF0 CHARACTERS__DRAW, line 283 of levelobj.pas 0x0804B68C LEVELS__DRAW, line 148 of levelobj.pas 0x0804C372 LEVELS__INIT, line 447 of levelobj.pas 0x0805BD82 MAINLOOP, line 157 of minerunner.pas
0x0805BFFE main, line 224 of minerunner.pas
0x08048C17

So how exactly does one read it ?
It would appear from this that characters.setImage crashed - could it be that
SDL crashes if the same bitmap file is loaded too often ? Or perhaps there is
something else that goes wrong when I do this.

What I will do next is to recode it so that setStatus merely changes a string
with the path to the correct image, and then use SDL_BlitSurface with SDL_LoadBMP as a parameter (e.g. only load on demand) but this could severly slow down the program so it is not really a final solution, and even
when the enemy bitmaps are
finished, surely I must be able to use the same file for all of them ?

The bitmaps are structured like this:
For each direction of movement, one bitmap containing six frames of animation
next to each other.

A sepperate function determines the frame number to play, and then adjust an
SDL_Rect to only blit the part
of the image containing the current frame.

Any ideas ?

PS. I will look into FPAsync, thanks Sebastian.

A.J. Venter

Reply by email

A.J. Venter
to Jonas Maebe: Have you tried compiling it with -ghl already? Jonas
Jonas Maebe wrote 7 lines
On dinsdag, september 17, 2002, at 01:05 , wrote: Have you tried compiling it with -ghl already? Jonas

I have now :-)
(That option is not in the manpage nor have I ever found it in the docs - I
wish I knew about it before)

Here is the output:
General protection fault.
No heap dump by heaptrc unit
Exitcode = 216
Runtime error 216 at 0x0804B8B4
0x0804B8B4 CHARACTERS__SETIMAGE, line 212 of levelobj.pas 0x0804B913 CHARACTERS__SETSTATUS, line 221 of levelobj.pas 0x0804BBF0 CHARACTERS__DRAW, line 283 of levelobj.pas 0x0804B68C LEVELS__DRAW, line 148 of levelobj.pas 0x0804C372 LEVELS__INIT, line 447 of levelobj.pas 0x0805BD82 MAINLOOP, line 157 of minerunner.pas
0x0805BFFE main, line 224 of minerunner.pas
0x08048C17

So how exactly does one read it ?
It would appear from this that characters.setImage crashed - could it be that
SDL crashes if the same bitmap file is loaded too often ? Or perhaps there is
something else that goes wrong when I do this.

What I will do next is to recode it so that setStatus merely changes a string
with the path to the correct image, and then use SDL_BlitSurface with SDL_LoadBMP as a parameter (e.g. only load on demand) but this could severly slow down the program so it is not really a final solution, and even
when the enemy bitmaps are
finished, surely I must be able to use the same file for all of them ?

The bitmaps are structured like this:
For each direction of movement, one bitmap containing six frames of animation
next to each other.

A sepperate function determines the frame number to play, and then adjust an
SDL_Rect to only blit the part
of the image containing the current frame.

Any ideas ?

PS. I will look into FPAsync, thanks Sebastian.

A.J. Venter

Reply by email

Jonas Maebe
to A.J. Venter: I have now :-) (That option is not in the manpage nor have I ever found it in the docs - I
A.J. Venter wrote
I have now :-) (That option is not in the manpage nor have I ever found it in the docs - I wish I knew about it before)

It should be in the docs (well, -g is in there, -gh and -gl should be mentioned as well). It's definitely in the help that you get when running ppc386 without any parameters.

Show quoted text 15 lines
Here is the output: General protection fault. No heap dump by heaptrc unit Exitcode = 216 Runtime error 216 at 0x0804B8B4 0x0804B8B4 CHARACTERS__SETIMAGE, line 212 of levelobj.pas 0x0804B913 CHARACTERS__SETSTATUS, line 221 of levelobj.pas 0x0804BBF0 CHARACTERS__DRAW, line 283 of levelobj.pas 0x0804B68C LEVELS__DRAW, line 148 of levelobj.pas 0x0804C372 LEVELS__INIT, line 447 of levelobj.pas 0x0805BD82 MAINLOOP, line 157 of minerunner.pas 0x0805BFFE main, line 224 of minerunner.pas 0x08048C17 So how exactly does one read it ?

It's a backtrace of the callstack. The place where your program crashed is address 0x0804B8B4, which is an instruction generated for line 212 of levelobj.pas, which is part of the method characters.setimage(). This method was called from line 221 of levelobj.pas within characters.setstatus etc.

It would appear from this that characters.setImage crashed -

Indeed.

could it be that SDL crashes if the same bitmap file is loaded too often ? Or perhaps there is something else that goes wrong when I do this.

I honestly don't know. To find this out, you should run the program in gdb, then you can view the values of the variables and fields when the program crashes.

Show quoted text 8 lines
What I will do next is to recode it so that setStatus merely changes a string with the path to the correct image, and then use SDL_BlitSurface with SDL_LoadBMP as a parameter (e.g. only load on demand) but this could severly slow down the program so it is not really a final solution, and even when the enemy bitmaps are finished, surely I must be able to use the same file for all of them ?

Probaly, yes. It's more likely that you aren't allocating enough memory somewhere (or that you are overwriting memory for one structure with data from another).

Jonas

Reply by email