Scripting API
This page summarizes the main gameplay scripting surface.
Base Types
Sendama\Engine\Core\Component
The base class for engine components.
Useful members and hooks:
getGameObject()getTransform()getRenderer()awake()onStart()onUpdate()onFixedUpdate()onStop()onResume()onSuspend()enable()disable()isEnabled()
Minimal component example:
<?php
namespace Sendama\MyGame\Scripts;
use Sendama\Engine\Core\Component;
class ScorePulse extends Component
{
public function onStart(): void
{
$this->getGameObject()->setTag('ui-score');
}
public function onUpdate(): void
{
$position = $this->getTransform()->getPosition();
$position->setX($position->getX() + 1);
$this->getTransform()->setPosition($position);
}
}
Sendama\Engine\Core\Behaviours\Behaviour
The standard base class for custom gameplay logic.
Adds convenience accessors:
activeScenescene
Collision and trigger hooks:
onCollisionEnter(CollisionInterface $collision)onCollisionStay(CollisionInterface $collision)onCollisionExit(CollisionInterface $collision)onTriggerEnter(ColliderInterface $collider)onTriggerStay(ColliderInterface $collider)onTriggerExit(ColliderInterface $collider)
Typical behaviour example:
<?php
namespace Sendama\MyGame\Scripts;
use Sendama\Engine\Core\Attributes\SerializeField;
use Sendama\Engine\Core\Behaviours\Behaviour;
use Sendama\Engine\Core\Vector2;
use Sendama\Engine\IO\Input;
use Sendama\Engine\IO\Enums\AxisName;
class PlayerController extends Behaviour
{
#[SerializeField]
private int $speed = 1;
#[SerializeField]
private ?Vector2 $spawnPoint = null;
public function onStart(): void
{
if ($this->spawnPoint) {
$this->getTransform()->setPosition($this->spawnPoint);
}
}
public function onUpdate(): void
{
$movement = new Vector2(
x: (int) round(Input::getAxis(AxisName::Horizontal) * $this->speed),
y: (int) round(Input::getAxis(AxisName::Vertical) * $this->speed),
);
$this->getTransform()->translate($movement);
}
}
Serialization Rules
Scene and prefab metadata can assign values to component properties when the scene is loaded.
Supported targets:
- public properties
- protected or private properties marked with
#[SerializeField]
Supported metadata payload keys:
datapropertiesproerties
The editor currently emits data.
SerializeField
Use #[SerializeField] on non-public fields that should be editable or serializable through scene/prefab metadata.
Typical use cases:
- float tuning values
- bool toggles
Vector2bounds- prefab references
- pool sizes
Example with a pooled projectile setup:
<?php
namespace Sendama\MyGame\Scripts\Weapons;
use Sendama\Engine\Core\Attributes\SerializeField;
use Sendama\Engine\Core\Behaviours\Behaviour;
use Sendama\Engine\Core\GameObject;
use Sendama\Engine\Core\Interfaces\GameObjectInterface;
class Gun extends Behaviour
{
#[SerializeField]
private ?GameObjectInterface $bulletPrefab = null;
#[SerializeField]
private int $poolSize = 24;
/** @var GameObjectInterface[] */
private array $bulletPool = [];
public function onStart(): void
{
if ($this->bulletPrefab) {
$this->bulletPool = GameObject::pool($this->bulletPrefab, $this->poolSize);
}
}
}
Input Facade
Sendama\Engine\IO\Input exposes static helpers for input checks.
| Method | Purpose |
|---|---|
Input::getAxis(AxisName $axisName): float |
Read a virtual axis |
Input::isKeyPressed(KeyCode|string $keyCode): bool |
Check held key |
Input::areAllKeysPressed(array $keyCodes): bool |
Require all keys |
Input::isAnyKeyPressed(array $keyCodes, bool $ignoreCase = true): bool |
Require any key |
Input::isAnyKeyReleased(array $keyCodes): bool |
Detect release in a set |
Input::isKeyDown(KeyCode|string $keyCode): bool |
Detect key-down edge |
Input::isKeyUp(KeyCode|string $keyCode): bool |
Detect key-up edge |
Input::isButtonDown(string $buttonName): bool |
Read named button |
Example fire input check:
<?php
use Sendama\Engine\IO\Input;
if (Input::isButtonDown('fire') || Input::isKeyDown('space')) {
$this->fireWeapon();
}
Authoring Pattern
The most maintainable script pattern in Sendama is:
- keep scene and prefab files declarative
- keep behavior in
Behaviourclasses - expose only the fields designers should tune
- use prefabs and serialized references instead of hard-coding every object in PHP
Collision handling is usually most maintainable when the receiving object reacts to the other collider directly:
<?php
use Sendama\Engine\Physics\Interfaces\ColliderInterface;
public function onTriggerEnter(ColliderInterface $collider): void
{
$other = $collider->getGameObject();
if (!$other) {
return;
}
if ($other->getTag() === 'enemy') {
$other->deactivate();
$this->getGameObject()->deactivate();
}
}