...
 
Commits (11)
  • Terence Martin's avatar
    Fix adding balls in debug mode · 71e5cb40
    Terence Martin authored
    I overlooked how the new keyboard shortcut for toggling between player
    and computer balls blocks you from being able to add a ball in debug
    mode.
    71e5cb40
  • Terence Martin's avatar
    Fix timing on ball lerping animations · 1966abf7
    Terence Martin authored
    Instead of having the code that vanishes the ball half vanish it with
    a short animation, then lerp the ball while playing another animation,
    we instead vanish directly but apply the lerp right away as well.
    
    This way the score updates roughly at the same time as the ball
    arrives there, which makes for a nicer visual look.
    
    In the case of a blocked ball this is not entirely true, but the score
    is only updating a few frames early and there are a lot of that going
    on all at once, so it blends and fools the eye.
    1966abf7
  • Terence Martin's avatar
    Include Billboard entity · 58911546
    Terence Martin authored
    This is a simple entity which has a visibility state and can easily
    display some text in a known font in the center of the screen.
    
    This will be used to tell the user what's going on as the various
    parts of the game play out.
    58911546
  • Terence Martin's avatar
    Display Billboard for start of round · fb4f1af5
    Terence Martin authored
    This displays the text that indicates what round of the game is about
    to start. This is followed by the maze generation which kicks off the
    rest of the game as per usual.
    fb4f1af5
  • Terence Martin's avatar
    Add next state to StateMachine · 68c15a88
    Terence Martin authored
    This allows the StateMachine to store a state in the state machine for
    later when it knows now what the state should be a short time from
    now.
    
    This saves having to have a bunch of extra variables to do this.
    68c15a88
  • Terence Martin's avatar
    Display Billboard for start player · b00e7dae
    Terence Martin authored
    At the start of the round, we display a billboard that tells the
    player who is starting first, so that they don't get all weirded out
    when the computer starts playing first.
    b00e7dae
  • Terence Martin's avatar
    Display Billboard for blocked ball removal · 50785b67
    Terence Martin authored
    Now when we are going to remove blocked balls, we wait for a moment
    and display a billboard so that the player knows what's about to
    happen, since it happens so fast.
    50785b67
  • Terence Martin's avatar
    Display Billboard for gray brick removal · e655fbbc
    Terence Martin authored
    Like what we did for the blocked ball removal, only this time for the
    gray bricks being removed.
    e655fbbc
  • Terence Martin's avatar
    Display Billboard for the final ball drop · 1e98d8e7
    Terence Martin authored
    In this case we need to add a different state that is just for the
    billboard, since we keep returning back to the final drop state after
    ever final ball finishes dropping.
    1e98d8e7
  • Terence Martin's avatar
    Display Billboard for no moves left · 9a60aade
    Terence Martin authored
    When either player has no moves left (which includes at the end of the
    round), we display a billboard to say that.
    
    Like the change for the start player announcement, this uses the next
    state to store where to go next, and like the final ball drop we go
    into another state to wait out the billboard timer.
    9a60aade
  • Terence Martin's avatar
    Use constant for billboard delay time · 0e059a59
    Terence Martin authored
    This seems nicer than hard coding it; it's easier to either change all
    values, or find places where specific billboards are waiting so that
    we can change them.
    
    Might be interesting to make a duration property on the Billboard
    entity and then have it set as part of the show() method and queried.
    
    Then we could say:
        this._billboard.show ("text", 35);
        if (this._state.hasElapsed (this._billboard.duration))
            this._billboard.hide ();
    
    To track per billboard timings.
    0e059a59
