Ogre3D + Handmade Script Language

A place to show off your latest screenshots and for people to comment on them. Only start a new thread here if you have some nice images to show off!
LuisSantosAKADjoker
Gnoblar
Posts: 6
Joined: Sat Nov 29, 2008 8:56 pm

Ogre3D + Handmade Script Language

Post by LuisSantosAKADjoker »

Hello everyone,

Over the last few months I’ve been working on a scripting language that feels friendly with C++ so I can use it in my own projects and also learn more about programming languages. My main focus has been on building script bindings for C++ engines.

After testing several scripting languages, I often felt frustrated because something was always missing. So I decided to create my own language and VM. This is an example of binding Ogre3D to my script system. It lets me expose C++ classes in a simple and direct way and then control the scene from scripts.
Image

Video:

Project/VM:
https://github.com/akadjoker/buOgre

If anyone is curious or wants to share feedback, I’d love to hear it.

Code: Select all


import math;
 
 include "keys.bu";
 include "constants.bu";
 

class Player
{
    var node;
    var entity;
    var animations;
    var currentState;
    var currentBase;
    var currentTop;

// Animações indexadas
var idleBase;
var idleTop;
var runBase;
var runTop;
var dance;
var sliceVertical;
var sliceHorizontal;

// Propriedades de movimento
var moveSpeed;
var rotationSpeed;
var isAttacking;
var attackCooldown;
var attackTimer;

// Espadas
var swordLeft;
var swordRight;
var trailLeft;
var trailRight;
var swordNodeLeft;
var swordNodeRight;

def init(scene,root)
{
    self.node = root.createChild();
    self.entity = scene.createEntity("Sinbad.mesh");
    self.entity.castShadows = true;
    self.node.attachObject(self.entity);
    self.node.setPosition(0, 5, -30);
    self.node.setScale(1, 1, 1);

    // Configurar animações
    self.idleBase = self.entity.getAnimationState("IdleBase");
    self.idleTop = self.entity.getAnimationState("IdleTop");
    self.runBase = self.entity.getAnimationState("RunBase");
    self.runTop = self.entity.getAnimationState("RunTop");
    self.dance = self.entity.getAnimationState("Dance");
    self.sliceVertical = self.entity.getAnimationState("SliceVertical");
    self.sliceHorizontal = self.entity.getAnimationState("SliceHorizontal");

    // Configurar loops
    self.idleBase.loop = true;
    self.idleTop.loop = true;
    self.runBase.loop = true;
    self.runTop.loop = true;
    self.sliceVertical.loop = false;
    self.sliceHorizontal.loop = false;
    self.dance.loop = true;
    self.dance.enabled = false;
    // Estado inicial: idle
    self.currentState = "idle";
    self.idleBase.enabled = true;
    self.idleTop.enabled = true;

    // Propriedades de gameplay
    self.moveSpeed = 50.0;
    self.rotationSpeed = 5.0;
    self.isAttacking = false;
    self.attackCooldown = 0.8;  // 800ms entre ataques
    self.attackTimer = 0.0;

    // Criar espadas
    self.swordLeft = scene.createEntity("Sword.mesh");
    self.swordRight = scene.createEntity("Sword.mesh");

    // Attach espadas aos bones das mãos
    self.entity.attachObjectToBone("Handle.L", self.swordLeft);
    self.entity.attachObjectToBone("Handle.R", self.swordRight);

    // Criar nodes para os trails (na ponta das espadas)
    self.swordNodeLeft = root.createChild();
    self.swordNodeRight = root.createChild();
 
}

def setState(newState)
{
    if (self.currentState == newState)
    {
        return;
    }

    // Desabilitar todas as animações
    self.idleBase.enabled = false;
    self.idleTop.enabled = false;
    self.runBase.enabled = false;
    self.runTop.enabled = false;
    self.sliceVertical.enabled = false;
    self.sliceHorizontal.enabled = false;
    self.dance.enabled = false;

    // Ativar animações do novo estado
    if (newState == "idle")
    {
        self.idleBase.enabled = true;
        self.idleTop.enabled = true;
 
  
    }
    elif (newState == "running")
    {
        self.runBase.enabled = true;
        self.runTop.enabled = true;
   
        
    }
    elif (newState == "attacking")
    {
        self.sliceVertical.enabled = true;
        self.sliceVertical.setTimePosition(0);  // Reinicia a animação
        self.isAttacking = true;
        self.dance.enabled = false;
    } elif (newState == "dance")
    {
        self.dance.enabled = true;
    }

    self.currentState = newState;
}

def handleInput(deltaTime)
{
    // Não processar movimento se estiver atacando
    if (self.isAttacking)
    {
        return;
    }

    var moveForward = 0.0;
    var turnDirection = 0.0;

    // UP/DOWN = mover para frente/trás
    if (isKeyDown(KEY_UP))
    {
        moveForward = 1.0;
    }
    if (isKeyDown(KEY_DOWN))
    {
        moveForward = -1.0;
    }

    // LEFT/RIGHT = rodar
    if (isKeyDown(KEY_LEFT))
    {
        turnDirection = 1.0;
    }
    if (isKeyDown(KEY_RIGHT))
    {
        turnDirection = -1.0;
    }

    // Rotacionar o player
    if (turnDirection != 0.0)
    {
        var currentYaw = self.node.getYaw();
        var newYaw = currentYaw + turnDirection * self.rotationSpeed * deltaTime;
        self.node.setYaw(newYaw);
    }

    // Mover o player
    if (moveForward != 0.0)
    {
        self.setState("running");

        // Mover na direção que o player está a olhar
        var currentYaw = self.node.getYaw();
        var moveX = sin(currentYaw) * moveForward;
        var moveZ = cos(currentYaw) * moveForward;

        var pos = self.node.getPosition();
        var newX = pos.x + moveX * self.moveSpeed * deltaTime;
        var newZ = pos.z + moveZ * self.moveSpeed * deltaTime;
        self.node.setPosition(newX, pos.y, newZ);
    }
    else
    {
        self.setState("idle");
    }

    // Ataque
    if (isKeyDown(KEY_P) && self.attackTimer <= 0.0)
    {
        self.setState("attacking");
        self.attackTimer = self.attackCooldown;
    }

    if (isKeyDown(KEY_O))
    {
        self.setState("dance");
    }
}

def update(deltaTime)
{
    // Atualizar timer de ataque
    if (self.attackTimer > 0.0)
    {
        self.attackTimer = self.attackTimer - deltaTime;
    }

    // Processar input
    self.handleInput(deltaTime);

    // Atualizar posição dos nodes dos trails (aproximação simples)
    var pos = self.node.getPosition();
    var yaw = self.node.getYaw();

    // Offset para as mãos (esquerda e direita)
    var leftX = pos.x + cos(yaw) * 1.0 - sin(yaw) * 0.5;
    var leftZ = pos.z + sin(yaw) * 1.0 + cos(yaw) * 0.5;
    var rightX = pos.x + cos(yaw) * 1.0 + sin(yaw) * 0.5;
    var rightZ = pos.z + sin(yaw) * 1.0 - cos(yaw) * 0.5;

    self.swordNodeLeft.setPosition(leftX, pos.y + 1.5, leftZ);
    self.swordNodeRight.setPosition(rightX, pos.y + 1.5, rightZ);

    // Atualizar animações ativas
    if (self.idleBase.enabled)
    {
        self.idleBase.addTime(deltaTime);
    }
    if (self.idleTop.enabled)
    {
        self.idleTop.addTime(deltaTime);
    }
    if (self.runBase.enabled)
    {
        self.runBase.addTime(deltaTime);
    }
    if (self.runTop.enabled)
    {
        self.runTop.addTime(deltaTime);
    }
    if (self.dance.enabled)
    {
        self.dance.addTime(deltaTime);
    }
    if (self.sliceVertical.enabled)
    {
        self.sliceVertical.addTime(deltaTime);

        // Verificar se animação de ataque terminou
        if (self.sliceVertical.hasEnded())
        {
            self.isAttacking = false;
            self.setState("idle");
        }
    }
}

}



