GC DevKit 快速入门 -- 游戏概览(二)

接上节 http://www.cnblogs.com/hangxin1940/archive/2013/04/11/3011555.html

创建屏幕视图

当导入屏幕视图类后,我们会在initUI函数中对它进行实例化,这时,游戏引擎就准备就绪了。

var titlescreen = new TitleScreen(),
    gamescreen = new GameScreen();

之后的内容会详细介绍屏幕视图的构造的。

当游戏引擎将场景创建好后,它会被存储在 GC.app.view 的根节点。任何 View 只要附加到根节点上,都会被呈现到屏幕上,而根节点视图有些特殊,它是 ui.StackView 的实例,ui.StackView 又是 ui.View 的子类, 它另外的功能就是压入和弹出视图栈,并且做相应的转换。

这里还有一些声音相关的代码,我们将会在结尾看到详细的说明。soundcontroller模块会返回一个 AudioManager 的单例对象,当我们转到游戏视图时,它会播放关卡音乐。

事件管理

在事件处理代码中,我们在两个屏幕视图中监听了游戏开始与结束的事件,并且管理 StackView

titlescreen.on('titlescreen:start', function () {
  //...
  GC.app.view.push(gamescreen);
  gamescreen.emit('app:start');
});

gamescreen.on('gamescreen:end', function () {
  //...
  GC.app.view.pop();
});

在收到游戏开始事件后,游戏视图会被压入rootView视图栈中,这里没有必要将已存在与试图栈中的标题视图删除,因为压入栈顶后这个游戏视图已经可见。默认情况下,压入另一个视图进入视图栈时会有一个横向滚动的动画,当然也可以关闭动画。下面我们通过标题视图来看看整个程序的事件流程的细节。

游戏等待状态: TitleScreen.js

标题视图是 TitleScreen类 的一个实例,在 ./src/TitleScreen.js 文件中定义,在 ./src/Application.js 中被实例化一次并加入到根书图,在整个生命周期中存在。

视图剖析

TitleScreen类的视图结构相对来说是比较简单的。它由一个图片来填充背景,以及被放置在背景中央并且看不见的一个视图,它被作为Play按钮。这个按钮将检测输入事件,然后向主程序发送一个事件并通知用户准备好开始游戏。下面来分析这个类:

import ui.View;
import ui.ImageView;

exports = Class(ui.ImageView, function (supr) {
  this.init = function (opts) {
    opts = merge(opts, {
      x: 0,
      y: 0,
      image: "resources/images/title_screen.png"
    });

    supr(this, 'init', [opts]);

    var startbutton = new ui.View({
      superview: this,
      x: 58,
      y: 313,
      width: 200,
      height: 100
    });

    startbutton.on('InputSelect', bind(this, function () {
      this.emit('titlescreen:start');
    }));
  };
});

首先,需要导入一下两个模块:

import ui.View;
import ui.ImageView;

ui.View类被用作一个基础的显示对象将元素渲染在屏幕上,要做到这点,一个视图必须得附加到游戏的场景中(视图树中的节点)。 视图具有样式属性,用来控制如何被渲染到屏幕上,并且可以触发和订阅事件,也可以增加/删除子视图或父视图。

ui.ImageView 类是 ui.View的子类,不但ui.View继承了父类的属性,而且还可以在视图中设置图像。

现在我们已经导入了所依赖的模块,现在可以定义我们的 TitleScreen 类。

exports = Class(ui.ImageView, function (supr) {
  this.init = function (opts) {
    opts = merge(opts, {
      //...
    });

    supr(this, 'init', [opts]);
  };
});

每一个类中定义的init方法都会在实例化的时候被执行,merge函数用来合并属性(犹如两个集合选取合集),用来将它合并的属性传递给构造函数。这之后,调用父类的init方法,并传入合并后的属性对象。

下面是完整的init方法:

this.init = function (opts) {
  opts = merge(opts, {
    x: 0,
    y: 0,
    image: "resources/images/title_screen.png"
  });

  supr(this, 'init', [opts]);

  this.build();
};

title_screen.png将会作为 ui.ImageView类的image属性加载。supr函数将当前对象以参数形式传递给父类来进行初始化。这三个参数分别是当前对象,以及将要调用的当前对象的方法名,还有包含当前对象属性的数组。

Play按钮

还记得在init结束时调用的这个build函数么:

this.build = function() {
  var startbutton = new ui.View({
    superview: this,
    x: 58,
    y: 313,
    width: 200,
    height: 100
  });

  startbutton.on('InputSelect', bind(this, function () {
    this.emit('titlescreen:start');
  }));
};

在标题视图中,我们创建了一个不可见的开始按钮,它位于背景图的中央,这个按钮视图通过superview属性附加于当前类,然后通过InputSelect监听器来捕获点击与触摸事件,最后,我们出发一个事件用以通知标题视图已经运行。

事件流程

我们目前只看到如何捕获用户的输入并传递给主程序,下面来介绍整个游戏的事件流程,之后会看到其余的事件

devkit

