将C ++对象包装到节点插件中的v8对象

时间:2013-05-02 02:38:44

标签: c++ node.js v8

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

目前,代码看起来像这样

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

以下是Init中定义的nodeNew初始值设定项和Foobar构造函数,以及FoobarSuperFoo的标题文件。

#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 Call

以下是该方法的使用方法

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;
};

1 个答案:

答案 0 :(得分:3)

只要使用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实例,您需要保存对构造函数的引用,并使用它来创建新实例,而不是调用{{1 }}。如果你考虑你编写的代码,new Foobar对JavaScript方面知之甚少,因为知道如何使用正确的方法创建对象的v8构造函数对象。

Foobar