Outline

In this week’s lab you will:

  • think more deeply about your major project
  • practice some of the tools and techniques you (might) want to use in your major project

Pre-lab checklist

Before you attend your lab session, make sure:

  • you can fork, pull & push to GitLab
  • you’ve generally got the hang of the content from the previous weeks’ labs

Introduction

The content in this weeks lab is designed to help you get started working on your major project, however, if you think it’ll be more helpful to go over previous labs that is okay too. Finish the first step, and then do as you wish!

There’s no pair work in this lab, but if you feel like pairing up (or forming an even bigger group!) anyway that is definitely encouraged—do so with the regular procedure.

If you have a question about anything to do with the course (labs, major projects, etc.), send a message to your tutor—they want to help you

Writing Task

It’s helpful when working on a big and new project to practice thinking concretely about the abstract and nebulous ideas that make up your design in your head. Writing is a great tool to aid this transformation, so for the next couple of weeks we’re going to give you some writing prompts relating to your major project. These will be the main component of your participation marks for the accompanying weeks.

The prompt for this week is:

How are you going to use interaction in your major project to communicate something to your audience?

Write 100-200 words following the prompt for this week and send it to your labs Teams channel. Try and get this done quickly, if you’ve spent more than 1/2 an hour on it—stop and send it anyway, go work on something else.

If responding to the prompt has brought up some existential questions, or just made you confused—please message one of your tutors!

Recap

The rest of this lab is a recap of things you’ve learned already, especially things which might be useful as you’re putting your major project together. That doesn’t mean that you should just take this code and copy it straight into your major project, instead think of it like a bunch of “tools” which you might need in your toolbox.

This also means that you don’t have to complete this lab from start to finish—there’s more content in here than you could expect to get through in one lab session anyway. Have a look through the different parts and have a go at something, and send a message to one of your tutors if you get stuck :)

Make sure if you use anything from this lab in your major project you mention it in your statement of originality (all snippets on this page are available under the MIT Licence). Here’s an example of how you might reference it in your SoO:

code:
  - comment: the "button" function in sketch.js comes from the _Buttons_ section of the lab 10 toolbox
    url: "https://cs.anu.edu.au/courses/comp1720/labs/10-project-toolbox/"
    licence: MIT
  // other code references follow...

Functions & parameters

By now you’ve all used functions in the lab content and most of you have used functions in the assignments. But because functions can do so many things it’s easy to get a bit confused about what they’re really for—so let’s revise a definition:

A function is a set of statements that performs a task or calculates a value.

Defining a function

A function in javascript has four main components:

  1. the function keyword: this lets javascript know that what follows is a function
  2. the name of the function
  3. the function’s parameters, enclosed by brackets ( and ) and separated with commas (you need to include the parentheses even if the function takes no parameters)
  4. the body of the function: one or more lines of code that the function will perform enclosed by squiggly braces ({})
  5. (optional) the function can include a final return statement, which makes the function return a value
function myFunction(x, y) {
  return x + y;
}

In the above example you can see a simple function (called myFunction) which takes two (number) parameters, adds them together and returns the result.

Calling a function

Calling a function looks a lot like parts 2 and 3 of the function definition. This is because you need to pass in one value for every parameter required by the function.

var x = myFunction(1, 2);
// x is now equal to 3

In the above example the first value 1 has been passed as the x parameter of the function and the second value 2 has been passed as the y parameter. Also, notice that myFunction returns a value (in this case x + y) which you can use it directly or assign it to a variable just like any other variable in your code, including passing it as a parameter to another function call.

What value would x be after this statement;

var x = myFunction(myFunction(3, 2), 1);

Many p5 functions that you use regularly return a value, e.g. random(), sin() and cos(). Can you think of some more?

Functions that do things

Functions don’t have to return a value, though—they can be useful just for the things that they do. For example, the ellipse() function doesn’t return an ellipse as a value (you don’t write var x = ellipse()). Instead, it makes something happen—it draws an ellipse to the canvas.

You can define your own functions to do more complex things:

function window(x, y, w, h) {
  // draw window pan
  fill(255);
  rect(x, y, w, h);
  // draw window cross
  stroke(0);
  line(x, y+h/2, x+w, y+h/2);
  line(x+w/2, y, x+w/2, y+h);
}

For more information have a look at the MDN article on functions.

Typography

Typography can make a big difference to the appearance of your sketch. Great typography can be hard to achieve but a little bit of effort goes a long way.

Getting font files

