Using OnScreenMenu with TCastleControl

Did you recompile + reinstall CGE packages after upgrading to CGE 6.5? Make sure you did.

I can’t reproduce the problem here, and there definitely should not be any problem if you drop a new component (like TCastleButton) on a form.

Looking at the screenshot, it seems that you mixed two advises – you create a Button, but you do it inside TMyControl.Create (instead, you most likely want to do it inisde FormCreate), and you set it’s Caption in TMyControl.Render (instead you probably wanted to set Caption once in FormCreate), and you never add this button to anything using Xxx.InsertFront(Button) (that’s why it’s not visible).

The purpose of the example with definiig your own TMyControl with TMyControl.Render was that inside TMyControl.Render you can place rendering of images, i.e. calls to TGLImage.Draw or UIFont.Print. As on Custom drawn 2D controls: player HUD | Manual | Castle Game Engine . Doing other things in TMyControl.Render is usually not useful, the purpose of TMyControl.Render is only to directly draw things on the screen. Some things you can move to TMyControl.Render is to call there Image.Draw, PlayerShip.Draw, Projectile[I].Draw etc. Probably everything you previously did in OnRender event can be moved to the TMyControl.Render.

To add other controls, like TCastleButton, you most likely want to do it in FormCreate. (It is possible to create them elsewhere, and add them to a different parent, but in your simple case you probably don’t need to complicate things more than necessary.) Creating a button is as simple as

Button := TCastleButton.Create(Self { some owner });
Button.Caption := 'TEST';
CastleControl1.Controls.InsertFront(Button);

You can use this, or very similar code, in your FormCreate.

Remember to also insert an instance of TMyControl, like

MyControl := TMyControl.Create(Self { some owner });
CastleControl1.Controls.InsertBack(MyControl);

For the beginning, I would encourage to read User Interface | Manual | Castle Game Engine carefully, and try the examples presented there. There are a couple of very small programs that you can directly compile yourself – take them and experiment with them :slight_smile: Do not paste the solutions into a larger existing program, instead just take the small example code from the manual, compile it, run, see if you can tweak some things like captions.

Once you understand that manual page, and how the examples work, adding things to a larger, existing program will be a breeze :slight_smile:

1 Like

Thanks, I got it. But now I have another question. For my game I need to read left mouse click input to shoot a projectile. I used Lazarus Form OnClick event to read it, but because of that I think I can’t use TCastleButton OnClick event. Can you help me with an alternative to read mouse click ? I saw that CastleControl have an OnPress event but it’s used for keys as well.

Yes, OnPress event is used to catch such events. You’ll receive a Event: TPressReleaseEent. Then you can check if (Event.EventType = itMouseButton) and then use Event.Position to get the position the mouse is currently at.

2 Likes

Another question. In my game I used ImageX := ImageX + number to move things around, but using this with CastleControl it’s doing something weird, when moving the mouse on the game screen things moves faster (maybe the OnUpdate is called more frequent?). So I tried to use the ImageX := ImageX + CastleControl.Fps.SecondsPassed*number but things move kinda laggy, the movement is not smooth. I’m doing something wrong ?

You should always adjust every animation you do in OnUpdate to the Fps.SecondsPassed. (This is true for all OnUpdate and related events – whether it’s TCastleControl.OnUpdate, TCastleWindow.OnUpdate, overridden TCastleUserInterface.Update.) See https://castle-engine.io/manual_quick_2d_game.php . The OnUpdate calls may happen with any frequency, depending on how heavy rendering you make etc.

So your second approach like ImageX := ImageX + CastleControl.Fps.SecondsPassed * 100 is correct, and will result in the image moving with a constant speed (“100 per second” in this example). I would have to see a complete code to tell what’s wrong.

Here’s the code https://pastebin.com/C7BNc69A.
I can give you the project if you want.

Code looks OK, and

MeteoriteX[i] := MeteoriteX[i] + CastleControl1.Fps.SecondsPassed*MSpeedX[i];
MeteoriteY[i] := MeteoriteY[i] + CastleControl1.Fps.SecondsPassed*MSpeedY[i];

should work smoothly. Remember to apply the same modification to

ProjectileY[i] := ProjectileY[i] + 10

That is, it should be

ProjectileY[i] := ProjectileY[i] + CastleControl1.Fps.SecondsPassed * 10

I think you can see what I mean in this video https://youtu.be/XsEGd-yUSWc

I can’t really see, but I guess you mean that when moving the mouse you get lower FPS?

You can display FPS on screen, see https://castle-engine.io/manual_optimization.php#section_fpc_show (“How to show the FPS value”).

I can’t reproduce it, but I would not be surprised if on some systems, moving the mouse makes different behavior with TCastleControl. That’s one of the reasons why using TCastleWindow is a better idea for games — the event loop in TCastleWindow is done such that it will still render smoothly (OnRender and OnUpdate will be produced), even when being flooded with mouse move events. With TCastleControl (that uses LCL), I cannot give this guarantee, and indeed I observed problems with “mouse look” in some 3D games.

This is what I meant in the manual page https://castle-engine.io/manual_window.php , that says that using TCastleWindow “… avoids some problems with Lazarus application loop (for example, mouse look is smooth)”.

So, I would suggest to change the game to use TCastleWindow. Eugene also suggested it earlier in this thread.

Yep. That sounds like a good idea. Thanks.