Skip to content

Commit

Permalink
Refactored code for scale using OOP and SOLID.
Browse files Browse the repository at this point in the history
- Reorganized all code into classes.
- Restructured code to use inheritance.
- Assigned a single responsibility to each class.
- Designed classes to be extensible and substitutable.
- Decoupled interfaces and used composition.
- Used dependency inversion to reduce unnessary complexity.
  • Loading branch information
saifkhichi96 committed Mar 27, 2023
1 parent e09c6c4 commit 3be512d
Show file tree
Hide file tree
Showing 39 changed files with 848 additions and 600 deletions.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
15 changes: 4 additions & 11 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,10 @@

def main():
import pygame
from src.game import Game
pygame.init()
from src.game_manager import GameManager

screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Quantum Pathways")

game = Game(screen)
game.main_loop()
gm = GameManager()
gm.run()

pygame.quit()

Expand All @@ -25,5 +19,4 @@ def main():
f.write(str(e))
f.write("\n\nTraceback information:\n")
traceback.print_exc(file=f)
print(f"An error occurred. See {error_file} for details.")
input("Press any key to exit...")
raise e
Empty file added src/character/__init__.py
Empty file.
71 changes: 71 additions & 0 deletions src/character/character.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from src.ui import Image

class Character:
def __init__(self, x, y, sprite_path, size, max_speed_x, max_speed_y,
acceleration_x=0, acceleration_y=0, friction_coefficient=0.0, gravity=0, max_health=100):
self.sprite = Image(sprite_path, size)
self.bbox = self.sprite.get_rect(topleft=(x, y))

self.x, self.y = x, y
self.max_speed_x, self.max_speed_y = max_speed_x, max_speed_y
self.acceleration_x, self.acceleration_y = acceleration_x, acceleration_y
self.friction_coefficient = friction_coefficient
self.gravity = gravity
self.vx, self.vy = 0, 0
self.max_health, self.health = max_health, max_health

def take_damage(self, damage):
self.health -= damage
if self.health <= 0:
self.defeated()

def defeated(self):
pass

def accelerate(self, direction):
self.vx += self.acceleration_x * direction[0]
self.vy += self.acceleration_y * direction[1]

def apply_friction(self, dt):
friction_x = -self.friction_coefficient * self.vx
friction_y = -self.friction_coefficient * self.vy

self.vx += friction_x #* dt
self.vy += friction_y #* dt

def compute_new_position(self, dt):
self.apply_friction(dt)
self.vx = max(-self.max_speed_x, min(self.max_speed_x, self.vx))
self.vy = max(-self.max_speed_y, min(self.max_speed_y, self.vy))
self.vy += self.gravity * dt
new_x = self.x + self.vx #* dt
new_y = self.y + self.vy #* dt
return new_x, new_y

def set_position(self, x, y):
self.x, self.y = x, y
self.bbox.x, self.bbox.y = self.x, self.y
self.sprite.position = (self.x, self.y)

def clamp_position(self, screen):
self.x = max(0, min(screen.get_width() - self.bbox.width, self.x))
self.y = max(0, min(screen.get_height() - self.bbox.height, self.y))
self.bbox.x, self.bbox.y = self.x, self.y

def update(self, dt):
new_x, new_y = self.compute_new_position(dt)
self.set_position(new_x, new_y)

def draw(self, screen):
self.clamp_position(screen)
self.sprite.draw(screen)

def handle_input(self, events, keys):
self.handle_events(events)
self.handle_keys(keys)

def handle_events(self, events):
pass

def handle_keys(self, keys):
pass
5 changes: 5 additions & 0 deletions src/character/entangled_pair.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from src.character.character import Character

class EntangledPair(Character):
def __init__(self, x, y):
super().__init__(x, y, 'entangled_pair.png', (32, 32), 4, 1, 0.9)
Empty file.
33 changes: 33 additions & 0 deletions src/character/player/ghost.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import pygame
from src.character.player.player import Player

class Ghost(Player):
def __init__(self, x, y):
super().__init__(x, y, 'ghost.png')
self.active = False

def activate(self, x, y):
self.set_position(x, y)
self.active = True

def deactivate(self):
self.active = False

def draw(self, screen):
if self.active:
super().draw(screen)

def update(self, dt):
if self.active:
super().update(dt)

def handle_keys(self, keys):
if self.active:
if keys[pygame.K_j]:
self.accelerate((-1, 0))
if keys[pygame.K_l]:
self.accelerate((1, 0))
if keys[pygame.K_i]:
self.accelerate((0, -1))
if keys[pygame.K_k]:
self.accelerate((0, 1))
8 changes: 8 additions & 0 deletions src/character/player/player.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from src.character.character import Character

