Contents
Articles
Behaviors
Books
Director News
Director Web Sites
FAQ
Games
Mailing Lists
News Groups
Project Examples
Reviews
Software
Tools
Useful Web Sites
Utilities
Xtras

Don't miss these
Overlay Dragger
goMU-LE (free)
Magnify-Alphamania
How to find all special system folders
Manipulating Date and Time using Lingo
Trim Function
Direct Media Balance Slider
Saving Global Variables to a File
authoring method docSprite()
DMFade
 

 

 

Behavior Asteroids game behaviour

Added on 4/29/2001

 

Compatibilities:
behavior D8 Mac PC Shockwave

Rating:

Author: BarrySwan (website)

Complete Asteroids game in a single behavior! Drop this behaviour onto a bitmap sprite and away you go!

Download PC Source    Download Mac Source
----------------------------------------------------------------------------------
-- Asteroids behaviour v1.0 22/04/01

-- Author: Barry Swan
-- Email:  gerbil@theburrow.co.uk
-- URL:    www.theburrow.co.uk

-- Drop this behaviour onto a bitmap sprite
-- Works on the sprite size, not the member
-- Should restore the bitmap member when finished with, but Director is buggy
-- calling endSprite upon exiting, so don't put anything important in the bitmap
-- member or keep a duplicate for easy restoration
----------------------------------------------------------------------------------

----------------------------------------------------------------------------------

------------------------------> Behaviour properties
property pAccelerate, pLeft, pRight, pFire
property pFGR, pFGG, pFGB, pFGColor
property pBGR, pBGG, pBGB, pBGColor

------------------------------>  Game properties
property pSN, pS, pM, pSRect, pSLoc, pSRegPoint
property piMember, pMRect, piM
property pGameRect, pW, pH, piGame
property plAsteroidGraphics
property plAsteroids
property pLevel
property pX, pY, pDX, pDY, pAngle
property piPlayer, pPlayerRect, plPlayer
property plBullets
property pScale
property pScore, pOldScore
property pLives
property pInvulnerability
property pMode
property piIntro, piGameOver
property pTimer

------------------------------>  Font properties
property plFontSmall, plFontBig
property piScoreText, pScoreTextRect
property piScore, pScoreRect
property piLivesText, pLivesTextRect
property piLives, pLivesRect

----------------------------------------------------------------------------------

------------------------------> Main game loop
on exitFrame me
  
  -- React to game state
  case pMode of
    #intro:
      
      -- Start game when fire is released
      if me.mKeyPressed(pFire) then
        repeat while me.mKeyPressed(pFire)
          nothing
        end repeat
        
        -- Set up game and prepare to play
        me.mSetUpLevel(1)
        pMode = #playing
      end if
    #gameover:
      
      -- Stay on game over screen for 3 seconds
      pTimer = pTimer - 1
      if pTimer <= 0 then
        piM.copyPixels(piIntro, pGameRect, pGameRect)
        pMode = #intro
      end if
    #playing:
      
      -- Update player
      me.mUpdatePlayer()
      
      -- Update asteroids
      tDied = me.mUpdateAsteroids()
      
      -- Update bullets
      me.mUpdateBullets()
      
      -- Check game status
      if tDied then
        pLives = pLives - 1
        if pLives < 0 then
          
          -- Game over code
          piM.copyPixels(piGameOver, pGameRect, pGameRect)
          pMode = #gameover
          pTimer = 100
          exit
        else
          
          -- Lost a life code
          pX = pW / 2
          pY = pH / 2
          pAngle = pi
          pDX = 0.0
          pDY = 0.0
          pInvulnerability = 40
          me.mDrawLives()
        end if
      else if plAsteroids = [] then me.mSetUpLevel(pLevel + 1)
      
      -- Update all graphics
      me.mDrawGame()
  end case
  
end

----------------------------------------------------------------------------------

------------------------------> Reacts to player input
on mUpdatePlayer me
  
  -- Reduce invulnerability
  if pInvulnerability then pInvulnerability = max(pInvulnerability - 1, 0)
  
  -- Rotate
  if me.mKeyPressed(pLeft) then pAngle = pAngle + 0.2
  else if me.mKeyPressed(pRight) then pAngle = pAngle - 0.2
  
  -- Accelerate / slow down
  if me.mKeyPressed(pAccelerate) then
    pDX = pDX + sin(pAngle) * 0.5
    pDY = pDY + cos(pAngle) * 0.5
  end if
  
  -- Move player
  pX = pX + pDX
  pY = pY + pDY
  
  -- Limit overall movement speed
  tSpeed = pDX * pDX + pDY * pDY
  if tSpeed > 100.0 then
    pDX = pDX * 100.0 / tSpeed
    pDY = pDY * 100.0 / tSpeed    
  end if
  
  -- Clip player
  if pX < 0.0 then pX = pX + pW
  else if pX >= pW then pX = pX - pW
  if pY < 0.0 then pY = pY + pH
  else if pY >= pH then pY = pY - pH
  
  -- Firing?
  if me.mKeyPressed(pFire) AND plBullets.count < 8 then
    tFX = sin(pAngle) * 7.0
    tFY = cos(pAngle) * 7.0
    tNewDX = pDX + tFX
    tNewDY = pDY + tFY
    plBullets.add([pX + tFX, pY + tFY, tNewDX, tNewDY, 20])
  end if
  
