AR酱 Magic Leap开发指南(6)-- Application File System

4
回复
365
查看
打印 上一主题 下一主题
[ 复制链接 ]
排名
2299
昨日变化

28

主题

249

帖子

1454

积分

Rank: 9Rank: 9Rank: 9

UID
156756
好友
11
蛮牛币
1330
威望
0
注册时间
2016-7-13
在线时间
485 小时
最后登录
2019-8-20

专栏作家

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 geekli 于 2019-8-20 20:33 编辑

许多应用程序需要在Magic Leap One上读写用户数据、记录日志、游戏分数等。所以本篇文章展示如何使用应用程序文件系统存储用户数据。在应用程序的私有沙箱文件系统中,可以根据安全设置将文件保存到不同的位置。无论具体位置如何,任何应用程序的私有文件夹都是:
  • documents/C1/ (writable_dir_path_locked_and_unlocked)
  • documents/C2/ (writable_dir_path)
  • tmp/ (tmp_dir_path)


关于这部分我们需要掌握:
  • 使用Lumin Runtime Editor将UITextEdit对象(用于输入文本的区域)应用到项目中。
  • 从系统键盘接收输入数据。
  • 检索应用程序将写入的路径。
  • 从文件中读取数据。
  • 当用户点击控件的bumper按钮时,将数据存储到文件中。



实现效果预览:



Step 1: 在Lumin Runtime Editor设置项目
1.从Package Manager启动Lumin Runtime Editor。
2.在Lumin Runtime Editor中创建一个新项目。

3.将其命名为AppStorage,然后单击Create Project。


4.在场景层次结构下,右键单击根节点。

5.单击 Insert > UI Nodes > UITextEdit。UITextEdit提供了一种使用系统键盘输入文本的简单方法。


6.将UITextEdit的名称更改为TextEdit,并应用以下设置。


7.设置Scale值为 (3.0, 3.0, 3.0)。



8.保存场景

场景效果如下图所示:


Step 2: 在Visual Studio (Windows)设置项目

1.启动Microsoft Visual Studio。
2.点击File > New > Import Magic Leap Mabu Projects。
3.在导入Magic Leap项目中单击Browse,并选择Lumin Runtime Editor项目的文件夹。

4.点击Import

在解决方案资源管理器下,AppStorage项目应该如下图所示:


Step 3: 在Visual Studio Code (Windows / macOS)设置项目

1.打开Visual Studio Code。
2.点击左侧的图标
3.在Lumin SDK窗口标题中,单击图标 ,设置Lumin SDK的路径(如果还没有设置)。通常是:/Users/user/MagicLeap/mlsdk/v0.x.x。
4.在签名证书窗口标题中,单击图标,然后设置.cert包签名证书文件的路径(如果还没有设置)。
5.回到Lumin Runtime Editor,在项目菜单上,单击Code Generation > Open code in External Editor。
6.出现下面窗口时单击OK即可。


项目文件夹如下图:



Step 4:脚本处理

Source Files文件夹(或Visual Studio code中的code/src文件夹)下,打开AppStorage.cpp脚本。Lumin Runtime已经为我们生成了大量的代码。下面我们将重点讨论需要修改的部分。
Directives, Namespaces and Globals

在脚本的顶部添加以下指令,在最后一个#include指令之后:
[AppleScript] 纯文本查看 复制代码
#include <lumin/event/KeyInputEventData.h>
#include <lumin/ui/UiKit.h>
#include <fstream>
接下来,添加以下指令和声明:
[AppleScript] 纯文本查看 复制代码
using namespace lumin;
using namespace lumin::ui;
using namespace std;

namespace {
  UiTextEdit* textEdit;
}


  • 命名空间lumin、lumin::ui和std简化了代码。
  • UiTextEdit* textEdit会将我们场景的TextEdit链接到脚本中的textEdit对象。