class Player(Character):
def __init__(self, x, y, sprite_path, size=(30, 30), max_speed_x=4, max_speed_y=4,
acceleration_x=4, acceleration_y=4, friction_coefficient=0.1, gravity=0, max_health=100):
super().__init__(x, y, sprite_path, size, max_speed_x, max_speed_y,
acceleration_x, acceleration_y, friction_coefficient, gravity, max_health)
self.collected_quarks = 0
135 changes: 135 additions & 0 deletions src/character/player/quarky.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import pygame
from src.character.player.player import Player
from src.character.player.ghost import Ghost
from src.character.entangled_pair import EntangledPair

class Quarky(Player):
def __init__(self, x, y):
super().__init__(x, y, 'quarky.png')
self.level = None

# Quarky has a 'ghost` that is a temporary copy of himself
# and appears when he uses the superposition ability
self.superposition_active = False
self.ghost = Ghost(self.bbox.x, self.bbox.y)

# Quarky can get entangled with another instance of himself
# and teleport to his entangled pair when he uses the
# entanglement ability
self.entanglement_active = False
self.entangled_pair = None

# Quarky can use quantum tunneling to tunnel through
# solid objects when he uses the quantum tunneling ability
self.quantum_tunneling_active = False

def set_level(self, level):
self.level = level

def collides_with_goal(self, goal):
return self.bbox.colliderect(goal.rect)

def collides_with_quark(self, quarks):
for quark in quarks:
if self.bbox.colliderect(quark.bbox):
return quark
return None

def merge_with_ghost(self):
self.set_position(self.ghost.bbox.x, self.ghost.bbox.y)
self.ghost.deactivate()

def draw(self, screen):
if self.entangled_pair:
self.entangled_pair.draw(screen)
super().draw(screen)
self.ghost.draw(screen)

def activate_superposition(self):
self.superposition_active = True
self.ghost.activate(self.x, self.y)

def deactivate_superposition(self):
if self.superposition_active:
self.superposition_active = False
self.merge_with_ghost()

def activate_entanglement(self):
self.entanglement_active = True

def toggle_entanglement(self):
if self.entanglement_active:
if self.entangled_pair:
self.set_position(self.entangled_pair.x, self.entangled_pair.y)
self.entangled_pair = None
self.entanglement_active = False
else:
self.entangled_pair = EntangledPair(self.x, self.y)

def activate_quantum_tunneling(self):
self.quantum_tunneling_active = True

def deactivate_quantum_tunneling(self):
if self.quantum_tunneling_active:
self.quantum_tunneling_active = False

def handle_events(self, events):
super().handle_events(events)
actions = {
pygame.K_m: self.deactivate_superposition,
pygame.K_t: self.deactivate_quantum_tunneling,
pygame.K_e: self.toggle_entanglement,
}

for event in events:
if event.type == pygame.KEYDOWN:
if event.key in actions:
actions[event.key]()

def handle_keys(self, keys):
super().handle_keys(keys)
self.ghost.handle_keys(keys)
if keys[pygame.K_LEFT]:
self.accelerate((-1, 0))
if keys[pygame.K_RIGHT]:
self.accelerate((1, 0))
if keys[pygame.K_UP]:
self.accelerate((0, -1))
if keys[pygame.K_DOWN]:
self.accelerate((0, 1))

def handle_quark_interaction(self, quark, level):
if quark.interaction == "superposition":
self.activate_superposition()
elif quark.interaction == "entanglement":
self.activate_entanglement()
elif quark.interaction == "quantum_tunneling":
self.quantum_tunneling_active = True
elif quark.interaction == "collect":
self.collected_quarks += 1

level.quarks.remove(quark)

def update(self, dt):
if self.level:
# Update the player's position while checking for collisions
new_x, new_y = self.compute_new_position(dt)
if self.quantum_tunneling_active:
self.set_position(new_x, new_y)
else:
new_bbox = pygame.Rect(new_x, self.y, self.bbox.width, self.bbox.height)
if not self.level.collides_with_wall(new_bbox):
self.set_position(new_x, self.y)

new_bbox = pygame.Rect(self.x, new_y, self.bbox.width, self.bbox.height)
if not self.level.collides_with_wall(new_bbox):
self.set_position(self.x, new_y)

# Quarks can be collected regardless of quantum tunneling
quark_collision = self.collides_with_quark(self.level.quarks)
if quark_collision:
self.handle_quark_interaction(quark_collision, self.level)

# Update the ghost if superposition is active
if self.superposition_active:
self.ghost.update(dt)
Empty file added src/data/__init__.py
Empty file.
File renamed without changes.
20 changes: 0 additions & 20 deletions src/entangled_pair.py

This file was deleted.

Loading

0 comments on commit 3be512d

Please sign in to comment.