Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions _posts/player_animation_collison/2025-01-07-PAC-Basics_IPYNB_2_.md
Original file line number Diff line number Diff line change
@@ -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
)

40 changes: 40 additions & 0 deletions _posts/player_animation_collison/2025-01-07-PAC1_IPYNB_2_.md
Original file line number Diff line number Diff line change
@@ -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:

![Image Description](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRWKlmwdjgWq7yCxuEGoBFMlyS1tYSbEzjw2Q&s)


# 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!


![Image Description](https://nighthawkcoders.github.io/portfolio_2025/images/platformer/sprites/lopezanimation.png)
9 changes: 9 additions & 0 deletions _posts/player_animation_collison/2025-01-07-PAC_IPYNB_2_.md
Original file line number Diff line number Diff line change
@@ -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
---

4 changes: 2 additions & 2 deletions assets/js/platformer/GameEnv.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
31 changes: 17 additions & 14 deletions assets/js/platformer/GameSetterSkibidi.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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 },
Expand Down
3 changes: 2 additions & 1 deletion assets/js/platformer/PlayerBase.js
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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;
Expand Down
50 changes: 31 additions & 19 deletions assets/js/platformer/PlayerSkibidi.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;


}

}
Expand Down
Loading