Metadata-Version: 2.4
Name: pygameP
Version: 0.0.1
Summary: Pygame Plus - 高级游戏开发框架：着色器、物理引擎、场景管理
Author: pygameP contributors
License: MIT
Project-URL: Homepage, https://github.com/pygameP/pygameP
Keywords: pygame,game,shader,physics,scene
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Games/Entertainment
Classifier: Topic :: Multimedia :: Graphics
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pygame>=2.0.0
Requires-Dist: PyOpenGL>=3.1.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Dynamic: license-file

# pygameP

**Pygame Plus** — 一个面向 Pygame 的高级扩展框架，提供 GLSL 着色器特效、性能优化工具、JSON 场景管理、简单物理引擎和扩展输入设备支持。

## 安装

```bash
pip install pygameP
```

依赖项会自动安装：
- `pygame >= 2.0.0`
- `PyOpenGL >= 3.1.0`（用于着色器支持）

## 核心特性

| 模块 | 功能 |
|------|------|
| **shaders** | GLSL 着色器系统 + 内置特效（灰度/模糊/反转/亮度/脉冲/波浪） |
| **performance** | 对象池、空间哈希、帧率监控、批处理渲染 |
| **scene** | `.pgstage` JSON 场景文件，支持多场景切换 |
| **physics** | 简单刚体物理（重力、碰撞、射线检测） |
| **input** | 键盘、鼠标、手柄、多点触摸统一输入管理 |

---

## 快速开始

### 1. GLSL 着色器特效

支持从 `.glsl` 文件加载或从代码字符串创建着色器。可作用于整个屏幕或单个精灵。

```python
from pygameP import Shader, ShaderEffect, BuiltInEffects

# 使用内置特效
grayscale = BuiltInEffects.grayscale()
blur = BuiltInEffects.blur(radius=3.0)
invert = BuiltInEffects.invert()
pulse = BuiltInEffects.pulse(speed=2.0)
wave = BuiltInEffects.wave(amplitude=0.05, frequency=10.0)

# 应用到整个屏幕
grayscale.apply(screen)

# 应用到单个精灵
pulse.apply(my_sprite)

# 自定义 GLSL 代码
my_shader = Shader(fragment_source="""
#version 330 core
in vec2 v_texcoord;
out vec4 frag_color;
uniform sampler2D u_texture;
uniform float u_time;
void main() {
    vec4 c = texture(u_texture, v_texcoord);
    frag_color = vec4(c.r, c.g * abs(sin(u_time)), c.b, c.a);
}
""")

# 从文件加载
custom = Shader(
    vertex_file="assets/shaders/default.vert",
    fragment_file="assets/shaders/plasma.frag"
)
```

### 2. 性能优化

```python
from pygameP import ObjectPool, SpatialHash, FPSMonitor, BatchRenderer

# 对象池 - 减少子弹/粒子的创建开销
bullet_pool = ObjectPool(lambda: Bullet(), initial_size=200)
bullet = bullet_pool.acquire()  # 从池中获取
# ... 使用后 ...
bullet_pool.release(bullet)     # 归还

# 空间哈希 - 快速碰撞检测
spatial = SpatialHash(cell_size=64)
spatial.insert(enemy, enemy.rect)
nearby = spatial.query(player.rect)  # 只检测附近对象

# FPS 监控 + 自适应质量
fps_monitor = FPSMonitor(target_fps=60)
while running:
    dt = fps_monitor.tick()
    if fps_monitor.should_reduce_quality():
        reduce_particle_count()

# 批处理渲染 - 合并绘制调用
batch = BatchRenderer(screen)
for sprite in sprites:
    batch.blit(sprite.image, sprite.rect.topleft)
batch.render()  # 一次性执行
```

### 3. 场景管理（.pgstage）

`.pgstage` 是 pygameP 的自定义场景文件格式，基于 JSON。

