Part 1: JavaScript Core Concepts (Basics)

%%js

// Activity 1: Variable Fixing
// This code has mistakes. Fix them so it works correctly.

var name = "Mario";
let score; // declare score but don't assign yet
const lives = 3;

score = 100;

console.log("Player:", name);
console.log("Score:", score);
console.log("Lives:", lives);

// TODO: Change `score` so it increases by 50 and log the new value.

<IPython.core.display.Javascript object>
%%js

// Activity 2: Function Completion
// Finish the function so it multiplies two numbers instead of adding.

function multiply(a, b) {
    // TODO: Replace return statement so it multiplies
    return a + b;
}

console.log("Expected 20:", multiply(4, 5));

<IPython.core.display.Javascript object>

Part 2: Canvas Activities

%%js

// Activity 3: Draw Your Own Shape
// The following draws a blue rectangle. Change it to draw a green square.

let canvas = document.createElement("canvas");
document.body.appendChild(canvas);
let ctx = canvas.getContext("2d");

canvas.width = 400;
canvas.height = 300;
canvas.style.border = "1px solid black";

ctx.fillStyle = "blue";
ctx.fillRect(50, 50, 200, 100);

// TODO: Change the color and dimensions to make it a green square.

<IPython.core.display.Javascript object>
%%js

// Activity 4: Move a Rectangle
// This code draws a rectangle. Modify it so it moves 2px to the right each frame.

let canvas2 = document.createElement("canvas");
document.body.appendChild(canvas2);
let ctx2 = canvas2.getContext("2d");

canvas2.width = 400;
canvas2.height = 200;
canvas2.style.border = "1px solid black";

let x = 20;

function animateRect() {
    ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
    ctx2.fillStyle = "purple";
    ctx2.fillRect(x, 50, 50, 50);

    // TODO: increase `x` so the square moves right
    requestAnimationFrame(animateRect);
}
animateRect();

<IPython.core.display.Javascript object>

Part 3: Moving Background Activities

%%js

// Activity 5: Background Image Setup
// The code is missing parts. Fill in the missing lines.

let canvas3 = document.createElement("canvas");
document.body.appendChild(canvas3);
let ctx3 = canvas3.getContext("2d");

canvas3.width = 600;
canvas3.height = 200;
canvas3.style.border = "1px solid black";

// TODO: Declare background and sprite as images
// const background = ...
// const sprite = ...

// TODO: Set `background.src` and `sprite.src` to image URLs

<IPython.core.display.Javascript object>
%%js

// Activity 6: Animate the Background
// The background should move left, but part of the code is missing.
// Complete the TODOs.

let canvas4 = document.createElement("canvas");
document.body.appendChild(canvas4);
let ctx4 = canvas4.getContext("2d");

canvas4.width = 600;
canvas4.height = 200;
canvas4.style.border = "1px solid black";

const background2 = new Image();
background2.src = "https://i.imgur.com/3e5pRfj.jpeg";

let bgX = 0;

function animateBackground() {
    ctx4.clearRect(0, 0, canvas4.width, canvas4.height);

    ctx4.drawImage(background2, bgX, 0, canvas4.width, canvas4.height);
    ctx4.drawImage(background2, bgX + canvas4.width, 0, canvas4.width, canvas4.height);

    // TODO: decrease bgX so it moves left
    // TODO: reset bgX when it reaches -canvas4.width

    requestAnimationFrame(animateBackground);
}
background2.onload = animateBackground;

%%js

// Activity 7 (Challenge): Floating Sprite!
// Modify this so the sprite "bobs" up and down while the background moves.

let canvas5 = document.createElement("canvas");
document.body.appendChild(canvas5);
let ctx5 = canvas5.getContext("2d");

canvas5.width = 600;
canvas5.height = 200;
canvas5.style.border = "1px solid black";

const bg = new Image();
bg.src = "https://i.imgur.com/3e5pRfj.jpeg";

const sprite = new Image();
sprite.src = "https://i.imgur.com/Qbl1bLZ.png";

let bgX2 = 0;
let frame = 0;

function animateScene() {
    ctx5.clearRect(0, 0, canvas5.width, canvas5.height);

    ctx5.drawImage(bg, bgX2, 0, canvas5.width, canvas5.height);
    ctx5.drawImage(bg, bgX2 + canvas5.width, 0, canvas5.width, canvas5.height);

    let spriteX = canvas5.width / 2 - 50;
    let spriteY = canvas5.height / 2 - 50;

    // TODO: add vertical floating effect using Math.sin() and frame
    ctx5.drawImage(sprite, spriteX, spriteY, 100, 100);

    bgX2 -= 2;
    if (bgX2 <= -canvas5.width) {
        bgX2 = 0;
    }

    frame++;
    requestAnimationFrame(animateScene);
}
bg.onload = animateScene;

