|
|
|
Asteroids game behaviour
Added on 4/29/2001
|
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
|
|