This diff is collapsed.
......@@ -190,7 +190,7 @@ module nurdz.game
*
* @param {Ball} ball the ball which will update the score
*/
function lerpBallPos (ball : Ball) : void
export function lerpBallToScore (ball : Ball) : void
{
ball.lerpTo ((ball.player == PlayerType.PLAYER_HUMAN)
? humanScorePos
......@@ -206,7 +206,6 @@ module nurdz.game
export function goalBallScore (ball : Ball) : void
{
adjustScore (ball.player, GOAL_BALL_SCORE);
lerpBallPos (ball);
}
/**
......@@ -218,7 +217,6 @@ module nurdz.game
export function partialBallScore (ball : Ball) : void
{
adjustScore (ball.player, ball.mapPosition.y * BALL_POSITION_MULTIPLIER);
lerpBallPos (ball);
}
/**
......
module nurdz.game
{
/**
/**
* The total number of teleport entities that get generated randomly into
* the maze.
*/
......
......@@ -74,6 +74,17 @@ module nurdz.game
*/
COMPUTER_TURN,
/**
* In this state, the code to check and see if there is a valid play
* for either the human or computer player has determined that that
* player does not have a move because everything else is blocked.
*
* In this state, the nextState value stores where to go from here and
* we idle in this state for a while allowing for a billboard to be
* displayed to say what is happening.
*/
NO_MOVE_AVAILABLE,
/**
* Either the human player or the AI has pushed a ball. This state
* remains in effect until the ball has finished moving, in which case
......@@ -99,6 +110,14 @@ module nurdz.game
*/
REMOVE_GRAY_BRICKS,
/**
* All of the gray bricks have been removed, so we are getting ready to
* commence the final drop. In this state we're just showing a billboard
* to tell the player what will happen, and then we can proceed to the
* actual final drop.
*/
BEGIN_FINAL_DROP,
/**
* All of the gray bricks have been removed, so we are now in the
* process of finding all balls that can still drop and dropping them.
......@@ -161,6 +180,14 @@ module nurdz.game
*/
private _previousState : GameState;
/**
* The state that the machine should probably go to next. This can be
* set by code when it knows at some point that it will be going to
* a different state so that it doesn't have to keep track of that
* state itself.
*/
private _nextState : GameState;
/**
* The list of objects that are interested in being informed when the
* state changes.
......@@ -221,14 +248,36 @@ module nurdz.game
get priorState () : GameState
{ return this._previousState; }
/**
* Store a state for later retrieval in this property. This is useful
* when code in some state knows (in a transient location) what state
* should be next. It can store that state here for later retrieval
* without having to keep track of a bunch of extra values.
*
* @param {GameState} newState the state to switch to next;
* informational only
*/
set nextState (newState : GameState)
{ this._nextState = newState; }
/**
* Get the previously stored next state; this will return NO_STATE if
* no next state has been stored.
*
* @returns {GameState} [description]
*/
get nextState () : GameState
{ return this._nextState; }
/**
* Construct a new state machine.
*/
constructor ()
{
// Set the current and previous states.
// Set the default states.
this._currentState = GameState.NO_STATE;
this._previousState = GameState.NO_STATE;
this._nextState = GameState.NO_STATE;
// Default our tick value.
this._ticksInState = 0;
......
......@@ -222,15 +222,11 @@ module nurdz.game
this.addAnimation ("p_idle_gone", 1, false, [14]);
this.addAnimation ("p_vanish", 10, false, [10, 11, 12, 13, 14]);
this.addAnimation ("p_appear", 10, false, [14, 13, 12, 11, 10]);
this.addAnimation ("p_score_start", 10, false, [10, 11, 12]);
this.addAnimation ("p_score_end", 10, false, [12, 12, 12, 13, 14]);
this.addAnimation ("c_idle", 1, false, [15]);
this.addAnimation ("c_idle_gone", 1, false, [19]);
this.addAnimation ("c_vanish", 10, false, [15, 16, 17, 18, 19]);
this.addAnimation ("c_appear", 10, false, [19, 18, 17, 16, 15]);
this.addAnimation ("c_score_start", 10, false, [15, 16, 17]);
this.addAnimation ("c_score_end", 10, false, [17, 17, 17, 18, 19]);
// The ball is not hidden by default (the first animation in the list
// is the one that plays by default).
......@@ -349,43 +345,6 @@ module nurdz.game
this._hidden = true;
}
/**
* Set the visual state of the ball to a partial vanish; this plays an
* animation that causes the ball to vanish half way and then stop.
*
* This is identical to the vanish state, but the ball ends up not fully
* vanished (but still considered hidden).
*
* This is meant to be paired with scoreEnd() to add the ability to
* insert an action that happens in the middle of the animation.
*/
scoreStart () : void
{
this.playAnimation (this._ballType == BallType.BALL_PLAYER
? "p_score_start"
: "c_score_start");
this._hidden = true;
}
/**
* Set the visual state of the ball to the rest of a partial vanish;
* this plays an animation that causes the ball to finish fully
* vanishing and then stop.
*
* This is identical to the vanish state in that the ball finally ends
* up fully vanished.
*
* This is meant to be paired with scoreStart() to add the ability to
* insert an action that happens in the middle of the animation.
*/
scoreEnd () : void
{
this.playAnimation (this._ballType == BallType.BALL_PLAYER
? "p_score_end"
: "c_score_end");
this._hidden = true;
}
/**
* Set the visual state of the ball to appear; this plays an animation
* that causes the ball to transition from a hidden to idle state. This
......
module nurdz.game
{
/**
* How wide our billboard is, in pixels.
*/
const BILLBOARD_WIDTH = STAGE_WIDTH / 3;
/**
* How tall our billboard is, in pixels.
*/
const BILLBOARD_HEIGHT = STAGE_HEIGHT / 5;
/**
* The color of the frame on the billboard
*/
const BILLBOARD_FRAME_COLOR = "#1a5276";
/**
* The color of the background of the billboard.
*/
const BILLBOARD_BACK_COLOR = "#515a5a";
/**
* This is a simple billboard entity; it renders itself as a box in the
* center of the screen with some text centered in it.
*
* This could be enhanced to be animated, styled, etc.
*/
export class Billboard extends Entity
{
/**
* The name of the font as given in the constructor.
*/
private _fontName : string;
/**
* The size of our font, in pixels.
*/
private _fontSize : number;
/**
* The full font string specification; this is a combination of the font name and size.
*/
private _fontFullSpec : string;
/**
* The text currently stored in the billboard.
*/
private _text : string;
/**
* An indication as to whether we are visible or not.
*/
private _visible : boolean;
/**
* Get the text that the billboard is currently displaying
*
* @returns {string} the current billboard text
*/
get text () : string
{ return this._text; }
/**
* Set the text that the billboard should display.
*
* @param {string} newString the text to display on this billboard
*/
set text (newString : string)
{ this.updateText (newString); }
/**
* Get an indication as to whether this billboard will render itself or
* not.
*
* @returns {boolean} true if this billboard will render itself or false
* otherwise
*/
get visible () : boolean
{ return this._visible; }
/**
* Change the visiblity state of this billboard. When this is false, the
* billboard does not render
*
* @param {boolean} newVisible the new state of the visibilty flag
*/
set visible (newVisible : boolean)
{ this._visible = newVisible; }
/**
* Construct a new billboard entity which will render on the given stage
* using the provided font name and font size.
*
* A billboard starts with no empty text; You can set the text to
* whatever you desire.
*
* @param stage the stage that will display this menu
* @param fontName the font name to render the menu with
* @param fontSize the size of the font to use to render items, in
* pixels
*/
constructor (stage : Stage, fontName : string, fontSize : number)
{
// Our billboard is centered on the stage and of a defined size
// always.
super ("billboard", stage,
(STAGE_WIDTH / 2) - (BILLBOARD_WIDTH / 2),
(STAGE_HEIGHT / 2) - (BILLBOARD_HEIGHT / 2),
BILLBOARD_WIDTH, BILLBOARD_HEIGHT, 1, {}, {});
// Store the values provided.
this._fontName = fontName;
this._fontSize = fontSize;
// Combine them together into a single string for later use
this._fontFullSpec = this._fontSize + "px " + this._fontName;
// Set some default text and start out hidden.
this.text = "";
this._visible = false;
}
/**
* Update the text that should be displayed in this billboard, and
* recalculate all internal values needed to render it properly.
*
* This is a raw internal operation.
*
* @param {string} newText the new text
*/
private updateText (newText : string)
{
this._text = newText;
}
/**
* Display the billboard on the stage with the given text.
*
* This is essentially a shortcut for altering the text and making sure
* that the visibilty is on.
*
* @param {string} text the text to display in the billboard
*/
show (text : string) : void
{
// Change the text using the accessor and be visible
this.text = text;
this._visible = true;
}
/**
* For orthogonality, this will hide the billboard by turning off its
* visibility. This leaves the text intact.
*/
hide () : void
{
this.visible = false;
}
/**
* Render ourselves using the provided renderer. This will render out the text as well as the
* current pointer.
*
* The position provided to us is ignored; we already have an idea of where exactly our contents
* will render.
*/
render (x : number, y : number, renderer : CanvasRenderer) : void
{
if (this._visible == false)
return;
// Draw the frame first.
renderer.fillRect (x, y, this._width, this._height, BILLBOARD_BACK_COLOR);
renderer.strokeRect (x, y, this._width, this._height, BILLBOARD_FRAME_COLOR, 4);
// Save the context and set up our font and font rendering. We want
// to horizontally and vertically center text around a point.
renderer.context.save ();
renderer.context.font = this._fontFullSpec;
renderer.context.textAlign = "center";
renderer.context.textBaseline = "middle";
// Render our text at the center of the stage
renderer.drawTxt (this._text, STAGE_WIDTH / 2, STAGE_HEIGHT / 2, 'white');
// Restore the context now.
renderer.restore ();
}
}
}
......@@ -1066,7 +1066,10 @@ module nurdz.game
// becomes set to true doesn't happen until the ball is
// visibly gone.
if (pos.y == MAZE_HEIGHT - 2 || this._droppingFinalBall == true)
this._droppingBall.scoreStart ();
{
this._droppingBall.vanish ();
lerpBallToScore (this._droppingBall);
}
else
this._ballMoveFinalized = true;
......
This diff is collapsed.
......@@ -18,6 +18,7 @@
"StateMachine.ts",
"entity/Pointer.ts",
"entity/Menu.ts",
"entity/Billboard.ts",
"entity/Player.ts",
"entity/MazeCell.ts",
"entity/Marker.ts",
......