def load_resources()
{



 
addResourceLocation("./media/Main", "FileSystem", "OgreInternal");

addResourceLocation("./media/RTShaderLib", "FileSystem", "OgreInternal");
addResourceLocation("./media/Terrain", "FileSystem", "OgreInternal");
addResourceLocation("./media/packs/SdkTrays.zip", "Zip", "Essential");
addResourceLocation("./media/packs/profiler.zip", "Zip", "Essential");


addResourceLocation("./assets/PBR", "FileSystem","General");
addResourceLocation("./assets/PBR/filament", "FileSystem","General");
addResourceLocation("./assets/materials/programs/GLSL", "FileSystem","General");
addResourceLocation("./assets/materials/programs/GLSL120", "FileSystem","General");
addResourceLocation("./assets/materials/programs/GLSL150", "FileSystem","General");
addResourceLocation("./assets/materials/programs/GLSL400", "FileSystem","General");
addResourceLocation("./assets/materials/programs/GLSLES", "FileSystem","General");
addResourceLocation("./assets/materials/programs/SPIRV", "FileSystem","General");
addResourceLocation("./assets/materials/scripts", "FileSystem","General");
addResourceLocation("./assets/materials/textures", "FileSystem","General");
addResourceLocation("./assets/materials/textures/terrain", "FileSystem","General");
addResourceLocation("./assets/models", "FileSystem","General");
addResourceLocation("./assets/particle", "FileSystem","General");
addResourceLocation("./assets/DeferredShadingMedia", "FileSystem","General");
addResourceLocation("./assets/DeferredShadingMedia/DeferredShading/post", "FileSystem","General");
addResourceLocation("./assets/PCZAppMedia", "FileSystem","General");
addResourceLocation("./assets/materials/scripts/SSAO", "FileSystem","General");
addResourceLocation("./assets/materials/textures/SSAO", "FileSystem","General");
addResourceLocation("./assets/volumeTerrain", "FileSystem","General");
addResourceLocation("./assets/CSMShadows", "FileSystem","General");
addResourceLocation("./assets/packs/Sinbad.zip", "Zip", "General");
addResourceLocation("./assets/packs/skybox.zip", "Zip", "General");
addResourceLocation("./assets/packs/skybox.zip", "Zip", "General");
addResourceLocation("./assets/packs/cubemapsJS.zip", "Zip", "General");
 

addResourceLocation("./assets/packs/filament_shaders.zip", "Zip", "General");
 
 
   
initialiseAllResourceGroups(); } CreateEngine(1024, 720, "FPS Controller", 1, false, true); load_resources(); CreatePlane("OceanSurface", 1000, 1000, 50, 50, true, 1, 1.0, 1.0); var scene = CreateScene(); scene.setSkyBox(true, "SkyBox", 1000.0); var rootNode = scene.getRoot(); var camera = rootNode.createChild(); // ========== CONFIGURAÇÃO INICIAL ========== scene.setAmbientLight(0.2, 0.2, 0.2); var sun = scene.createLight("Sun", 1); // 1 = directional sun.setDiffuse(1.0, 0.95, 0.9); sun.setSpecular(0.5, 0.5, 0.5); var sunNode = rootNode.createChild(); sunNode.attachObject(sun); sunNode.setDirection(0.3, -0.75, 0.5,TS_LOCAL,0,0,-1); // Aponta para baixo var water = scene.createEntity("OceanSurface"); water.setMaterial("OceanHLSL_GLSL"); var waterNode = rootNode.createChild(); waterNode.attachObject(water); waterNode.setPosition(0, 10, 0); // altura da água scene.setFog(3, 0.9, 0.7, 0.5, 0.001, 100.0, 1800.0); var tg = scene.createTerrainGroup(); tg.configureDefaults(sun); tg.loadHeightmap(0, 0, "terrain.png"); tg.loadAllTerrains(); tg.freeTemporaryResources(); // CÂMERA var cam = scene.createCamera("MainCam"); cam.setNearClip(0.1); camera.attachObject(cam); camera.setPosition(0, 30, 80); camera.lookAt(0, 5, 0, TS_WORLD); var lf = scene.createLensFlare(cam, 0,60,50); var viewport = CreateViewPort(cam); viewport.setBackgroundColor(0.2, 0.3, 0.4); viewport.setDimensions(0,0,1,1); var currentShadowType = 0; def setupShadows(type) {
scene.setShadowTechnique(type); if (type == 3 || type == 4) // TEXTURE shadows { scene.setShadowTextureSize(2048); scene.setShadowTextureCount(4); scene.setShadowFarDistance(1500.0); scene.setShadowDirLightTextureOffset(0.6); scene.setShadowTextureSelfShadow(true); scene.setShadowCasterRenderBackFaces(false); scene.setShadowColour(0.5, 0.5, 0.5); } } currentShadowType = 2; setupShadows(currentShadowType); var player = Player(scene,rootNode); var cam2 = scene.createCamera("OgreCam"); cam2.setNearClip(0.1); var q = Quaternion(0, 0, 1, 0); // identidade (sem rotação) var p = Vector3(0, 0.25,-10.6); // offset na frente do rosto player.entity.attachObjectToBoneEx("Head", cam2, q, p); // camera2.lookAt(0, 5, 0, TS_WORLD); var viewport2 = CreateViewPort(cam2,1); viewport2.setBackgroundColor(0.2, 0.3, 0.4); viewport2.setDimensions(0,0,0.2,0.2); var tpController = ThirdPersonController(camera, player.node); tpController.setOffset(0, 8.0, 50); // Create FPS controller var fpsController = FPSController(camera); fpsController.moveSpeed = 150.0; // velocidade de movimento fpsController.mouseSensitivity = 0.15; // sensibilidade do mouse // Mouse tracking var lastMouseX = getMouseX(); var lastMouseY = getMouseY(); var time=0.0; while(EngineCanUpdate()) { var deltaTime = getDeltaTime(); var fps = getFPS(); time = time + deltaTime; fpsController.setMoveForward(isKeyDown(KEY_W)); fpsController.setMoveBackward(isKeyDown(KEY_S)); fpsController.setMoveLeft(isKeyDown(KEY_A)); fpsController.setMoveRight(isKeyDown(KEY_D)); fpsController.setMoveUp(isKeyDown(KEY_Q)); fpsController.setMoveDown(isKeyDown(KEY_Z)); if (isKeyDown(KEY_1)) { currentShadowType = 0; setupShadows(currentShadowType); } if (isKeyDown(KEY_2)) { currentShadowType = 1; setupShadows(currentShadowType); } if (isKeyDown(KEY_3)) { currentShadowType = 2; setupShadows(currentShadowType); } if (isKeyDown(KEY_4)) { currentShadowType = 3; setupShadows(currentShadowType); } if (isKeyDown(KEY_5)) { currentShadowType = 4; setupShadows(currentShadowType); } tpController.update(deltaTime, 0,0); lf.update(); // Calculate mouse delta var mouseX = getMouseX(); var mouseY = getMouseY(); var mouseDeltaX = 0; var mouseDeltaY = 0; if (isMouseButtonDown(MOUSE_LEFT)) { mouseDeltaX = mouseX - lastMouseX; mouseDeltaY = mouseY - lastMouseY; } lastMouseX = mouseX; lastMouseY = mouseY; // Update controller //fpsController.update(deltaTime, -mouseDeltaX, mouseDeltaY); player.update(deltaTime); var pos = player.node.getPosition(); var h = tg.getHeightAtWorldPosition(pos.x, 0, pos.z); player.node.setPosition(pos.x, h + 4.8, pos.z); UpdateEngine(deltaTime); } ReleaseEngine();