C/C++前端开发

内容纲要

Hello Indeex

这里将先构建一基于控制台的个简单Hello Indeex。在开始前,需要确保你本级上已经安装相关开发工具并可用,相关工具及技术可咨询专业人士或者通过搜索引擎获得。

  1. 创建一个新的C++文件indeex.cpp,如下所示:
#include <indeex/clientlib.h>
#include <indeex/client.h>

[[indeex::genericjs]] void domOutput(const char* str)
{
        client::console.log(str);
}

void Main()
{
        domOutput("Hello Indeex");
}
  1. Main函数代表应用程序编译入口,由于底层语言无法直接操作DOM,因此需要指定Indeex domOutput使用[[indeex::genericjs]]属性在ECMAScript(国内又名Javascript)中进行编译:
/opt/indeex/bin/clang++ -target indeex -indeex-mode=wasm -indeex-wasm-loader=indeex.js -O2 -o indeex.wasm indeex.cpp

此命令生成两个文件:一个ECMAScript Loader(indeex.js)和一个二进制文件(indeex.wasm)在浏览器中混合使用。控制台由ECMAScript负责打印出来,保证与DOM或任何外部ECMAScript库或者其他ECMAScript代码进行交互。

  1. 这里需要一个简单的HTML页面:

indeex.html

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>c/c++ demo with indeex - http://www.indeex.cc</title>
  </head>
  <body>
    <canvas id="indeexcanvas"></canvas>
    <script src="indeex.js"></script>
  </body>
</html>

只需要使用ECMAScript Loader,二进制文件就会自动加载。

  1. 在根目录中启动本地HTTP服务器。由于我是前端工程师,这里我使用http-server,但任何你喜欢的服务器都可以:
http-server -p 8081
  1. 然后使用任何你喜欢的现代浏览器访问您的indeex.html页面,例如http://127.0.0.1:8081

C/C++前端开发

Hello Canvas

  1. 由于使用requestAnimationFrame可以使Canvas获取最佳性能,但Canvas 2D API不能直接从读取二进制文件,因此需要在编译器中生成ECMAScript代码:
#include <indeex/clientlib.h>
#include <indeex/client.h>


// 所有图形绘制代码都需要保留在ES中。可以用[[cheerp::genericjs]]标签来标记整个class
// 所有属性和方法都将被编译为标准的ECMAScript
class [[indeex::genericjs]] Graphics
{
private:
    // 像操作任何其他C++对象一样在编译后可以使用标准的ECMAScript来操作DOM对象
    static client::HTMLCanvasElement* canvas;
    static client::CanvasRenderingContext2D* canvasCtx;
    static int width;
    static int height;
public:
    // 用于提供对DOM和Canvas API的访问,方便编译为二进制
    static void initializeCanvas(int w, int h)
    {
        width = w;
        height = h;
        canvas = (client::HTMLCanvasElement*)client::document.getElementById("pongcanvas");
        canvas->set_width(w);
        canvas->set_height(h);
        client::document.get_body()->appendChild(canvas);
        canvasCtx = (client::CanvasRenderingContext2D*)canvas->getContext("2d");
    }
    static void debugOutput(const char* str)
    {
        canvasCtx->set_font("24px sans-serif");
        canvasCtx->fillText(str, 0, height - 24);
    }
};

// 调用并编译
void Main()
{
    Graphics::initializeCanvas(800, 800);
    Graphics::debugOutput("Hello Canvas");
}
  1. 已经创建好了Graphics类并使用[[cheerp::genericjs]]属性对其进行了标记。Indeex将会生成标准的ECMAScript代码,这样就可以在C ++中完成对DOM的操作,而不会影响任何性能、多余代码或者占用资源。Main中的代码被编译为二进制,并将二进制导入进来并编译为ECMAScript代码。

  2. 刷新浏览器,可以看到如下内容:

C/C++前端开发

Hello Graphics

