An enhanced JavaScript mini-game where players control a farmer to collect crops within a time limit. This project demonstrates ES6 modules, arrow functions, this binding, and modern JavaScript practices.
- Wheat 🌾: 1 point (most common)
- Pumpkin 🎃: 3 points (medium rarity)
- Golden Apple 🍎: 5 points (rare, most valuable)
Each crop type has unique visual styling and spawn probabilities.
- Crop spawn rate increases as time progresses
- Starts at 0.8 seconds between spawns
- Reaches up to 3x faster spawn rate by the end
- Creates escalating challenge and urgency
- Crows 🐦⬛: Move horizontally across the screen with bobbing animation
- Reduce player score by 2 points when touched
- Spawn occasionally from screen edges
- Add dynamic challenge and risk/reward gameplay
- Prerequisites: Modern web browser with ES6 module support
- Setup: Simply open
index.htmlin your browser - Controls:
- Arrow keys (←→↑↓) to move the farmer
- P key to pause/resume
- Start button to begin playing
- Reset button to return to menu
Collect at least 15 points within 60 seconds to win. Different crops award different point values, and avoiding crows is crucial for maintaining your score.
main.js- Entry point and game initializationGame.js- Main game logic and state managementFarmer.js- Player character with movement and collision detectionCrop.js- Collectible crops with different types and point valuesObstacle.js- Static scarecrows and moving crowsInput.js- Keyboard input handlingEntity.js- Base class for all game objects
Arrow functions are used throughout the codebase to preserve lexical this binding:
// Event listeners preserve Game instance context
this.ui.start.addEventListener("click", () => this.start());
// Array processing maintains correct scope
this.crops.filter(c => aabb(this.player, c));
this.crows.forEach(crow => crow.update(dt, this));
// RAF callback preserves Game instance
this.tick = (ts) => {
this.update(dt);
this.render();
requestAnimationFrame(this.tick);
};Arrow Functions: Preserve lexical this from enclosing scope
// In Game constructor - arrow function preserves Game instance
this.tick = (ts) => {
this.update(dt); // 'this' refers to Game instance
};Method References: Lose context when passed as callbacks
// Method loses 'this' context when passed as callback
this._onResize = this.onResize.bind(this); // Must use .bind()Event Listeners: Need explicit binding for cleanup
// Input class - .bind() needed for proper cleanup
this._onKeyDown = this.onKeyDown.bind(this);
window.addEventListener("keydown", this._onKeyDown);.bind(this) is used in two specific scenarios:
- Event Listener Cleanup (Input.js):
this._onKeyDown = this.onKeyDown.bind(this);
// Allows: window.removeEventListener("keydown", this._onKeyDown);- Resize Handler Cleanup (Game.js):
this._onResize = this.onResize.bind(this);
// Allows: window.removeEventListener("resize", this._onResize);- JSDoc Comments: All classes and methods documented with type information
- Modular Architecture: Clean separation of concerns across ES6 modules
- Modern JavaScript: Uses const/let, template literals, arrow functions
- Error Handling: Graceful fallbacks for missing DOM elements
- Performance: Efficient collision detection and rendering
Requires modern browser with ES6 module support:
- Chrome 61+
- Firefox 60+
- Safari 11+
- Edge 16+
- ✅ Q1: Arrow functions,
thisbinding, andbind()usage with documentation - ✅ Q2: Two new gameplay features (crop types + difficulty curve + moving obstacles)
- ✅ Q3: ES6 modules with proper import/export and JSDoc comments
- ✅ Q4: Written reflection on JavaScript concepts and improvement suggestions