Overview
This document explains how to create and use scripts with objects in your engine. Scripts allow you to add custom behavior, logic, and event handling to your GameObjects and UI elements.
Scripts are attached to GameObject or UiElement instances via the Component base class. Each object can have multiple components/scripts that run in order.
Component Structure
namespace Engine.Scripting
{
public abstract class Component
{
public Vector2 Position { get; set; }
public Vector2 Size { get; set; }
public bool Visible { get; set; }
public virtual void Update(float deltaTime) { }
public virtual void Render() { }
}
}
All scripts inherit from Component and implement:
• Update(float deltaTime) - Called once per frame
• Render() - For rendering-specific logic (optional)
• Position, Size, Visible - Properties to access/modify
Creating Scripts
Basic Script Template
using OpenTK;
using Engine.Scripting;
namespace MyGame.Scripts
{
public class MoveScript : Component
{
public float Speed { get; set; } = 100f;
public Vector2 Direction { get; set; } = new Vector2(1f, 0f);
public override void Update(float deltaTime)
{
Position += Direction * Speed * deltaTime;
}
}
}
Using with GameObject
// Create a GameObject
var player = new GameObject("Player", new Vector2(100, 100), new Vector2(50, 50));
// Add a script
var moveScript = new MoveScript();
player.AddComponent(moveScript);
// Add to workspace
workspace.Add(player);
Using with UI Elements
// Create a Button
var button = new Button("Click Me", texture, position, size);
// Add a script to handle click
var clickHandler = new ClickHandler();
button.AddComponent(clickHandler);
// Add to workspace
workspace.Add(button);
Properties and Events
Accessing Object Properties
Scripts have built-in properties to access the parent object:
public class ScriptExample : Component
{
public void Update(float deltaTime)
{
// Access position, size, visibility
Console.WriteLine($"Position: {Position}");
Console.WriteLine($"Size: {Size}");
Console.WriteLine($"Visible: {Visible}");
// Modify properties
Position += new Vector2(10, 0);
}
Creating Events in Scripts
public class EventScript : Component
{
public event Action? OnValueChanged;
public event Action? OnEnterBounds;
public event Action? OnExitBounds;
public override void Update(float deltaTime)
{
if (Position.X > 500)
{
OnValueChanged?.Invoke();
}
}
}
Common Script Patterns
Movemnt Script
public class MovementScript : Component
{
public Vector2 Speed { get; set; } = new Vector2(100, 100);
public Vector2 TargetPosition { get; set; }
public float MovementSpeed { get; set; } = 300f;
public override void Update(float deltaTime)
{
// Smooth movement toward target
var distance = TargetPosition - Position;
if (distance.Length() > MovementSpeed * deltaTime)
{
Position += distance.Normalized() * MovementSpeed * deltaTime;
}
else
{
Position = TargetPosition;
}
}
}
Timer Script
public class TimerScript : Component
{
public float Duration { get; set; } = 5f;
public event Action<float>? OnTimeUpdate;
public event Action? OnComplete;
public override void Update(float deltaTime)
{
var progress = Duration - (Duration - deltaTime);
OnTimeUpdate?.Invoke(progress);
if (progress <= 0)
{
OnComplete?.Invoke();
}
}
}
Component Lifecycle
- Created - Component is instantiated and added to an object
- Updated - Update(deltaTime) called once per frame
- Visible - Visible property controls whether Render() is called
- Removed - Component removed from object's list
Best Practices
Keep Scripts Small and Focused
Each script should handle one specific behavior. Create separate scripts for:
• Movement
• Animation
• State changes
• Collision logic
• UI interactions
Summary
Create scripts by inheriting from Component
• Override Update() to define behavior
• Use events to communicate with other scripts
• Attach scripts using object.AddComponent(script)
• Remove scripts using object.RemoveComponent(script)
• Keep scripts focused on single responsibilities