Bowling outdated

From Blue Mars Developer Guidebook

Jump to: navigation, search

Contents

Overview

The Bowling minigame (Game/Extensions/BowlingExtension.xml) demonstrates the following features:

Here's the state transition diagram for the bowling game with the following key features:

  1. An initial state
  2. A finish state
  3. An outermost state loop that indicates we have the option of playing the game again and again until we quit.
  4. An inner gameplay loop representing prepare-throw-reset.

Image:bowlingstates.png

Class Description

Here's the header of our script, Game/Scripts/Entities/Minigames/AR/bowling.lua, the entity class description including the list of state names from our state transition diagram, and our entity variables.

BowlingGame =
{
  Properties = 
  {
    camJumpRight = {x=.25,y=0,z=0},
    defaultImpPow = 50,
    xAngImpMul = -1,
  },
  
  States = 
  {
    "Init",
    "ShowAlley",
    "PrepareToThrow",
    "ThrowBall",
    "ResetAfterThrow",
    "ClearLane",
    "Finish",
  },
  
  Editor=
  {
    Icon="ar_test.bmp",--(in Editor/ObjectIcons)
    ShowBounds=0,
  },
  
  FSCommands =
  {
    throw = "Bowling:Throw",
    timedOut = "Bowling:TimedOut",
    playagain = "Bowling:PlayAgain",
    exit = "Bowling:Exit",--placeholder
  },

  Actions = 
  {
    mouseX = "hud_mousex",
    mouseY = "hud_mousey",
    mouseClick = "hud_mouseclick",
    rightMouseClickDown = "hud_mouserightbtndown",
    rightMouseClickUp = "hud_mouserightbtnup",
    arrowRight = "next_spectator_target",
    arrowLeft = "prev_spectator_target",
  },
  
  pins={},        --for tracking pins
  balls={},       --for tracking ball
  frameScores={}, --cumulative score array (1 score per frame)
  temp={},        --frameScore storage for debug

  hud_controller = "Libs/UI/AR_Bowling/bowlCtrlContainer.swf",
  hud_scoreboard = "Libs/UI/AR_Bowling/scoreboard1.swf",
  playagain = "Libs/UI/AR_Bowling/playAgain.swf", 

  ROLLING_FIRST_BALL = 1, --scoring states
  ROLLING_SECOND_BALL = 2,
  STRIKE_LAST_BALL = 3,
  TWO_CONSEC_STRIKES = 4,
  STRIKE_2_BALLS_AGO = 5,
  SPARE_LAST_BALL = 6,      
  
  rotLeftLimit = 0.04,
  rotRightLimit = -0.06,
  ball,
  bScoreWasRecorded = false,
  bPinsShouldReset = false,
  bGameIsOver = false,
  bRollingBackwards,
  scoreState = 1,
  firstBallInFrame = 0,
  rollingFrame = 1,
  totalScore = 0,
  ballCount = 0,

  time = 0,
  vecX = 0,
  vecY = 0,
  impulsePow = 0,
  lastDist = 0,
  spinStrength = 0,
  spinImp = 0,
  breakPtDist = 8,
  finalFrameNumber = 10,--number of frames in game
  cam,  
  mXorig = 0, --initial mouse right-click x-value for aim
  vInitBallPos = {x=0,y=0,z=0},  
  vInitCamPos = {x=0,y=0,z=0}, --centered throwing position
  vInitCamAng = {x=0,y=0,z=0}, --centered aiming angle  
  vFirstCamAng = {x=0,y=0,z=0},--aiming angle, when right-click down
  vCamPos = {x=0,y=0,z=0},     --throwing position
}

Initialization

As described in Minigame Basics, by convention we implement a Start function that initializes and launches the game. This Start function:

  1. initialize the entity variables that refer to the bowling ball and pins and custom camera
  2. load all the Flash movies used in the HUD
  3. set the field-of-view of the custom camera
  4. activate the custom camera
  5. enable calls to the OnUpdate callbacks in this script
  6. transition to the Init state

Note that commented out call to ARDebug Utilities function. That is left uncommented during development to enable verbose logging output and error-checking with the Lua debugger, and commented out when delivered.

