c++ - 将 C++ 对象包装到 Node 插件中的 v8 对象

标签 c++ node.js v8

我目前正在用 C++ 编写一个 Node 插件,我遇到了一个问题,我需要创建并返回一个 v8 数组,其中填充了 v8 包装的 C++ 对象实例。

目前,代码看起来像这样

v8::Handle<v8::Value> Controller::nodeArray(const v8::Arguments& args)
{
    v8::HandleScope scope;

    Controller* controller= ObjectWrap::Unwrap<Controller>(args.This());
    const std::vector<Foobar*>* foobars = controller->getFoobars();
    unsigned int foobarCount = foobars->size();

    v8::Handle<v8::Array> foobarsArray = v8::Array::New(foobarCount);
    std::vector<Foobar*>::const_iterator foobar = foobars->begin();

    for(unsigned int i = 0; i < foobarCount; i++)
    {
        // Need to create a v8 Object that wraps a single instance of a 
        // Foobar object in "foobars"

        // Then push the object to the v8 Array?
        // foobarsArray->Set(i, [some Foobar instance]);
        snake++;
    }

    return foobarsArray;
}

但是,我在 for 循环中尝试了几种不同的方法,但均无济于事。我应该怎么做呢?

Foobar 和 SuperFoo

这里是Foobar中定义的Init初始化器和nodeNew构造函数,以及Foobar的头文件code> 和 SuperFoo.

#define BUILDING_NODE_EXTENSION

#ifndef FOOBAR_H_
#define FOOBAR_H_

#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <node.h>
#include <string>
#include <vector>

#include <iostream>

#include "EnvironmentObject.h"
#include "SuperFoo.h"
#include "Grid.h"
#include "GridSection.h"
#include "Point.h"
#include "Teams.h"
#include "Vector.h"

class SuperFoo;
class Grid;

class Foobar : public SuperFoo
{
public:
    Foobar();
    virtual ~Foobar();
    Foobar(int id, const Point& location, const int& team, const Grid& world);
    Foobar(const Foobar& snake);

    // Node Implementation
    static void Init(v8::Handle<v8::Object> target);

private:
    // Node Implementation
    static v8::Handle<v8::Value> nodeNew(const v8::Arguments& args);
    static v8::Handle<v8::Value> nodeGetID(const v8::Arguments& args);
    static v8::Handle<v8::Value> nodeGetTeam(const v8::Arguments& args);
    static v8::Handle<v8::Value> nodeGetState(const v8::Arguments& args);
    static v8::Handle<v8::Value> nodeGetVelocity(const v8::Arguments& args);

    int id_;
    int team_;
    int state_;
    Vector* velocity_;
    const Grid* world_;
};

#endif /* FOOBAR_H_ */
#define BUILDING_NODE_EXTENSION

#ifndef GAMEOBJECT_H_
#define GAMEOBJECT_H_

#include <string>

#include <node.h>

#include "Point.h"
#include "Vector.h"

class SuperFoo : public node::ObjectWrap
{
public:
    SuperFoo()
        : collidable_(true), stationary_(true) {}
    virtual ~SuperFoo();
    SuperFoo(const std::string& type, const Point& position);
    SuperFoo(const SuperFoo& object);

    virtual bool collide(SuperFoo& object) = 0;

    Point getPosition() const;
    std::string getType() const;

    void setPosition(const Point& position);

    bool isCollidable() const;
    bool isStationary() const;

    void setCollidable(bool coolide);
    void setStationary(bool stationary);

protected:
    Point* position_;

private:
    // Node Implementation
    static v8::Handle<v8::Value> nodeGetPosition(const v8::Arguments& args);

    std::string* type_;
    bool collidable_;
    bool stationary_;
};

#endif /* SUPERFOO_H_ */
void Foobar::Init(v8::Handle<v8::Object> target)
{
    // Prepare constructor template
    v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(nodeNew);
    tpl->SetClassName(v8::String::NewSymbol("Foobar"));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);
    // Prototype functions
    tpl->PrototypeTemplate()->Set(v8::String::NewSymbol("getID"), v8::FunctionTemplate::New(nodeGetID)->GetFunction());
    tpl->PrototypeTemplate()->Set(v8::String::NewSymbol("getVelocity"), v8::FunctionTemplate::New(nodeGetVelocity)->GetFunction());
    tpl->PrototypeTemplate()->Set(v8::String::NewSymbol("getState"), v8::FunctionTemplate::New(nodeGetState)->GetFunction());

    v8::Persistent<v8::Function> constructor = v8::Persistent<v8::Function>::New(tpl->GetFunction());
    target->Set(v8::String::NewSymbol("Foobar"), constructor);
}