程序成功运行,并装载好游戏后,用户首先会进入标题视图。单击开始按钮后titlescreen:start事件会被发出,并被上层的程序捕获,在那里,游戏视图将会加载,之后,用户开完游戏,直到 gamescreen:end 事件发出,上层代码删除游戏试图,最终又回到标题视图。

进行游戏: GameScreen.js

GameScreen类定义在 ./src/GameScreen.js 文件,它也是项目中最长的代码了。其中大部分代码都是在构建视图结构,我们在前面已经了解其中的一些细节。除了建立子视图与游戏资源,它还定义了游戏逻辑相关的函数以及游戏结束时显示得分的方法。后面我们将会看到比较重要的一些代码。

设置屏幕

与之前的代码一样,首先会导入一些模块

import animate;
import device;
import ui.View;
import ui.ImageView;
import ui.TextView;
import src.MoleHill as MoleHill;

之前已经讲过 ui.View, ui.ImageView, 与 device,现在主要看看其他的模块。

ui.TextView的作用,应该很容易猜到,它主要是显示文字,除了常规试图的样式之外,还可以对它进行字号与颜色的设置。

animate模块主要用来为视图、对象以及样式生成动画,它所生成的是补间动画,也就在移动位置之间进行插值,以生成动画。更重要的是,它针对原生设备进行了专门的优化,我们应该在游戏中善加利用此模块,而不是手动的进行额外的计算。之后的代码中我们会遇到它,到时候在进行详细的说明。

最后的一个模块导入语句比较有意思:

import src.MoleHill as MoleHill;

src.MoleHill类引用了工程目录中的./src/MoleHill.js 文件。除了Devkit引擎的模块与类之外,我们还可以自己定义,并且被项目导入并引用。as语句用来给模块或类起个别名,方便我们更加方便的引用,不必输入繁长的路径。

TitleScreen类相同,GameScreen也只在Application.js中被实例化一次,init函数用来定义尺寸以进行屏幕适配,并且将绿草地填充为背景,通过supr函数为父类传递构造属性。

this.init = function (opts) {
  opts = merge(opts, {
    x: 0,
    y: 0,
    width: 320,
    height: 480,
    backgroundColor: '#37B34A'
  });

  supr(this, 'init', [opts]);

  this.build();
};

this.build = function() {
  this.on('app:start', bind(this, start_game_flow));

  this._scoreboard = new ui.TextView({
    superview: this,
    x: 0,
    y: 15,
    width: device.width,
    height: 50,
    autoSize: false,
    size: 38,
    verticalAlign: 'middle',
    textAlign: 'center',
    multiline: false,
    color: '#fff'
  });

  var x_offset = 5;
  var y_offset = 160;
  var y_pad = 25;
  var layout = [[1, 0, 1], [0, 1, 0], [1, 0, 1]];

  this._molehills = [];

  //循环,布局网格,先是行然后是列
  for (var row = 0, len = layout.length; row < len; row++) {
    for (var col = 0; col < len; col++) {
        //如果是1,则创建一个鼹鼠
      if (layout[row][col] !== 0) {
        var molehill = new MoleHill();
        molehill.style.x = x_offset + col * molehill.style.width;
        molehill.style.y = y_offset + row * (molehill.style.height + y_pad);
        this.addSubview(molehill);
        this._molehills.push(molehill);

        //打到鼹鼠时,更新得分
        molehill.on('molehill:hit', bind(this, function () {
          if (game_on) {
            score = score + hit_value;
            this._scoreboard.setText(score.toString());
          }
        }));
      }
    }
  }

  this._countdown = new ui.TextView({
    superview: this._scoreboard,
    visible: false,
    x: 260,
    y: -5,
    width: 50,
    height: 50,
    size: 24,
    color: '#fff',
    opacity: 0.7
  });
};

build函数的代码比之前看到过的稍微有点长,但是它很容易看懂。首先,在启动游戏时监听app:start事件,app:start是游戏的根所派发的事件,当开始按钮被处理后,会执行start_game_flow函数。

定义好用户得分牌后,会在屏幕上定义鼹鼠洞网格以及定义它们的位置与大小,这里创建了一定数量的MoleHill对象,将它们作为子视图附加到GameScreen对象,并且为每一个MoleHill对象都注册了敲打事件用以更新用户得分。

MoleHill类定义在工程中的./src/MoleHill.js文件,稍后会说到。基本上它是一个图像的集合,用来生成鼹鼠出洞,敲头等复合图像,以及动画相关的代码。

最后,创建一个倒计时文本,作为得分牌的子视图。

GC DevKit 快速入门 -- 游戏概览(三) http://www.cnblogs.com/hangxin1940/archive/2013/04/13/3017640.html

posted on   黑暗伯爵  阅读(522)  评论(0编辑  收藏  举报

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述
历史上的今天:
2008-04-13 (c#)数据结构与算法分析 --树

导航

< 2013年4月 >
31 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 1 2 3 4
5 6 7 8 9 10 11

统计

点击右上角即可分享
微信分享提示