function BowlingGame:Start()
  self:GetEntities();
  self:GetInitPos();
  self:LoadFlash();
  local bowlFov = g_Deg2Rad * 50;
  Game.SetViewFov(self.cam.view, bowlFov);                                              

  self.cam:Start();
  self:Activate(1);
  --ARDebug(3);
  self:GotoState("Init");
end
function BowlingGame:GetEntities()
  self.pins = {};
  i=0; 
  local link=self:GetLinkTarget("pin", i);
  while (link) do
    table.insert(self.pins, {
      entity=link,
      pos=link:GetWorldPos(),
      ang=link:GetWorldAngles(),
      scale=link:GetScale(),
    });
    i=i+1;
    link=self:GetLinkTarget("pin", i);
  end
  local i=0;
  local link=self:GetLinkTarget("ball", i);
  while (link) do
    table.insert(self.balls, {
      entity=link,
      pos=link:GetWorldPos(),
      ang=link:GetWorldAngles(),
      scale=link:GetScale(),
    });
    i=i+1;
    link=self:GetLinkTarget("ball", i);
  end
  self.ball = System.GetEntityByName("Ball1");
  self.cam = System.GetEntityByName("MiniCamera_1stPersonBowl");  
end
function BowlingGame:GetInitPos()
  self.vInitBallPos = self.ball:GetWorldPos();
  self.vInitCamPos = self.cam:GetWorldPos();
  self.vInitCamAng = self.cam:GetWorldAngles();
end
function BowlingGame:ResetInitPos()
  self.bPinsShouldReset = false;  --to determine whether to reset
  self.bScoreWasRecorded = false;
  self.scoreState = self.ROLLING_FIRST_BALL;
  self.firstBallInFrame = 0;      --ball 1 score in a frame (if not a strike)
  self.rollingFrame = 1;          --number of frame in which next ball will be rolled
  self.totalScore = 0;
  self.bGameIsOver = false;
end
function BowlingGame:LoadFlash()
  HUD.LoadFlash(self.hud_controller);
  HUD.LoadFlash(self.playagain);
  self:LoadScoreboard();
end
function BowlingGame:LoadScoreboard()
  HUD.LoadFlash(self.hud_scoreboard);
  HUD.DockFlash(self.hud_scoreboard, eFD_Stretch);
  HUD.ShowFlash(self.hud_scoreboard);
  HUD.SetFlashVariable(self.hud_scoreboard,"totalScore"," ")
end

States

Init

The initial state:

  1. sets the ball in the initial position
  2. loads the scoreboard HUD
  3. transitions to the PrepareToThrow state
BowlingGame.Init =
{
  OnBeginState = function(self)
    self:ResetInitPos();
    self:LoadScoreboard();
    self:GotoState("PrepareToThrow");
  end,
}

PrepareToThrow

Image:bowlingstart.png

On entry, this state:

  1. sets the initial camera position and direction
  2. displays the bowling throw controller

The throw controller is a Flash movie with Actionscript that tracks the mouse and calculates throw parameters to apply to the bowling ball. The OnUpdate callback checks if the Actionscript in the throw controller has issued a throw command - if so, then it transitions to the Throw state.