v8::Handle<v8::Value> Foobar::nodeNew(const v8::Arguments& args)
{
    v8::HandleScope scope;

    int id = args[0]->NumberValue();
    Point* position = ObjectWrap::Unwrap<Point>(args[1]->ToObject());
    int team = args[2]->NumberValue();
    Grid* world = ObjectWrap::Unwrap<Grid>(args[3]->ToObject());

    Foobar* foobar = new Foobar(id, *position, team, *world);

    foobar->Wrap(args.This());

    return args.This();
}
v8::Handle<v8::Value> Controller::nodeSpawnFoobar(const v8::Arguments& args)
{
    Controller* gridController = ObjectWrap::Unwrap<Controller>(args.This());

    int team = args[0]->NumberValue();
    gridController->createFoobar(foobarID++, team);

    return v8::Undefined();
}

void Controller::spawnFoobar(int id, int team)
{
    Point createPosition;
    if(team == Teams::kBlue)
    {
        createPosition = world_->getAreaPosition(Teams::kBlue)->getPosition();
    }
    else if (team == Teams::kRed)
    {
        createPosition = world_->getAreaPosition(Teams::kRed)->getPosition();
    }

    int xh = createPosition.get()[0] - EnvironmentObject::kAreaSize / 2
    int yh = createPosition.get()[1] + EnvironmentObject::kAreaSize / 2;

    int x = (rand() % EnvironmentObject::kAreaSize) + xh;
    int y = (rand() % EnvironmentObject::kAreaSize) + yh - EnvironmentObject::kAreaSize;

    foobars_->push_back(new Foobar(id, Point(x, y), team, *world_));
}

Javascript 调用

这是该方法的使用方式

this.update = function() {
    if([some event]) {
        controller.createFoobar();
        console.log(this.getFoobars())
    }
}

this.getFoobars = function() {
    var foobars = controller.getFoobars();
    var foobarsArray = new Array();

    for(i = 0; i < foobars.length; i++) {
        var foobar = foobar[i];

        var position = foobar.getPosition();
        var posX = position.getX();
        var posY = position.getY();
        var positionPoint = new Point(posX, posY);

        var velocity = foobar.getVelocity();
        var toX = velocity.getToX();
        var toY = velocity.getToX();
        var velocityVector = new Vector(toX, toY);

        var foobarObj = {
                id: foobar.getID(),
                team: foobar.getTeam(),
                position: positionPoint,
                velocity: velocityVector,
                state: foobar.getState()
        }

        foobarsArray.push(foobarObj);
    }

    return miniSnakesArray;
};

最佳答案

只要 Foobar 实例已使用您的 nodeNew 构造函数创建,或者更具体地说,只要 Wrap 已在某些时候被调用点在对象上,你应该可以这样做:

v8::Local<v8::Array> foobarsArray = v8::Array::New(foobarCount);

for(unsigned int i = 0; i < foobarCount; i++){
  foobarsArray->Set(i, (*foobars)[i]->handle_);
}

return scope.Close(foobarsArray);

Node 也有一些帮助工具来缩短你的 Init:

// Prototype functions
node::SetPrototypeMethod(tpl, "getID", nodeGetID);
node::SetPrototypeMethod(tpl, "getVelocity", nodeGetVelocity);
node::SetPrototypeMethod(tpl, "getState", nodeGetState);

在您的情况下,由于您不是直接在 JS 中创建 Foobar 实例,因此您希望保存对构造函数的引用,并使用它来创建新实例,而不是调用新的 Foobar。如果您考虑您编写的代码,Foobar 对 JavaScript 方面的知识知之甚少,因为它是 v8 构造函数对象,它知道如何使用正确的方法创建对象。

// Save a global reference
v8::Persistent<v8::Function> foobarConstructor;

// Inside 'Init', assign the constructor to the global
foobarConstructor = v8::Persistent<v8::Function>::New(tpl->GetFunction());
target->Set(v8::String::NewSymbol("Foobar"), foobarConstructor);


// Then instead of 'Foobar* instance = new Foobar'
int argc = 4;
Local<Value> argv[] = {
  // The 4 arguments.
};
v8::Local<v8::Object> instance = foobarConstructor->NewInstance(argc, argv);

关于c++ - 将 C++ 对象包装到 Node 插件中的 v8 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16329491/

相关文章:

c++ - 为什么在从控制台编译后取消引用 string::iterator 不会在 .end() 处引发错误?

c++ - 如何在 Arduino 上将 HexBytes 数组转换为 C/C++ 中的字符串?

javascript - Firebase 实时数据库触发太多更新事件

javascript - 如何将两个以上的对象数组合并为一个对象数组

android - V8 在 mac 上为 android 构建

C++——msvc2012下的Qt+v8

C++11 std::to_string(double) - 没有尾随零

c++ - android NDK 提示 std::nearbyint 不是 std 的成员

c++ - 从线程使用 v8 句柄失败

javascript - EJS (node.js) 中的动态模板