PDA

View Full Version : Help me please :) (starfighter game with Delphi 6 + DelphiX)



Wizard
05-12-2006, 10:58 AM
Hi guys, I previously posted a topic under internal error Pro-2688 and got some feedback suggesting that I update Delphi 6. I did and the same error is still there. I'm coding a starfighter game with Delphi 6 and DelphiX.

This is what happens when my bomb hits my player: The app freezes and I have to use cntrl, alt & delete to termanate. After pressing run again in the IDE nothing happens and when I press Pause in the IDE the following error is shown: Project raised exception class EAccessViolation with message Access violation at adress 0000000 read of adress 0000000. When I press OK on this error another error appears, which is: Internal Error PRO - 2688 with delphi 32.exe - BORdbk60.dll on the toolbar of the error. Then I have to close the IDE with cntrl, alt & delete again.

My collision code is correct, I think, and sometimes the game works perfectly.


Is there an expert who can help me please?


Some of my code:


//This is the player class
TPlayer = class(TImageSprite)
private
Fired: Integer;
public
procedure DoMove(MoveCount: Integer); override;
end;

//This is the Bomb class
TBomb = class(TImageSprite)
public
procedure DoMove(MoveCount: Integer); override;
procedure DoCollision(Sprite: TSprite; var Done: Boolean);override;
end;

function TForm1.NewPlayer;
begin
Player_No := Player_No + 1;
with TPlayer.Create(DXSpriteEngine1.Engine) do
begin
Player.Image := Form1.DXImageList1.Items.Find('Player');
Player.X := 500;
Player.Y := 710;
Player.Width := Player.Image.Width;
Player.Height := Player.Image.Height;
Result := True;
Lives:= Lives -1;
end;
end;

procedure TForm1.GameEnd;
begin
If Player_No >2 then
with DXDraw1.Surface.Canvas do
begin
DXTimer1.Enabled := False;
Timer1.Enabled := False;
DXWaveList1.Items.Find('Tada').Play(False);
Font.Size := 26;
Font.Color := clYellow;
DXDraw1.Surface.Fill(0);
TextOut(290,220,'GAME OVER,YOU LOST :)');
TextOut(290,270,'PRESS ESCAPE KEY AND TRY AGAIN');
end;
end;

procedure TPlayer.DoMove(MoveCount: Integer);
var
MyX: Double;
MyY : Double;
begin
If moveLeft and
(x>5) then
X := X - 10;

If moveright and
((X+Form1.DXImageList1.Items.Find('Player').Width)<Form1>5) then
Y := Y - 10;

if Movedown and
(y<form1.DXDraw1.Height-65)then
Y:= Y + 10;

MyX := X;
MyY := y;

//Check whether button1 is pressed (SPACEBAR)
If isButton1 in Form1.DXInput1.States Then
begin
if Fired <= 3 then
begin
Inc(Fired);
with TBullet.Create(Form1.DXSpriteEngine1.Engine) do
begin
Image := Form1.DXImageList1.Items.Find('Bullet');
Form1.DXWaveList1.Items.Find('Fire').Play(False);
X := MyX + 30; //Set it's X pos to our current X pos
Y := MyY; //Set it's Y pos to our current Y pos
Width := Image.Width; //Set it's size
Height := Image.Height;
end;
end;
end;
end;


procedure TBomb.DoMove(MoveCount: integer);
begin

Y := Y + 25;
Collision;
if (Y >= Form1.DXDraw1.Height +20) Then
Dead;
end;


procedure TBomb.DoCollision(Sprite: TSprite; var Done: Boolean);
begin
If (Sprite is TPlayer) Then
begin
Sprite.Collisioned := False;
Sprite.Dead; //Kill the Sprite
Form1.DXWaveList1.Items.Find('hit').Play(False);
Player.Dead;
Done := False;
end;
end;


Called in DXTimer:
if (player.Deaded) and (Player_No <= 2) then
NewPlayer;
GameEnd;

grudzio
05-12-2006, 11:35 AM
I think the problem is with three last lines:


if &#40;player.Deaded&#41; and &#40;Player_No <= 2&#41; then
NewPlayer;
GameEnd;

the GameEnd is always called. And since it disables timer the game freezes. Try this



if &#40;player.Deaded&#41; then begin
if &#40;Player_No <= 2&#41; then
NewPlayer
else
GameEnd;
end;

