Final Project Documentation

SonarGame Documentation

Overview

SonarGame is an interactive browser-based game that uses a sonar sensor connected to an Arduino to control gameplay. The game features two modes – Submarine and Exploration – where players navigate through underwater environments by physically moving their hand or an object in front of the sonar sensor.

System Requirements

  • Computer with a modern web browser (Chrome recommended for WebSerial API)
  • Arduino board (Uno or similar)
  • HC-SR04 ultrasonic sensor
  • USB cable to connect Arduino to computer
  • Basic electronic components (jumper wires, optional breadboard)

Installation

Web Application Setup

  1. Download the game files to your local machine:
    • index.html
    • style.css
    • sketch.js (main game file)
    • webSerial.js (for Arduino communication)
  2. Set up the file structure:
sonar-game/
├── index.html
├── style.css
├── js/
│   ├── sketch.js
│   └── webSerial.js

Arduino Setup

  1. Connect the HC-SR04 ultrasonic sensor to your Arduino:
    • VCC to 5V on Arduino
    • GND to GND on Arduino
    • TRIG to pin 9 on Arduino
    • ECHO to pin 10 on Arduino
  2. Upload the Arduino code (see Arduino Code section)

Game Setup

HTML Structure

Create an index.html file with the following structure:

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sonar Game</title>
    <link rel="stylesheet" href="style.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
</head>
<body>
    <div id="gameContainer">
        <div id="gameCanvas"></div>
        
        <div id="controls">
            <div id="modeSelector">
                <h2>Select Game Mode</h2>
                <button id="submarineMode">Submarine Mode</button>
                <button id="explorationMode">Exploration Mode</button>
            </div>
            
            <div id="instructions" style="display: none;">
                <p id="gameInstructions"></p>
                <button onclick="document.getElementById('instructions').style.display='none';document.getElementById('modeSelector').style.display='flex';">Back to Mode Selection</button>
            </div>
            
            <div id="gameInfo">
                <div>Score: <span id="scoreDisplay">0</span></div>
                <div>Level: <span id="levelDisplay">1</span></div>
                <div>Lives: <span id="livesDisplay">3</span></div>
            </div>
            
            <div id="sonarControls">
                <div id="sonarSimulator">
                    <label for="sonarRange">Simulate Sonar (0-400cm): <span id="sonarValue">200</span></label>
                    <input type="range" id="sonarRange" min="0" max="400" value="200">
                </div>
                
                <div id="arduinoControls">
                    <button id="toggleSimulator">Toggle Simulator</button>
                    <button id="connectArduino">Connect Arduino</button>
                    <button id="disconnectArduino">Disconnect Arduino</button>
                </div>
            </div>
        </div>
    </div>

    <script src="js/webSerial.js"></script>
    <script src="js/sketch.js"></script>
</body>
</html>

CSS Styling

Create a style.css file:

css
body {
    margin: 0;
    padding: 0;
    font-family: Arial, sans-serif;
    background-color: #111;
    color: #0f0;
}

#gameContainer {
    display: flex;
    flex-direction: column;
    height: 100vh;
}

#gameCanvas {
    flex-grow: 1;
}

#controls {
    height: 60px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 20px;
    background-color: #222;
}

#modeSelector {
    display: flex;
    flex-direction: column;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: rgba(0, 0, 0, 0.8);
    padding: 20px;
    border-radius: 10px;
    text-align: center;
}

#instructions {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: rgba(0, 0, 0, 0.8);
    padding: 20px;
    border-radius: 10px;
    text-align: center;
}

button {
    background-color: #0f0;
    color: #000;
    border: none;
    padding: 8px 16px;
    margin: 5px;
    border-radius: 5px;
    cursor: pointer;
}

button:hover {
    background-color: #0c0;
}

#gameInfo {
    display: flex;
    gap: 20px;
}

#sonarControls {
    display: flex;
    align-items: center;
}

#sonarSimulator {
    margin-right: 20px;
}

input[type="range"] {
    width: 200px;
    margin: 0 10px;
}

Game Mechanics

Game Modes

  1. Submarine Mode:
    • Navigate a submarine through underwater caves
    • Avoid obstacles like rocks, mines, and enemy submarines
    • Collect power-ups for extra lives and points
  2. Exploration Mode:
    • Explore ocean depths with diving gear
    • Avoid sharks, jellyfish, and trash
    • Collect treasures and discover sea creatures

Controls