end

on mKeyPressed me, tKey
  
  -- Return key pressed state of tKey  
  case tKey of
    "UP CURSOR": return keyPressed(126)
    "DOWN CURSOR": return keyPressed(125)
    "LEFT CURSOR": return keyPressed(123)
    "RIGHT CURSOR": return keyPressed(124)
    "SHIFT": return the shiftDown
    otherwise: return keyPressed(tKey)
  end case
  
end

------------------------------> Moves asteroids and checks whether they hit the player
on mUpdateAsteroids me
  
  -- Move asteroids
  if plAsteroids <> [] then
    repeat with a in plAsteroids
      
      -- Move asteroid
      tSpeed = (4 - a[4])
      tAngle = a[3]
      tX = a[1]
      tY = a[2]
      tX = tX + sin(tAngle) * tSpeed
      tY = tY + cos(tAngle) * tSpeed
      
      -- Clip asteroid
      if tX < 0.0 then tX = tX + pW
      else if tX >= pW then tX = tX - pW
      if tY < 0.0 then tY = tY + pH
      else if tY >= pH then tY = tY - pH
      
      -- Collision with player (if not invulnerable)
      if pInvulnerability = 0 then
        tRadius = plAsteroidGraphics[a[4]][2] + 5
        tDX = pX - tX
        tDY = pY - tY
        if tDX * tDX + tDY * tDY <= tRadius * tRadius then return TRUE
      end if
      
      -- Store new position
      a[1] = tX
      a[2] = tY      
    end repeat
  end if
  
  -- Return normal message
  return FALSE
  
end

------------------------------> Moves bullets and checks whether they hit asteroids
on mUpdateBullets me
  
  -- Move bullets
  if plBullets <> [] then
    tCount = plBullets.count
    repeat while tCount
      
      -- Get bullet
      tlBullet = plBullets[tCount]
      
      -- Age bullet
      if tlBullet[5] <= 0 then plBullets.deleteAt(tCount)
      else
        tlBullet[5] = tlBullet[5] - 1
        
        -- Move bullet
        tAngle = tlBullet[3]
        tX = tlBullet[1] + tlBullet[3]
        tY = tlBullet[2] + tlBullet[4]
        
        -- Clip bullet
        if tX < 0.0 then tX = tX + pW
        else if tX >= pW then tX = tX - pW
        if tY < 0.0 then tY = tY + pH
        else if tY >= pH then tY = tY - pH
        
        -- Collisions with asteroids
        tAsteroid = plAsteroids.count
        tHit = FALSE
        repeat while tAsteroid
          
          -- Get asteroid value
          tlAsteroid = plAsteroids[tAsteroid]
          tAX = tlAsteroid[1]
          tAY = tlAsteroid[2]
          tRadius = plAsteroidGraphics[tlAsteroid[4]][2] + 2
          
          -- Did bullet hit?
          tDX = tAX - tX
          tDY = tAY - tY
          if tDX * tDX + tDY * tDY <= tRadius * tRadius then
            tHit = TRUE
            exit repeat
          end if
          
          -- Use next asteroid
          tAsteroid = tAsteroid - 1
        end repeat
        
        -- React to if bullet hit something
        if tHit then
          
          -- Remove bullet
          plBullets.deleteAt(tCount)
          
          -- Split or destroy asteroid
          tSize = tlAsteroid[4]
          
          -- Increase score according to size of asteroid
          pScore = pScore + [10, 3, 1][tSize]
          
          if tSize > 1 then
            
            -- Create two more smaller asteroids
            repeat with a = 1 to 2
              
              -- Create and alter properties of asteroids
              tlNewAsteroid = tlAsteroid.duplicate()
              tlNewAsteroid[4] = tSize - 1
              tlNewAsteroid[3] = tlNewAsteroid[3] + random(180) / 180.0 * pi() - pi() / 2.0
              
              -- Store in list
              plAsteroids.add(tlNewAsteroid)
            end repeat
          end if
          
          -- Remove asteroid
          plAsteroids.deleteAt(tAsteroid)
        else
          
          -- Position bullet
          tlBullet[1] = tX
          tlBullet[2] = tY
        end if
      end if
      
      -- Use next bullet
      tCount = tCount - 1
    end repeat
  end if
  