BowlingGame.PrepareToThrow =
{
  OnBeginState = function(self)
    self.cam:SetWorldPos(self.vInitCamPos);
    self.cam:SetWorldAngles(self.vInitCamAng);    
    CopyVector(self.vCamPos, self.vInitCamPos);
    self.bAimEnabled = false;
    self:ShowController();
  end,
  OnUpdate = function(self,time)
    local action = HUD.GetLastAction();
    if (action ~= "") then
      if (action == self.Actions.rightMouseClickDown) then
        self.mXorig = System.GetHardwareMouseX();   
        self.vFirstCamAng = self.cam:GetAngles();
        self.bAimEnabled = true;
      elseif (action == self.Actions.rightMouseClickUp) then
        self.bAimEnabled = false;
      elseif ((action == self.Actions.mouseX or action == self.Actions.mouseY) and self.bAimEnabled) then
        local mX = System.GetHardwareMouseX();
        local mDiff = self.mXorig - mX;
        local newCamAngle = g_Vectors.temp_v1;
        CopyVector(newCamAngle, self.vFirstCamAng);
        local rotationAmt = ((mDiff*g_Pi)/2048);
        
        newCamAngle.z = newCamAngle.z + rotationAmt;
        newCamAngle.z = clamp(newCamAngle.z, self.rotRightLimit, self.rotLeftLimit);      
        self.cam:SetAngles(newCamAngle);  --use this to set rotation vector for addimpulse

      elseif (action == self.Actions.arrowRight) then
        if (self.vCamPos.x < 215.3) then --xLimitRight
          FastSumVectors(self.vCamPos, self.vCamPos, self.Properties.camJumpRight);
          self.cam:SetLocalPos(self.vCamPos);
        end
      elseif (action == self.Actions.arrowLeft) then
        if (self.vCamPos.x > 214.4) then  --xLimitLeft
          SubVectors(self.vCamPos, self.vCamPos, self.Properties.camJumpRight);
          self.cam:SetLocalPos(self.vCamPos);
        end
      end
    end

    local command = HUD.GetLastFSCommand();
    if (command ~= "") then
      local arg = HUD.GetLastFSArgs();
      if (command == self.FSCommands.throw) then        
        self.time = tonumber(string.match(arg, "%d+ "));
        self.vecX = tonumber(string.match(arg, "[%s][%-]?[%d]+[%s]"));
        self.vecY = math.abs(tonumber(string.match(arg, "[%s][%-]?[%d]+$")));
        
        if (self.vecY == 0) then self.vecY = .5 end;
        self.spinStrength = (self.vecX/self.vecY);  
        if (self.time ~= 0) then        
          self.impulsePow = 50 + ( clamp((1000 - self.time), 0, 600 ) / 12); --range pow from 50 to 100
        else
          self:ShowController();
        end
        local strengthCheck = math.abs(self.spinStrength);  --stronger spin = shorter break point distance
        if (strengthCheck < .5) then 
          self.breakPtDist = 9;
        elseif (strengthCheck < 1) then
          self.breakPtDist = 7;
        elseif (strengthCheck < 2) then
          self.breakPtDist = 5;
        else
          self.breakPtDist = 3;
        end     
        self:GotoState("ThrowBall");
      elseif (command == self.FSCommands.timedOut) then
        ARDebugMessage("Oops! Too slow.", 5); 
        self:ShowController(); --restart controller
      end     
    end
    HUD.ClearLastFSCommand();     
    HUD.ClearLastAction();  
  end,
  OnEndState = function(self)
    self:HideController();
  end,
}

ThrowBall

Image:bowlinggdc.png

  1. throw the bowling ball with an impulse using the camera direction and parameters from the throw controller
BowlingGame.ThrowBall =
{
  OnBeginState = function(self)
    local camX = (self.cam:GetWorldPos()).x;
    local ballPos = g_Vectors.temp_v2;
    CopyVector(ballPos, self.vInitBallPos);
    ballPos.x = camX;
    self.ball:SetWorldPos(ballPos);
    
    local impulseDir = g_Vectors.temp_v3;
    local rotation_vec = self.cam:GetDirectionVector();
    NormalizeVector(rotation_vec);
    CopyVector(impulseDir, rotation_vec);
    self.spinImp = clamp(self.spinStrength, -5, 5);
    self.bRollingBackwards = false;
    self.lastDist = 0;
    self:Throw(impulseDir);
  end,
  OnUpdate = function(self,time)
    local dist = (self.ball:GetWorldPos()).y - self.vInitBallPos.y;
    --add impulse each frame to create curve (fake the breaking point)
    if ((not self.bRollingBackwards) and (dist > self.breakPtDist and dist < 18)) then 
      self.ball:AddImpulse(-1, nil, g_Vectors.v000, 0, 0, g_Vectors.v001, self.spinImp * .2);
      self.ball:AddImpulse(-1, nil, g_Vectors.v000, 0, 0, g_Vectors.v010, self.spinImp * .8);
    end
    if (dist < self.lastDist) then
      self.bRollingBackwards = true;
    end
    if (self.bRollingBackwards and dist < 18) then
      self.ball:AddImpulse(-1, nil, g_Vectors.v100, 1, 0, g_Vectors.v100, self.Properties.xAngImpMul);
    end
    if (self.ball:GetSpeed() <= 0.3) then
      if (self.vInitBallPos.y ~= (self.ball:GetWorldPos()).y) then
        self:GotoState("ResetAfterThrow");
      end
    end
    self.lastDist = dist;
  end,
  OnEndState = function(self)
  end,
}