Wizard
05-12-2006, 11:54 AM
Hi, thanks for your reply. I tried your code and it still gives the same error :(

But...I think you are correct...the disabling of the timer in GameEnd is causing the problem!!!!

When I'm not disabling the timer there's no error. Problem is, where do you think I should now diasble the timer for the game to end? I'm still learning and appreciate any help/suggestions :-)

Legolas
05-12-2006, 12:38 PM
You need to release the surface after drawing on it:

procedure TForm1.GameEnd;
begin
If Player_No >2 then
begin
DXDraw1.Surface.Fill(0);
with DXDraw1.Surface.Canvas do
begin
Font.Size := 26;
Font.Color := clYellow;
TextOut(290,220,'GAME OVER,YOU LOST :)');
TextOut(290,270,'PRESS ESCAPE KEY AND TRY AGAIN');
Release;
end;
DXWaveList1.Items.Find('Tada').Play(False);
DXTimer1.Enabled := False;
Timer1.Enabled := False;
end;
end;

Wizard
05-12-2006, 12:56 PM
I tried the amended code for GameEnd as suggested but it creates the same problem :(

When the timer is not disabled, it works 100%...

grudzio
05-12-2006, 01:28 PM
Can you post more code? (At least the DXTimer OnTimer event). Or provide some download link. Currently I cannot tell why it doesnt work.

Maybe you should consider rearranging your code so you dont need to disable timer.

Btw. My first and only DelphiX game was also a starfighter :D

Legolas
05-12-2006, 01:39 PM
I agree with grudzio. I'm just curious to see why you are using a dxtimer and a timer together :wink:

Wizard
05-12-2006, 01:40 PM
Thanks, this is also my first attempt at a game. Been programming since 2004 and it's the best thing ever :)

Here's my OnTimer event:


procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
begin
DXDraw1.Surface.Fill(0);
DXSpriteEngine1.Draw;
DXImageList1.Items.Find('Earth').Draw(DXDraw1.Surf ace, Earthx, Earthy,0);
DXImageList1.Items.Find('Explode1').Draw(DXDraw1.S urface, Explode1x, Explode1y,0);
DXImageList1.Items.Find('Explode2').Draw(DXDraw1.S urface, Explode2x, Explode2y,0);
DXImageList1.Items.Find('Planet').Draw(DXDraw1.Sur face, Planetx, planety,0);
if not DXDraw1.CanDraw then Exit;
DXInput1.Update;
DXSpriteEngine1.Move(1);
DXSpriteEngine1.Dead;
DXSpriteEngine1.Draw;
if (player.Deaded) then begin
if (Player_No <= 2) then
NewPlayer
else
GameEnd;
end;
with DXDraw1.Surface.Canvas do
begin
Brush.Style := bsClear;
Font.Size := 12;
Font.Color := clTeal;
Textout(0,60, 'FPS: '+inttostr(DXTimer1.FrameRate));
TextOut(0,0,'Time: ' + IntToStr(Seconds) + ', Enemy Ships left: ' + IntToStr(enimies));
TextOut(0,40, 'Lives left: ' + IntToStr(Lives));
If (Enimies = 0) Then
begin
DXTimer1.Enabled := False;
Timer1.Enabled := False;
DXWaveList1.Items.Find('Tada').Play(False);
Font.Size := 26;
Font.Color := clYellow;
TextOut(290,220,'Game Over, your time: ' + IntToStr(Seconds) + ' seconds');
end;
Release;
end;
DXDraw1.Flip;
end;


procedure TForm1.Timer1Timer(Sender: TObject);
begin
Player.Fired := 0;
Inc(Seconds);
end;

Thanks again for your help :)

jdarling
05-12-2006, 02:08 PM
Can you post up a zip file containing your code, or a zip containing code that shows off the problem? From the pieces that you have posted, its very difficult to figure out exactly what is wrong.

Also, its always a good idea to try and build a small version that displays the same error as your main application. Usually this will help to eliminate the possibilities, and most of the time you can spot the error yourself with less to look at.

grudzio
05-12-2006, 02:13 PM
I think I see it. Its the DXInput1.Update line. When DXTimer is disabled input is not updated and game does not respond to keyboard/mouse.

So my suggestion is don't disable DXTimer. I suppose that you wanted to disable it so the game over text is displayed. I think that better solution is to make separate procedure for different game stages like intro, maingame and game over. Here is an example code:



type
TGameState = &#40;gsIntro,gsMain,gsGameOver&#41;;

var
gameState &#58; TGameState = gsIntro;

procedure Intro;
begin
//draws intro screen, main menu, etc
//if play option chosen then gamestate &#58;= gsMain;
end;

procedure Main;
begin
//updates input, updates player, enemies, draws everything
// if player is dead then gameState &#58;= gsGameOver
end;

procedure GameOver
begin
//displays gameover text
//if key pressed then gameState &#58;= gsIntro
end;

procedure TForm1.DXTimer1Timer&#40;Sender &#58; TObject; lagcount &#58; integer&#41;;
begin
if not DXDraw1.CanDraw then exit;
case GameState of
gsIntro &#58; intro;
gsMain &#58; main;
gsGameOver &#58; gameover;
end;
DXDraw1.Flip;
end;


And definately get rid of the second timer :)