> **场景编辑器下载：** `.pgstage` 文件由 **[Objector Coder](https://tomlct2015.github.io/Objector-Coder/#download)** 可视化编辑器创建和管理，pygameP 库只负责加载和运行场景。
> 下载地址：https://tomlct2015.github.io/Objector-Coder/#download

```json
{
  "name": "ExampleLevel",
  "width": 1600,
  "height": 1200,
  "background_color": [20, 25, 40],
  "camera_x": 0,
  "camera_y": 0,
  "properties": {
    "music": "assets/music/level1.ogg",
    "difficulty": "normal"
  },
  "entities": [
    {
      "type": "Player",
      "x": 100,
      "y": 800,
      "layer": 5,
      "hp": 100,
      "tag": "player"
    },
    {
      "type": "Enemy",
      "x": 500,
      "y": 800,
      "layer": 4,
      "hp": 50,
      "ai": "patrol"
    }
  ]
}
```

Python 中使用：

```python
from pygameP import Scene, SceneManager, SceneEntity

# 创建场景
scene = Scene("Level1", width=1600, height=1200)
scene.background_color = (20, 25, 40)
scene.add_entity(SceneEntity(100, 800, hp=100, tag="player"))

# 保存为 .pgstage 文件
scene.save("levels/level1.pgstage")

# 加载场景
loaded = Scene.load("levels/level1.pgstage")

# 多场景管理（带过渡效果）
manager = SceneManager()
manager.add_scene("menu", Scene("Menu"))
manager.add_scene("game", Scene.load("levels/level1.pgstage"))
manager.switch_to("game", transition_duration=0.5)

# 游戏主循环
while running:
    dt = clock.tick(60) / 1000.0
    manager.update(dt)
    manager.draw(screen)
```

### 4. 简单物理引擎

```python
from pygameP import RigidBody, PhysicsWorld, BoxCollider, CircleCollider

# 创建物理世界
world = PhysicsWorld(gravity=980.0)

# 动态刚体（受重力影响）
player = RigidBody(x=100, y=0, mass=1.0, collider=BoxCollider(32, 64))
player.restitution = 0.3  # 弹性
player.friction = 0.2     # 摩擦
world.add_body(player)

# 静态刚体（地面、平台）
ground = RigidBody(x=0, y=600, mass=0, collider=BoxCollider(800, 40))
world.add_body(ground)

# 施加力或冲量
player.apply_force(500, 0)        # 持续力
player.apply_impulse(0, -300)     # 跳跃（瞬间）

# 每帧更新
world.update(dt)

# 碰撞回调
def on_hit(body1, body2):
    print("碰撞！")
world.on_collision = on_hit

# 射线检测
hit = world.raycast((100, 300), (1, 0), max_distance=500)
if hit:
    body, distance, point = hit
    print(f"命中 {body}，距离 {distance}")
```

### 5. 扩展输入设备

```python
from pygameP import InputManager

input_mgr = InputManager()

# 映射动作到多种输入
input_mgr.map_action("jump", "keyboard", pygame.K_SPACE)
input_mgr.map_action("jump", "gamepad", (0, 0))  # 手柄 0 的按钮 0

input_mgr.map_action("shoot", "mouse", 1)  # 鼠标左键
input_mgr.map_action("move_right", "gamepad", (0, "axis_0"))

# 游戏主循环
while running:
    events = pygame.event.get()
    input_mgr.update(events)

    if input_mgr.is_action_just_pressed("jump"):
        player.jump()
    if input_mgr.is_action_pressed("move_right"):
        player.move_right()

    # 模拟输入（手柄摇杆）
    move_x = input_mgr.get_action_value("move_right")

    # 直接访问手柄
    pad = input_mgr.get_gamepad(0)
    if pad:
        left_stick = pad.get_left_stick()
        pad.rumble(0.5, 0.5, 100)  # 震动

    # 触摸输入
    if input_mgr.touch.is_touching():
        pos = input_mgr.touch.get_touch_position()
```

支持的输入设备：
- **键盘** — 按键按下/释放/刚刚按下
- **鼠标** — 位置、相对运动、滚轮、按钮状态
- **手柄** — 按钮、摇杆轴、方向帽、震动（rumble）
- **触摸** — 多点触控、触摸开始/结束/移动

---

## API 参考

### `Shader`
- `Shader(vertex_source, fragment_source, vertex_file, fragment_file)` — 创建着色器
- `shader.use()` / `shader.stop()` — 启用/停用
- `shader.set_uniform(name, value)` — 设置 uniform（支持 float/int/vec2/vec3/vec4）
- `shader.apply_to_surface(surface)` — 应用于整个屏幕
- `shader.apply_to_sprite(sprite)` — 应用于单个精灵

### `BuiltInEffects`（内置特效）
- `grayscale()` — 灰度
- `blur(radius)` — 模糊
- `invert()` — 颜色反转
- `brightness(amount)` — 亮度
- `pulse(speed)` — 脉冲发光
- `wave(amplitude, frequency)` — 波浪扭曲

### `ObjectPool`
- `acquire()` — 获取对象
- `release(obj)` — 归还对象
- `release_all()` — 归还所有
- `resize(n)` — 调整池大小

### `SpatialHash`
- `insert(obj, rect)` — 插入对象
- `query(rect)` — 查询区域内对象
- `query_nearby(obj, rect)` — 查询附近（排除自己）
- `remove(obj)` / `clear()`

### `Scene` / `SceneManager`
- `scene.save(path)` — 保存为 `.pgstage`
- `Scene.load(path)` — 加载 `.pgstage`
- `manager.switch_to(name, transition_duration)` — 切换场景

### `PhysicsWorld`
- `add_body(body)` / `remove_body(body)`
- `update(dt)` — 更新物理（自动处理重力和碰撞）
- `raycast(start, direction, max_distance)` — 射线检测

### `InputManager`
- `update(events)` — 更新所有输入设备
- `is_action_pressed(action)` — 动作是否被按住
- `is_action_just_pressed(action)` — 动作是否刚刚按下
- `get_action_value(action)` — 获取模拟值（-1 到 1）
- `map_action(action, device, binding)` — 映射动作

---

## 完整示例

```python
import pygame
from pygameP import (
    SceneManager, Scene, SceneEntity,
    PhysicsWorld, RigidBody, BoxCollider,
    InputManager, FPSMonitor, BuiltInEffects
)

pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()

# 场景
manager = SceneManager()
game = Scene("Game", 800, 600)
game.background_color = (30, 40, 60)
manager.add_scene("game", game)
manager.switch_to("game")

# 物理
world = PhysicsWorld(gravity=980.0)
player = RigidBody(400, 100, mass=1.0, collider=BoxCollider(32, 32))
world.add_body(player)
ground = RigidBody(0, 550, mass=0, collider=BoxCollider(800, 50))
world.add_body(ground)

# 输入
input_mgr = InputManager()
input_mgr.map_action("jump", "keyboard", pygame.K_SPACE)
input_mgr.map_action("left", "keyboard", pygame.K_LEFT)
input_mgr.map_action("right", "keyboard", pygame.K_RIGHT)

# 性能监控
fps = FPSMonitor(target_fps=60)

# 着色器
effect = BuiltInEffects.pulse(speed=2.0)

running = True
while running:
    dt = clock.tick(60) / 1000.0
    fps.tick()

    events = pygame.event.get()
    input_mgr.update(events)

    for event in events:
        if event.type == pygame.QUIT:
            running = False

    # 输入
    if input_mgr.is_action_just_pressed("jump") and player.grounded:
        player.apply_impulse(0, -500)
    if input_mgr.is_action_pressed("left"):
        player.apply_force(-300, 0)
    if input_mgr.is_action_pressed("right"):
        player.apply_force(300, 0)

    # 更新
    world.update(dt)
    manager.update(dt)

    # 绘制
    manager.draw(screen)
    pygame.draw.rect(screen, (255, 200, 100),
                     (player.x, player.y, 32, 32))
    pygame.draw.rect(screen, (100, 100, 100),
                     (ground.x, ground.y, 800, 50))

    pygame.display.flip()

pygame.quit()
```

## 许可证

MIT License