One good place to look for (usable) font files is the Google Fonts GitHub repo (it’s the place where all the files which power https://fonts.google.com/ are stored).

If you want to use one of these fonts, here’s the process:

  1. find a font you like (perhaps using the main Google Fonts interface)

  2. find the corresponding .ttf file in the GitHub repo and download it (for example, if you want to use the Akronim typeface then the relevant subfolder in GitHub is ofl/akronim)

  3. from the same subfolder, look for the licence file (again, in the case of Akronim it’s called OFL.txt, which if you click through you discover means that the font is available under the SIL OPEN FONT LICENSE Version 1.1)

  4. add the licensing info to your SoO straight away (because forgetting to do it later is no excuse!), e.g.

assets:
  - comment: "Akronim" font from Google Fonts
    url: "https://github.com/google/fonts/tree/master/ofl/akronim"
    licence: SIL OPEN FONT LICENSE Version 1.1
    // other asset references follow...

Loading fonts

p5 can load fonts just like it can load images—here are the steps:

  1. save your font file to your assets folder
  2. load the font with the loadFont() function. Because font files can be large, it’s best to load your files in the preload() function.
var myFont;
function preload() {
  myFont = loadFont('assets/my-font-file.otf');
}

function setup() {
  textFont(myFont);
  text('p5*js', 10, 50);
}

Laying fonts out

Its important to consider size, colour, style and position for the textual content of your sketch.

Text colour can be set in the same way as any visual element in p5. Use the fill() and stroke() functions to set the colours of the text and its outline.

Text size also makes a big difference to how we understand text content. Use the textSize() function to establish a heirarchy of content, i.e. the more important content should be larger than the less important content.

Text style (bold and italics) can be used to emphasise certain content. You can achieve this with the textStyle() function:

textStyle(ITALIC);
textStyle(BOLD);

Text is also useful for arranging textual content. For example, if you set the textAlign() to:

textAlign(CENTER, CENTER)

this will mean that the position parameters will mark the centre point of your text. See the textAlign() reference for more alignment options.

Buttons

There are plenty of ways to make a button in p5, each has its own pros and cons. If you have your own preferred way then feel free to skip over this section.

We’ll revise the method of button building from the lectures. This method is a function which both draws the button and returns a boolean value representing whether or not the button has been clicked.

To implement this we define a function which takes 5 parameters, the first 4 are the position and size of the button, the last is the text the button will show. If you wanted buttons of varying colours or something else you may wish to add one (or more) colour parameters.

function button(x, y, w, h, buttonText) {
  //draw the button
  rect(x, y, w, h);
  text(buttonText, x+5, y+5);
  // return whether the button is pressed.
  return mouseX > x &&
         mouseX < x + w &&
         mouseY > y &&
         mouseY < y + h &&
         mouseIsPressed;
}

Note that the return statement above is split across multiple lines—this is just to make it more readable (for a human), p5 doesn’t care whether it’s all on one line or spread across several lines like this.

With this function defined we can easily make many buttons while keeping our code short and simple.

To use our button we can simply put it inside an if statement. In the example below, the score variable is incremented every time the user clicks the button.

if(button(40, 40, 60, 20, "Click me")) {
  score = score + 1;
}

However, there are some downsides to this method. Because the button function draws and returns the value, the button will be drawn before the action the button triggers. This can cause problems—if you want to draw something (e.g. a different background) while the button is pressed you might end up drawing over the button itself.

The simplest solution to this kind of problem is to call the button function again at the end of the draw loop.

if(button(40, 40, 60, 20, "Click me")) {
  // call to background will draw over the button
  background(255, 0, 0);
}
// call again to redraw.
button(40, 40, 60, 20, "Click me");

What other ways of drawing a “button” can you think of? What are the pros and cons, and how do they compare to the one described above?

Scene management

Scene management is important when you’re creating a game or interactive artwork that needs more than one stage/section/scene. Scene management might seem like a challenge, but you can build it out of the tools you already know.

To keep your code readable it’s best to keep the code for each of your scenes in separate functions. Create a global variable to keep track of the scene number, and use it to switch between scenes in your draw() function.

Here’s the basic structure:

var sceneCounter = 1;

function draw() {
  if (sceneCounter == 1){
    drawScene1();
  } else if (sceneCounter == 2){
    drawScene2();
  } 
}

function drawScene1() {
  // scene 1 draw code...
}
function drawScene2() {
  // scene 2 draw code...
}

Now you need to define the conditions for changing the scene counter. This might happen after a certain number of frames or when a user clicks a button.

if(frameCount > 80 && sceneCounter == 1) {
  sceneCounter = 2;
}

The code above changes to scene two after 80 frames if the scene counter is still on 1. It would also be possible to set the scene counter back to zero with another condition, for example if the user clicks a restart button. Because our draw function just draws the scene based on the sceneCounter variable, we don’t need to do anything except change the value of sceneCounter.

Responsive design

“Responsive design” sounds fancy, but it really just means that your sketch will still look good regardless of what screen size it is viewed on, including tiny smartphone screens!. To make this work, the first thing you’ll want to implement is the p5 windowResized() callback function which is called when the user resizes their window.

For example, you might have noticed that with all the p5 sketches you’ve written so far that if you re-size your browser window your p5 canvas doesn’t resize with it. To make that happen, you can call the resizeCanvas() function inside your windowResized() callback:

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}

This means that the canvas size will change whenever you resize the browser window (try it and see!).

