Mark Dixon Page 1
12 – Functions and Modules
Mark Dixon Page 2
Questions: Parameters• Name a parameter in the following code:
Sub Move(ByRef obj, ByVal dist) obj.style.pixelLeft = obj.style.pixelLeft + dist obj.style.pixelTop = obj.style.pixelTop + distEnd Sub
Move imgShip, 25
• Name a formal parameter
• Name an actual parameter
objdist
imgShip
25
imgShip
25
objdist
Mark Dixon Page 3
Session Aims & Objectives• Aims, to introduce:
– the idea of a function as a way to make code shorter and easier to understand
– the idea of modules as a way to split up large programs and share code between pages
• Objectives,by end of this week’s sessions, you should be able to:
– create your own function definitions– call these functions– appropriately split a program into multiple
modules– reuse modules in several pages/programs
Mark Dixon Page 4
Example: Interceptor (analysis)SPECIFICATION
• User Requirements – to be entertained
• Software Requirements– Functional:
–display image of space ship, which can be moved using the left and right arrow keys
–display images of asteroids, which the user must block using the space ship (thereby gaining points)
– Non-functionalshould be playable in real time
Mark Dixon Page 5
Example: Interceptor (design)• Computer games & simulations work like
board games:
Mark Dixon Page 6
Problem Solving: Collision Detection
• 2 types of problem:– familiar (seen before –
remember solution)– novel (work out solution)
• generate algorithm:– solve it on paper– draw diagrams– work through possibilities– ask how did I do that– what steps did I take?
Mark Dixon Page 7
Example: Interceptor v1 (code)Option ExplicitDim xIncDim score
Sub window_OnLoad() Randomize imgShip.style.pixelTop = document.body.clientheight - imgShip.height imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) xInc = 0 score = 0 window.setInterval "Main", 20 End Sub
Sub document_OnKeyDown() Select Case window.event.keyCode Case 37 xInc = xInc + 2 Case 39 xInc = xInc - 2 End Select End Sub
Sub Main Dim nxt nxt = imgShip.style.pixelLeft - xInc If nxt < 0 Or nxt > document.body.clientWidth - imgShip.width Then xInc = -xInc Else imgShip.style.pixelLeft = nxt End If
imgAst1.style.pixelTop = imgAst1.style.pixelTop + 4 If (imgAst1.style.pixelTop + imgAst1.height) > document.body.clientheight Then imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If
If imgAst1.style.pixelTop + imgAst1.height > imgShip.style.pixelTop Then If imgAst1.style.pixelLeft + imgAst1.width > imgShip.style.pixelLeft Then If imgAst1.style.pixelLeft < imgShip.style.pixelLeft + imgShip.width Then score = score + 1 parScore.innerText = "Score: " & score imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If End If End If End Sub
Sub window_OnLoad() Randomize imgShip.style.pixelTop = document.body.clientheight - imgShip.height imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) xInc = 0 score = 0 window.setInterval "Main", 20 End Sub
Mark Dixon Page 8
Example: Interceptor v1 (code)Option ExplicitDim xIncDim score
Sub window_OnLoad() Randomize imgShip.style.pixelTop = document.body.clientheight - imgShip.height imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) xInc = 0 score = 0 window.setInterval "Main", 20 End Sub
Sub document_OnKeyDown() Select Case window.event.keyCode Case 37 xInc = xInc + 2 Case 39 xInc = xInc - 2 End Select End Sub
Sub Main Dim nxt nxt = imgShip.style.pixelLeft - xInc If nxt < 0 Or nxt > document.body.clientWidth - imgShip.width Then xInc = -xInc Else imgShip.style.pixelLeft = nxt End If
imgAst1.style.pixelTop = imgAst1.style.pixelTop + 4 If (imgAst1.style.pixelTop + imgAst1.height) > document.body.clientheight Then imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If
If imgAst1.style.pixelTop + imgAst1.height > imgShip.style.pixelTop Then If imgAst1.style.pixelLeft + imgAst1.width > imgShip.style.pixelLeft Then If imgAst1.style.pixelLeft < imgShip.style.pixelLeft + imgShip.width Then score = score + 1 parScore.innerText = "Score: " & score imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If End If End If End Sub
Sub document_OnKeyDown() Select Case window.event.keyCode Case 37 xInc = xInc + 2 Case 39 xInc = xInc - 2 End Select End Sub
Mark Dixon Page 9
Example: Interceptor v1 (code)Option ExplicitDim xIncDim score
Sub window_OnLoad() Randomize imgShip.style.pixelTop = document.body.clientheight - imgShip.height imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) xInc = 0 score = 0 window.setInterval "Main", 20 End Sub
Sub document_OnKeyDown() Select Case window.event.keyCode Case 37 xInc = xInc + 2 Case 39 xInc = xInc - 2 End Select End Sub
Sub Main Dim nxt nxt = imgShip.style.pixelLeft - xInc If nxt < 0 Or nxt > document.body.clientWidth - imgShip.width Then xInc = -xInc Else imgShip.style.pixelLeft = nxt End If
imgAst1.style.pixelTop = imgAst1.style.pixelTop + 4 If (imgAst1.style.pixelTop + imgAst1.height) > document.body.clientheight Then imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If
If imgAst1.style.pixelTop + imgAst1.height > imgShip.style.pixelTop Then If imgAst1.style.pixelLeft + imgAst1.width > imgShip.style.pixelLeft Then If imgAst1.style.pixelLeft < imgShip.style.pixelLeft + imgShip.width Then score = score + 1 parScore.innerText = "Score: " & score imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If End If End If End Sub
Sub MainDim nxt nxt = imgShip.style.pixelLeft - xInc If nxt < 0 Or nxt > document.body.clientWidth - imgShip.width Then xInc = -xInc Else imgShip.style.pixelLeft = nxt End If
imgAst1.style.pixelTop = imgAst1.style.pixelTop + 4 If (imgAst1.style.pixelTop + imgAst1.height) > document.body.clientheight Then imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If
If imgAst1.style.pixelTop + imgAst1.height > imgShip.style.pixelTop Then If imgAst1.style.pixelLeft + imgAst1.width > imgShip.style.pixelLeft Then If imgAst1.style.pixelLeft < imgShip.style.pixelLeft + imgShip.width Then score = score + 1 parScore.innerText = "Score: " & score imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If End If End IfEnd Sub
Mark Dixon Page 10
Example: Interceptor (user interface)
Mark Dixon Page 11
Problem: Repeated Calculations• implementation (code)
– more complicated than algorithm– technical detail (how)
If imgAst1.style.pixelTop + imgAst1.height > imgShip.style.pixelTop Then If imgAst1.style.pixelLeft + imgAst1.width > imgShip.style.pixelLeft Then If imgAst1.style.pixelLeft < imgShip.style.pixelLeft + imgShip.width Then score = score + 1 parScore.innerText = "Score: " & score imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If End IfEnd If
e.g. right = left + width
Mark Dixon Page 12
Procedures and Functions• Both Procedures and Functions
– Group of statements– Identified by unique name– mirror real life activities
• Procedures – just do something
• Functions – return a value– used to perform calculations
Mark Dixon Page 13
Built in Functions• Sqr – gives square root of a number:
Sqr(16) returns 4
Sqr(9) returns 3
Sqr(4) returns 2
• Rnd() – generates random numbers between 0 and 0.99999999…
• Right, Mid, Left …
Mark Dixon Page 14
User Defined Functions (how)
• Syntax very similar to procedure definition: Function name(parameters) Statementblock name = value End Function
• where– name represents function’s name (you choose)– parameters represent information needed– value represent the return value
Mark Dixon Page 15
Functions: FtoC
• The declaration:
Function FtoC(F)
FtoC = ((f-32) * 5) / 9
End Function
• The call: parRes.innerText = FtoC(50)
Mark Dixon Page 16
Functions: Fahrenheit to Celsius
Mark Dixon Page 17
Functions: Largest• What will first and second contain?
Mark Dixon Page 18
• Consider the following function definition: Function Twice(num)
Twice = num * 2
End Function
• What do the following return: Twice(6)
Dim b
b = 12
Twice(b)
Questions: Functions
12
24
Mark Dixon Page 19
Example: Interceptor v2• Function makes code easier to read (closer
to pseudo-code / algorithm):
If imgAst1.style.pixelTop + imgAst1.height > imgShip.style.pixelTop Then If pixelRight(imgAst1) > imgShip.style.pixelLeft Then If imgAst1.style.pixelLeft < pixelRight(imgShip) Then score = score + 1 parScore.innerText = "Score: " & score imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If End If End If End Sub
Function pixelRight(obj) pixelRight = obj.style.pixelLeft + obj.width End Function
Mark Dixon Page 20
Question: Function Headers• Write the first line of a function definition to
convert pounds to euros:
• Write the first line of a function definition to convert minutes and hours to minutes:
Function Minutes(Mins, Hours)
Function Euros(Pounds)
Mark Dixon Page 21
Example: Interceptor v3 If ShipCollide(imgAst1) Then score = score + 1 parScore.innerText = "Score: " & score imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If
Function ShipCollide(obj1) ShipCollide = False If obj1.style.pixelTop + obj1.height > imgShip.style.pixelTop Then If pixelRight(obj1) > imgShip.style.pixelLeft Then If obj1.style.pixelLeft < pixelRight(imgShip) Then ShipCollide = True End If End If End If End Function
Function pixelRight(obj) pixelRight = obj.style.pixelLeft + obj.width End Function
Mark Dixon Page 22
Question: Functions• Write a function that converts kilometres to
miles (multiply the number of kilometres by 1.6 to get miles):
Function Miles(km)
Miles = km * 1.6
End Function
Mark Dixon Page 23
Functions: Total
Mark Dixon Page 24
Problem: InterceptorOption ExplicitDim xIncDim score
Sub window_OnLoad() Randomize imgShip.style.pixelTop = document.body.clientheight - imgShip.height imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) xInc = 0 score = 0 window.setInterval "Main", 20 End Sub
Sub document_OnKeyDown() Select Case window.event.keyCode Case 37 xInc = xInc + 2 Case 39 xInc = xInc - 2 End Select End Sub
Sub Main Dim nxt nxt = imgShip.style.pixelLeft - xInc If nxt < 0 Or nxt > document.body.clientWidth - imgShip.width Then xInc = -xInc Else imgShip.style.pixelLeft = nxt End If
imgAst1.style.pixelTop = imgAst1.style.pixelTop + 4 If (imgAst1.style.pixelTop + imgAst1.height) > document.body.clientheight Then imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If
If imgAst1.style.pixelTop + imgAst1.height > imgShip.style.pixelTop Then If imgAst1.style.pixelLeft + imgAst1.width > imgShip.style.pixelLeft Then If imgAst1.style.pixelLeft < imgShip.style.pixelLeft + imgShip.width Then score = score + 1 parScore.innerText = "Score: " & score imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If End If End If End Sub
Option ExplicitDim xIncDim score
Sub window_OnLoad() Randomize imgShip.style.pixelTop = document.body.clientheight - imgShip.height imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) xInc = 0 score = 0 window.setInterval "Main", 20 End Sub
Sub document_OnKeyDown() Select Case window.event.keyCode Case 37 xInc = xInc + 2 Case 39 xInc = xInc - 2 End Select End Sub
Sub Main Dim nxt nxt = imgShip.style.pixelLeft - xInc If nxt < 0 Or nxt > document.body.clientWidth - imgShip.width Then xInc = -xInc Else imgShip.style.pixelLeft = nxt End If
imgAst1.style.pixelTop = imgAst1.style.pixelTop + 4 If (imgAst1.style.pixelTop + imgAst1.height) > document.body.clientheight Then imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If
If ShipCollide(imgAst1) Then score = score + 1 parScore.innerText = "Score: " & score imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If End Sub
Function ShipCollide(obj1) ShipCollide = False If obj1.style.pixelTop + obj1.height > imgShip.style.pixelTop Then If pixelRight(obj1) > imgShip.style.pixelLeft Then If obj1.style.pixelLeft < pixelRight(imgShip) Then ShipCollide = True End If End If End If End Function
Function pixelRight(obj) pixelRight = obj.style.pixelLeft + obj.width End Function
• Code is longer(but easier to read)
Mark Dixon Page 25
Modules• Projects can contain many modules/units
– web pages (*.htm)– vb script file (*.vbs)
• Modules– divide your code into separate parts– available to other pages and modules, using:
<script language=vbscript src=Interceptor.vbs></script>
Mark Dixon Page 26
Example: Interceptor v4<script language=vbscript src=Interceptor.vbs></script><script language=vbscript>Option ExplicitDim xIncDim score
Sub window_OnLoad() Randomize imgShip.style.pixelTop = document.body.clientheight - imgShip.height imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) xInc = 0 score = 0 window.setInterval "Main", 20 End Sub
Sub document_OnKeyDown() Select Case window.event.keyCode Case 37 xInc = xInc + 2 Case 39 xInc = xInc - 2 End Select End Sub
Sub Main Dim nxt nxt = imgShip.style.pixelLeft - xInc If nxt < 0 Or nxt > document.body.clientWidth - imgShip.width Then xInc = -xInc Else imgShip.style.pixelLeft = nxt End If
imgAst1.style.pixelTop = imgAst1.style.pixelTop + 4 If (imgAst1.style.pixelTop + imgAst1.height) > document.body.clientheight Then imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If
If ShipCollide(imgAst1) Then score = score + 1 parScore.innerText = "Score: " & score imgAst1.style.pixelTop = 0 imgAst1.style.pixelLeft = Rnd() * (document.body.clientWidth - imgAst1.width) End If End Sub</script>
Function ShipCollide(obj1) ShipCollide = False If obj1.style.pixelTop + obj1.height > imgShip.style.pixelTop Then If pixelRight(obj1) > imgShip.style.pixelLeft Then If obj1.style.pixelLeft < pixelRight(imgShip) Then ShipCollide = True End If End If End IfEnd Function
Function pixelRight(obj) pixelRight = obj.style.pixelLeft + obj.widthEnd Function
• vb script file (module) holds functions and general procedures
Interceptor.htm
Interceptor.vbs
Mark Dixon Page 27
Example: Interceptor v5<script language=vbscript src=Interceptor.vbs></script><script language=vbscript>Option ExplicitDim xIncDim score
Sub window_OnLoad() Randomize MoveToBottom imgShip MoveRndHor imgAst1 xInc = 0 score = 0 window.setInterval "Main", 20 End Sub
Sub document_OnKeyDown() Select Case window.event.keyCode Case 37 xInc = xInc + 2 Case 39 xInc = xInc - 2 End Select End Sub
Sub Main MoveShip
MoveDown imgAst1, 4 If AtBottom(imgAst1) Then MoveRndHor imgAst1 End If
If HitShip(imgAst1) Then IncreaseScore MoveRndHor imgAst1 End If End Sub</script>
Sub MoveToBottom(obj) obj.style.pixelTop = document.body.clientHeight - obj.heightEnd Sub
Sub MoveRndHor(obj) obj.style.pixelTop = 0 obj.style.pixelLeft = Rnd() * (document.body.clientWidth - obj.width)End Sub
Sub MoveDown(obj, dist) obj.style.pixelTop = obj.style.pixelTop + distEnd Sub
Function HitShip(obj) HitShip = False If obj.style.pixelTop + obj.height > imgShip.style.pixelTop Then If pixelRight(obj) > imgShip.style.pixelLeft Then If obj.style.pixelLeft < pixelRight(imgShip) Then HitShip = True End If End If End IfEnd Function
Function pixelRight(obj) pixelRight = obj.style.pixelLeft + obj.widthEnd Function
Function AtBottom(obj) AtBottom = (obj.style.pixelTop + obj.height) > document.body.clientheightEnd Function
Sub IncreaseScore() score = score + 1 parScore.innerText = "Score: " & scoreEnd Sub
Sub MoveShip()Dim nxt nxt = imgShip.style.pixelLeft - xInc If nxt < 0 Or nxt > document.body.clientWidth - imgShip.width Then xInc = -xInc Else imgShip.style.pixelLeft = nxt End IfEnd Sub
Mark Dixon Page 28
Example: Interceptor v5• Main code reads almost like algorithm:
Sub Main MoveShip
MoveDown imgAst1, 2 If AtBottom(imgAst1) Then MoveRndHor imgAst1 End If
If HitShip(imgAst1) Then IncreaseScore MoveRndHor imgAst1 End If End Sub
Sub Main MoveShip
MoveDown imgAst1, 4 If AtBottom(imgAst1) Then MoveRndHor imgAst1 End If
If HitShip(imgAst1) Then IncreaseScore MoveRndHor imgAst1 End If End Sub
Mark Dixon Page 29
Example: Interceptor v6• Functions and
Procedures
• benefits when code gets larger
• easy to add extra asteroid
Mark Dixon Page 30
Sharing Modules
• 2 pages can use same module:
Sub window_OnLoad() Dim ang Dim s Dim i s = "" For i = 1 To 12 s = s & "<div id=div" & i & " style=""position: absolute;"">" & i & "</div>" Next s = s & "<img id=imgMid style=""position: absolute;"" src=dot.gif />" For i = 1 To 18 s = s & "<img id=imgSec" & i & " style=""position: absolute;"" src=dot.gif />" Next document.body.innerHTML = s imgMid.style.pixelleft = document.body.clientwidth / 2 imgMid.style.pixeltop = document.body.clientheight / 2 ang = 6.2 / 12 For i = 1 To 12 Position document.body.children("div" & i), 200, ang * i Next window.setinterval "ShowHands", 500 End Sub
Sub ShowHands() Dim ang Dim s Dim i ang = 6.2 / 60 s = Second(Now()) For i = 1 To 18 Position document.body.children("imgSec" & i), i * 10, ang * s Next End Sub
Sub Position(objO, o, a) objO.style.pixelleft = imgMid.style.pixelleft + Sin(a) * o objO.style.pixeltop = imgMid.style.pixeltop - Cos(a) * o End Sub
Option Explicit Const orbit = 150 Dim ang Dim angInc Dim earthLft Dim earthTop Dim ang2 Sub Window_OnLoad() earthLft = imgEarth.style.pixelleft earthTop = imgEarth.style.pixeltop imgMoon.Style.PixelLeft = earthLft imgMoon.Style.PixelTop = earthTop + orbit window.SetInterval "MoonRotate", 50 ang = 0 angInc = 0.025 ang2 = 0 End Sub Sub MoonRotate() ang = ang + angInc imgMoon.Style.PixelLeft = earthLft + (Sin(ang) * orbit) imgMoon.Style.PixelTop = earthTop + (Cos(ang) * orbit) ang2 = ang2 - (angInc * 3) imgAstr.Style.PixelLeft = imgMoon.style.pixelleft + (Sin(ang2) * 50) imgAstr.Style.PixelTop = imgMoon.style.pixeltop + (Cos(ang2) * 50) End Sub
Clock Orbit
Mark Dixon Page 31
Tutorial Exercises: Interceptor• LEARNING OBJECTIVE:
– use functions to shorten your code and make it easier to modify
• Task 1: Get the Interceptor example (from the lecture) working.
• Task 2: Modify your page to play a suitable sound when the asteroid collides with the ship.
• Task 3: Modify your page to have 4 asteroids, which the player must avoid; and an escape pod which the player must pick up (hit). Give your player 5 lives (lose a life each time the space craft hits an asteroid).
Mark Dixon Page 32
Tutorial Exercises: Position• LEARNING OBJECTIVE:
– use a module file to share code between pages
• Task 1: Get the Clock (v2) example (from the lecture) working.
• Task 1: Create a web site that contains copies of your orbit and clock examples.
• Task 2: Create a module file containing shared code between the modules for the position procedure.