Section 4

We're going to re-factor some of our update code. Begin by creating a new instance method as follows.

updateGameBoardAndControls
    self drawGameBoard.
    self updateFireButtonLabel.
    self updateCounters.
    self changed

Modify our #mouseUp:forMorph:cell: instance method to use this new update code.

mouseUp: evt forMorph: aSketchMorph cell: aCell
    | renderer pixelPositionWithinBoard cellForRedraw |
    renderer := CellRenderer rendererFor: aCell grid: self grid form: self boardForm.
    pixelPositionWithinBoard := self boardRelativePositionFor: evt.
    cellForRedraw := renderer mouseUpWithinBoardOffset: pixelPositionWithinBoard.
    self redrawCell: cellForRedraw.
    self incrementMoves.
    self updateGameBoardAndControls

Open up a new LaserGame morph to check how we're doing.

Next, we're going to add a "New Game" button. The existing control panel looks crowded for a third button. The existing ones do not need to be so large. I'd like to make them both smaller and put them together horizontally in the same row. Then we could add a second row with a new buttton.

While we're in here changing around our button code, we should revisit how we have the "Quit" button coded. If we make the button smaller and maybe a little closer to the "Fire" button to make more room on the control panel, we could find the user accidently hitting the "Quit" button sometimes. Modify the #quitGame method to confirm the user's choice before actually exiting the game.

quitGame
    (self confirm: 'Are you sure you want to quit?') ifTrue: [self delete]

The code to layout the buttons is only going to get messier to read if we add a 2nd row and third button. Let's refactor a bit here too. Add the following instance method to calclulate the layout-frame for a control panel button if we specify the row and column for it.

buttonLayoutFrameForRow: fromBottom column: fromLeft
    | buttonHeight buttonWidth xOffset xOrigin yOrigin xCorner yCorner yOffset |
    buttonHeight := 20.
    buttonWidth := 40.
    xOffset := (self panelWidth - (2 * buttonWidth)) // 3.
    yOffset := 10.

    xOrigin := xOffset * fromLeft.
    xOrigin := xOrigin + ((fromLeft - 1) * buttonWidth).

    yOrigin := yOffset * fromBottom.
    yOrigin := yOrigin + (fromBottom * buttonHeight).
    yOrigin := yOrigin negated.

    xCorner := xOrigin + buttonWidth.
    yCorner := yOrigin + buttonHeight.

    ^LayoutFrame
        fractions: (0 @ 1 corner: 0 @ 1)
        offsets: (xOrigin@yOrigin corner: xCorner@yCorner)

We need to create the "New Game" button.

makeNewGameButton
    ^self makeButton: 'New' action: #newGame state: nil

Next we modify the #addButtonsToPanel: method to use the new layout technique for all our control panel buttons, including the new one.

addButtonsToPanel: panel
    | layout |
    layout := self buttonLayoutFrameForRow: 1 column: 1.
    panel addMorph: self makeQuitGameButton fullFrame: layout.

    layout := self buttonLayoutFrameForRow: 1 column: 2.
    panel addMorph: self makeFireLaserButton fullFrame: layout.

    layout := self buttonLayoutFrameForRow: 2 column: 1.
    panel addMorph: self makeNewGameButton fullFrame: layout.

    ^panel

For now, just add a stub method to handle the new game request.

newGame

We have a little more refactoring to do. Add a new instance method on LaserGame.

initializeDirty
    self dirty: Dictionary new

We're going to use that in the initialization of "dirty" and when we create a new game. Here's the modified #dirty method.

dirty
    dirty isNil ifTrue: [self initializeDirty].
    ^dirty

Open up a new LaserGame morph to check how we're doing.

Index Page Next Page

Copyright © 2007, 2008, 2009, 2010 Stephan B Wessels    stevewessels@me.com