That was pretty easy, but to make your sketches truly responsive you need to define all the sizes and positions in terms of width and height. You have already used p5’s width and height variables to position things e.g. in the center of the canvas. It’s a good idea to position and size all your elements as a fraction of the width or height`. Take for example a regular button:

function notResponsiveButton() {
  rect(150, 150, 140, 50);
  textSize(22);
  text("CLICK ME", 165, 182);
}

The button above would look just fine on a normal laptop screen where it would take up about a quarter of the width of the screen. But if you looked at this sketch on a smartphone screen it might run all the way off the screen.

You can fix this by defining the position in terms of the width variable:

function semiResponsiveButton() {
  rect(width*0.1, width*0.1, width*0.3, width*0.1);
  textSize(width*0.05);
  text("CLICK ME", width*0.13, width*0.17);
}

By defining the button in relation to the width of the canvas it will now shrink and grow in scale with the window. The above function is called semiResponsive because although it will fit on any screen it will likely become too small to use on mobile devices.

The last trick in the “responsive design” book is to create a break point. This is where the size and position of a particular object is changed when the window is resized to above or below a certain size.

function responsiveButton() {
  if(width > 400) { // large screen breakpoint
    rect(width*0.1, width*0.1, width*0.3,width*0.1);
    textSize(width*0.05);
    text("CLICK ME", width*0.13,width*0.17);
  } else { // mobile screen breakpoint
    rect(width*0.1, width*0.1, width*0.8,width*0.1);
    textSize(width*0.05);
    text("CLICK ME", width*0.36 ,width*0.17);
  }
}

Going all the way with “responsive design” isn’t 100% necessary for your major project. The requirements state that your major project must

run smoothly in fullscreen at the test URL on any canvas size from 1920x1080 (in the CSIT labs) to 2560x1440 (in the PK iMac labs) make sure you test it out in the labs

So it can’t only work on one size screen (so make sure you use width and height and not just hard-coded numbers like 1920 or 1080), but it doesn’t have to work on tiny screens (so you don’t necessarily need to do the “breakpoint” thing described above).

Still, this stuff is really important if you want to publish your work online. The internet runs on screens of all shapes and sizes, it’s estimated that 60% of all internet traffic is now from mobile devices. If you want all users to be able to have see your work, responsive design is an important consideration.

push() and pop()

The p5 drawing model involves calling a bunch of functions to set various “settings” (colours, lines, transformations, alignment, etc.) which will affect the shapes that you draw.

As an example, if you’re using the “loop a drawMyObject(obj) function over a collection of objects” technique that we’ve been using a lot in the labs, you’ve probably seen something like:

function drawMyObject(obj){
  fill(200);
  noStroke();
  translate(obj.x, obj.y);
  rectMode(CENTER);
  // more drawing code goes here...
}

Let’s assume that the drawMyObject(obj) function doesn’t “clean up after itself”, it just leaves the stroke/fill/translate/rectMode settings the way it set them at the beginning

This will work ok if there’s only one type of object in your sketch, because the drawMyObject(obj) settings are the only ones you’ll need. However, if there’s another type of object in your sketch (and therefore a drawMyOtherObject(otherObj) function), then you may well need to reset all the drawing settings at the end of drawing each type of object.

You could do this manually, by saving the previous colour/strokeWeight/etc. to variables and reset them when you’re done. However, a much easier way is to use the push() and pop() functions to do this for you automatically. Check the reference for more info.

Have a look back over the kaleidoscope lab for more information.

Content licences

Whenever you’re coding or making anything which includes stuff that other people have made it’s crucial that you only use content with an appropriate licence. All creative work (including the stuff you make in this course) is automatically covered by copyright in Australia. Authors can choose to publish their work under another licence such as Creative Commons or Public Domain. The Creative Commons licences provide a simple, standardised way for individual creators, companies and institutions to share their work with others on flexible terms without infringing copyright. The licences allow users to reuse, remix and share the content legally.

If you wish to use the content (images/audio/text/etc.) of other creaters in your work you must credit it in your statement-of-originality.yml and ensure that the creator has released it under a licence which allows you to use it in that way.

There are a number of websites that publish only Creative Commons content.

  • Unsplash posts images which can be used freely.
  • Freesound contains free audio files (e.g. sound effects, background music)
  • The Newgrounds Audio Portal contains heaps of background music which can be used under various creative commons licences. The licence for each track can be viewed under the “Licensing Terms” section in the sidebar.

It’s also possible to search google images for Creative Commons content. To do so, open up google images and enter your search term. Click on “Tools” on the right side under the search bar; some drop-down menus will appear. Now click on “Usage Rights” and select one of the options other than “Not filtered by licence”. This will return only results licenced under the selected option.

Don’t forget that even if you use appropriately licenced content you still need to credit it in your statement-of-originality.yml.

Summary

Congratulations! In this lab you:

  • put some more tools in your toolbox

Now go and make an amazing major project!

Updated:    11 Jan 2021 / Responsible Officer:    Head of School / Page Contact:    Charles Martin