On-screen menu

On-screen menu in "The Castle" - main menu
On-screen menu in "The Castle" - configure controls
On-screen menu in "The Castle" - pause menu
Lights editor in "view3dscene" - also an on-screen menu
Terrain parameters (from engine "terrain" demo) are also an on-screen menu

The TCastleOnScreenMenu is a user interface control (TUIControl descendant) displaying an on-screen menu. All the menu items are displayed vertically on the screen. You can click on menu items, or choose them using the keyboard. Each menu item is a full-featured UI control. In the common case, a menu item is an instance of TCastleMenuButton, which descends from TCastleButton so you have available the event OnClick. In general, menu item is any UI control.

Menu items may also have attached an "accessory" which is often used as an extra label (like a "Yes" / "No" state of some configuration option), a slider (e.g. to control sound volume or texture quality). In general, an "accessory" is just a child UI control of the menu-item, and can be any UI control (TUIControl). So you can really insert any convoluted things inside the on-screen menu:)

You create and insert the on-screen menu instance just like all other UI controls.

Once created, you should add menu items using the TCastleOnScreenMenu.Add method. It has a couple of overloaded versions. In the simplest case, you can use the Add(string) or Add(string, TNotifyEvent) methods, that add a simplest menu item, and optionally register your callback to handle it's click event.

A simplest example program:


Deprecated: Function create_function() is deprecated in /var/www/cge-www-preview/geshi/geshi.php on line 4751
uses CastleWindow, CastleUIControls, CastleOnScreenMenu;
 
var
  Window: TCastleWindowBase;
  OnScreenMenu1: TCastleOnScreenMenu;
 
type
  TEventHandler = class
    class procedure NewGameClick(Sender: TObject);
    class procedure LoadGameClick(Sender: TObject);
  end;
 
class procedure TEventHandler.NewGameClick(Sender: TObject);
begin
  // ... new game
end;
 
class procedure TEventHandler.LoadGameClick(Sender: TObject);
begin
  // ... load game from disk
end;
 
begin
  Window := TCastleWindowBase.Create(Application);
  Window.Open;
 
  OnScreenMenu1 := TCastleOnScreenMenu.Create(Application);
  OnScreenMenu1.Add('New game', @TEventHandler(nil).NewGameClick);
  OnScreenMenu1.Add('Load game', @TEventHandler(nil).LoadGameClick);
  OnScreenMenu1.Anchor(hpMiddle);
  OnScreenMenu1.Anchor(vpMiddle);
  Window.Controls.InsertFront(OnScreenMenu1);
 
  Application.Run;
end.

There are examples of using this class in

  • examples/lazarus/model_3d_with_2d_controls/
  • examples/2d_standard_ui/
  • examples/terrain/
  • Inside The Castle game.

On-screen menu over a 3D world

You can use various UI controls on top of each other. So you can have TCastleOnScreenMenu displayed on top of a 3D world (by default, scene manager already acts as a viewport). You can control the existence of any UI control either by removing/adding it from the Controls list, or by changing it's Exists property.

If the game is already started, in single player games, you usually want to pause the game when the on-screen menu is displayed. You can do this easily by Items.Paused property. Use the TUIState to create a state like TStateOptions that will contain the "options" user-interface (e.g. using TCastleOnScreenMenu), and underneath pause the game by setting Viewport.Items.Paused := true.

Background under on-screen menu

In addition to previous ideas, you may want to change the menu TCastleOnScreenMenu.FullSize to true. Otherwise, menu receives input only when mouse hovers over it. When FullSize = true, the menu obscures completely controls under it as far as key processing is concerned (although controls behind are still visible as a background).

  • So if you want your menu to be displayed and used orthogonally to the "live" 3D world underneath, leave FullSize = false.

  • For initial game menu with items like "New Game", you probably want to disable the camera input for this scene. This allows you to display interactive 3D scene in the background, but block user from interacting with it (after all, the user should only interact with your menu on the initial screen). To do this simply set FullSize = true.

If you want to place a static 2D image under menu, you can use TCastleImageControl underneath, instead of a 3D scene.