ResetAfterThrow

This state:

  1. updates/saves the score for this frame
  2. reset the pins
  3. reset the ball
  4. transition to the PrepareToThrow state, or ClearLane if the game is over
BowlingGame.ResetAfterThrow =
{
  OnBeginState = function(self)
    local down=self:CheckPins();
    self:RecordScore(down); 
    self.bScoreWasRecorded = true;
    self:ResetPins();
    self:ResetBall();
    if (self.bGameIsOver) then 
      self:GotoState("ClearLane");
    else
      self:GotoState("PrepareToThrow");
    end
  end,
  OnEndState = function(self)
  end,
}

ClearLane

Image:Bowlfinal.png

This end-of-game state:

  1. hides the bowling controls
  2. displays the play-again button

The OnUpdate callback checks if the play-again button has been clicked. If so, transition back to the Init state.

BowlingGame.ClearLane =
{
  OnBeginState = function(self)
    self:GetEntities();
    self:HideController();
    self:ShowPlayAgain();
  end,
  OnUpdate = function(self,time)
    if (HUD.GetLastFSCommand() == self.FSCommands.playagain) then
      HUD.UnloadFlash(self.hud_scoreboard);
      self:GotoState("Init");
    elseif (HUD.GetLastFSCommand() == self.FSCommands.exit) then
      self:GotoState("Finish");
    end
    HUD.ClearLastFSCommand();
  end,
  OnEndState = function(self)
    self:HidePlayAgain();
  end,
} 

Finish

The finish state performs some good-citizen cleanup on itself:

  1. deactivates the custom camera
  2. removes (and completely unloads from memory) the HUD
  3. turns off calls to OnUpdate callbacks
BowlingGame.Finish =
{
  OnBeginState = function(self)
    self.cam:Stop();
    HUD.UnloadFlash(self.hud_scoreboard);
    self:Activate(0); 
  end,
}

Functions

Here are the support functions used by the states.

  1. Show the throw controller
  2. Make it mouse sensitive
  3. Call the Actionscript function start in the throw controller
function BowlingGame:ShowController()
  HUD.ShowFlash(self.hud_controller);
  HUD.ModalFlash(self.hud_controller);
  HUD.InvokeFlashMethod(self.hud_controller,"start");
end
  1. Hide the throw controller
  2. Turn off mouse sensitivity (and hide the cursor)
  3. Call the Actionscript function Initialize in the throw controller
function BowlingGame:HideController()
  HUD.HideFlash(self.hud_controller);
  HUD.NonModalFlash();
  HUD.InvokeFlashMethod(self.hud_controller,"control_mc.initialize");
end
  1. Show the play-again button
  2. Make it mouse sensitive (and show the cursor)
function BowlingGame:ShowPlayAgain()
  HUD.ShowFlash(self.playagain);
  HUD.ModalFlash(self.playagain);
end
  1. Hide the play-again button
  2. Turn off mouse-sensitivity (and hide the cursor)
function BowlingGame:HidePlayAgain()
  HUD.HideFlash(self.playagain);
  HUD.NonModalFlash();
end
  1. add an impulse to the bowling ball
function BowlingGame:Throw(impulseDir)
  self.ball:AddImpulse(-1, nil, impulseDir, self.impulsePow, 0, g_Vectors.v011, self.spinImp);  
end
  1. reset the ball to its saved initial position
function BowlingGame:ResetBall()
  if (self.bScoreWasRecorded) then
    for i,v in pairs(self.balls) do --reset BALL for debug
      local entity=v.entity;
      entity:SetWorldPos(v.pos);
      entity:SetWorldAngles(v.ang);
      entity:SetScale(v.scale);
      entity:AwakePhysics(1);
    end
  end