<IPython.core.display.Javascript object>

Extra Practice Questions

  1. Why does requestAnimationFrame work better than setInterval for animations?
  2. What happens if you forget to call ctx.clearRect() inside an animation loop?
  3. How would you modify the background speed so it moves faster?
  4. (Challenge) Make the sprite move left and right with the arrow keys.

Homework: Moving Background with JavaScript and Canvas

In this lesson, we learned how to make a background move continuously while keeping a sprite centered.

We will now practice by filling in missing pieces of code and editing snippets.


Part 1: Understanding the Core

The moving background is achieved by:

  1. Updating the x position of the background each frame.
  2. Drawing two images side by side to create a seamless loop.
  3. Using requestAnimationFrame for smooth animation.

Activity 1: Fill in the Code

Below is the Background class with missing code.
Fill in the blanks (???) to complete it.

class Background extends GameObject {
  update() {
    // Shift the background left
    this.x = (this.x - ???) % ???;
  }

  draw(ctx) {
    // Draw two images side by side
    ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
    ctx.drawImage(this.image, this.x + ???, this.y, this.width, this.height);
  }
}


# Activity 2: Edit the Code

Right now, the background always scrolls to the left.
Task: Modify the update() method so the background can also scroll right when this.speed is negative.

Hint: Youll need to adjust the math inside update() so the % this.width logic works both ways.

# Activity 3 - Speed Control
Currently in the game the speed is fixed:


```python
var gameSpeed = 5;

Task:

Add keyboard controls so that:

Pressing the Arrow Up increases gameSpeed.

Pressing the Arrow Down decreases gameSpeed.

Starter Code (fill in the blanks):

window.addEventListener('keydown', function(event) {
  if (event.key === "ArrowUp") {
    gameSpeed += ???;
  } else if (event.key === "ArrowDown") {
    gameSpeed = Math.max(1, gameSpeed - ???);
  }
});

Activity 4: Add a Second Background Layer

Parallax scrolling makes games look more realistic. You can add two background objects moving at different speeds.

Task: Duplicate the backgroundObj creation code, but use a different speedRatio. Then, draw both layers in the animate() loop.

Starter Code:

// Background layers
const backgroundObj1 = new Background(backgroundImg, canvasWidth, canvasHeight, 0, 0, 0.1);
const backgroundObj2 = new Background(backgroundImg, canvasWidth, canvasHeight, 0, 0, ???);  // slower speed

function animate() {
  ctx.clearRect(0, 0, canvasWidth, canvasHeight);
  backgroundObj1.update();
  backgroundObj1.draw(ctx);
  backgroundObj2.update();
  backgroundObj2.draw(ctx);
  spriteObj.draw(ctx);
  requestAnimationFrame(animate);
}

Activity 5: Complexity Question

Each frame, the program:

Updates background position(s).

Draws background(s).

Draws the sprite.

Question:

If there are n background layers, what is the time complexity of each frame’s animate() call?

What about memory complexity?

Basic Instructions:

1) Create a file called something like background.md just as long as it ends with .md (Strongly recommend placing it in a folder named hacks)

2) In your new file, after creating your heading, make sure to create an ID for your image, something like <canvas id="world"></canvas>, you can copy this ID and change ‘world’ to whatever you want.

3) Still in the same file, under the ID, open your script for code by typing <script>, and under that, create your code for your moving image using code displayed from lesson/popcorn hacks

4) Finish your script (code for background) by adding </script>, this should be the last line of the file.

Grading (May be modified in class)

  • .55 - No work done, no effort shown by group or student

  • .75 - Student shows they put in effort, but didn’t complete any assigned tasks

  • .8 - Background shows, but isn’t animated

  • .85 - Background shows, isn’t animated, but there is a second background object

  • .89 - Background shows and IS ANIMATED, but work is submitted late and Complexity Questions are unanswered. (There may be some exeptions for late work if students were not present for the lesson)

  • .90 - Background shows and IS ANIMATED, complexity questions are not done or answered incorrectly

  • .91 - Background is shown and animated, one complexity question is answered AND CORRECT

  • .92 - Background is shown and animated, both complexity questions are answered correctly