REAVT2 / alien_system.py
testrro's picture
Update alien_system.py
510fbd5 verified
import json
import os
import random
import time # ← এই লাইনটি যোগ করতে হবে
from dataclasses import dataclass, asdict
from typing import List, Dict, Optional, Tuple
from enum import Enum
import math
from datetime import datetime
from rng_system import get_rng
class AlienType(Enum):
"""এলিয়েনের ধরণ"""
SCOUT = "scout" # ছোট, দ্রুত
FIGHTER = "fighter" # মাঝারি, স্ট্যান্ডার্ড
BOMBER = "bomber" # বড়, ধীর
BOSS = "boss" # খুব বড়, শক্তিশালী
class AlienBehavior(Enum):
"""এলিয়েনের আচরণের ধরণ (ডিটারমিনিস্টিক)"""
DIVE = "dive" # ডাইভ অ্যাটাক
CIRCLE = "circle" # বৃত্তাকার পথ
STRAIGHT = "straight" # সরলরেখা
ZIGZAG = "zigzag" # জিগজ্যাগ
FOLLOW = "follow" # প্লেয়ার ফলো
RANDOM = "random" # এলোমেলো (র‍্যান্ডম)
@dataclass
class AlienPattern:
"""এলিয়েন আক্রমণের প্যাটার্ন (ডিটারমিনিস্টিক)"""
behavior: AlienBehavior
speed: float
amplitude: float # জিগজ্যাগ/সার্কেলের জন্য
frequency: float # জিগজ্যাগের ফ্রিকোয়েন্সি
duration: float # প্যাটার্ন চলার সময়
next_pattern: Optional['AlienPattern'] = None
@dataclass
class Alien:
"""এলিয়েন অবজেক্ট"""
id: int
type: AlienType
x: float
y: float
health: int
pattern: AlienPattern
pattern_start_time: float
speed_multiplier: float
def to_dict(self):
return {
'id': self.id,
'type': self.type.value,
'x': round(self.x, 2),
'y': round(self.y, 2),
'health': self.health,
'pattern': self.pattern.behavior.value
}
@dataclass
class SpawnEvent:
"""স্পন ইভেন্ট"""
time: float
alien_type: AlienType
x: float
y: float
pattern: AlienPattern
class AlienPatternLibrary:
"""
এলিয়েন প্যাটার্ন লাইব্রেরি - ডিটারমিনিস্টিক প্যাটার্নের সেট
PDF অনুযায়ী: এলিয়েনরা ডিটারমিনিস্টিক, র‍্যান্ডম নয়
"""
def __init__(self, patterns_file: str = "data/alien_patterns.json"):
self.patterns_file = patterns_file
self.patterns: Dict[AlienType, List[AlienPattern]] = {}
self._load_patterns()
def _load_patterns(self):
"""প্যাটার্ন লোড করা"""
if os.path.exists(self.patterns_file):
with open(self.patterns_file, 'r') as f:
data = json.load(f)
for alien_type, patterns in data.items():
self.patterns[AlienType(alien_type)] = [
AlienPattern(**p) for p in patterns
]
else:
# ডিফল্ট প্যাটার্ন তৈরি
self._create_default_patterns()
def _create_default_patterns(self):
"""ডিফল্ট প্যাটার্ন তৈরি (PDF-এর মতো)"""
# Scout এলিয়েনের প্যাটার্ন
self.patterns[AlienType.SCOUT] = [
AlienPattern(AlienBehavior.DIVE, 5.0, 0, 0, 2.0),
AlienPattern(AlienBehavior.STRAIGHT, 4.0, 0, 0, 1.5),
AlienPattern(AlienBehavior.CIRCLE, 3.0, 50, 1, 3.0),
AlienPattern(AlienBehavior.ZIGZAG, 4.5, 30, 2, 2.5)
]
# Fighter এলিয়েনের প্যাটার্ন
self.patterns[AlienType.FIGHTER] = [
AlienPattern(AlienBehavior.FOLLOW, 3.5, 0, 0, 3.0),
AlienPattern(AlienBehavior.DIVE, 4.0, 0, 0, 2.5),
AlienPattern(AlienBehavior.STRAIGHT, 3.0, 0, 0, 2.0),
AlienPattern(AlienBehavior.ZIGZAG, 3.5, 40, 1.5, 3.0)
]
# Bomber এলিয়েনের প্যাটার্ন
self.patterns[AlienType.BOMBER] = [
AlienPattern(AlienBehavior.STRAIGHT, 2.0, 0, 0, 4.0),
AlienPattern(AlienBehavior.CIRCLE, 1.8, 80, 0.5, 5.0),
AlienPattern(AlienBehavior.FOLLOW, 2.2, 0, 0, 3.5)
]
# Boss এলিয়েনের প্যাটার্ন
self.patterns[AlienType.BOSS] = [
AlienPattern(AlienBehavior.CIRCLE, 1.5, 100, 0.3, 8.0),
AlienPattern(AlienBehavior.FOLLOW, 2.0, 0, 0, 5.0),
AlienPattern(AlienBehavior.DIVE, 2.5, 0, 0, 4.0),
AlienPattern(AlienBehavior.STRAIGHT, 1.8, 0, 0, 6.0)
]
def get_pattern_cycle(self, alien_type: AlienType) -> List[AlienPattern]:
"""একটি এলিয়েনের জন্য প্যাটার্ন সাইকেল রিটার্ন করে"""
return self.patterns.get(alien_type, self.patterns[AlienType.FIGHTER])
class AlienSpawner:
"""
এলিয়েন স্পনার - PDF-এর SpawnAlien রুটিনের ইমপ্লিমেন্টেশন
র‍্যান্ডম অবস্থান তৈরি করতে RNG ব্যবহার করে, কিন্তু এলিয়েনের আচরণ ডিটারমিনিস্টিক
"""
def __init__(self, pattern_library: AlienPatternLibrary,
screen_width: int = 800, screen_height: int = 600):
self.rng = get_rng()
self.pattern_library = pattern_library
self.screen_width = screen_width
self.screen_height = screen_height
self.aliens: List[Alien] = []
self.spawn_history: List[SpawnEvent] = []
self.next_alien_id = 0
# স্পন প্যারামিটার
self.spawn_rate = 0.5 # প্রতি সেকেন্ডে এলিয়েন
self.last_spawn_time = time.time() # ← এখানে time.time() ব্যবহার করা হয়েছে
self.max_aliens = 20
# স্ট্যাটিস্টিক্স
self.total_spawned = 0
self.total_killed = 0
def _get_random_spawn_position(self) -> Tuple[float, float]:
"""
এলোমেলো স্পন অবস্থান (র‍্যান্ডম - PDF অনুযায়ী)
"""
side = self.rng.next_random_range(0, 3) # 0=উপরে, 1=নিচে, 2=বামে, 3=ডানে
if side == 0: # উপরে
x = self.rng.next_random_float(0, self.screen_width)
y = -50
elif side == 1: # নিচে
x = self.rng.next_random_float(0, self.screen_width)
y = self.screen_height + 50
elif side == 2: # বামে
x = -50
y = self.rng.next_random_float(0, self.screen_height)
else: # ডানে
x = self.screen_width + 50
y = self.rng.next_random_float(0, self.screen_height)
return x, y
def _select_alien_type(self) -> AlienType:
"""
এলোমেলো এলিয়েন টাইপ সিলেক্ট (র‍্যান্ডম)
"""
r = self.rng.next_random_float()
if r < 0.5: # ৫০% scout
return AlienType.SCOUT
elif r < 0.8: # ৩০% fighter
return AlienType.FIGHTER
elif r < 0.95: # ১৫% bomber
return AlienType.BOMBER
else: # ৫% boss
return AlienType.BOSS
def _create_alien(self, alien_type: AlienType, x: float, y: float) -> Alien:
"""
নতুন এলিয়েন তৈরি
"""
# এলিয়েন টাইপ অনুযায়ী স্বাস্থ্য
health_map = {
AlienType.SCOUT: 1,
AlienType.FIGHTER: 3,
AlienType.BOMBER: 5,
AlienType.BOSS: 20
}
# প্যাটার্ন সাইকেল থেকে প্রথম প্যাটার্ন নেওয়া
patterns = self.pattern_library.get_pattern_cycle(alien_type)
pattern = patterns[0]
# স্পিড মাল্টিপ্লায়ার (ছোট ভ্যারিয়েশন)
speed_multiplier = 0.9 + self.rng.next_random_float() * 0.2
alien = Alien(
id=self.next_alien_id,
type=alien_type,
x=x,
y=y,
health=health_map[alien_type],
pattern=pattern,
pattern_start_time=time.time(),
speed_multiplier=speed_multiplier
)
self.next_alien_id += 1
return alien
def update(self, dt: float, player_x: float = 400, player_y: float = 300):
"""
প্রতি ফ্রেমে আপডেট
"""
current_time = time.time()
# নতুন এলিয়েন স্পন
if (len(self.aliens) < self.max_aliens and
current_time - self.last_spawn_time > 1.0 / self.spawn_rate):
alien_type = self._select_alien_type()
x, y = self._get_random_spawn_position()
alien = self._create_alien(alien_type, x, y)
self.aliens.append(alien)
self.spawn_history.append(SpawnEvent(
time=current_time,
alien_type=alien_type,
x=x,
y=y,
pattern=alien.pattern
))
self.total_spawned += 1
self.last_spawn_time = current_time
# এলিয়েনদের অবস্থান আপডেট (ডিটারমিনিস্টিক প্যাটার্ন অনুযায়ী)
aliens_to_remove = []
for alien in self.aliens:
self._update_alien_position(alien, dt, player_x, player_y)
# স্ক্রিনের বাইরে চলে গেলে রিমুভ
if (alien.x < -200 or alien.x > self.screen_width + 200 or
alien.y < -200 or alien.y > self.screen_height + 200):
aliens_to_remove.append(alien)
# মৃত এলিয়েন রিমুভ
for alien in aliens_to_remove:
if alien in self.aliens:
self.aliens.remove(alien)
self.total_killed += 1
def _update_alien_position(self, alien: Alien, dt: float,
player_x: float, player_y: float):
"""
এলিয়েনের অবস্থান আপডেট (প্যাটার্ন অনুযায়ী - ডিটারমিনিস্টিক)
"""
time_in_pattern = time.time() - alien.pattern_start_time
# প্যাটার্নের সময় শেষ হলে পরবর্তী প্যাটার্নে যাওয়া
if time_in_pattern > alien.pattern.duration:
patterns = self.pattern_library.get_pattern_cycle(alien.type)
current_index = patterns.index(alien.pattern) if alien.pattern in patterns else 0
next_index = (current_index + 1) % len(patterns)
alien.pattern = patterns[next_index]
alien.pattern_start_time = time.time()
time_in_pattern = 0
speed = alien.pattern.speed * alien.speed_multiplier * dt * 60 # 60 FPS ধরে
# প্যাটার্ন অনুযায়ী মুভমেন্ট
if alien.pattern.behavior == AlienBehavior.DIVE:
# প্লেয়ারের দিকে ডাইভ
dx = player_x - alien.x
dy = player_y - alien.y
dist = math.sqrt(dx*dx + dy*dy)
if dist > 0:
alien.x += (dx / dist) * speed
alien.y += (dy / dist) * speed
elif alien.pattern.behavior == AlienBehavior.CIRCLE:
# বৃত্তাকার পথ
angle = time_in_pattern * alien.pattern.frequency
alien.x += math.cos(angle) * speed
alien.y += math.sin(angle) * speed
elif alien.pattern.behavior == AlienBehavior.STRAIGHT:
# সরলরেখায় (পূর্ব নির্ধারিত দিকে)
alien.x -= speed # বামে
elif alien.pattern.behavior == AlienBehavior.ZIGZAG:
# জিগজ্যাগ প্যাটার্ন
alien.x -= speed
alien.y += math.sin(time_in_pattern * alien.pattern.frequency) * alien.pattern.amplitude * dt
elif alien.pattern.behavior == AlienBehavior.FOLLOW:
# প্লেয়ারকে ফলো
dx = player_x - alien.x
dy = player_y - alien.y
dist = math.sqrt(dx*dx + dy*dy)
if dist > 100: # ১০০ পিক্সেল দূরত্বে রাখে
if dist > 0:
alien.x += (dx / dist) * speed * 0.5
alien.y += (dy / dist) * speed * 0.5
# র‍্যান্ডম বিহেভিয়ার (শুধু যদি সেট করা থাকে)
elif alien.pattern.behavior == AlienBehavior.RANDOM:
alien.x += (self.rng.next_random_float() - 0.5) * speed * 2
alien.y += (self.rng.next_random_float() - 0.5) * speed * 2
def damage_alien(self, alien_id: int, damage: int = 1) -> bool:
"""এলিয়েনকে আঘাত করা"""
for alien in self.aliens:
if alien.id == alien_id:
alien.health -= damage
if alien.health <= 0:
self.aliens.remove(alien)
self.total_killed += 1
return True
break
return False
def get_aliens_data(self) -> List[dict]:
"""UI-এর জন্য এলিয়েন ডাটা"""
return [alien.to_dict() for alien in self.aliens]
def get_stats(self) -> dict:
"""পরিসংখ্যান"""
return {
'total_spawned': self.total_spawned,
'total_killed': self.total_killed,
'active_aliens': len(self.aliens),
'spawn_rate': self.spawn_rate
}
def get_spawn_history(self, limit: int = 50) -> List[dict]:
"""স্পন হিস্ট্রি"""
return [
{
'time': datetime.fromtimestamp(e.time).strftime('%H:%M:%S'),
'type': e.alien_type.value,
'position': f"({int(e.x)},{int(e.y)})"
}
for e in self.spawn_history[-limit:]
]
class AlienAIManager:
"""
এলিয়েন এআই ম্যানেজার - ডিটারমিনিস্টিক প্যাটার্ন ম্যানেজ করে
PDF অনুযায়ী: এলিয়েনরা ডিটারমিনিস্টিক
"""
def __init__(self):
self.pattern_library = AlienPatternLibrary()
self.current_cycle_index = 0
self.cycle_length = 4 # প্রতি ৪ রাউন্ডে প্যাটার্ন রিসেট
def get_attack_wave_pattern(self, wave_number: int) -> List[AlienPattern]:
"""
ওয়েব নম্বর অনুযায়ী অ্যাটাক প্যাটার্ন
ডিটারমিনিস্টিক - প্রতি ওয়েভে একই প্যাটার্ন রিপিট
"""
base_pattern = self.pattern_library.get_pattern_cycle(AlienType.FIGHTER)
# ওয়েব নম্বর অনুযায়ী প্যাটার্ন মডিফাই
wave_index = (wave_number // self.cycle_length) % len(base_pattern)
return [base_pattern[wave_index]]
def predict_next_attack(self, current_wave: int) -> str:
"""
পরবর্তী অ্যাটাকের ধরণ প্রেডিক্ট (ডিটারমিনিস্টিক)
"""
next_pattern = self.get_attack_wave_pattern(current_wave + 1)
return f"পরবর্তী অ্যাটাক: {next_pattern[0].behavior.value}"