NecroDOME
05-12-2006, 02:25 PM
offtopic: I like the smilys in you code!

Wizard
05-12-2006, 03:18 PM
Obrigado (Thanks :-)) Grudzio, I'll try your suggestion...it makes sense to do it the way you suggested...

I'll post again when I figured it out :-)

Diaboli
22-12-2006, 06:21 PM
I have found that using two or more DXTimers will f*** things up (like, not work at all) dunno if this is just me doing something wrong or what... :P

seiferalmasy
22-12-2006, 11:46 PM
yeah you are not supposed to use 2, I read it somewhere that it is limited to 1 anyway.

I use carlo Barbosa's threaded timer at the moment but I have only ever needed the use for one.

Paizo
02-01-2007, 12:03 PM
i edit your code:



procedure TForm1.DXTimer1Timer&#40;Sender&#58; TObject; LagCount&#58; Integer&#41;;
begin

//You are drawing before check DXDraw1.CanDraw
DXDraw1.Surface.Fill&#40;0&#41;;
DXSpriteEngine1.Draw;
DXImageList1.Items.Find&#40;'Earth'&#41;.Draw&#40;DXDraw1.Surf ace, Earthx, Earthy,0&#41;;
DXImageList1.Items.Find&#40;'Explode1'&#41;.Draw&#40;DXDraw1.S urface, Explode1x, Explode1y,0&#41;;
DXImageList1.Items.Find&#40;'Explode2'&#41;.Draw&#40;DXDraw1.S urface, Explode2x, Explode2y,0&#41;;
DXImageList1.Items.Find&#40;'Planet'&#41;.Draw&#40;DXDraw1.Sur face, Planetx, planety,0&#41;;
if not DXDraw1.CanDraw then Exit;

DXInput1.Update;
DXSpriteEngine1.Move&#40;1&#41;;
DXSpriteEngine1.Dead;
DXSpriteEngine1.Draw;
if &#40;player.Deaded&#41; then begin
if &#40;Player_No <= 2&#41; then
NewPlayer
else
GameEnd;

//here you disable dx timer...you will be unable to print anything on video by doing this!!!!
//by disabling DX timer you "freeze" the game because the procedure TForm1.DXTimer1Timer is NEVER called.


end;
with DXDraw1.Surface.Canvas do
begin
Brush.Style &#58;= bsClear;
Font.Size &#58;= 12;
Font.Color &#58;= clTeal;
Textout&#40;0,60, 'FPS&#58; '+inttostr&#40;DXTimer1.FrameRate&#41;&#41;;
TextOut&#40;0,0,'Time&#58; ' + IntToStr&#40;Seconds&#41; + ', Enemy Ships left&#58; ' + IntToStr&#40;enimies&#41;&#41;;
TextOut&#40;0,40, 'Lives left&#58; ' + IntToStr&#40;Lives&#41;&#41;;
If &#40;Enimies = 0&#41; Then
begin
DXTimer1.Enabled &#58;= False;
Timer1.Enabled &#58;= False;
DXWaveList1.Items.Find&#40;'Tada'&#41;.Play&#40;False&#41;;
Font.Size &#58;= 26;
Font.Color &#58;= clYellow;
TextOut&#40;290,220,'Game Over, your time&#58; ' + IntToStr&#40;Seconds&#41; + ' seconds'&#41;;
end;
Release;
end;
DXDraw1.Flip;
end;

hope it help!
i suggest you to do not use Dx timer except of inizialize, finalize and print on video.