# main_game.py from ursina import * import math import random def simulate_update(duration: float) -> None: for _ in range(int(duration / time.dt)): update() def test_dark_mode_transition() -> None: global is_dark_mode, time_elapsed is_dark_mode = False time_elapsed = 0 exit_dark_mode() simulate_update(normal_mode_duration + 1) assert is_dark_mode, "Failed to switch to dark mode" assert ambient_light.color == ambient_light_dark, "Ambient light color incorrect in dark mode" assert ground.texture == None, "Ground texture should be None in dark mode" assert sky.texture == None, "Sky texture should be None in dark mode" assert aura.enabled == True, "Aura should be enabled in dark mode" simulate_update(dark_mode_duration + 1) assert not is_dark_mode, "Failed to switch to normal mode" assert ambient_light.color == ambient_light_normal, "Ambient light color incorrect in normal mode" assert ground.texture == 'grass', "Ground texture should be 'grass' in normal mode" assert sky.texture == 'sky_sunset', "Sky texture should be 'sky_sunset' in normal mode" assert aura.enabled == False, "Aura should be disabled in normal mode" print("Dark mode transition test passed!") def test_enemy_attack() -> None: global player, enemy player.position = Vec3(10, 0, 10) enemy.position = Vec3(10, 0, 11) simulate_update(1) print("Enemy attack test passed!") def distance_to(pos1: Vec3, pos2: Vec3) -> float: return math.sqrt((pos1.x - pos2.x) ** 2 + (pos1.z - pos2.z) ** 2) def distance_to_player() -> float: return distance_to(player.position, enemy1.position) app = Ursina(fullscreen=True) window.size = Vec2(1920, 1080) window.title = "My First Person Game" from ursina.prefabs.first_person_controller import FirstPersonController player = FirstPersonController() player.position = Vec3(0, 1, 0) # Ensure player spawns above the ground player.speed = 4 run_speed = 30 player_health = 100 player_ammo = 10 player_score = 0 ground = Entity(model="plane", scale=(400, 1, 400)) ground.texture_scale = (40, 40) ground.texture = "grass" ground.collider = BoxCollider(ground) sky = Sky(texture="sky_sunset") pause_menu_enabled = False pause_menu = Text(text='PAUSED', color=color.black, scale=2, position=(0, 0.2), enabled=pause_menu_enabled) def toggle_pause_menu() -> None: global pause_menu_enabled pause_menu_enabled = not pause_menu_enabled pause_menu.enabled = pause_menu_enabled player.enabled = not pause_menu_enabled def input(key: str) -> None: if key == 'p': toggle_pause_menu() if key == 'left mouse down': player_attack() if key == 'right mouse down': shoot_bullet() if key == 'r': reload() # Sound effects hit_sound = Audio('hit.wav', autoplay=False) shoot_sound = Audio('shoot.wav', autoplay=False) reload_sound = Audio('reload.wav', autoplay=False) enemy_hit_sound = Audio('enemy_hit.wav', autoplay=False) enemy_death_sound = Audio('enemy_death.wav', autoplay=False) class Enemy(Entity): def __init__(self, position: Vec3, enemy_type: str) -> None: super().__init__() self.position = position self.type = enemy_type self.health = 50 if enemy_type == 'basic' else 100 self.model = 'quad' self.texture = 'guh.png' if enemy_type == 'basic' else 'zombie.png' self.scale = 8 self.billboard = True self.y = 4 self.speed = 15 if enemy_type == 'basic' else 10 enemy1 = Enemy(position=Vec3(10, 0, 10), enemy_type='basic') aura = Entity(model='sphere', color=color.red, scale=10, position=enemy1.position, enabled=False, double_sided=True) ambient_light_normal = color.rgb(255, 255, 255) ambient_light_dark = color.rgb(0, 0, 0) dark_mode_duration = 10 normal_mode_duration = 10 is_dark_mode = False time_elapsed = 0 def enter_dark_mode() -> None: global is_dark_mode is_dark_mode = True ambient_light.color = ambient_light_dark ground.texture = None sky.texture = None aura.enabled = True def exit_dark_mode() -> None: global is_dark_mode is_dark_mode = False ambient_light.color = ambient_light_normal ground.texture = 'grass' sky.texture = 'sky_sunset' aura.enabled = False ambient_light = Entity() ambient_light.color = ambient_light_normal def enemy_attack() -> None: global player_health print("Enemy attacks!") update_health(player_health - 10) hit_sound.play() obstacles = [ Entity(model='cube', color=color.gray, scale=(5, 5, 5), position=Vec3(0, 2.5, 0), collider='box'), Entity(model='cube', color=color.gray, scale=(5, 5, 5), position=Vec3(30, 2.5, -10), collider='box'), Entity(model='cube', color=color.gray, scale=(5, 5, 5), position=Vec3(-30, 2.5, 10), collider='box') ] trees = [ Entity(model='cube', color=color.green, scale=(2, 10, 2), position=Vec3(-10, 5, -10), collider='box'), Entity(model='cube', color=color.green, scale=(2, 10, 2), position=Vec3(15, 5, 25), collider='box'), Entity(model='cube', color=color.green, scale=(2, 10, 2), position=Vec3(-25, 5, 15), collider='box') ] hills = [ Entity(model='sphere', color=color.brown, scale=(10, 5, 10), position=Vec3(-20, 2.5, -20), collider='box'), Entity(model='sphere', color=color.brown, scale=(15, 8, 15), position=Vec3(25, 4, 25), collider='box') ] # HUD health_text = Text(text=f'Health: {player_health}', color=color.red, position=(-0.85, 0.45), scale=1.5) ammo_text = Text(text=f'Ammo: {player_ammo}', color=color.blue, position=(-0.85, 0.4), scale=1.5) score_text = Text(text=f'Score: {player_score}', color=color.green, position=(-0.85, 0.35), scale=1.5) def update_enemy() -> None: move_towards_target(enemy1, player.position) def move_towards_target(entity: Entity, target_pos: Vec3) -> None: enemy_speed = entity.speed * (2 if is_dark_mode else 1) dx = target_pos.x - entity.x dz = target_pos.z - entity.z distance_to_target = distance_to(entity.position, target_pos) if distance_to_target > 0.1: move_x = dx / distance_to_target * enemy_speed * time.dt * (0.8 + 0.4 * random.random()) move_z = dz / distance_to_target * enemy_speed * time.dt * (0.8 + 0.4 * random.random()) if not any([check_collision(entity.position + Vec3(move_x, 0, move_z), obstacle) for obstacle in obstacles + trees + hills]): entity.x += move_x entity.z += move_z if distance_to(player.position, entity.position) < 2: enemy_attack() def check_collision(pos: Vec3, obstacle: Entity) -> bool: return ( pos.x >= obstacle.position.x - obstacle.scale_x / 2 and pos.x <= obstacle.position.x + obstacle.scale_x / 2 and pos.z >= obstacle.position.z - obstacle.scale_z / 2 and pos.z <= obstacle.position.z + obstacle.scale_z / 2 ) def update_health(new_health: int) -> None: global player_health player_health = max(0, new_health) health_text.text = f'Health: {player_health}' if player_health <= 0: print("Player died!") application.quit() def update_ammo(new_ammo: int) -> None: global player_ammo player_ammo = new_ammo ammo_text.text = f'Ammo: {player_ammo}' def update_score(new_score: int) -> None: global player_score player_score = new_score score_text.text = f'Score: {player_score}' def player_attack() -> None: if distance_to(player.position, enemy1.position) < 5: print("Player attacks enemy!") hit_sound.play() enemy1.health -= 10 if enemy1.health <= 0: print("Enemy killed!") enemy_death_sound.play() update_score(player_score + 100) destroy(enemy1) bullets = [] def shoot_bullet() -> None: if player_ammo > 0: bullet = Entity(model='sphere', color=color.blue, scale=0.2, position=player.position + Vec3(0, 1, 0)) bullet.rotation = player.rotation bullet.direction = bullet.forward bullets.append(bullet) update_ammo(player_ammo - 1) shoot_sound.play() def update_bullets() -> None: global bullets for bullet in bullets[:]: bullet.position += bullet.direction * time.dt * 50 if distance_to(bullet.position, enemy1.position) < 2: print("Bullet hits enemy!") enemy1.health -= 20 bullets.remove(bullet) destroy(bullet) enemy_hit_sound.play() if enemy1.health <= 0: print("Enemy killed by bullet!") enemy_death_sound.play() update_score(player_score + 100) destroy(enemy1) def reload() -> None: update_ammo(10) reload_sound.play() def update() -> None: global time_elapsed if not pause_menu_enabled: forward = player.camera_pivot.forward right = player.camera_pivot.right forward.y = 0 right.y = 0 forward.normalize() right.normalize() move_x = 0 move_z = 0 if held_keys["d"]: move_x += player.speed * time.dt * right.x move_z += player.speed * time.dt * right.z if held_keys["a"]: move_x -= player.speed * time.dt * right.x move_z -= player.speed * time.dt * right.z if held_keys["w"]: move_x += player.speed * time.dt * forward.x move_z += player.speed * time.dt * forward.z if held_keys["s"]: move_x -= player.speed * time.dt * forward.x move_z -= player.speed * time.dt * forward.z if held_keys["shift"]: player.speed = run_speed else: player.speed = 4 if not any([check_collision(player.position + Vec3(move_x, 0, move_z), obstacle) for obstacle in obstacles + trees + hills]): player.x += move_x player.z += move_z border_x = 190 border_z = 190 player.x = clamp(player.x, -border_x, border_x) player.z = clamp(player.z, -border_z, border_z) update_enemy() update_bullets() aura.position = enemy1.position time_elapsed += time.dt if is_dark_mode and time_elapsed > dark_mode_duration: exit_dark_mode() time_elapsed = 0 elif not is_dark_mode and time_elapsed > normal_mode_duration: enter_dark_mode() time_elapsed = 0 app.run() test_dark_mode_transition() test_enemy_attack()