end

------------------------------> Actually draw everything into the member
on mDrawGame me
  
  -- Clear working bitmap
  piGame.fill(pGameRect, [#color: pBGColor])
  
  -- Draw player (if not flashing)
  if NOT pInvulnerability OR pInvulnerability mod 4 < 2 then
    
    -- Create rotated player
    piPlayer.fill(pPlayerRect, [#color: pBGColor])
    tPoints = plPlayer.count - 1
    tlPoint = plPlayer[1]
    tAngle = tlPoint[1] + pAngle
    tRadius = tlPoint[2]
    tp1 = point(\
        integer(sin(tAngle) * tRadius) + 12,\
        integer(cos(tAngle) * tRadius) + 12\
    )
    repeat with a = 1 to tPoints
      
      -- Find end point
      tlPoint = plPlayer[a + 1]
      tAngle = tlPoint[1] + pAngle
      tRadius = tlPoint[2]
      tp2 = point(\
          integer(sin(tAngle) * tRadius) + 12,\
          integer(cos(tAngle) * tRadius) + 12\
      )
      
      -- Draw line
      piPlayer.draw(tp1, tp2, [#color: pFGColor])
      
      -- New start point is previous end point
      tp1 = tp2
    end repeat
    
    -- Draw rotated player onscreen
    tX = pX - 12
    tY = pY - 12
    tDestRect = pPlayerRect + rect(tX, tY, tX, tY)
    me.mDrawGraphic(piPlayer, tDestRect, pPlayerRect)
  end if
  
  -- Draw bullets
  if plBullets <> [] then
    repeat with a in plBullets
      piGame.setPixel(a[1], a[2], pFGColor)
    end repeat
  end if
  
  -- Draw asteroids
  if plAsteroids <> [] then
    repeat with a in plAsteroids
      
      -- Get location
      tX = integer(a[1])
      tY = integer(a[2])
      
      -- Get required variables
      tlAsteroid = plAsteroidGraphics[a[4]]
      
      tRadius = tlAsteroid[2]
      tSourceRect = tlAsteroid[3]
      tDestRect = tSourceRect + rect(tX, tY, tX, tY) - tRadius
      
      -- Draw the asteroid
      me.mDrawGraphic(tlAsteroid[1], tDestRect, tSourceRect)
    end repeat
  end if
  
  -- Show score
  me.mDrawScore()
  
  tX = pW - pScoreRect.width - 5
  tDestRect = pScoreRect + rect(tX, 5, tX, 5)
  piGame.copyPixels(piScore, tDestRect, pScoreRect, [#ink: 36, #bgcolor: pBGColor])
  
  tX = tX - pScoreTextRect.width - 5
  tDestRect = pScoreTextRect + rect(tX, 5, tX, 5)
  piGame.copyPixels(piScoreText, tDestRect, pScoreTextRect, [#ink: 36, #bgcolor: pBGColor])
  
  -- Show lives
  tY = pH - pLivesRect.height - 5
  tDestRect = pLivesRect + rect(5, tY, 5, tY)
  piGame.copyPixels(piLives, tDestRect, pLivesRect, [#ink: 36, #bgcolor: pBGColor])
  
  tX = pLivesRect.width + 10
  tY = pH - pLivesTextRect.height - 5
  tDestRect = pLivesTextRect + rect(tX, tY, tX, tY)
  piGame.copyPixels(piLivesText, tDestRect, pLivesTextRect, [#ink: 36, #bgcolor: pBGColor])
  
  -- Copy to the member
  piM.copyPixels(piGame, pGameRect, pGameRect)
  
end

------------------------------> Update the score graphics
on mDrawScore me
  
  -- Only draws score if it's changed
  if pScore <> pOldScore then
    
    -- Convert score to string of 4 digits
    tScore = string(pScore)
    repeat while tScore.length < 4
      tScore = "0" & tScore
    end repeat
    
    -- Draw score into score graphic
    me.mText(plFontBig, piScore, 0, 0, tScore)
    
    -- Stops score being redrawn in future
    pOldScore = pScore
  end if
  
end

------------------------------> Update the lives graphics
on mDrawLives me
  
  -- Draw lives into lives graphic
  me.mText(plFontBig, piLives, 0, 0, string(pLives))
  
end

----------------------------------------------------------------------------------

------------------------------> Initialises the game
on beginSprite me
  
  -- Initialise director variables
  the randomSeed = the milliseconds
  
  -- Initialise colour properties
  pFGColor = rgb(pFGR, pFGG, pFGB)
  pBGColor = rgb(pBGR, pBGG, pBGB)
  
  -- Initialise fonts
  plFontSmall = me.mCreateFont(8, 12, pFGColor, pBGColor, #fixed)
  plFontBig = me.mCreateFont(16, 24, pFGColor, pBGColor, #fixed)
  
  -- Create text
  piScoreText = me.mText(plFontSmall, 0, 0, "SCORE")
  pScoreTextRect = piScoreText.rect
  piScore = me.mText(plFontBig, 0, 0, "0000")
  pScoreRect = piScore.rect
  
  piLivesText = me.mText(plFontSmall, 0, 0, "LIVES")
  pLivesTextRect = piLivesText.rect
  piLives = me.mText(plFontBig, 0, 0, "3")
  pLivesRect = piLives.rect
  
  -- Initialise sprite properties
  pSN = me.spriteNum
  pS = sprite(pSN)
  pSRect = pS.rect
  pSLoc = pS.loc
  pSRegPoint = pS.member.regpoint
  
  -- Initialise member properties
  pM = pS.member
  pMRect = pM.rect
  piMember = pM.image.duplicate()
  
  -- Initialise game properties
  pMode = #intro
  pGameRect = rect(0, 0, pSRect.width, pSRect.height)
  pW = pGameRect.width
  pH = pGameRect.height
  piGame = image(pGameRect.width, pGameRect.height, 16)
  
  piM = pM.image
  pM.image = image(pSRect.width, pSRect.height, 16)
  piM.fill(pGameRect, [#color: pBGColor])
  pS.rect = pSRect
  
  -- Create asteroid graphics
  plAsteroidGraphics = []
  repeat with a = 1 to 3
    
    -- Create asteroid images
    case a of
      1: tiAsteroid = image(8, 8, 16)
      2: tiAsteroid = image(32, 32, 16)
      3: tiAsteroid = image(64, 64, 16)
    end case
    
    -- Draw asteroids
    tAsteroidRect = tiAsteroid.rect    
    tiAsteroid.fill(tAsteroidRect, [#color: pBGColor])
    tRadius = tAsteroidRect.width / 2
    tp1 = point(tRadius, tRadius * 2)
    repeat with b = 0 to 15
      
      -- Alter radius
      if b < 15 then tNewRadius = random(tRadius / 4) + tRadius * 3 / 4
      else tNewRadius = tRadius
      
      -- Get angles for asteroid
      tAngle1 = (b / 8.0 * pi())
      tAngle2 = ((b + 1) / 8.0 * pi())
      
      -- Get points
      tp2 = point(\
          integer(sin(tAngle2) * (tNewRadius - 0.5)) + tRadius,\
          integer(cos(tAngle2) * (tNewRadius - 0.5)) + tRadius,\
      )
      
      -- Draw asteroid
      tiAsteroid.draw(tp1, tp2, [#color: pFGColor])      
      
      -- Store point for next loop
      tp1 = tp2
    end repeat
    
    -- Store data
    plAsteroidGraphics.add([tiAsteroid, tRadius, tAsteroidRect])
  end repeat
  
  -- Set up player
  plPlayer = [[0, 12], [pi() / 2, 6], [pi() * 2 / 3, 4], [pi() * 4 / 3, 4], [pi() * 3 / 2, 6], [0, 12]]
  piPlayer = image(24, 24, 16)
  pPlayerRect = rect(0, 0, 24, 24)
  
  -- Set up game
  pScale = max(pGameRect.width, pGameRect.height) / 2
  
  -- Set up miscellaneous screens
  me.mDrawIntro()
  me.mDrawGameOver()
  
  -- Show intro
  piM.copyPixels(piIntro, pGameRect, pGameRect)

end

------------------------------> Clears up the game after use
on endSprite me
  
  -- Restore member image
  pM.image = image(piMember.width, pMRect.height, piMember.depth)
  pM.image.copyPixels(piMember, pMRect, pMRect)
  pM.regpoint = pSRegPoint
  
  -- Restore sprite
  pS.loc = pSLoc
  pS.rect = pSRect
  
end

----------------------------------------------------------------------------------

------------------------------> Draws a graphic and wraps where necessary
on mDrawGraphic me, tiGraphic, tDestRect, tSourceRect
  
  -- Initialise variables  
  tL = tDestRect[1]
  tT = tDestRect[2]
  tR = tDestRect[3]
  tB = tDestRect[4]
  
  -- Draw member looped at edges as appropriate
  if tL < 0.0 then
    if tT < 0.0 then        
      piGame.copyPixels(tiGraphic, tDestRect, tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(pW, 0, pW, 0), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(0, pH, 0, pH), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(pW, pH, pW, pH), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
    else if tB > pH then
      piGame.copyPixels(tiGraphic, tDestRect, tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(pW, 0, pW, 0), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(0, -pH, 0, -pH), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(pW, -pH, pW, -pH), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
    else        
      piGame.copyPixels(tiGraphic, tDestRect, tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(pW, 0, pW, 0), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
    end if
  else if tR >= pW then
    if tT < 0.0 then        
      piGame.copyPixels(tiGraphic, tDestRect, tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(-pW, 0, -pW, 0), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(0, pH, 0, pH), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(-pW, pH, -pW, pH), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
    else if tB > pH then
      piGame.copyPixels(tiGraphic, tDestRect, tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(-pW, 0, -pW, 0), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(0, -pH, 0, -pH), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(-pW, -pH, -pW, -pH), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
    else        
      piGame.copyPixels(tiGraphic, tDestRect, tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(-pW, 0, -pW, 0), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
    end if
  else
    if tT < 0.0 then
      piGame.copyPixels(tiGraphic, tDestRect, tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(0, pH, 0, pH), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
    else if tB > pH then
      piGame.copyPixels(tiGraphic, tDestRect, tSourceRect, [#ink: 36, #bgcolor: pBGColor])
      piGame.copyPixels(tiGraphic, tDestRect + rect(0, -pH, 0, -pH), tSourceRect, [#ink: 36, #bgcolor: pBGColor])
    else
      piGame.copyPixels(tiGraphic, tDestRect, tSourceRect, [#ink: 36, #bgcolor: pBGColor])
    end if
  end if      
  
end

------------------------------> Sets up a level as appropriate
on mSetUpLevel me, tLevel
  
  -- Initialise variables  
  pLevel = tLevel
  pX = pGameRect.width / 2
  pY = pGameRect.height / 2
  pDX = 0.0
  pDY = 0.0
  pAngle = pi
  pSpeed = 0
  if tLevel = 1 then
    pLives = 3
    pScore = 0
    me.mDrawScore()
    me.mDrawLives()
  else if tLevel mod 3 = 0 then
    pLives = min(pLives + 1, 9)
    me.mDrawLives()
  end if
  
  -- Initialise asteroids
  plAsteroids = []
  repeat with a = 1 to tLevel
    
    -- Get initialisation variables
    tAngle = random(360) / 180.0 * pi()
    tX = sin(tAngle) * pScale / 2 + pScale
    tY = cos(tAngle) * pScale / 2 + pScale
    
    -- Store variables
    plAsteroids.add([tX, tY, tAngle, 3])
  end repeat  
  
  -- Initialise bullets
  plBullets = []
  
end

------------------------------> Draws the intro screen
on mDrawIntro me
  
  -- Create member
  piIntro = image(pGameRect.width, pGameRect.height, 16)
  
  -- Clear working bitmap
  piIntro.fill(pGameRect, [#color: pBGColor])
  
  -- Draw random stars
  repeat with a = 1 to 100    
    piIntro.setPixel(random(pW), random(pH), pFGColor)
  end repeat
  
  -- Show text
  me.mCenterText(plFontBig, piIntro, 20, "ASTEROIDS")
  me.mCenterText(plFontSmall, piIntro, 90, "ACCELERATE =" && pAccelerate && "KEY", 1)
  me.mCenterText(plFontSmall, piIntro, 110, "ROTATE LEFT =" && pLeft && "KEY", 1)
  me.mCenterText(plFontSmall, piIntro, 130, "ROTATE RIGHT =" && pRight && "KEY", 1)
  me.mCenterText(plFontSmall, piIntro, 150, "FIRE =" && pFire && "KEY", 1)
  me.mCenterText(plFontSmall, piIntro, 200, "PRESS FIRE TO START", 1)
  
end

------------------------------> Draws the game over screen
on mDrawGameOver me
  
  -- Create member
  piGameOver = image(pGameRect.width, pGameRect.height, 16)
  
  -- Clear working bitmap
  piGameOver.fill(pGameRect, [#color: pBGColor])
  
  -- Draw random stars
  repeat with a = 1 to 100    
    piGameOver.setPixel(random(pW), random(pH), pFGColor)
  end repeat
  
  -- Show text
  me.mCenterText(plFontBig, piGameOver, pH / 2, "GAME OVER")
  
end

----------------------------------------------------------------------------------

------------------------------> Create a font
on mCreateFont me, tW, tH, tFGColor, tBGColor, tStyle
  
  -- Create font list
  tlFont = [#style: tStyle, #width: tW, #height: tH, #bgcolor: tBGColor, #font: [:]]
  
  -- Create letters
  tCharsToCreate = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ .,\/=-"
  tChars = tCharsToCreate.length
  repeat with a = 1 to tChars
    
    -- Set up character variables
    tChar = tCharsToCreate.char[a]
    tlChar = []
    
    -- Get data for character
    case tChar of
        
        -- Numbers
      "0": tlCharData = [[[0, 0], [1, 0]], [[1, 1]], [[0, 1]], [[0, 0]], [[1, 0], [0, 1]]]        
      "1": tlCharData = [[[0.5, 0], [0.5, 1]]]
      "2": tlCharData = [[[0, 0], [0.75, 0]], [[1, 0.25]], [[0, 1]], [[1, 1]]]        
      "3": tlCharData = [[[0.25, 0], [1, 0.5]], [[0.25, 1]], [[0, 0.5], [1, 0.5]]]        
      "4": tlCharData = [[[0.75, 1], [0.75, 0]], [[0, 0.75]], [[1, 0.75]]]        
      "5": tlCharData = [[[1, 0], [0, 0]], [[0, 0.25]], [[1, 0.25]], [[0, 1]]]        
      "6": tlCharData = [[[0.5, 0], [0, 1]], [[1, 1]], [[0.25, 0.5]]]        
      "7": tlCharData = [[[0, 0], [1, 0]], [[0.5, 1]]]        
      "8": tlCharData = [[[0, 0], [1, 0]], [[0, 1]], [[1, 1]], [[0, 0]]]        
      "9": tlCharData = [[[0.5, 1], [1, 0]], [[0, 0]], [[0.75, 0.5]]]
        
        -- Characters
      "A": tlCharData = [[[0, 1], [0.5, 0]], [[1, 1]], [[0.25, 0.5], [0.75, 0.5]]]
      "B": tlCharData = [[[0, 0], [1, 0]], [[0, 0.5]], [[1, 1]], [[0, 1]], [[0, 0]]]
      "C": tlCharData = [[[1, 0], [0, 0.5]], [[1, 1]]]
      "D": tlCharData = [[[0, 0], [1, 0.5]], [[0, 1]], [[0, 0]]]
      "E": tlCharData = [[[1, 0], [0, 0.5]], [[1, 1]], [[0, 0.5], [1, 0.5]]]
      "F": tlCharData = [[[1, 0], [0, 0]], [[0, 1]], [[0, 0.5], [1, 0.5]]]
      "G": tlCharData = [[[1, 0], [0, 0.5]], [[1, 1]], [[1, 0.5]]]
      "H": tlCharData = [[[0, 0], [0, 1]], [[0, 0.5], [1, 0.5]], [[1, 0], [1, 1]]]
      "I": tlCharData = [[[0.5, 0], [0.5, 1]]]
      "J": tlCharData = [[[0, 0], [1, 0]], [[1, 0.5]], [[0, 1]]]
      "K": tlCharData = [[[0, 0], [0, 1]], [[1, 0], [0, 0.5]], [[1, 1]]]
      "L": tlCharData = [[[0, 0], [0, 1]], [[1, 1]]]
      "M": tlCharData = [[[0, 1], [0, 0]], [[0.5, 0.5]], [[1, 0]], [[1, 1]]]
      "N": tlCharData = [[[0, 1], [0, 0]], [[1, 1]], [[1, 0]]]
      "O": tlCharData = [[[0, 0], [1, 0]], [[1, 1]], [[0, 1]], [[0, 0]]]        
      "P": tlCharData = [[[0, 1], [0, 0]], [[1, 0.5]], [[0, 0.5]]]
      "Q": tlCharData = [[[0, 0], [1, 0]], [[1, 1]], [[0, 1]], [[0, 0]], [[0.5, 0.5], [1, 1]]]        
      "R": tlCharData = [[[0, 1], [0, 0]], [[1, 0.5]], [[0, 0.5]], [[1, 1]]]
      "S": tlCharData = [[[1, 0], [0, 0.5]], [[1, 0.5]], [[0, 1]]]
      "T": tlCharData = [[[0, 0], [1, 0]], [[0.5, 0], [0.5, 1]]]
      "U": tlCharData = [[[0, 0], [0, 1]], [[1, 1]], [[1, 0]]]
      "V": tlCharData = [[[0, 0], [0.5, 1]], [[1, 0]]]
      "W": tlCharData = [[[0, 0], [0.25, 1]], [[0.5, 0.5]], [[0.75, 1]], [[1, 0]]]
      "X": tlCharData = [[[0, 0], [1, 1]], [[1, 0], [0, 1]]]
      "Y": tlCharData = [[[1, 0], [1, 0.5]], [[0, 1]], [[0, 0], [1, 0.5]]]
      "Z": tlCharData = [[[0, 0], [1, 0]], [[0, 1]], [[1, 1]]]
        
        -- Punctuation
      ".": tlCharData = [[[0.5, 1], [0.5, 1]]]
      ",": tlCharData = [[[0.5, 0.75], [0.5, 1]]]
      "\": tlCharData = [[[0, 0], [1, 1]]]
      "/": tlCharData = [[[0, 1], [1, 0]]]
      "=": tlCharData = [[[0, 0.33], [1, 0.33]], [[0, 0.66], [1, 0.66]]]
      "-": tlCharData = [[[0, 0.5], [1, 0.5]]]
        
        -- Miscellaneous
      " ": -- No graphics is drawn        
    end case
    
    -- Set width according to fixed width or proportional
    if tStyle = #fixed then tCW = tW
    else
      
      -- Get width for character
      case tChar of
        "1", "I", ".", ",": tCW = 0.0
        "=", "-": tCW = 0.75
        "M", "W": tCW = 1.5
        " ": tCW = 0.5
        otherwise: tCW = 1.0    
      end case
      
      tCW = max(integer(tCW * tW), 1)
    end if
    
    -- Create character graphic
    tiChar = image(tCW, tH, 32)
    tCharRect = rect(0, 0, tCW, tH)
    tiChar.fill(tCharRect, [#color: tBGColor])
    
    -- Draw the character
    if tChar <> " " then
      tFW = tCW - 1
      tFH = tH - 1
      tpEnd = point(0, 0)
      repeat with b in tlCharData
        
        -- Is this a complete line or following on from the previous one?
        if b.count = 2 then
          tStart = b[1]
          tpStart = point(\
            integer(tStart[1] * tFW - 0.49),\
            integer(tStart[2] * tFH - 0.49)\
        )
          tEnd = b[2]
        else
          tpStart = tpEnd
          tEnd = b[1]
        end if
        
        -- Process end point
        tpEnd = point(\
            integer(tEnd[1] * tFW - 0.49),\
            integer(tEnd[2] * tFH - 0.49)\
        )
        
        -- Draw line
        tiChar.draw(tpStart, tpEnd, [#color: tFGColor])
      end repeat
    end if
    
    -- Save character list
    tlFont.font[tChar] = [tiChar, tCharRect, tCW]
  end repeat
  
  -- Return new font object
  return tlFont
  
end

------------------------------> Writes text into a buffer
on mText me, tlFont, tiImage, tX, tY, tText, tGap, tInk
  
  -- Set font reference for speed
  tlFontChars = tlFont.font
  
  -- Set parameters if missed
  if NOT objectP(tiImage) then
    tInk = tGap
    tGap = tText
    tText = tY
    tY = tX
    tX = tiImage
    tNeedBuffer = TRUE
  else tNeedBuffer = FALSE
  
  if voidP(tInk) then
    
    -- Set ink and gap if missing
    if integerP(tGap) then tInk = #copy
    else if symbolP(tGap) then
      tInk = tGap
      tGap = 2
    else
      tInk = #copy
      tGap = 2
    end if
  end if
  
  -- Convert string to uppercase
  tChars = tText.length
  repeat with a = 1 to tChars
    
    -- Get ASCII code of char
    tASCII = charToNum(tText.char[a])
    
    -- Convert lower case letters to upper case
    if tASCII >= 97 AND tASCII <= 122 then put numToChar(tASCII - 32) into tText.char[a]
  end repeat
  
  -- Create new buffer for text
  if tNeedBuffer then
    
    -- Loop through string
    tW = 0
    repeat with a = 1 to tChars
      
      -- Get character
      tChar = tText.char[a]
      
      -- Get character width
      tlChar = tlFontChars.getAProp(tChar)
      if NOT voidP(tlChar) then tW = tW + tlChar[3] + tGap
    end repeat
    
    -- Create buffer
    tW = tW - tGap
    tH = tlFont.height
    tiImage = image(tW, tH, 16)
    tiImage.fill(rect(0, 0, tW, tH), [#color: tlFont.bgcolor])
    
    -- Alter parameters as required
    tInk = #copy
    tX = 0
    tY = 0
  end if
  
  -- Store background color reference for speed if required
  if tInk = #transparent then tBGColor = tlFont.bgcolor
  
  -- Loop through string
  repeat with a = 1 to tChars
    
    -- Get character
    tChar = tText.char[a]
    
    -- Get character data
    tlChar = tlFontChars.getAProp(tChar)
    if NOT voidP(tlChar) then
      
      -- Copy to image
      tSourceRect = tlChar[2]
      tDestRect = tSourceRect + rect(tX, tY, tX, tY)
      
      if tInk = #copy then tiImage.copyPixels(tlChar[1], tDestRect, tSourceRect)
      else tiImage.copyPixels(tlChar[1], tDestRect, tSourceRect, [#ink: 36, #bgcolor: tBGColor])
      
      -- Shift next character
      tX = tX + tlChar[3] + tGap
    end if
  end repeat
  
  -- Return new image pointer if created
  if tNeedBuffer then return tiImage
  
end

------------------------------> Centers text into a buffer
on mCenterText me, tlFont, tiImage, tX, tY, tText, tGap, tInk
  
  -- Allow for missing parameters
  if stringP(tY) then
    tInk = tGap
    tGap = tText
    tText = tY
    tY = tX
    tX = tiImage.rect.width / 2
  end if
  
  if voidP(tInk) then
    
    -- Set ink if missing
    if integerP(tGap) then tInk = #copy
    else if symbolP(tGap) then tInk = tGap
    else tInk = #copy
  end if
  
  if voidP(tGap) then tGap = 2
  
  -- Create text
  tiText = me.mText(tlFont, 0, 0, tText, tGap, tInk)
  
  -- Draw text
  tTextRect = tiText.rect
  tX = tX - tTextRect.width / 2
  tDestRect = tTextRect + rect(tX, tY, tX, tY)  
  if tInk = #copy then tiImage.copyPixels(tiText, tDestRect, tTextRect)
  else tiImage.copyPixels(tiText, tDestRect, tTextRect, [#ink: 36, #bgcolor: tlFont.bgcolor])
  
end

----------------------------------------------------------------------------------

------------------------------> Prevents behaviour being attached to inappropriate sprite
on IsOkToAttach me, tSType, tSN
  
  -- Only attach to valid sprites
  if tSN >= 1 then
    if tSType = #graphic AND sprite(tSN).member.type = #bitmap then return TRUE
  end if
  
  -- Return false
  return FALSE
  
end

------------------------------> Set parameters when behaviour is set
on getPropertyDescriptionList me
  
  -- Set up data
  tlData = [:]
  
  -- Set up valid keys
  tKeys = "abcdefghijklmnopqrstuvwxyz"
  tlKeys = []
  tlKeys.add("UP CURSOR")
  tlKeys.add("DOWN CURSOR")
  tlKeys.add("LEFT CURSOR")
  tlKeys.add("RIGHT CURSOR")
  tlKeys.add("SHIFT")
  repeat with a = 1 to tKeys.length
    tlKeys.add(tKeys.char[a])
  end repeat
  
  -- Controls
  tlData[#pAccelerate] = [\
      #format: #string,\
      #default: "UP CURSOR",\
      #range: tlKeys,\
      #comment: "Key to accelerate:"\
  ]  
  tlData[#pLeft] = [\
      #format: #string,\
      #default: "LEFT CURSOR",\
      #range: tlKeys,\
      #comment: "Key to rotate counter-clockwise:"\
  ]  
  tlData[#pRight] = [\
      #format: #string,\
      #default: "RIGHT CURSOR",\
      #range: tlKeys,\
      #comment: "Key to rotate clockwise:"\
  ]  
  tlData[#pFire] = [\
      #format: #string,\
      #default: "SHIFT",\
      #range: tlKeys,\
      #comment: "Key to fire:"\
  ]  
  
  -- Foreground colour
  tlData[#pFGR] = [\
      #format: #integer,\
      #default: 255,\
      #range: [#min:0, #max: 255],\
      #comment: "Foreground RED component:"\
  ]  
  tlData[#pFGG] = [\
      #format: #integer,\
      #default: 255,\
      #range: [#min:0, #max: 255],\
      #comment: "Foreground GREEN component:"\
  ]  
  tlData[#pFGB] = [\
      #format: #integer,\
      #default: 255,\
      #range: [#min:0, #max: 255],\
      #comment: "Foreground BLUE component:"\
  ]  
  
  -- Background colour
  tlData[#pBGR] = [\
      #format: #integer,\
      #default: 0,\
      #range: [#min:0, #max: 255],\
      #comment: "Background RED component:"\
  ]  
  tlData[#pBGG] = [\
      #format: #integer,\
      #default: 0,\
      #range: [#min:0, #max: 255],\
      #comment: "Background GREEN component:"\
  ]  
  tlData[#pBGB] = [\
      #format: #integer,\
      #default: 0,\
      #range: [#min:0, #max: 255],\
      #comment: "Background BLUE component:"\
  ]  
  
  -- Return options
  return tlData
  
end

------------------------------> Returns description of behaviour in behaviour inspector
on getBehaviorDescription me
  
  -- Set information text
  tText = "Asteroids behaviour v1.0 22/04/01" & RETURN & RETURN
  
  tText = tText & "Author: Barry Swan" & RETURN
  tText = tText & "Email:  gerbil@theburrow.co.uk" & RETURN
  tText = tText & "URL:    www.theburrow.co.uk" & RETURN & RETURN
  
  tText = tText & "Drop this behaviour onto a bitmap sprite" & RETURN
  tText = tText & "Works on the sprite size, not the member" & RETURN
  tText = tText & "Should restore the bitmap member when finished with, but Director is buggy"
  tText = tText & "calling endSprite upon exiting, so don't put anything important in the bitmap"
  tText = tText & "member or keep a duplicate for easy restoration"
  
  -- Return information
  return tText
  
end

 


Contact

MMI
36 South Court Sq
Suite 300
Newnan, GA 30263
USA

Send e-mail