ursina

repository·master·Indexed 25 days ago

https://github.com/pokepetter/ursina

An easy-to-use game engine and framework for Python 3.10+, built on top of Panda3D. It simplifies game development through high-level abstractions like Entities, a simplified input system, and built-in UI prefabs. The engine includes support for procedural shapes, 3D model and texture importing, an Audio class for sound management with audio groups, and camera controls for perspective and orthographic projections.

Tokens
17.6K
Snippets
9
Records
119
Agent score
82%

What's inside ursina

  1. Create a basic Ursina game

    master

    A minimal Ursina application requires importing the engine, initializing the Ursina() application instance, defining entities, and calling app.run().

    To create a game:

    1. Create a .py file (e.g., ursina_game.py).
    2. Use from ursina import * to import the necessary components.
    3. Define an update() function if you need logic to run every frame. The engine calls this automatically.
    4. Use held_keys to handle keyboard input.
    5. Run the script using python ursina_game.py.
    from ursina import *           # this will import everything we need from ursina with just one line.
    
    app = Ursina()
    
    player = Entity(
        model = 'cube' ,           # finds a 3d model by name
        color = color.orange,
        scale_y = 2
        )
    
    def update():                  # update gets automatically called by the engine.
        player.x += held_keys['d'] * .1
        player.x -= held_keys['a'] * .1
    
    
    app.run()                     # opens a window and starts the game.
  2. Install Ursina

    master

    To install the stable version of Ursina, ensure you have Python 3.10 or newer installed, then run:

    pip install ursina

    Advanced Installation Options

    Development Version: To install the latest development version directly from GitHub:

    pip install git+https://github.com/pokepetter/ursina.git

    Editable Mode (for source modification): If you want to edit the source code of the engine itself, clone the repository and install it with the --editable flag:

    git clone https://github.com/pokepetter/ursina.git
    cd ursina
    pip install --editable .

    With Extras: To install Ursina along with its optional dependencies:

    pip install ursina[extras]

    Targeting Specific Python Versions: If you need to target a specific Python version (e.g., 3.x):

    python3.xx -m pip install ursina
  3. Manage audio via audio_groups

    master

    Ursina uses audio_groups to allow bulk volume control for different types of sounds. The default groups are:

    • music
    • ambient
    • sfx
    • dialogue

    When you assign an Audio instance to a group, its effective volume is calculated as: self.volume * Audio.volume_multiplier * group_volume_multiplier.

    You can adjust the multiplier for a group by accessing audio_groups.

  4. Set global shader inputs

    master
    When you set an attribute on a Shader instance that exists in its default_input dictionary, Ursina automatically updates that input for all Entity instances currently in the scene that are using that shader. This allows for global shader parameter updates (like time or light positions) across multiple entities simultaneously.
  5. How Sequence handles pausing and entities

    master

    A Sequence's update loop respects several conditions that can halt its progress:

    1. Global Pause: If application.paused is True, the sequence pauses unless ignore_paused=True was set.
    2. Local Pause: If self.paused is True, the sequence pauses unless ignore_paused=True was set.
    3. Entity State: If an entity is assigned to the sequence, the sequence will pause if self.entity.enabled is False or if self.entity.ignore is True.

    This allows you to tie the lifecycle of an animation sequence directly to the visibility or state of a game object.

  6. How PhysicsEntity and Entity relate

    master

    A PhysicsEntity is not a direct replacement for Entity, but a wrapper. It contains an internal self.entity (a standard Ursina Entity) which handles the visual representation (model, texture, color), while self.node (a BulletRigidBodyNode) handles the physical simulation.

    When you move a PhysicsEntity via position or rotation, you are actually moving the underlying physics node. The visual self.entity is then parented to this node so it follows the physics simulation automatically.

  7. Access gamepad inputs via held_keys

    master

    Gamepad axes and triggers are mapped to the held_keys dictionary, allowing you to read analog input values (typically between -1.0 and 1.0) in an update() loop.

    If multiple gamepads are connected, the keys are prefixed with the gamepad name (e.g., gamepad_1). The primary gamepad uses the prefix gamepad.

    Available Keys for the primary gamepad:

    • Left Stick: gamepad left stick x, gamepad left stick y
    • Right Stick: gamepad right stick x, gamepad right stick y
    • Triggers: gamepad left trigger, gamepad right trigger

    Available Keys for secondary gamepads (index > 0):

    • gamepad_{index} left stick x
    • gamepad_{index} left stick y
    • gamepad_{index} right stick x
    • gamepad_{index} right stick y
    • gamepad_{index} left trigger
    • gamepad_{index} right trigger
  8. Format text with rich text tags

    master

    The Text class supports inline tags for styling specific parts of a string. Tags are enclosed in < and >.

    Supported Tags:

    • Colors: Use color names directly or via rgb() and hsv() functions.
      • <red>Text<default> (resets to default color)
      • <rgb(1, 0, 0)>Red Text<default>
      • <hsv(0, 1, 1)>Red Text<default>
    • Scaling: <scale:n> where n is a float. Note: This works best for titles and may not work well in the middle of a sentence.
    • Images: <image:texture_name> inserts an inline image using the specified texture.
    t = Text(text='<red>Red <blue>Blue <image:my_icon> Icon<default>')
  9. Switch between Perspective and Orthographic projection

    master

    The Camera supports two projection modes via the orthographic boolean property:

    1. Perspective (Default): camera.orthographic = False. Uses a PerspectiveLens. The fov property controls the horizontal field of view.
    2. Orthographic: camera.orthographic = True. Uses an OrthographicLens. The fov property controls the vertical film size.

    Switching this property automatically updates the underlying Panda3D lens and ensures mouse raycasting remains accurate.

  10. Merge two shaders using the + operator

    master

    Ursina allows you to combine two shaders using the + operator. This is intended to merge vertex shader inputs, uniforms, and outputs.

    Note: The vertex shaders must have matching #version declarations, or an exception will be raised. The resulting shader combines the inputs/outputs of both shaders into a single vertex shader stage.

    from ursina.shaders.unlit_shader import unlit_shader
    from ursina.shaders.matcap_shader import matcap_shader
    
    # Combines the properties of both shaders
    combined_shader = unlit_shader + matcap_shader
  11. Configure Mesh rendering modes

    master

    The mode parameter in the Mesh constructor determines how the vertices are connected. Use the MeshModes enum or the corresponding string values:

    • 'triangle': Standard triangle mesh (default).
    • 'ngon': Uses triangle fans (useful for complex polygons).
    • 'quad': Uses quads (automatically triangulated).
    • 'line': Renders lines between vertices.
    • 'point': Renders individual points.
    • 'tristrip': Renders triangle strips.
  12. Use RPCPeer for remote procedure calls

    master

    The RPCPeer class is the primary interface for high-level networking. It wraps a Peer object and provides a mechanism to register and call functions across the network using Remote Procedure Calls (RPCs).

    To use it:

    1. Initialize RPCPeer (which creates an underlying Peer).
    2. Register functions as procedures using the @rpc(peer_instance) decorator. Functions must include type annotations for all arguments following connection and time_received.
    3. Call registered procedures on a Connection object using the syntax connection.procedure_name(arg1, arg2, ...).
    4. Call update() in your main loop to process incoming network events.

    Important Requirements:

    • Every registered procedure must have at least two arguments: connection and time_received.
    • Arguments must be type-annotated so the DatagramReader knows how to deserialize them.
    • You can restrict procedures to host_only=True or client_only=True during registration.