end
  1. reset the pins to their saved initial positions
function BowlingGame:ResetPins()
  if (self.bScoreWasRecorded) then      
    if (self.bPinsShouldReset) then --true unless set false according to state in RecordScore()
      for i,v in pairs(self.pins) do
        local entity=v.entity;
        entity:SetWorldPos(v.pos);
        entity:SetWorldAngles(v.ang);
        entity:SetScale(v.scale);
        entity:AwakePhysics(1);
      end
    end
  end
end
  1. return the number of downed pins
function BowlingGame:CheckPins(frameTime)
  local down=0;
  for i,v in pairs(self.pins) do
    local entity=v.entity;
    local pinup=vecNormalize(entity:GetDirectionVector(2));
    if (vecDot(pinup, g_Vectors.up)<0.97 or ((entity:GetWorldPos()).y ~= v.pos.y)) then 
      down=down+1;
    end
  end
  return down;
end
  1. this is the complicated one - it implements the bowling scoring rules
function BowlingGame:RecordScore(down)
  self.bPinsShouldReset = true;
  local lastFrameTot = 0; --for scoring after strikes/spares
  local lastFrameNum = 0; 
  local frameTot = 0; --for directly scoring frame
  
  if (self.scoreState==self.ROLLING_FIRST_BALL) then
    if (down==10) then      --strike
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball1","X");
      self.rollingFrame = self.rollingFrame + 1;
      self.scoreState = self.STRIKE_LAST_BALL;
    else
      self.firstBallInFrame = down;
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball1",""..self.firstBallInFrame.."");
      self.scoreState = self.ROLLING_SECOND_BALL;       
      self.bPinsShouldReset = false;
    end 
  elseif (self.scoreState==self.ROLLING_SECOND_BALL) then
    down = down - self.firstBallInFrame;  
    if (down < 0) then down = 0 end;  
    
    if (self.rollingFrame == self.finalFrameNumber) then
        HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball2",""..down.."");
        frameTot = self:AddFrame (self.firstBallInFrame + down);
        HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."score",""..frameTot..""); 
        HUD.SetFlashVariable(self.hud_scoreboard,"totalScore",""..frameTot.."");      
        self.rollingFrame = self.rollingFrame + 1;--to end game   
    elseif (self.firstBallInFrame + down == 10) then  --spare
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball2","/");
      self.rollingFrame = self.rollingFrame + 1;
      self.scoreState = self.SPARE_LAST_BALL;
    else  --miss
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball2",""..down.."");
      frameTot = self:AddFrame(self.firstBallInFrame + down);
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."score",""..frameTot.."");
      self.rollingFrame = self.rollingFrame + 1;    
      self.scoreState = self.ROLLING_FIRST_BALL;
    end

  elseif (self.scoreState==self.SPARE_LAST_BALL) then
    lastFrameTot = self:AddFrame (10 + down);
    lastFrameNum = self.rollingFrame - 1;
    HUD.SetFlashVariable(self.hud_scoreboard,"frame"..lastFrameNum.."score",""..lastFrameTot.."");
    if (down == 10) then
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball1","X");  
      self.rollingFrame = self.rollingFrame + 1;
      self.scoreState = self.STRIKE_LAST_BALL;
    else
      self.firstBallInFrame = down;
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball1",""..self.firstBallInFrame.."");
      self.scoreState = self.ROLLING_SECOND_BALL;       
      self.bPinsShouldReset = false;
    end

  elseif (self.scoreState==self.STRIKE_LAST_BALL) then
    if (down == 10) then --strike after a strike
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball1","X");  
      self.rollingFrame = self.rollingFrame + 1;
      self.scoreState = self.TWO_CONSEC_STRIKES;
    else
      self.firstBallInFrame = down;
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball1",""..self.firstBallInFrame.."");
      self.scoreState = self.STRIKE_2_BALLS_AGO;          
      self.bPinsShouldReset = false;
    end

  elseif (self.scoreState==self.TWO_CONSEC_STRIKES) then
    lastFrameTot = self:AddFrame(20 + down);
    lastFrameNum = self.rollingFrame - 2;
    HUD.SetFlashVariable(self.hud_scoreboard,"frame"..lastFrameNum.."score",""..lastFrameTot.."");
            
    if (down == 10) then  
      if (self.rollingFrame == self.finalFrameNumber) then  
        lastFrameTot = self:AddFrame(10 + down);                                                
        lastFrameNum = self.rollingFrame - 1;
        HUD.SetFlashVariable(self.hud_scoreboard,"frame"..lastFrameNum.."score",""..lastFrameTot.."");
        HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball1","X");
        frameTot = self:AddFrame (down);
        HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."score",""..frameTot.."");
        HUD.SetFlashVariable(self.hud_scoreboard,"totalScore",""..frameTot.."");
        ARDebugMessage("Game Over"),5);
        self.bGameIsOver = true;
      else
        HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball1","X");
        self.rollingFrame = self.rollingFrame + 1;
      end
    else
      self.firstBallInFrame = down;
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball1",""..self.firstBallInFrame.."");
      self.scoreState = self.STRIKE_2_BALLS_AGO;          
      self.bPinsShouldReset = false;
    end
  elseif (self.scoreState==self.STRIKE_2_BALLS_AGO) then
    down = down - self.firstBallInFrame;  
    if (down < 0) then down = 0 end;      
    lastFrameTot = self:AddFrame (10 + self.firstBallInFrame + down);
    lastFrameNum = self.rollingFrame - 1;
    HUD.SetFlashVariable(self.hud_scoreboard,"frame"..lastFrameNum.."score",""..lastFrameTot.."");  
    if (self.firstBallInFrame + down == 10) then  --spare
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball2","/");
      if (self.rollingFrame == self.finalFrameNumber) then  
        lastFrameTot = self:AddFrame(10 + self.firstBallInFrame + down);                                                
        lastFrameNum = self.rollingFrame - 1; 
        HUD.SetFlashVariable(self.hud_scoreboard,"frame"..lastFrameNum.."score",""..lastFrameTot.."");
        HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball1","X");
        
        frameTot = self:AddFrame (self.firstBallInFrame + down);
        HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."score",""..frameTot.."");
        HUD.SetFlashVariable(self.hud_scoreboard,"totalScore",""..frameTot.."");
        ARDebugMessage("Game Over",5);
        self.bGameIsOver = true;
      else
        self.rollingFrame = self.rollingFrame + 1;
        self.scoreState = self.SPARE_LAST_BALL;
      end
    else
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."ball2",""..down.."");  
      frameTot = self:AddFrame (self.firstBallInFrame + down);
      HUD.SetFlashVariable(self.hud_scoreboard,"frame"..self.rollingFrame.."score",""..frameTot.."");
      if (self.rollingFrame == self.finalFrameNumber) then
        HUD.SetFlashVariable(self.hud_scoreboard,"totalScore",""..frameTot.."");
        ARDebugMessage("Game Over",5);
        self.bGameIsOver = true;
      else
        self.rollingFrame = self.rollingFrame + 1;  
        self.scoreState = self.ROLLING_FIRST_BALL;
      end   
    end
  end

  if (self.rollingFrame > self.finalFrameNumber) then
    ARDebugMessage("Game Over",5);
    HUD.SetFlashVariable(self.hud_scoreboard,"totalScore",""..self.totalScore.."");
    self.bGameIsOver = true;
  end
end
  1. add a score to the current frame total
function BowlingGame:AddFrame(toAdd)
  self.totalScore = self.totalScore + toAdd;                                    
  if (#(self.frameScores) < self.finalFrameNumber) then
    self.frameScores[#(self.frameScores) + 1] = self.totalScore; --(total score up to 1st unscored frame)
  end
  return self.totalScore;       
end
Problems with this wiki page? Contact us either by: Support Email or Support Ticket System

Blue Mars Guidebook Privacy Policy
Blue Mars Guidebook Community Guidelines

Personal tools