glm::vec3 AppStorage::getInitialPrismSize()更改为:
[AppleScript] 纯文本查看 复制代码
const glm::vec3 AppStorage::getInitialPrismSize() const {
  return glm::vec3(2.0f, 2.0f, 0.5f);
}
初始化
[AppleScript] 纯文本查看 复制代码
int AppStorage::init() {

  ML_LOG(Debug, "AppStorage Initializing.");

  createInitialPrism();
  lumin::ui::Cursor::SetScale(prism_, 0.03f);
  spawnInitialScenes();
  //cast the TextEdit node
  textEdit = static_cast<UiTextEdit*>(prism_->findNode("TextEdit", prism_->getRootNode()));

  //retrieve the writeable path and the prepare the data.txt file to be read
  ifstream myfilein(BaseApp::getWritablePath() + "data.txt");
  string line, text;
  text = "";

  //if the file is open read its contents line by line
  if (myfilein.is_open()) {
    while (getline(myfilein, line)) {
      text += line + '\n';
    }
    myfilein.close();
  }

  //set the text of the textEdit to become the file's contents
  textEdit->setText(text);
  
  return 0;
}
  • createInitialPrism()创建Prism。
  • ui::Cursor::SetScale(prism_, 0.03f)设置Prism (prism_)光标的比例。
  • spawnInitialScenes() 实例化我们唯一的场景。
  • textEdit = static_cast<UiTextEdit*>(prism->findNode("TextEdit", prism->getRootNode()))表示并转换场景的textEdit节点。
  • BaseApp::getWritablePath()检索应用程序写入的私有路径。
  • while (getline(myfilein, line))循环读取文件的内容,并逐渐将它们添加到文本字符串中。
  • textEdit->setText(text)将textEdit的文本更改为存储在文件中的内容,如果文件不存在,则更改为空字符串。


注意:不要在应用程序中硬编码路径。路径会随着安全设置的不同而变化。使用getWritablePath()回调即可。

bool AppStorage::eventListener(lumin::ServerEvent* anEvent)方法在运行时监听事件并接收bumper按钮点击。
[AppleScript] 纯文本查看 复制代码
bool AppStorage::eventListener(lumin::ServerEvent* anEvent) {
  if (anEvent->isInputEventType()) {
    InputEventData* inputEventData = static_cast<InputEventData*>(anEvent);
    KeyInputEventData* keyEventData = static_cast<KeyInputEventData*>(inputEventData);
    if (keyEventData->keyCode() == input::KeyCodes::AKEYCODE_EX_BUMPER) {
      ofstream myfileout(BaseApp::getWritablePath() + "data.txt");
      myfileout << textEdit->getText() + "\n";
      myfileout.close();
    }
  }

  return false;
}
此方法将每个事件捕获为ServerEvent* anEvent。如果事件是InputEvent(引用输入的事件),则执行以下操作:
  • 将InputEventData转换为InputEventData
  • 将相关的KeyInputEventData转换为keyEventData
  • 检查keyEventData是否引用AKEYCODE_EX_BUMPER事件。



如果bumper被点击了,则:
  • ofstream myfileout(BaseApp::getWritablePath() + "data.txt")备编写相同的data.txt文件。
  • myfileout << textEdit->getText() + "\n"将用户的输入写入文件。
  • myfileout.close()关闭文件。


Step 5:Build

构建签名.mpk文件并将其安装到设备上的过程取决于使用的IDE。
Visual Studio (Windows)
  • 使用USB-C电缆将Magic Leap One连接到计算机。
  • 选择调试配置和ML目标。
  • 切换到Magic Leap调试器。
  • 运行该应用程序。
  • 如果需要调试,单击Continue继续执行。


Visual Studio Code (Windows / macOS)

  • 把你的设备插入电脑。
  • 单击左边的图标
  • 将调试目标设置为Lumin OS Debug
  • 单击三角形图标开始调试。


Step 6:总结

  • 如果这是你第一次在设备上部署应用程序,则会打开一个安装证书的通知。在这种情况下,接受证书安装应用程序即可。
  • 一旦证书被接受,地球模型就会出现。用OK手势让它旋转,或者用手指手势(看到你指尖上的一个小立方体)。长时间按住触发器移动整个Prism的位置。
  • 如果应用程序无法识别手的姿势,关闭所有应用程序(长时间按住Home按钮),重新启动我们的应用程序。
  • 如果你仍然什么也没看到,看看你周围的一切,因为设备启动时的方向决定了它在世界上的起始方向。

完整代码参考:

[AppleScript] 纯文本查看 复制代码
// %BANNER_BEGIN%
// ---------------------------------------------------------------------
// %COPYRIGHT_BEGIN%
//
// Copyright (c) 2018 Magic Leap, Inc. All Rights Reserved.
// Use of this file is governed by the Creator Agreement, located
// here: https://id.magicleap.com/creator-terms
//
// %COPYRIGHT_END%
// ---------------------------------------------------------------------
// %BANNER_END%

// %SRC_VERSION%: 1

#include <AppStorage.h>
#include <lumin/node/RootNode.h>
#include <lumin/ui/Cursor.h>
#include <ml_logging.h>
#include <scenes.h>
#include <PrismSceneManager.h>

#include <lumin/event/KeyInputEventData.h>
#include <lumin/ui/UiKit.h>
#include <fstream>

using namespace lumin;
using namespace lumin::ui;
using namespace std;


//using namespace lumin
namespace {
  UiTextEdit* textEdit;
}

