"""Complete API reference for the AxisPy Engine, used as context for AI chat."""
from __future__ import annotations
[docs]
def get_engine_api_reference() -> str:
"""Return a comprehensive API reference string for the engine."""
return _ENGINE_API_REFERENCE
_ENGINE_API_REFERENCE = (
"# AxisPy Engine API Reference\n\n"
"## Architecture\n"
"AxisPy uses an Entity-Component-System (ECS) architecture built on pygame.\n"
"- **Entity**: A game object with a name, components, children, groups, tags, and a layer.\n"
"- **Component**: Data attached to an entity (Transform, SpriteRenderer, etc.).\n"
"- **System**: Logic that processes entities each frame (PhysicsSystem, RenderSystem, etc.).\n"
"- **World**: Container for all entities and systems. Manages the game loop phases.\n"
"- **Scene**: Wrapper around a World. Scenes are saved as JSON files.\n\n"
"## Scripting\n"
"Scripts are plain Python classes attached via `ScriptComponent`.\n"
"The engine auto-injects `self.entity` and `self.logger` into script instances.\n\n"
"### Script Lifecycle Methods\n"
"```python\n"
"class MyScript:\n"
" def on_start(self): # Called once when the entity enters the scene\n"
" pass\n"
" def on_update(self, dt): # Called every frame, dt = delta time in seconds\n"
" pass\n"
" def on_fixed_update(self, dt): # Called at fixed physics rate (60 Hz)\n"
" pass\n"
" def on_collision_enter(self, other_entity, collision_info): # collision begins\n"
" # collision_info has .normal (Vector2), .penetration (float)\n"
" pass\n"
" def on_collision_exit(self, other_entity): # collision ends\n"
" pass\n"
" def on_trigger_enter(self, other_entity): # entering a trigger zone\n"
" pass\n"
" def on_trigger_exit(self, other_entity): # exiting a trigger zone\n"
" pass\n"
" def on_destroy(self): # entity is destroyed\n"
" pass\n"
" def on_enable(self): # entity becomes visible (show())\n"
" pass\n"
" def on_disable(self): # entity becomes hidden (hide())\n"
" pass\n"
"```\n\n"
"### Injected Helper Methods (available on self in scripts)\n"
"```python\n"
"self.entity # The Entity this script is attached to\n"
"self.logger # Logger instance (self.logger.info('msg'))\n"
"self.find(name) # Find entity by name in the world\n"
"self.get_children(name) # Get children of entity found by name\n"
"self.destroy() # Destroy this entity\n"
"self.hide() # Hide this entity\n"
"self.show() # Show this entity\n"
"self.process_physics(enabled) # Enable/disable physics on this entity\n"
"self.change_scene(scene_name) # Change to another scene file\n"
"self.call_group(group, method, *args) # Call method on all scripts in a group\n"
"self.instantiate_prefab(path, parent=None, name=None, x=None, y=None, rotation=None, scale_x=None, scale_y=None)\n"
"self.spawn_prefab(...) # Alias for instantiate_prefab\n"
"self.start_coroutine(generator) # Start a coroutine\n"
"self.stop_coroutines() # Stop all coroutines on this script\n"
"self.tween(entity, attr_path, target, start=None, duration=1.0, easing=None, on_complete=None, loops=0, yoyo=False)\n"
"self.cancel_tweens(entity=None) # Cancel tweens\n"
"\n"
"# Event system\n"
"self.subscribe_to_event(event_name, callback, target_entity=None)\n"
"self.unsubscribe_from_event(event_name, callback, target_entity=None)\n"
"self.emit_global_event(event_name, *args, **kwargs) # Queued (1-frame latency)\n"
"self.emit_local_event(event_name, *args, **kwargs) # Queued on this entity\n"
"self.emit_global_event_immediate(event_name, *args, **kwargs) # Synchronous\n"
"self.emit_local_event_immediate(event_name, *args, **kwargs) # Synchronous on entity\n"
"```\n\n"
"## Core Classes\n\n"
"### Vector2\n"
"```python\n"
"from core.vector import Vector2\n"
"v = Vector2(x, y)\n"
"v.magnitude() # Length\n"
"v.normalize() # Unit vector\n"
"v.dot(other) # Dot product\n"
"v.distance_to(other)\n"
"v.angle_to(other) # Degrees\n"
"v.lerp(other, t) # Linear interpolation\n"
"v.rotate(degrees) # Rotate vector in degrees\n"
"Vector2.zero() # (0, 0)\n"
"Vector2.one() # (1, 1)\n"
"Vector2.up() # (0, -1)\n"
"Vector2.down() # (0, 1)\n"
"Vector2.left() # (-1, 0)\n"
"Vector2.right() # (1, 0)\n"
"# Supports +, -, *, /, ==, !=\n"
"```\n\n"
"### Entity\n"
"```python\n"
"entity.name # str\n"
"entity.id # UUID string\n"
"entity.layer # str (e.g. 'Default')\n"
"entity.groups # set[str]\n"
"entity.tags # set[str]\n"
"entity.parent # Entity or None\n"
"entity.children # list[Entity]\n"
"entity.world # World\n"
"entity.add_component(component)\n"
"entity.get_component(ComponentType) # Returns component or None\n"
"entity.remove_component(ComponentType)\n"
"entity.add_child(child_entity)\n"
"entity.remove_child(child_entity)\n"
"entity.get_child(name) # First child with name\n"
"entity.add_group(group)\n"
"entity.remove_group(group)\n"
"entity.has_group(group)\n"
"entity.add_tag(tag)\n"
"entity.remove_tag(tag)\n"
"entity.has_tag(tag)\n"
"entity.set_layer(layer)\n"
"entity.hide()\n"
"entity.show()\n"
"entity.is_visible()\n"
"entity.process_physics(enabled)\n"
"entity.destroy()\n"
"```\n\n"
"### World\n"
"```python\n"
"world = entity.world\n"
"world.create_entity(name='MyEntity')\n"
"world.destroy_entity(entity)\n"
"world.get_entity_by_name(name)\n"
"world.get_entities_by_name(name) # Returns list\n"
"world.get_entities_with(ComponentType) # All entities with component\n"
"world.get_entities_in_group(group)\n"
"world.query() # Returns EntityQuery for fluent filtering\n"
"# EntityQuery usage:\n"
"results = world.query().with_component(Transform, SpriteRenderer).in_group('enemies').with_tag('boss').visible().all()\n"
"# Event system\n"
"world.events.subscribe(event_name, callback)\n"
"world.events.unsubscribe(event_name, callback)\n"
"world.events.emit(event_name, *args, **kwargs)\n"
"world.events.emit_immediate(event_name, *args, **kwargs)\n"
"# Scene changes\n"
"world.request_scene_change(scene_path)\n"
"```\n\n"
"## Components\n\n"
"### Transform\n"
"```python\n"
"from core.components import Transform\n"
"t = Transform(x=0, y=0, rotation=0, scale_x=1, scale_y=1)\n"
"t.x, t.y # Position\n"
"t.rotation # Degrees (0-360)\n"
"t.scale_x, t.scale_y # Scale\n"
"t.position # Vector2\n"
"t.translate(dx, dy) # Move relative\n"
"```\n\n"
"### SpriteRenderer\n"
"```python\n"
"from core.components import SpriteRenderer\n"
"sr = SpriteRenderer(color=(255,255,255), width=50, height=50, image_path=None)\n"
"sr.image_path # Path to image file\n"
"sr.color # (r, g, b) tuple\n"
"sr.width # Scaled width (read/write)\n"
"sr.height # Scaled height (read/write)\n"
"sr.load_image(path)\n"
"```\n\n"
"### BoxCollider2D\n"
"```python\n"
"from core.components import BoxCollider2D\n"
"bc = BoxCollider2D(width=50, height=50, offset_x=0, offset_y=0, is_trigger=False, rotation=0)\n"
"bc.width, bc.height\n"
"bc.offset_x, bc.offset_y\n"
"bc.is_trigger # True = trigger zone (no physics response)\n"
"bc.category_mask, bc.collision_mask\n"
"bc.rotation # Local rotation in degrees\n"
"```\n\n"
"### CircleCollider2D\n"
"```python\n"
"from core.components import CircleCollider2D\n"
"cc = CircleCollider2D(radius=25, offset_x=0, offset_y=0, is_trigger=False, rotation=0)\n"
"cc.radius\n"
"cc.offset_x, cc.offset_y\n"
"cc.is_trigger\n"
"cc.category_mask, cc.collision_mask\n"
"cc.rotation\n"
"```\n\n"
"### PolygonCollider2D\n"
"```python\n"
"from core.components import PolygonCollider2D\n"
"pc = PolygonCollider2D(points=[Vector2(-10,-10), Vector2(10,-10), Vector2(0,10)])\n"
"pc.points # list[Vector2]\n"
"pc.offset_x, pc.offset_y\n"
"pc.is_trigger\n"
"pc.category_mask, pc.collision_mask\n"
"pc.rotation\n"
"```\n\n"
"### Rigidbody2D\n"
"```python\n"
"from core.components import Rigidbody2D\n"
"rb = Rigidbody2D(mass=1.0, gravity_scale=1.0, body_type='dynamic')\n"
"rb.mass\n"
"rb.gravity_scale\n"
"rb.body_type # 'dynamic', 'static', 'kinematic'\n"
"rb.velocity_x # Current velocity\n"
"rb.velocity_y\n"
"rb.linear_damping\n"
"rb.angular_velocity\n"
"rb.angular_damping\n"
"rb.can_rotate # bool\n"
"rb.restitution # Bounciness (0-1)\n"
"rb.friction\n"
"rb.apply_force(x, y)\n"
"rb.apply_impulse(x, y)\n"
"rb.apply_torque(torque)\n"
"rb.apply_angular_impulse(angular_impulse)\n"
"```\n\n"
"### CameraComponent\n"
"```python\n"
"from core.components import CameraComponent\n"
"cam = CameraComponent(zoom=1.0, viewport_width=1.0, viewport_height=1.0, active=True)\n"
"cam.zoom # Camera zoom level (min 0.01)\n"
"cam.active # Only one camera should be active\n"
"cam.shake(intensity, duration, decay='linear') # Camera shake effect\n"
"```\n\n"
"### AnimatorComponent\n"
"```python\n"
"from core.components import AnimatorComponent\n"
"anim = AnimatorComponent(controller=None)\n"
"# controller is an AnimationController with states and transitions\n"
"```\n\n"
"### ParticleEmitterComponent\n"
"```python\n"
"from core.components import ParticleEmitterComponent\n"
"pe = ParticleEmitterComponent()\n"
"pe.emitting # bool\n"
"pe.emission_rate # particles per second\n"
"pe.max_particles\n"
"pe.lifetime # seconds\n"
"pe.speed, pe.speed_variance\n"
"pe.direction, pe.spread # degrees\n"
"pe.gravity_x, pe.gravity_y\n"
"pe.start_color, pe.end_color # (r,g,b,a)\n"
"pe.start_size, pe.end_size\n"
"pe.shape # 'point', 'circle', 'rectangle'\n"
"```\n\n"
"### SoundComponent\n"
"```python\n"
"from core.components import SoundComponent\n"
"sound = SoundComponent(sound_path='audio/sfx.wav', volume=1.0, loop=False, autoplay=False)\n"
"sound.play()\n"
"sound.stop()\n"
"sound.set_volume(vol)\n"
"```\n\n"
"### TimerComponent\n"
"```python\n"
"from core.components.timer import TimerComponent\n"
"timer = TimerComponent(duration=1.0, one_shot=True, autostart=False, callback=self.on_timeout)\n"
"timer.start()\n"
"timer.stop()\n"
"timer.reset()\n"
"```\n\n"
"### ScriptComponent\n"
"```python\n"
"from core.components import ScriptComponent\n"
"sc = ScriptComponent(script_path='scripts/my_script.py', class_name='MyScript')\n"
"```\n\n"
"### TilemapComponent\n"
"```python\n"
"from core.components import TilemapComponent\n"
"tm = TilemapComponent(tile_width=16, tile_height=16)\n"
"tm.get_cell(layer, x, y)\n"
"tm.set_cell(layer, x, y, tile_id)\n"
"tm.world_to_tile(world_x, world_y)\n"
"tm.tile_to_world(tile_x, tile_y)\n"
"```\n\n"
"### Lighting Components\n"
"```python\n"
"from core.components.light import PointLight2D, SpotLight2D, LightOccluder2D\n"
"light = PointLight2D(radius=200, color=(255,255,200), intensity=1.0, falloff=1.5)\n"
"spot = SpotLight2D(radius=300, color=(255,255,200), intensity=1.0, angle=0, cone_angle=45)\n"
"occluder = LightOccluder2D(shape='box', width=50, height=50)\n"
"# occluder shapes: 'box', 'circle', 'polygon'\n"
"```\n\n"
"### UI Components\n"
"```python\n"
"from core.components.ui import (\n"
" TextRenderer, ButtonComponent, TextInputComponent,\n"
" SliderComponent, ProgressBarComponent, CheckBoxComponent,\n"
" ImageRenderer, HBoxContainerComponent, VBoxContainerComponent,\n"
" GridBoxContainerComponent\n"
")\n"
"text = TextRenderer(text='Hello', font_size=24, color=(255,255,255))\n"
"btn = ButtonComponent(text='Click Me', width=120, height=40)\n"
"# ButtonComponent emits 'pressed' event on the entity\n"
"```\n\n"
"### Steering AI Components\n"
"```python\n"
"from core.components.steering import (\n"
" SteeringAgentComponent, SeekBehavior, FleeBehavior,\n"
" ArriveBehavior, WanderBehavior,\n"
" SeparationBehavior, CohesionBehavior, AlignmentBehavior\n"
")\n"
"agent = SteeringAgentComponent(max_speed=200, max_force=500, mass=1.0)\n"
"seek = SeekBehavior(target_x=100, target_y=200, weight=1.0)\n"
"flee = FleeBehavior(target_x=0, target_y=0, panic_distance=200)\n"
"arrive = ArriveBehavior(target_x=100, target_y=100, slow_radius=50)\n"
"wander = WanderBehavior(wander_radius=50, wander_distance=80)\n"
"```\n\n"
"## Input System\n"
"```python\n"
"import pygame\n"
"from core.input import Input\n"
"# Keyboard\n"
"Input.get_key(pygame.K_LEFT) # True while held\n"
"Input.get_axis('Horizontal') # -1 to 1 (left/right or a/d)\n"
"Input.get_axis('Vertical') # -1 to 1 (up/down or w/s)\n"
"# Mouse\n"
"Input.get_mouse_button(0) # Left=0, Middle=1, Right=2\n"
"Input.get_mouse_position() # (x, y) screen coords\n"
"Input.get_game_mouse_position() # (x, y) in game/world coords\n"
"# Gamepad\n"
"Input.get_joy_button(button, instance_id=-1)\n"
"Input.get_joy_button_down(button, instance_id=-1)\n"
"Input.get_joy_axis(axis, instance_id=-1) # -1 to 1\n"
"Input.get_joy_hat(hat=0, instance_id=-1) # (x, y)\n"
"Input.get_joystick_count()\n"
"# Touch (mobile)\n"
"Input.get_touches() # dict of active TouchPoint\n"
"Input.get_touches_started() # began this frame\n"
"Input.get_gesture() # TouchGesture object\n"
"```\n\n"
"## Coroutines\n"
"```python\n"
"def on_start(self):\n"
" self.start_coroutine(self.my_routine())\n"
"\n"
"def my_routine(self):\n"
" yield 1.0 # Wait 1 second\n"
" self.logger.info('After 1 second')\n"
" yield 0.5 # Wait 0.5 seconds\n"
" self.logger.info('After 1.5 seconds total')\n"
"```\n\n"
"## Tweens\n"
"```python\n"
"def on_start(self):\n"
" from core.tween import Easing\n"
" self.tween(self.entity, 'Transform.x', target=500, duration=2.0, easing=Easing.ease_in_out_quad)\n"
"# Available easings: linear, ease_in_quad, ease_out_quad, ease_in_out_quad,\n"
"# ease_in_cubic, ease_out_cubic, ease_in_out_cubic, ease_in_sine, ease_out_sine,\n"
"# ease_in_out_sine, ease_in_expo, ease_out_expo, ease_in_out_expo,\n"
"# ease_in_back, ease_out_back, ease_in_out_back, bounce_out\n"
"```\n\n"
"## State Machine\n"
"```python\n"
"from core.state_machine import StateMachine, State\n"
"class IdleState(State):\n"
" def on_enter(self): pass\n"
" def on_update(self, dt): pass\n"
" def on_exit(self): pass\n"
"class RunState(State):\n"
" def on_enter(self): pass\n"
" def on_update(self, dt): pass\n"
" def on_exit(self): pass\n"
"# In script:\n"
"def on_start(self):\n"
" self.sm = StateMachine(self.entity)\n"
" self.sm.add_state('idle', IdleState())\n"
" self.sm.add_state('run', RunState())\n"
" self.sm.start('idle')\n"
"def on_update(self, dt):\n"
" self.sm.update(dt)\n"
" if Input.get_key('right'):\n"
" self.sm.transition_to('run')\n"
"```\n\n"
"## Save/Load\n"
"```python\n"
"from core.save_manager import SaveManager\n"
"sm = SaveManager()\n"
"sm.save('slot1', {'score': 100, 'level': 3})\n"
"data = sm.load('slot1') # Returns dict or None\n"
"sm.delete('slot1')\n"
"sm.list_slots() # Returns list of slot names\n"
"```\n\n"
"## Physics Queries\n"
"```python\n"
"# From a script, access physics via world systems:\n"
"physics = self.entity.world.get_system(PhysicsSystem)\n"
"# Overlap queries:\n"
"entities = physics.overlap_box(x, y, width, height)\n"
"entities = physics.overlap_circle(x, y, radius)\n"
"```\n\n"
"## Networking & Multiplayer\n\n"
"### HTTPClientComponent\n"
"```python\n"
"from core.components import HTTPClientComponent\n"
"http = HTTPClientComponent(base_url='https://api.example.com', timeout=30.0)\n"
"http.get('/data', tag='fetch')\n"
"http.post('/submit', body={'key': 'val'}, tag='submit')\n"
"# In on_update:\n"
"for response in http.poll():\n"
" if response.ok:\n"
" data = response.json()\n"
"```\n\n"
"### HTTPRequestComponent\n"
"```python\n"
"from core.components import HTTPRequestComponent\n"
"req = HTTPRequestComponent(url='https://api.example.com/data', method='GET')\n"
"req.send()\n"
"# In on_update:\n"
"if req.is_done():\n"
" print(req.status_code, req.response_body)\n"
"```\n\n"
"### WebSocketComponent\n"
"```python\n"
"from core.components import WebSocketComponent\n"
"ws = WebSocketComponent(mode='client', url='ws://localhost:8765')\n"
"ws.start()\n"
"ws.send_json({'type': 'hello'})\n"
"# In on_update:\n"
"for sender, msg in ws.poll():\n"
" pass\n"
"```\n\n"
"### MultiplayerComponent\n"
"```python\n"
"from core.components import MultiplayerComponent\n"
"mp = MultiplayerComponent(player_name='Player1', max_players=8)\n"
"mp.host_game('MyRoom')\n"
"mp.join_game('ws://localhost:8765', 'Player2')\n"
"mp.set_ready(True)\n"
"mp.start_game()\n"
"mp.rpc('take_damage', {'amount': 10})\n"
"mp.request_spawn('prefabs/player.entity')\n"
"# Listens to global events: mp_player_joined, mp_game_started, mp_rpc, mp_spawn\n"
"```\n\n"
"### NetworkIdentityComponent\n"
"```python\n"
"from core.components import NetworkIdentityComponent\n"
"net_id = NetworkIdentityComponent(net_id='1234', owner_id='host', is_local_player=True)\n"
"net_id.sync_transform = True\n"
"```\n\n"
"### WebRTCComponent\n"
"```python\n"
"from core.components import WebRTCComponent\n"
"rtc = WebRTCComponent(ice_servers='stun:stun.l.google.com:19302', data_channel_label='game')\n"
"rtc.start()\n"
"rtc.create_offer()\n"
"rtc.send('Hello peer!')\n"
"# In on_update:\n"
"for sender, msg in rtc.poll():\n"
" if sender == 'datachannel':\n"
" pass\n"
"```\n\n"
"### WebviewComponent\n"
"```python\n"
"from core.components import WebviewComponent\n"
"wv = WebviewComponent(url='https://example.com', title='My Webview', width=800, height=600)\n"
"wv.open()\n"
"wv.evaluate_js('document.title')\n"
"# In on_update:\n"
"for result in wv.poll():\n"
" pass\n"
"```\n\n"
"### ResourceManager\n"
"```python\n"
"from core.resources import ResourceManager\n"
"image = ResourceManager.load_image('assets/images/player.png')\n"
"sound = ResourceManager.load_sound('assets/sounds/jump.wav')\n"
"ResourceManager.unload_image('assets/images/player.png')\n"
"```\n\n"
"### ObjectPool\n"
"```python\n"
"from core.object_pool import ObjectPool\n"
"pool = ObjectPool(self.entity.world, prefill={'bullet': (create_bullet, 20)})\n"
"bullet = pool.acquire('bullet')\n"
"pool.release('bullet', bullet)\n"
"```\n\n"
"### SceneTransition\n"
"```python\n"
"from core.scene_transition import SceneTransition\n"
"transition = SceneTransition(duration=0.5, color=(0, 0, 0))\n"
"transition.start_out() # Fade to color\n"
"transition.start_in() # Fade from color\n"
"```\n\n"
"## Common Patterns\n\n"
"### Platformer Character\n"
"```python\n"
"import pygame\n"
"class Player:\n"
" def on_start(self):\n"
" self.speed = 200\n"
" self.jump_force = 400\n"
" self.rb = self.entity.get_component(Rigidbody2D)\n"
" self.grounded = False\n"
" def on_update(self, dt):\n"
" h = Input.get_axis('Horizontal')\n"
" self.rb.velocity_x = h * self.speed\n"
" if self.grounded and Input.get_key(pygame.K_SPACE):\n"
" self.rb.velocity_y = -self.jump_force\n"
" def on_collision_enter(self, other, info):\n"
" if info.normal[1] < -0.5:\n"
" self.grounded = True\n"
" def on_collision_exit(self, other):\n"
" self.grounded = False\n"
"```\n\n"
"### Top-Down Movement\n"
"```python\n"
"class TopDownController:\n"
" def on_start(self):\n"
" self.speed = 150\n"
" self.transform = self.entity.get_component(Transform)\n"
" def on_update(self, dt):\n"
" dx = Input.get_axis('Horizontal')\n"
" dy = Input.get_axis('Vertical')\n"
" self.transform.x += dx * self.speed * dt\n"
" self.transform.y += dy * self.speed * dt\n"
"```\n\n"
"### Spawning Enemies\n"
"```python\n"
"class Spawner:\n"
" def on_start(self):\n"
" self.subscribe_to_event('timeout', self.spawn, self.entity)\n"
" def spawn(self):\n"
" enemy = self.instantiate_prefab('prefabs/enemy.entity',\n"
" x=self.entity.get_component(Transform).x,\n"
" y=self.entity.get_component(Transform).y)\n"
"```\n\n"
"### Scene Transitions\n"
"```python\n"
"class Portal:\n"
" def on_trigger_enter(self, other):\n"
" if other.has_tag('player'):\n"
" self.change_scene('scenes/level2.scene')\n"
"```\n"
)