The game is controlled using a sonar sensor. The distance measured by the sonar determines the vertical position of the player:

  • Closer to the sensor = higher position on screen
  • Further from sensor = lower position on screen

Scoring System

  • Each obstacle successfully avoided: +1 point
  • Power-up collection: +10 points
  • Level increases every 20 points
  • Starting with 3 lives
  • Game over when lives reach 0

Game Elements

  1. Obstacles:
    • Submarine mode: rocks, mines, enemy submarines
    • Exploration mode: sharks, jellyfish, trash
    • Colliding with obstacles reduces lives
  2. Power-ups:
    • Extra life: Restores 1 life
    • Extra points: Adds 10 points
  3. Visual effects:
    • Sonar waves: Visually represent sonar activity
    • Particles: Created on collisions and power-up collection

P5JS

 

 

Arduino Integration

Arduino Code

cpp
// SonarGame Arduino Code
// Connects HC-SR04 ultrasonic sensor to send distance readings to browser

// Pin definitions
const int trigPin = 9;  // Trigger pin of the HC-SR04
const int echoPin = 10; // Echo pin of the HC-SR04

// Variables
long duration;
int distance;

void setup() {
  // Initialize Serial communication
  Serial.begin(9600);
  
  // Configure pins
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() {
  // Clear the trigger pin
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  
  // Send a 10μs pulse to trigger
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  // Read the echo pin, duration in microseconds
  duration = pulseIn(echoPin, HIGH);
  
  // Calculate distance in centimeters
  // Speed of sound is 343m/s = 34300cm/s
  // Duration is time for sound to travel to object and back
  // So distance = (duration * 34300) / 2 / 1000000
  distance = duration * 0.034 / 2;
  
  // Limit range to 0-400cm to match game expectations
  if (distance > 400) distance = 400;
  if (distance < 0) distance = 0;
  
  // Send the distance to the Serial port
  Serial.println(distance);
  
  // Small delay before next reading
  delay(50);
}

WebSerial Integration

The game uses the WebSerial API to communicate with the Arduino. The webSerial.js file should handle:

  1. Requesting port access from the browser
  2. Opening serial connection
  3. Reading and parsing serial data
  4. Handling connection errors

Here’s a sample implementation:

javascript
// webSerial.js - Handles communication with Arduino via WebSerial API

let port;
let serialActive = false;
let reader;
let readableStreamClosed;

async function setUpSerial() {
  if ('serial' in navigator) {
    try {
      // Request port access
      port = await navigator.serial.requestPort();
      
      // Open the port with appropriate settings
      await port.open({ baudRate: 9600 });
      
      serialActive = true;
      
      // Set up reading from the port
      const decoder = new TextDecoder();
      const readableStreamClosed = port.readable.pipeTo(new WritableStream({
        write(chunk) {
          // Process each chunk of data
          let string = decoder.decode(chunk);
          
          // Call the readSerial function from sketch.js
          if (typeof readSerial === 'function') {
            readSerial(string);
          }
        }
      }));
      
      console.log("Serial connection established successfully");
    } catch (error) {
      console.error("Error opening serial port:", error);
    }
  } else {
    console.error("WebSerial API not supported in this browser");
    alert("WebSerial is not supported in this browser. Please use Chrome or Edge.");
  }
}

Customization

Adding New Obstacles

To add new obstacles, modify the createObstacle() function in sketch.js:

javascript
function createObstacle() {
  // Increase the range for obstacle types
  let obstacleType;
  
  if (gameMode === "submarine") {
    obstacleType = floor(random(4)); // Increased from 3 to 4
  } else {
    obstacleType = floor(random(4)) + 4; // Adjusted accordingly
  }
  
  let obstacle = {
    x: width + 50,
    y: random(50, height - 50),
    width: random(30, 80),
    height: random(20, 60),
    speed: 2 + level * 0.5,
    type: obstacleType,
  };
  
  obstacles.push(obstacle);
}

// Then update the drawObstacles() function to handle the new type
function drawObstacles() {
  for (let obstacle of obstacles) {
    // ... existing code ...
    
    if (gameMode === "submarine") {
      // ... existing obstacle types ...
      else if (obstacle.type === 3) {
        // New obstacle type
        // Add drawing code here
      }
    } else {
      // ... existing code ...
      else if (obstacle.type === 7) {
        // New obstacle type for exploration mode
        // Add drawing code here
      }
    }
  }
}

Adjusting Difficulty

To adjust game difficulty, modify these variables:

  1. Initial values in the resetGame() function:
    javascript
    function resetGame() {
      score = 0;
      level = 1;
      lives = 5; // Increased from 3 for easier gameplay
      // ...
    }
  2. Obstacle generation rate in the updateGame() function:
    javascript
    if (millis() - lastObstacleTime > 2500 - level * 75) { // Adjusted timing
      createObstacle();
      lastObstacleTime = millis();
    }
  3. Obstacle speed in the createObstacle() function:
    javascript
    let obstacle = {
      // ...
      speed: 1.5 + level * 0.3, // Slower progression
      // ...
    };

Troubleshooting

Game Performance Issues

If the game is running slowly:

  1. Reduce the number of background elements
  2. Decrease particle effects
  3. Lower the frequency of sonar waves
javascript
function createBackgroundElements() {
  const numElements = 30; // Reduced from 50
  // ...
}

function createParticles(x, y, count, particleColor) {
  count = Math.floor(count / 2); // Half the number of particles
  // ...
}

Arduino Connection Problems

  1. Cannot connect to Arduino:
    • Ensure Arduino is connected via USB
    • Verify correct driver installation
    • Try using a different USB port
    • Restart browser and try again
  2. Erratic sonar readings:
    • Check sensor wiring connections
    • Ensure stable power supply
    • Add smoothing to the readings:
javascript
// In Arduino code, add smoothing:
const int numReadings = 5;
int readings[numReadings];
int readIndex = 0;
int total = 0;
int average = 0;

void setup() {
  // Initialize all the readings to 0
  for (int i = 0; i < numReadings; i++) {
    readings[i] = 0;
  }
  // ... existing setup code ...
}

void loop() {
  // ... existing sonar reading code ...
  
  // Subtract the last reading
  total = total - readings[readIndex];
  // Read from sensor
  readings[readIndex] = distance;
  // Add the reading to the total
  total = total + readings[readIndex];
  // Advance to the next position in the array
  readIndex = (readIndex + 1) % numReadings;
  // Calculate the average
  average = total / numReadings;
  
  // Send the smoothed value
  Serial.println(average);
  
  // ... delay code ...
}
  1. Browser compatibility:
    • WebSerial API is only supported in Chromium-based browsers (Chrome, Edge)
    • Ensure your browser is up to date

Mid Term Project

Concept

“Stock Picker Fun” is a fast-paced, simplified stock market simulation game. The player’s goal is to quickly decide whether to buy or sell stocks based on their recent price trends. The game features:

  • Simplified Stocks: Three fictional stocks (AAPL, GOOGL, MSFT) with fluctuating prices.
  • Quick Decisions: Players must make rapid buy/sell decisions based on visual cues.
  • Visual History: Mini-graphs display each stock’s recent price history, aiding in decision-making.
  • Clear UI: A clean and intuitive user interface with color-coded indicators.
  • Progressive Difficulty: The speed of stock price changes increases over time, adding challenge.
  • Profit/Loss Tracking: A simple display of the player’s money and score.

A Highlight of Some Code That You’re Particularly Proud Of

I’m particularly proud of the drawGraph() function:

function drawGraph(data, x, y) {
    stroke('#fff');
    noFill();
    beginShape();
    for (let i = 0; i < data.length; i++) {
        vertex(x + i * 5, y + 40 - (data[i] - data[0]) * 0.5);
    }
    endShape();
    noStroke();

Embedded Sketch

Reflection and Ideas for Future Work or Improvements

Reflection:

This game successfully simplifies the stock market experience, making it accessible and engaging for a wide audience. The visual history and clear UI provide valuable feedback, allowing players to quickly grasp the mechanics and make informed decisions. The progressive speed adds a layer of challenge, keeping the gameplay dynamic.

Ideas for Future Work or Improvements:

  1. More Data Visualization:
    • Add candlestick charts or other advanced visualizations to provide more detailed stock information.
    • Implement real-time data streaming from an API to simulate live market conditions.
  2. Advanced Trading Features:
    • Introduce different order types (limit orders, stop-loss orders).
    • Add the ability to short stocks (bet on price declines).
    • Include options trading.
  3. Dynamic News Events:
    • Generate random news events that impact stock prices, adding an element of unpredictability.
    • Use visual cues or animations to indicate the impact of news.
  4. User Profiles and Persistence:
    • Implement user profiles to save game progress and track performance over time.
    • Use local storage or a database to persist data.
  5. Sound Effects and Animations:
    • Add sound effects for buy/sell actions, price changes, and game events.
    • Incorporate more animations to enhance the visual feedback and create a more immersive experience.
  6. More Stock types:
    • Add more stock types, that have different volatilities.
  7. Game over conditions:
    • Add game over conditions, such as running out of money.
  8. Add a pause feature:
    • Add a pause feature to the game.
  9. Mobile optimization:
    • Optimize the game for mobile devices, using touch controls and responsive design.

By implementing these improvements, the game can be transformed into a more comprehensive and engaging stock market simulation.

Startup Funding Visualization

Concept

This project visualizes startup funding data by representing different startups as interactive elements on the screen. Users can hover over a startup to see its funding amount and valuation, and click on a startup to view more detailed information. The goal is to create an intuitive and engaging way to explore startup funding rounds.

Code Highlight

One of the key sections of the code is how the information is displayed when a startup is hovered over. The following snippet effectively creates a tooltip-like interaction:

text(`${this.emoji} ${this.name}`, this.x, this.y - 15);

if (hovered) {
  fill(255, 200);
  rect(mouseX, mouseY, 160, 50, 10);
  fill(0);
  textSize(12);
  text(`💰 $${this.amountRaised}M`, mouseX + 80, mouseY + 20);
  text(`📈 $${this.valuation}M`, mouseX + 80, mouseY + 40);
}

 


This block dynamically positions the tooltip near the cursor and provides a quick summary of key financial metrics.

Embedded Sketch

 

Reflection and Future Work

While the current implementation effectively visualizes funding data, there are several areas for improvement:

  • Scalability: The current approach might become inefficient with a large dataset. Optimizing how data is rendered could enhance performance.
  • More Interactivity: Adding filtering options for different funding rounds (Seed, Series A, B, etc.) could improve user experience.
  • Enhanced Visualization: Implementing different shapes or colors to represent different funding rounds would make distinctions clearer.
  • Data Integration: Connecting to a live API to fetch real-time funding data would make this visualization more dynamic and useful.

Overall, this project provides an engaging way to explore startup funding data, and with future iterations, it can be expanded into a more powerful analytical tool.

OOP Class 3

Concept: Blooming Emoji Garden

The Blooming Emoji Garden is a generative artwork that simulates a lively, interactive garden filled with animated emojis. The artwork is inspired by the beauty and dynamism of nature, where flowers bloom, insects flutter, and life interacts in playful and unexpected ways. Using Object-Oriented Programming (OOP) in p5.js, the piece brings together a collection of emojis that grow, rotate, and interact with each other, creating a vibrant and ever-changing visual experience.


Highlight of Code: Dynamic Interactions with checkNeighbors()

One part of the code I’m particularly proud of is the checkNeighbors() method in the BloomingEmoji class. This method enables the emojis to interact with each other in a dynamic and organic way. Here’s the code snippet:

checkNeighbors(shapes) {
  for (let other of shapes) {
    if (other !== this) { // Avoid self-comparison
      let d = dist(this.x, this.y, other.x, other.y); // Distance between emojis
      if (d < (this.size + other.size) / 2) { // If emojis overlap
        this.growthRate *= 0.99; // Slow down growth
        this.x += random(-2, 2); // Add a little jiggle
        this.y += random(-2, 2);
      }
    }
  }
}

 

Why I’m Proud of It:

  • Dynamic Behavior: This method makes the emojis feel alive. When they overlap, they jiggle and slow down their growth, creating a sense of connection and interaction.
  • Performance Optimization: Despite checking interactions between all emojis, the method is efficient enough to run smoothly with up to 50 emojis.
  • Organic Feel: The randomness in the jiggle (random(-2, 2)) adds an organic, natural feel to the interactions, making the garden feel more alive.

Embedded Sketch

You can interact with the Blooming Emoji Garden below. Click anywhere on the canvas to add new emojis and watch them grow, rotate, and interact!


Reflection and Ideas for Future Work

What Worked Well:

  • The use of emojis made the artwork visually appealing and accessible.
  • The interactions between emojis added a layer of complexity and engagement.
  • The user interaction (click to add emojis) made the artwork feel participatory and fun.

Challenges:

  • Performance became an issue with too many emojis. Optimizing the checkNeighbors() method was crucial.
  • Balancing randomness and control was tricky. Too much randomness made the garden feel chaotic, while too little made it feel static.

Ideas for Future Improvements:

  1. More Emojis and Variety:
    • Add more emoji types, such as animals, weather symbols, or food, to make the garden even more diverse.
  2. Advanced Interactions:
    • Introduce different types of interactions, such as emojis “attracting” or “repelling” each other based on their type (e.g., bees attracted to flowers).
  3. Sound Effects:
    • Add sound effects, like buzzing for bees or rustling for flowers, to enhance the immersive experience.
  4. Garden Themes:
    • Allow users to choose different garden themes (e.g., desert, forest, underwater) with corresponding emojis and backgrounds.
  5. Mobile Optimization:
    • Make the artwork responsive and touch-friendly for mobile devices, so users can interact with it on the go.
  6. Save and Share:
    • Add a feature to save or share the garden as an image or animation, so users can preserve their creations.

Conclusion

The Blooming Emoji Garden is a playful and dynamic generative artwork that combines the beauty of nature with the whimsy of emojis. It’s a testament to the power of Object-Oriented Programming and creative coding in p5.js. With its engaging interactions and endless possibilities for customization, the garden invites users to explore, create, and imagine. 🌸🐝🦋

Week 2

Concept

This sketch explores the interaction between two screen squares, incorporating movement and “emotional” behavior. The squares are initially placed randomly on the canvas, and they shrink and change color when they overlap, representing a form of “embarrassment.” The goal is to create a simple yet dynamic visual experience where the squares react to user interaction (mouse clicks) and their proximity. When clicked, the squares move toward the mouse position, and if they get too close, they start shrinking and changing color. This sketch is an experiment with combining basic geometric shapes and dynamic behavior in p5.js.

Code Highlight

One section of code I’m particularly proud of is the implementation of the shrink-and-color-change behavior. Here’s the part where the squares react when they “feel embarrassed”:

 

// Check for "embarrassment" (if squares overlap)
let distance = dist(square1.x, square1.y, square2.x, square2.y);
if (distance < (square1.size / 2 + square2.size / 2)) {
  square1.shrink = true;
  square2.shrink = true;
}

// If embarrassed, shrink and change color
if (square1.shrink) {
  square1.size -= 0.5;
  square1.color = color(random(255), random(255), random(255)); // Random color
  if (square1.size < 10) {
    square1.shrink = false; // Start over
    square1.size = 50; // Reset size
  }
}

if (square2.shrink) {
  square2.size -= 0.5;
  square2.color = color(random(255), random(255), random(255)); // Random color
  if (square2.size < 10) {
    square2.shrink = false; // Start over
    square2.size = 50; // Reset size
  }
}

 This logic triggers the shrinking and color change when the distance between the two squares becomes small enough (i.e., they overlap). It creates a fun dynamic where the squares seem to react in real time, making the sketch feel more alive.

Embedded Sketch

You can view and interact with the sketch directly in the p5.js editor, or here’s an embedded link to the live sketch:

Reflection and Future Work

This project started with a simple concept of square interaction, but it quickly became more dynamic by adding emotional “reactions” like shrinking and changing color. The interaction of movement toward the mouse creates an element of control, while the “embarrassment” response adds unpredictability.

For future improvements, I’d consider the following:

  1. Adding sound effects to accompany the “embarrassment” reaction, like a shriek or a sound that corresponds with the color change. This would enhance the multisensory aspect of the experience.
  2. More complex behaviors: Perhaps, when the squares get too small, they could “reproduce” into smaller squares, creating a chain reaction, or they could break apart into multiple pieces.
  3. Interactivity: Instead of just reacting to the mouse, I could add additional interaction methods, such as keyboard inputs or random events that change the behavior of the squares.
  4. Visual effects: Adding gradient colors or animations when the squares change could make the transition smoother and more visually engaging.

This sketch could evolve into a larger concept where geometric shapes and their “emotions” become central to the user interaction, possibly forming the foundation of a game or interactive artwork.

Self Portrait Mohidul

 

Week 1: Self Portrait

Concept: Drawing a portrait that looks professional, wearing a suit.

 

Section I am proud of: Drawing the Suit of the Portrait.

// Draw suit
  fill(30); // Dark gray suit color
  beginShape(); // Left lapel
  vertex(140, 340);
  vertex(200, 280);
  vertex(180, 340);
  endShape(CLOSE);

New things I have learned drawing the suit:

//Vertex

Embedded sketch

Reflection: The hadest part was to start the project and aligning the dots and vertex well. So for next one, I will learn more on the coordinates system and have a paper on my hand before drawing it.