AppStorage::AppStorage() {
  ML_LOG(Debug, "AppStorage Constructor.");

  // Place your constructor implementation here.
}

AppStorage::~AppStorage() {
  ML_LOG(Debug, "AppStorage Destructor.");

  // Place your destructor implementation here.
}

const glm::vec3 AppStorage::getInitialPrismSize() const {
  return glm::vec3(2.0f, 2.0f, 0.5f);
}

void AppStorage::createInitialPrism() {
  prism_ = requestNewPrism(getInitialPrismSize());
  if (!prism_) {
    ML_LOG(Error, "AppStorage Error creating default prism.");
    abort();
  }
  prismSceneManager_ = new PrismSceneManager(prism_);
}

int AppStorage::init() {

  ML_LOG(Debug, "AppStorage Initializing.");

  createInitialPrism();
  lumin::ui::Cursor::SetScale(prism_, 0.03f);
  spawnInitialScenes();
  //cast the TextEdit node
  textEdit = static_cast<UiTextEdit*>(prism_->findNode("TextEdit", prism_->getRootNode()));

  //retrieve the writeable path and the prepare the data.txt file to be read
  ifstream myfilein(BaseApp::getWritablePath() + "data.txt");
  string line, text;
  text = "";

  //if the file is open read its contents line by line
  if (myfilein.is_open()) {
    while (getline(myfilein, line)) {
      text += line + '\n';
    }
    myfilein.close();
  }

  //set the text of the textEdit to become the file's contents
  textEdit->setText(text);
 
  return 0;
}

int AppStorage::deInit() {
  ML_LOG(Debug, "AppStorage Deinitializing.");

  // Place your deinitialization here.

  return 0;
}

void AppStorage::spawnInitialScenes() {

  // Iterate over all the exported scenes
  for (auto& exportedSceneEntry : scenes::externalScenes ) {

    // If this scene was marked to be instanced at app initialization, do it
    const SceneDescriptor &sd = exportedSceneEntry.second;
    if (sd.getInitiallySpawned()) {
      lumin::Node* const spawnedRoot = prismSceneManager_->spawn(sd);
      if (spawnedRoot) {
        if (!prism_->getRootNode()->addChild(spawnedRoot)) {
          ML_LOG(Error, "AppStorage Failed to add spawnedRoot to the prism root node");
          abort();
        }
      }
    }
  }
}

bool AppStorage::updateLoop(float fDelta) {

  // Place your update here.

  // Return true for your app to continue running, false to terminate the app.
  return true;
}

bool AppStorage::eventListener(lumin::ServerEvent* anEvent) {
  if (anEvent->isInputEventType()) {
    InputEventData* inputEventData = static_cast<InputEventData*>(anEvent);
    KeyInputEventData* keyEventData = static_cast<KeyInputEventData*>(inputEventData);
    if (keyEventData->keyCode() == input::KeyCodes::AKEYCODE_EX_BUMPER) {
      ofstream myfileout(BaseApp::getWritablePath() + "data.txt");
      myfileout << textEdit->getText() + "\n";
      myfileout.close();
    }
  }

  return false;
}



------AR Portal(AR开发者社区)整理
关注微信公众号:AR开发者社区  (国内领先的AR开发者交流学习社区和AR内容平台)

7日久生情
2382/5000
排名
1387
昨日变化

0

主题

742

帖子

2382

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
135463
好友
0
蛮牛币
73
威望
0
注册时间
2016-1-23
在线时间
748 小时
最后登录
2019-8-21
沙发
2019-8-3 09:29:48 只看该作者
6666666666666666okok
7日久生情
2114/5000
排名
4092
昨日变化

0

主题

1390

帖子

2114

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
254705
好友
1
蛮牛币
1914
威望
0
注册时间
2017-11-16
在线时间
362 小时
最后登录
2019-8-21
板凳
2019-8-5 08:39:06 只看该作者
66666666666666666666666666666
排名
64935
昨日变化

0

主题

30

帖子

81

积分

Rank: 2Rank: 2

UID
259926
好友
0
蛮牛币
174
威望
0
注册时间
2017-12-16
在线时间
49 小时
最后登录
2019-8-21
地板
2019-8-5 17:05:25 只看该作者
太难了9999999999999
5熟悉之中
802/1000
排名
4110
昨日变化

1

主题

270

帖子

802

积分

Rank: 5Rank: 5

UID
245227
好友
0
蛮牛币
984
威望
0
注册时间
2017-9-21
在线时间
171 小时
最后登录
2019-8-21
5#
2019-8-6 09:23:10 只看该作者
买这东西的都是智商欠费的啊
您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则