Understanding GameEngine Events
Overriding Event Methods
Method Summary
Override These
Useful Access
Others
The Itty Bitty GameEngine -- Overview
Your Own Java Game -- Step by step tutorial to build a simple "Pong" game
Converting Your Game to JavaScript -- What you need to know to run your game in a web browser
Class GameWgt -- The visual components of a GameEngine game
Overriding GameEvent -- The programmatic components of a GameEngine game (You are here)
Widget Specification Text -- File format for GameMaker.txt and how to make your own
GameEvent is a class that JavaGame already knows about, so when the game engine needs to tell you that your ball widget collided with your paddle widget, there's already a subroutine ("method") defined in the GameEvent base class that knows what to do with collision events. Of course the base class doesn't know anything at all about what to do with collisions, but when you subclass it, then your new Pong object has your own code that does know, right? You programmed it, it does just exactly what you told it to do -- even if you didn't want to tell it to do that. Computers are like that, obedient to a fault. They read your mind, but only when your mind told your fingers to type into the computer the instructions you were thinking. It helps when your fingers do what your mind told them to do, but that works most of the time. So does the computer, so when it isn't working, we spend most of our effort finding and fixing the problems where everything started: what we thought we were doing. The biggest benefit that OOPS gives to programmers is a type-safe way for the main program (the GameEngine) to call subroutines that don't even exist when the main program is written and compiled -- that would be your collision code in your subclass of GameEvent -- and not have the computer crash because you made a mistake.
But before you get too far into how to process widget events, you probably should know something about widgets, in the "Class GameWgt" page. Start there, then come back. Jumping back and forth is OK.
The basic idea is that the widgets you defined in GameMaker (as you did in the "Your Own Java Game" tutorial) do all the display work of your game, and your GameEvent subclass (think: Pong.java) handles all their interactions, and the GameEngine just sits there and does what you told it to.
Did you work through the "Your Own Java Game" tutorial? Even if you didn't understand everything you did, it helps to see what happened, so you know what to look for when you look under the hood. After all, if you get in a car and step on the gas -- all without knowing anything about automotive drive trains -- and it lunges forward, then when you look under the hood, you would not be looking for a squirrel cage or a wind-up rubber band connected to the driveshaft, squirrels and rubber bands just aren't that strong.
You made five widgets in the Pong game, so when you start to think about
collisions -- when you actually saw the ball bounce off the paddle
(or fail to bounce) -- you can reasonably expect that the code you typed
into the Collided method has something to do with it. Especially
if you tried to run the partial game before you put any code in. This kind
of cause-and-effect reasoning is very important when debugging your code.
It's also very important when you think about what code to write.
Some of these event handlers are one-time handlers, mostly at the beginning of the game (but one at the end, if I can get it working).
Then there are some access methods for getting and setting the class
data. There isn't much of that, so there are few of these. Most of the
utility functions you need to use access the game data, which is in
the
JavaGame class. You need to use
those methods for most of the game-general stuff your game needs to
do.
These four methods get access to GameEvent data:
DefaultKeyFocus GetClickLoc GetRefWgt SetRefWgt
Game Control
Collidable
Keyboardable
Clickable
Dragable
Rolloverable
Useful Access
Others
String GameList(JavaGame whom)GameList returns a text descriptor of all the specified widgets in a game. The code is normally generated when you click the "Build" button in GameMaker. It is called once before StartUp, and then it builds the widgets from this text descriptor list. You must call the super to preserve the reference to the host JavaGame.
Parameters whom A reference to the host JavaGame, which is kept in theGame Returns The generated text string Normally you don't need to be concerned with the meaning of the numbers in the text string returned by this method, it is created by the Build button in GameMaker. However, some of the widget creation features of GameMaker are not yet working, so you might need to create your own widgets by hand to go in this list. See "Widget Specification" for the details about how to do that.
void StartUp()After the initial widgets have been created, StartUp is called to do any other initialization the client game may have. StartUp is normally overridden in the client subclass. If you gave Java-correct names to any widgets in GameMaker, those variables are assigned values by the generated code here. You may also include here any game-specific startup code you deem appropriate to your game.
void DoOften()DoOften is called once each frame to do whatever game processing needs to be done often. You should get in and get out, so that the animation flows smoothly. Omit overriding this method if unneeded.
void GameEnding()GameEnding is called once when the game window is about to close, so you can do whatever needs to be done at the end. Omit overriding this method if unneeded. [GameEnding is not known to work]
boolean Collided(GameWgt whom, GameWgt hitt)Collided is called when a Bump-enabled (Collidable) sprite overlaps another Bump-enabled widget, or if it runs off the edge of the game board (if it is also Bump-enabled).
Parameters whom reference to the sprite widget, hitt reference to the widget it Collided with, or null of it ran off the board edge Returns true to stop looking (for more collisions on whom) You should override Collided when your game wants to respond to collisions between sprite widgets (which have their own velocity and are designated Bumpable) and other widgets that have been designated Bumpable. It is best when you can identify a class of response for recognizable widget types, so the number of different tests in minimal.
In the Pong example, there is only one Bumpable sprite widget and two other widgets it can collide with. Ten billiard balls on a pool table would have 90 possible interactions (not counting the edges of the table itself) so you might try to have a single kind of interaction when two balls hit, so that your code does not spend a lot of time deciding what to do.
void BlurEv(GameWgt whom)BlurEv is called for a widget when it loses focus. Your code may also call BlurEv to unconditionally terminate focus for any other reason. You should call super to do the default defocussing (including telling the widget that it is losing focus) unless you want to cancel the blur. If you cancel a blur that is called before another widget is about to gain focus, then that focus is also cancelled. Mostly you should avoid overriding BlurEv, because it's too easy to get caught in infinite recursion (the computer -- or at least your game -- crashes).
Parameters whom The widget losing focus, or null if unknown by caller
void FocusEv(GameWgt whom, int vert, int horz)FocusEv is called for any widget that is "Focusable" when the user clicks on it. Your code may also call FocusEv to give focus to a widget for any other reason. You must call super to do the default focus processing unless you choose to cancel it. The base class calls the whom.SetFocus method for this widget, and the widget also has the opportunity to cancel (refuse) the focus. Whatever widget has focus, the class variable FocusWgt receives a reference to that widget, and your program can get that reference using the access method GetRefWgt.
Parameters whom The widget to be given focus vert The vertical offset into this widget where it was clicked horz The horizontal offset into this widget Only one widget at a time can have focus, so BlurEv is called for any previous widget with focus before any other widget can get it. If BlurEv (or the widgent it calls) refuses to give up focus, then the new widget does not receive focus.
When a user types on the keyboard -- there is nominally only one keyboard to a computer -- the keystrokes are sent to a particular widget to handle them. In a game like Pong this may not have any significance, your core game code is responsible for dispatching the activities invoked by keystrokes, but if you have text fields that the user can type new text into, the computer must know which text field this key code should be sent to; that widget is said to have the focus, and the FocusEv is the way to shift the focus from one widget to another. See also DefaultKeyFocus which ensures that your program can catch keystrokes when no widget has focus.
When GameTxLn widgets receive the focus, a caret (blinking vertical bar) at the current selection point starts blinking to tell the user where the typed keystrokes will go. In GameMaker, widgets that have the focus but without an obvious place to receive text, a dotted line of "marching ants" follows the outline of that widget to show the focus. Typing the EnterKey will typically open up a dialog to change the widget's color or text.
void KeyData(GameWgt whom, char info)KeyData is called to dispatch keystrokes if FocusWgt is not null, or else if DefaultFocus is not null, and that widget accepts keystrokes. The KeyData method in the base class separates out the control keys to call their specified event methods, so if you override KeyData, you should call super if you want that to happen and this keystroke is not yours.
Parameters whom The widget that has focus info The key that was pressed
void GotArrowKey(GameWgt whom, char info)GotArrowKey is called for any widget that has focus when the user types one of the arrow keys. If FocusWgt is null and DefaultFocus is null, or if that widget does not accept keystrokes, then GotArrowKey is not called. The base class uses GotArrowKey to move a dragable widget one pixel at time, so you should call super if this is not yours.
Parameters whom The widget that has focus info The arrow key that was pressed, one of the constant values JavaGame.Arro_UP, JavaGame.Arro_DOWN, JavaGame.Arro_LEFT, or JavaGame.Arro_RIGHT.
void GotEnterKey(GameWgt whom)GotEnterKey is called when the user types the EnterKey, if FocusWgt is not null, or else if DefaultFocus is not null, and that widget accepts keystrokes. If a standard dialog is open, it is closed and returns true. If your game can open a standard alert or input dialog, you should call super so it can get its OK clicked. Your subclass can return either true or false, because the first caller doesn't care.
Parameters whom The widget that has focus Returns true if taken (by alert or input dlog) When you override this method, you should first call super and check its return value; if true, you should do whatever you had the alert or input dialog open for.
void GotEscKey(GameWgt whom)GotEscKey is called when the user types the EscapeKey, if FocusWgt is not null, or else if DefaultFocus is not null, and that widget accepts keystrokes. The base class uses GotEscKey to cancel an outstanding drag and to terminate any focus, so you should call super if you want that effect and this is not yours.
Parameters whom The widget that has focus
void GotTabKey(GameWgt whom)GotTabKey is called when the user types the TabKey, if FocusWgt is not null, or else if DefaultFocus is not null, and that widget accepts keystrokes. There is no default behavior in the base class.
Parameters whom The widget that has focus
void KeyFld(GameWgt whom, char info)KeyFld is called for any widget that has focus when the user types any other key. If FocusWgt is null and DefaultFocus is null, or if that widget does not accept keystrokes, then KeyFld is not called. The base class uses KeyFld to insert keystrokes in an entry text field, so you should call super if this is not yours.
Parameters whom The widget that has focus info The key that was typed
void ClickEvt(GameWgt whom, int vert, int horz)ClickEvt is called for a widget that is "Clickable" when the user clicks on it (mouse down followed by mouse up on the same widget). FocusEv has already been called for this widget. The base class uses ClickEvt to detect and process double-click events, so you should call super if you want that to happen and this is not yours. You would normally override ClickEvt to process button clicks.
Parameters whom The widget that was clicked vert The vertical offset into this widget where it was clicked horz The horizontal offset into this widget The vertical and horizontal offsets are relative to the top-left corner of the widget whom. Call whom.AddPrntsPos(whom.GetPosn()) to get the position relative to the window.
A click event is defined to be when the user presses the mouse button on a widget and releases it before moving off that widget, and before moving very far if the widget is also Draggable. Your code can be notified separately for the mouse down and the mouse up events if the widget is Draggable. If you don't really want the widget to be dragged, you can override StartDrag and return null.
GameWgt StartDrag(GameWgt whom, int vert, int horz)After a MouseDn is called for a widget that is "Dragable" and the user moves the mouse at least eight pixels with the button still pressed, then it becomes a drag and StartDrag is called. If you override this method, you can either cancel the drag by returning null (without calling super), or else substitute another (possibly new) widget for (in the same location as) the clicked widget when you call super, and the replacement will be what is dragged. If you do this, there is some additional code needed in your MouseUp override so that the Dropped event works correctly.
Parameters whom The widget that was clicked vert The vertical offset into this widget where it was clicked horz The horizontal offset into this widget Returns The widget being dragged, or null if cancelled The vertical and horizontal offsets are relative to the top-left corner of this widget. Call whom.AddPrntsPos(whom.GetPosn()) to get the position relative to the window.
void Dragging(GameWgt whom, int vert, int horz)After a StartDrag has been called for a Dragable widget and the user continues to move the mouse, Dragging is called for the same widget. Override this method to do something with the dragged widget's new position. Dragging in the base class updates the dragged widget's position, so call super before you try to use that position.
Parameters whom The widget that is being dragged vert The vertical offset into this widget before it moves horz The horizontal offset into this widget The vertical and horizontal offsets are relative to the top-left corner of this widget before its position has been adjusted by super. To get the position relative to the window, you should calculate whom.AddPrntsPos(whom.GetPosn()) before calling super.
void Dropped(GameWgt whom)After a StartDrag has been called for a Dragable widget and the user releases the mouse button, Dropped is called for the same widget. If you override this method and do something with the Dropped widget that could invalidate further drags on it using the arrow keys, you should also call BlurEv for it, or else make sure it cannot take focus. The base class does nothing with Dropped, so it is not necessary to call super.
Parameters whom The widget that was dragged
void CancelDrag(GameWgt whom)CancelDrag is called to cancel (terminate without effect) a drag. The default CancelDrag replaces the WgtBeingDrug (if non-null and matches the parameter) to its starting location as specified in class variable DrugWgtBase.
Parameters whom The widget being dragged
void MouseDn(GameWgt whom, int vert, int horz)MouseDn is called for a widget that is "Dragable" when the user presses the (right) mouse button down on some widget. If the button is released without moving the mouse, then it is just a ClickEvt and no drag is attempted.
Parameters whom The widget that was clicked vert The vertical offset into this widget where it was clicked horz The horizontal offset into this widget The vertical and horizontal offsets are relative to the top-left corner of this widget. Call whom.AddPrntsPos(whom.GetPosn()) to get the position relative to the window.
void MouseUp(GameWgt whom, int vert, int horz)MouseUp is called for a widget that is "Dragable" when the user releases the mouse button over the same widget that was clicked or dragged. If the mouse is moved away from the clicked widget (and there is no drag in process) then MouseUp is not called (and there is no consequent ClickEvt). If your StartDrag override supplied an alternate widget to be dragged, then there is some additional coded needed here (a later release will move this to the base class where it belongs, but it's not working there yet).
Parameters whom The widget that was clicked vert The vertical offset into this widget where it was clicked horz The horizontal offset into this widget The vertical and horizontal offsets are relative to the top-left corner of this widget. Call whom.AddPrntsPos(whom.GetPosn()) to get the position relative to the window.
void RollIn(GameWgt whom, int vert, int horz)RollIn is called when the user first rolls the mouse over a widget that accepts rollover events. [This has not been tested]
Parameters whom The widget that has focus and the mouse is over it vert The vertical offset of the mouse in this widget horz The horizontal offset of the mouse in this widget
void RollOut(GameWgt whom, int vert, int horz)RollOut is called the first frame that the mouse is no longer over a widget that was sent a RollIn event. [This has not been tested]
Parameters whom The widget that has focus and the mouse is not over it vert The vertical offset of the mouse relative to this widget but now outside its rectangle horz The horizontal offset of the mouse relative to this widget but outside its rectangle
void RollOver(GameWgt whom, int vert, int horz)RollOver is called each subsequent frame that the mouse is over a widget that was sent a RollIn event. [This has not been tested]
Parameters whom The widget that has focus and the mouse is over it vert The vertical offset of the mouse in this widget horz The horizontal offset of the mouse in this widget
void DefaultKeyFocus(GameWgt whom)DefaultKeyFocus defines a widget to receive keystrokes when no widget has focus. Pass it null to cancel the setting.
int GetClickLoc()GetClickLoc returns the vertical and horizontal offsets (16 bits each) into the FocusWgt where it was clicked, or -1 after the mouse is released or the widget has lost its focus. ClickLocn is set by FocusEv, and cleared (to -1) by BlurEv.
GameWgt GetRefWgt(int why)GetRefWgt can be called at any time to determine which widget has focus (is being clicked or dragged or typeable). Use SetRefWgt to set them.
Parameters why A number used to select which widget you want:
-1=FocusWgt, 0=RollyWgt, 1=ClickWgt, 2=WgtBeingDrugReturns The selected widget, or null if none. Four widget references are maintained by the GameEngine to support these events:
FocusWgt is generally set by FocusEv and cleared by BlurEv, but a widget can refuse to give up focus (or BlurEv can refuse for it), in which case FocusEv will fail. FocusEv can also refuse to grant focus, or the widget can refuse to accept it, or it can be flagged as "no-focus" (see GameScro) and the low-level mouse event handler won't even try. You should avoid overriding the default GameEngine focus behavior unless you really need it, because it's very easy to make the rules so complicated as to be inconsistent, which will make your game hard to play.ClickWgt is generally set by mouse-down and cleared by mouse-up, and is used to determine if a mouse click should be reported as a ClickEvt. It is also used to decide when to start a drag. If you change the default behavior, these operations may misbehave.
RollyWgt is generally set for a widget that accepts rollover events, and cleared when the mouse exits the rollover. If you change the default behavior, widget rollover may misbehave.
WgtBeingDrug is generally set by StartDrag and cleared by MouseUp or CancelDrag, and is used to control dragging behavior. If you change the default behavior, widget dragging may misbehave.
void SetRefWgt(int why, GameWgt whom)SetRefWgt can be called at any time to set which widget has focus (is being clicked or dragged or typeable). Use GetRefWgt to get the current settings.
Parameters why A number used to select which widget you want to set:
-1=FocusWgt, 0=RollyWgt, 1=ClickWgt, 2=WgtBeingDrugwhom Thed widget you want to set it to, or else null. Four widget references are maintained by the GameEngine to support these events:
FocusWgt is generally set by FocusEv and cleared by BlurEv, but a widget can refuse to give up focus (or BlurEv can refuse for it), in which case FocusEv will fail. FocusEv can also refuse to grant focus, or the widget can refuse to accept it, or it can be flagged as "no-focus" (see GameScro) and the low-level mouse event handler won't even try. You should avoid overriding the default GameEngine focus behavior unless you really need it, because it's very easy to make the rules so complicated as to be inconsistent, which will make your game hard to play.ClickWgt is generally set by mouse-down and cleared by mouse-up, and is used to determine if a mouse click should be reported as a ClickEvt. It is also used to decide when to start a drag. If you change the default behavior, these operations may misbehave.
RollyWgt is generally set for a widget that accepts rollover events, and cleared when the mouse exits the rollover. If you change the default behavior, widget rollover may misbehave.
WgtBeingDrug is generally set by StartDrag and cleared by MouseUp or CancelDrag, and is used to control dragging behavior. If you change the default behavior, widget dragging may misbehave.
int GetValue(int why)
void SetValue(int why, int whom)You can override GetValue/SetValue in your subclass if you need access to something we didn't think of.
Rev. 2021 May 27