diff --git a/_posts/player_animation_collison/2025-01-07-PAC-Basics_IPYNB_2_.md b/_posts/player_animation_collison/2025-01-07-PAC-Basics_IPYNB_2_.md new file mode 100644 index 00000000..31170414 --- /dev/null +++ b/_posts/player_animation_collison/2025-01-07-PAC-Basics_IPYNB_2_.md @@ -0,0 +1,117 @@ +--- +layout: post +title: Player, Animation, and Collisons (PAC) +author: Aaryav Lal +description: How does PAC really work? +permalink: /player_animation_collison/PAC +toc: True +--- + +# Game Development Overview + +In game development, three core components often involved in creating interactive experiences are **Player**, **Animation**, and **Collision**. Understanding these components is crucial to building a functional game. Let's break them down: + +## 1. Player + +The **Player** is typically the entity that the user controls within the game. It can represent a character, vehicle, or object, and the player's actions often define the core gameplay. Key aspects include: + +- **Movement**: The player can be moved using input controls like keyboard, mouse, or game controllers. +- **Attributes**: Players often have specific attributes like health, speed, or strength. +- **Interaction**: The player interacts with the game world by collecting items, fighting enemies, or completing objectives. + +### Example: +```python +class Player: + def __init__(self, x: float, y: float, speed: float = 5.0): + """ + Initialize the player at position (x, y) with a default movement speed. + + Parameters: + x (float): The player's starting x-coordinate. + y (float): The player's starting y-coordinate. + speed (float): The player's movement speed. Defaults to 5. + """ + self.x = x + self.y = y + self.speed = speed + + def move(self, dx: float, dy: float): + """ + Move the player based on input direction (dx, dy) and speed. + + Parameters: + dx (float): The change in the x-direction. + dy (float): The change in the y-direction. + """ + self.x += dx * self.speed + self.y += dy * self.speed + + def get_position(self) -> tuple: + """ + Get the current position of the player as a tuple (x, y). + + Returns: + tuple: The player's current position. + """ + return self.x, self.y + + +## 2. Animation + +**Animation** is what brings the game world to life by providing movement or visual changes to the game’s elements. This involves changing the appearance or position of sprites over time to simulate movement or transitions. + +Key concepts in animation include: + +- **Frames**: Animation is typically composed of individual images called frames. When shown in sequence, they create the illusion of motion. +- **Frame Rate**: The speed at which frames are displayed, usually measured in frames per second (FPS). A higher FPS makes animations smoother. +- **Sprites**: These are 2D images or 3D models that are animated within the game. +- **Tweening**: Short for "in-betweening", this is the process of generating intermediate frames between two keyframes, providing a smooth transition. + +### Example: +```python +class Animation: + def __init__(self, frames, frame_rate): + self.frames = frames + self.frame_rate = frame_rate + self.current_frame = 0 + self.elapsed_time = 0 + + def update(self, delta_time): + self.elapsed_time += delta_time + if self.elapsed_time > 1 / self.frame_rate: + self.current_frame = (self.current_frame + 1) % len(self.frames) + self.elapsed_time = 0 + + +## 3. Collision + +**Collision** detection is crucial in games to determine when objects or characters interact with each other. It allows the game to respond to events like a player hitting an obstacle, picking up an item, or attacking an enemy. + +Key concepts in collision include: + +- **Bounding Box**: The simplest method of collision detection, where each object is enclosed in a rectangular or circular boundary. If these boundaries overlap, a collision is detected. +- **Pixel-Perfect Collision**: A more precise method of detection where the individual pixels of two objects are compared. This ensures more accurate detection but is computationally more expensive. +- **Collision Response**: Once a collision is detected, the game must decide how to respond, whether stopping movement, bouncing off surfaces, triggering damage, or generating game events. + +### Example: +```python +class Collision: + @staticmethod + def check_collision(rect1, rect2): + """ + Check for a collision between two rectangular objects. + + Parameters: + rect1: The first rectangle with attributes x, y, width, and height. + rect2: The second rectangle with attributes x, y, width, and height. + + Returns: + bool: True if the rectangles are colliding, False otherwise. + """ + return ( + rect1.x < rect2.x + rect2.width and + rect1.x + rect1.width > rect2.x and + rect1.y < rect2.y + rect2.height and + rect1.y + rect1.height > rect2.y + ) + diff --git a/_posts/player_animation_collison/2025-01-07-PAC1_IPYNB_2_.md b/_posts/player_animation_collison/2025-01-07-PAC1_IPYNB_2_.md new file mode 100644 index 00000000..33313431 --- /dev/null +++ b/_posts/player_animation_collison/2025-01-07-PAC1_IPYNB_2_.md @@ -0,0 +1,40 @@ +--- +layout: post +title: Player, Animation, and Collisons (PAC) +author: Aditya Srivastava +description: How does PAC really work? +permalink: /player_animation_collison/PAC +toc: True +--- + +# What is animation: +Animating is the process of creating the illusion of movement by displaying a sequendce of images or frames. This is important to our game and many other games because this is how our characters appear to be walking and jumping. Here is an example: + + + + +# How Do We Animate in Our Game? + +In our game, all characters across levels use **sprite sheets** for animation. A **sprite sheet** is a large image containing a grid of smaller images (frames), each showing the character in a slightly different pose. These frames are displayed in rapid succession to create smooth animations for actions like walking, jumping, or attacking. + +Each frame represents a character from different angles or performing specific actions, with slight variations between frames to create the illusion of movement. + +Here's an example of what a sprite sheet might look like: + +- **Character Actions**: The sprite sheet contains frames for different actions (e.g., walking, jumping, attacking). +- **Animation Flow**: The frames are shown in sequence to make the animation appear seamless and natural. + +By cycling through the frames at the correct speed, we create fluid and continuous motion for the character in the game. + +### Example Sprite Sheet: +(You can add your image or a link to an example sprite sheet here) + +### How It Works: +1. **Loading the Sprite Sheet**: The game loads the sprite sheet, breaking it into individual frames. +2. **Animation Timing**: Each frame is displayed for a brief period before moving to the next one, based on the animation's frame rate. +3. **Smooth Transitions**: By repeating this process continuously, the character's animation looks smooth and lifelike. + +This technique helps bring our characters to life and gives the game its dynamic feel! + + + diff --git a/_posts/player_animation_collison/2025-01-07-PAC_IPYNB_2_.md b/_posts/player_animation_collison/2025-01-07-PAC_IPYNB_2_.md new file mode 100644 index 00000000..74d2714d --- /dev/null +++ b/_posts/player_animation_collison/2025-01-07-PAC_IPYNB_2_.md @@ -0,0 +1,9 @@ +--- +layout: post +title: Player, Animation, and Collisons (PAC) +author: Aneesh Devi +description: How does PAC really work? +permalink: /player_animation_collison/PAC +toc: True +--- + diff --git a/assets/js/platformer/GameEnv.js b/assets/js/platformer/GameEnv.js index 6b351262..4a24616e 100644 --- a/assets/js/platformer/GameEnv.js +++ b/assets/js/platformer/GameEnv.js @@ -235,12 +235,12 @@ export class GameEnv { } break; case "s": - if (keys.includes("a") && keys.includes("s")) { + if (key.includes("a") && key.includes("s")) { // If both "a" and "s" are clicked if (GameEnv.player?.x > 2) { GameEnv.backgroundDirection = -5; } - } else if (keys.includes("d") && keys.includes("s")) { + } else if (key.includes("d") && key.includes("s")) { // If both " d" and "s" are clicked if (GameEnv.player?.x < (GameEnv.innerWidth - 2)) { GameEnv.backgroundDirection = 5; diff --git a/assets/js/platformer/GameSetterSkibidi.js b/assets/js/platformer/GameSetterSkibidi.js index 15521de8..5e56edcf 100644 --- a/assets/js/platformer/GameSetterSkibidi.js +++ b/assets/js/platformer/GameSetterSkibidi.js @@ -44,7 +44,7 @@ const assets = { hitbox: { widthPercentage: 0.06, heightPercentage: 0.5}, width: 60, height: 500, - scaleSize: 100 + scaleSize: 90 }, cabin: { src: "/images/platformer/obstacles/cabin.png", @@ -491,20 +491,23 @@ const assets = { { name: 'laser', id: 'Laser', class: Laser, data: assets.obstacles.laser, xPercentage: 0.75, yPercentage: 0.5 }, { name: 'skibidiTitan', id: 'skibidiTitan', class: skibidiTitan, data: assets.enemies.skibidiTitan, xPercentage: 0.35, yPercentage: 0.5, minPosition: 0.5 }, { name: 'sand', id: 'platform', class: Platform, data: assets.platforms.sand }, - { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.1, yPercentage: 0.9 }, - { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.3, yPercentage: 0.7 }, - { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.5, yPercentage: 0.8 }, - { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.7, yPercentage: 0.6 }, - { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.4, yPercentage: 0.4 }, - { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.2, yPercentage: 0.3 } , - { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.6, yPercentage: 0.2 }, - { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.8, yPercentage: 0.5 }, + { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.3, yPercentage: 0.87 }, + { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.34, yPercentage: 0.8}, + { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.38, yPercentage: 0.8 }, + { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.42, yPercentage: 0.8 }, + { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.45, yPercentage: 0.75 }, + { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.6, yPercentage: 0.71 } , + { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.14, yPercentage: 0.84 }, + { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.7, yPercentage: 0.84 }, { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.3, yPercentage: 0.4 }, - ///{ name: 'coin', id: 'coin', class: Coin, data: assets.obstacles.vbucks, xPercentage: 0.475, yPercentage: 0.5 }, - { name: 'coin', id: 'coin', class: Coin, data: assets.obstacles.vbucks, xPercentage: 0.325, yPercentage: 0.7 }, - { name: 'coin', id: 'coin', class: Coin, data: assets.obstacles.vbucks, xPercentage: -0.0125, yPercentage: 0.4 }, - { name: 'coin', id: 'coin', class: Coin, data: assets.obstacles.vbucks, xPercentage: 0.0125, yPercentage: 0.4 }, - { name: 'coin', id: 'coin', class: Coin, data: assets.obstacles.vbucks, xPercentage: 0.0325, yPercentage: 0.4 }, + { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.36, yPercentage: 0.8 }, + { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.4, yPercentage: 0.8 }, + { name: 'blocks', id: 'jumpPlatform', class: BlockPlatform, data: assets.platforms.sand, xPercentage: 0.32, yPercentage: 0.87 }, + //{ name: 'coin', id: 'coin', class: Coin, data: assets.obstacles.vbucks, xPercentage: 0.475, yPercentage: 0.5 }, + { name: 'coin', id: 'coin', class: Coin, data: assets.obstacles.coin, xPercentage: 0.287, yPercentage: 0.3 }, + { name: 'coin', id: 'coin', class: Coin, data: assets.obstacles.coin, xPercentage: 0.51, yPercentage: 0.9 }, + //{ name: 'coin', id: 'coin', class: Coin, data: assets.obstacles.vbucks, xPercentage: 0.495, yPercentage: 0.87}, + //{ name: 'coin', id: 'coin', class: Coin, data: assets.obstacles.vbucks, xPercentage: 0.35, yPercentage: 0.88 }, { name: 'SkibidiToilet', id: 'SkibidiToilet', class: SkibidiToilet, data: assets.enemies.skibidiToilet, xPercentage: 0.3, minPosition: 0.07 }, { name: 'SkibidiToilet', id: 'SkibidiToilet', class: SkibidiToilet, data: assets.enemies.skibidiToilet, xPercentage: 0.5, minPosition: 0.3 }, { name: 'SkibidiToilet', id: 'SkibidiToilet', class: SkibidiToilet, data: assets.enemies.skibidiToilet, xPercentage: 0.75, minPosition: 0.5 }, diff --git a/assets/js/platformer/PlayerBase.js b/assets/js/platformer/PlayerBase.js index 9f20c7f4..2407cb95 100644 --- a/assets/js/platformer/PlayerBase.js +++ b/assets/js/platformer/PlayerBase.js @@ -1,6 +1,7 @@ import GameEnv from './GameEnv.js'; import Character from './Character.js'; import GameControl from './GameControl.js'; +import SettingsControl from './SettingsControl.js'; /** * @class PlayerBase class * @description PlayeiBase.js key objective is to handle the user-controlled player's actions and animations. @@ -52,7 +53,7 @@ export class PlayerBase extends Character { this.setY(this.y - (this.bottom * 0.35)); } updateMovement() { - const speedMultiplier = GameEnv.playerSpeedMultiplier || 1; // Default to 1 if not set + const speedMultiplier = SettingsControl.gameSpeed || 1; // Default to 1 if not set switch (this.state.animation) { case 'idle': break; diff --git a/assets/js/platformer/PlayerSkibidi.js b/assets/js/platformer/PlayerSkibidi.js index f10c2060..e6566cb6 100644 --- a/assets/js/platformer/PlayerSkibidi.js +++ b/assets/js/platformer/PlayerSkibidi.js @@ -138,26 +138,38 @@ export class PlayerSkibidi extends PlayerBaseOneD { /// Using PlayerBaseOneD add } break; - case "laser": // - if (this.collisionData.touchPoints.this.right || this.collisionData.touchPoints.this.left) { - if (GameEnv.difficulty === "normal" || GameEnv.difficulty === "hard") { - if (this.state.isDying == false) { - this.state.isDying = true; - this.canvas.style.transition = "transform 0.5s"; - this.canvas.style.transform = "rotate(-90deg) translate(-26px, 0%)"; - GameEnv.playSound("PlayerDeath"); - setTimeout(async() => { - await GameControl.transitionToLevel(GameEnv.levels[GameEnv.levels.indexOf(GameEnv.currentLevel)]); - }, 900); - } - } else if (GameEnv.difficulty === "easy" && this.collisionData.touchPoints.this.right) { - this.x -= 10; - } else if (GameEnv.difficulty === "easy" && this.collisionData.touchPoints.this.left) { - this.x += 10; - } - + case "laser": + // Adding a delay before the laser is spawned (3 seconds) + if (!this.spawnTime) { + this.spawnTime = Date.now(); // Record the spawn time when player spawns + } + + const timeSinceSpawn = Date.now() - this.spawnTime; // Calculate time since spawn + const delayBeforeLaser = 3000; // 3 seconds delay before spawning the laser + + // Only show and activate the laser after the delay + if (timeSinceSpawn >= delayBeforeLaser) { + if (this.collisionData.touchPoints.this.right || this.collisionData.touchPoints.this.left) { + if (GameEnv.difficulty === "normal" || GameEnv.difficulty === "hard") { + if (this.state.isDying == false) { + this.state.isDying = true; + this.canvas.style.transition = "transform 0.5s"; + this.canvas.style.transform = "rotate(-90deg) translate(-26px, 0%)"; + GameEnv.playSound("PlayerDeath"); + setTimeout(async() => { + await GameControl.transitionToLevel(GameEnv.levels[GameEnv.levels.indexOf(GameEnv.currentLevel)]); + }, 900); } - break; + } else if (GameEnv.difficulty === "easy" && this.collisionData.touchPoints.this.right) { + this.x -= 10; + } else if (GameEnv.difficulty === "easy" && this.collisionData.touchPoints.this.left) { + this.x += 10; + } + } + } + break; + + } } diff --git a/assets/js/platformer/SettingsControl.js b/assets/js/platformer/SettingsControl.js index 01208567..2fb3da02 100644 --- a/assets/js/platformer/SettingsControl.js +++ b/assets/js/platformer/SettingsControl.js @@ -65,623 +65,6 @@ const backgroundDim = { let isOpen = true -// define the SettingsControl class -// export class SettingsControl extends LocalStorage{ -// constructor(){ //default keys for localStorage -// var keys = { -// userID:"userID", -// currentLevel:"currentLevel", -// isInverted:"isInverted", -// gameSpeed:"gameSpeed", -// gravity:"gravity", -// difficulty: "difficulty", -// }; -// super(keys); //creates this.keys -// } - -// reloadGame() { -// // Add code to reload or restart your game here -// // You may want to perform actions like resetting the game state, restarting the level, etc. -// // Example: -// window.location.reload(); // Reload the entire page (this might not be suitable for all scenarios) -// // Alternatively, you may have a custom function to handle game restart logic. -// } - - -// /** -// * Note. Separated from constructor so that class can be created before levels are addeda -// * -// * Initializes the SettingsControl instance. -// * Loads all keys from local storage. -// * For each key, -// * * If it exists in local storage, loads and parses its value. -// * * Else when the key does not exist in local storage, sets key to the corresponding GameEnv.js variable. -// */ -// initialize(){ -// // Load all keys from local storage -// this.loadAll(); - -// window.addEventListener("difficulty", (e) => { -// // Update the difficulty value when a difficulty event is fired -// this[this.keys.difficulty] = e.detail.difficulty(); -// // Update the difficulty value in the game environment -// GameEnv.difficulty = parseFloat(this[this.keys.difficulty]); -// // Save the difficulty value to local storage -// this.save(this.keys.difficulty); - -// // Reload the game to apply the new difficulty settings -// this.reloadGame(); -// }); - -// /** -// * Handles a key by checking if it exists in local storage and parsing its value. -// * If the key does not exist in local storage, it sets the key to the current value of the game environment variable. -// * -// * @param {string} key - The localstorae key. -// * @param {*} gameEnvVariable - The corresponding game environment variable. -// * @param {function} [parser=(val) => val] - An optional function to parse the value from local storage. -// * If no parser parameter/function is provided, (val) => val is unchanged. -// * Else if parser is provided, the value is parsed ... e.g.: -// * * (val) => vall === "true" parses the value as a boolean -// * * (val) => parseFloat(val) parses the value as a floating point number -// */ -// const handleKey = (key, gameEnvVariable, parser = (val) => val) => { -// if (this[this.keys[key]]) { -// return parser(this[this.keys[key]]); -// } else { -// this[this.keys[key]] = gameEnvVariable; -// return gameEnvVariable; -// } -// }; - -// /* Call the handleKey function to set up each game environment variable -// * The handleKey function takes three parameters: -// * * key - the local storage key -// * * gameEnvVariable - the corresponding game environment variable -// * * parser - an optional function to parse the value extracted from local storage -// */ -// // 'userID', the value is parsed as a string -// GameEnv.userID = handleKey('userID', GameEnv.userID); -// // 'currentLevel', the value is parsed as a an index into the GameEnv.levels array -// GameEnv.currentLevel = handleKey('currentLevel', GameEnv.levels[Number(this[this.keys.currentLevel])]); -// // 'isInverted', the value is parsed to a boolean -// GameEnv.isInverted = handleKey('isInverted', GameEnv.isInverted, (val) => val === "true"); -// // 'gameSpeed', the value is parsed to a floating point number -// GameEnv.gameSpeed = handleKey('gameSpeed', GameEnv.gameSpeed, parseFloat); -// // 'gravity', the value is parsed to a floating point number -// GameEnv.gravity = handleKey('gravity', GameEnv.gravity, parseFloat); -// // 'difficulty', the value is parsed to a floating point number -// GameEnv.difficulty = handleKey('difficulty', GameEnv.difficulty); - - -// // List for th 'userID' update event -// window.addEventListener("userID", (e)=>{ -// // Update the userID value when a userID event is fired -// this[this.keys.userID] = e.detail.userID(); -// // Update the userID value in the game environment -// GameEnv.userID = this[this.keys.userID]; - -// Socket.sendData("name",GameEnv.userID); -// // Save the userID value to local storage -// this.save(this.keys.userID); -// }); - -// // Listen for the 'resize' update event -// window.addEventListener("resize",()=>{ -// // Update the current level index when the level changes -// this[this.keys.currentLevel] = GameEnv.levels.indexOf(GameEnv.currentLevel); -// // Save the current level index to local storage -// this.save(this.keys.currentLevel); -// }); - -// // Listen for the 'isInverted' update event -// window.addEventListener("isInverted", (e)=>{ -// // Update the isInverted value when an invert event is fired -// this[this.keys.isInverted] = e.detail.isInverted(); -// // Update the isInverted value in the game environment -// GameEnv.isInverted = this[this.keys.isInverted]; -// // Save the isInverted value to local storage -// this.save(this.keys.isInverted); -// }); - -// // Listen for the 'gameSpeed' update event -// window.addEventListener("gameSpeed",(e)=>{ -// // Update the gameSpeed value when a speed event is fired -// this[this.keys.gameSpeed] = e.detail.gameSpeed(); -// // Update the gameSpeed value in the game environment -// GameEnv.gameSpeed = parseFloat(this[this.keys.gameSpeed]); -// // Save the gameSpeed value to local storage -// this.save(this.keys.gameSpeed); -// }); - -// // Listen for the 'gravity' update event -// window.addEventListener("gravity",(e)=>{ -// // Update the gravity value when a gravity event is fired -// this[this.keys.gravity] = e.detail.gravity(); -// // Update the gravity value in the game environment -// GameEnv.gravity = parseFloat(this[this.keys.gravity]); -// // Save the gravity value to local storage -// this.save(this.keys.gravity); -// }); - -// // Listen for the 'gravity' update event -// window.addEventListener("difficulty",(e)=>{ -// // Update the gravity value when a gravity event is fired -// this[this.keys.difficulty] = e.detail.difficulty(); -// // Update the gravity value in the game environment -// GameEnv.difficulty = parseFloat(this[this.keys.difficulty]); -// // Save the gravity value to local storage -// this.save(this.keys.difficulty); -// }); - -// window.addEventListener("isTheme", (e)=>{ -// // Update the isInverted value when an invert event is fired -// this[this.keys.isTheme] = e.detail.isTheme(); -// // Update the isInverted value in the game environment -// GameEnv.isTheme = this[this.keys.isTheme]; -// // Save the isInverted value to local storage -// this.save(this.keys.isTheme); -// }); - -// } - -// /** -// * Getter for the userID property. -// * Creates a div with a text input for the user to enter a userID. -// * The input's value is bound to the GameEnv's userID string. -// * @returns {HTMLDivElement} The div containing the userID input. -// */ -// get userIDInput() { -// const div = document.createElement("div"); -// div.innerHTML = "User ID: "; // label - -// const userID = document.createElement("input"); // get user defined userID -// userID.type = "text"; -// userID.value = GameEnv.userID; // GameEnv contains latest userID -// userID.maxLength = 10; // set maximum length to 10 characters -// userID.className = "input userID"; // custom style in platformer-styles.scss - -// userID.addEventListener("change", () => { -// // dispatch event to update userID -// window.dispatchEvent(new CustomEvent("userID", { detail: {userID:()=>userID.value} })); -// }); - -// Socket.sendData("name",GameEnv.userID) - -// div.append(userID); // wrap input element in div -// return div; -// } - -// /** -// * Getter for the levelTable property. -// * Creates a table with a row for each game level. -// * Each row contains the level number and the level tag. -// * Passive levels are skipped and not added to the table. -// * @returns {HTMLTableElement} The table containing the game levels. -// */ -// get levelTable(){ -// // create table element -// var t = document.createElement("table"); -// t.className = "table levels"; -// //create table header -// var header = document.createElement("tr"); -// var th1 = document.createElement("th"); -// th1.innerText = "#"; -// header.append(th1); -// var th2 = document.createElement("th"); -// th2.innerText = "Level Tag"; -// header.append(th2); -// t.append(header); - -// // Create table rows/data -// for(let i = 0, count = 1; i < GameEnv.levels.length; i++){ -// if (GameEnv.levels[i].passive) //skip passive levels -// continue; -// // add level to table -// var row = document.createElement("tr"); -// var td1 = document.createElement("td"); -// td1.innerText = String(count++); //human counter -// row.append(td1); -// // place level name in button -// var td2 = document.createElement("td"); -// td2.innerText = GameEnv.levels[i].tag; -// row.append(td2); -// // listen for row click -// row.addEventListener("click",()=>{ // when player clicks on the row -// //transition to selected level -// GameControl.transitionToLevel(GameEnv.levels[i]); // resize event is triggered in transitionToLevel -// }) -// // add level row to table -// t.append(row); -// } - -// return t; //returns