接下来开始制作游戏。首先绘制接球的小木块。

  1. 创建一个Platform class作为游戏中唯一可控制的实例对象,只能使用键盘向左和向右移动,游戏背景为黑色,对象为白色小木块。而且不在这个类上使用 cheerp::genericjs 属性:
class Platform
{
private:
    int x;
    int h;
    int width;
    int height;
public:
        Platform(int x, int y, int width, int height):x(x),y(y),width(width),height(height)
    {
    }
    int getX() const
    {
        return x;
    }
    int getY() const
    {
        return y;
    }
    int getWidth() const
    {
        return width;
    }
    int getHeight() const
    {
        return width;
    }
    void render() const
    {
        Graphics::drawRect(w, y, width, height, 0xffffff);
    }                                    
};
  1. 给这个类配置一些基本的属性和一个渲染函数,然后将渲染委托给Graphics类。将drawRect函数添加到Graphics类中:
static void drawRect(int w, int y, int width, int height, int rgb)
    {
        int r = rgb&0xff;
        int g = (rgb>>8)&0xff;
        int b = (rgb>>16)&0xff;
        canvasCtx->set_fillStyle(client::String("").concat("rgb("r, ",", g, ",", b, ")"));
        canvasCtx->fillRect(x, y, width, height);
    }
  1. 实例化一个全局Platform实例,添加一个顶级函数来处理应用程序的主循环来清除背景并重新渲染画布。

重新编译:

C/C++前端开发

Hello Animation & Keyboard Event

  1. 添加一个keydown事件来处理键盘控制。由于是DOM交互,这段代码将被标记为genericjs, 它会更新小木块的位置:
void moveLeft()
    {
        x -= 3;
    }
    void moveRight()
    {
        x += 3;
    }
  1. keyDown事件:
void Graphics::keyDownHandler(client::KeyboardEvent* e)
{
    if(e->get_keyCode() == 37)
        platform.moveLeft();
    else
        platform.moveRight();
}
  1. 现在可以移动小木块了:
    C/C++前端开发

Hello Finally

  1. 接下来就是球的移动了。创建一个Ball类,有位置和速度。需要在二进制中保留这个类,不需要使用[[cheerp::genericjs]]标记:
class Ball
{
private:
    int x;
    int y;
    int vx;
    int vy;
public:
    Ball(int x, int y, int vx, int vy):x(x),y(y),vx(vx),vy(vy)
    {
    }
    void update()
    {
        x += vx;
        y += vy;
    }
    // 球出界了返回true
    bool collide(const Platform& platform, int maxX, int maxY)
    {
        // 底部
        if(y >= maxY)
            return true;
        // 左右边界
        if(x <= 0 || x >= maxX)
            vx = -vx;
        // 顶部
        if(y <= 0)
            vy = -vy;
        // 碰撞检测
        if(platform.getX() < x && (platform.getX() + platform.getWidth()) > x &&
            platform.getY() < y && (platform.getY() + platform.getHeight()) > y)
        {
            vy = -vy;
        }
        return false;
    }
    void render()
    {
        Graphics::drawCircle(x, y, 5, 0xffffff);
    }
};
  1. Ball::collide会一直检查球是否已经超出底部,并给出文字提示:
void mainLoop()
{    
    // 重置背景为黑色
    Graphics::drawRect(0, 0, 400, 400, 0);
    // 绘制小木块
    platform.render();
    // 更新球的位置和状态
    ball.update();
    // 碰撞检测
    bool hasLost = ball.collide(platform, 400, 400);
    if(hasLost)
        Graphics::debugOutput("You lost!");
    // 渲染球
    ball.render();
}
  1. 最后刷新浏览器:

C/C++前端开发

一切看起来都还不错!

Indeex通过将C/C++编译为高性能的二进制代码和高级动态编程语言ECMAScript代码来开发高性能的前端应用或者游戏,而且还可以与DOM或者其他ECMAScript库进行无缝交互,动态控制内存和垃圾回收。

code enjoy! ʕ•ᴥ•ʔ

作者:indeex

链接:http://indeex.cc

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


发表评论

您的电子邮箱地址不会被公开。