RPG 记忆宫殿

Created 5.09

这是一个脑洞很大的设定。 首先,这是一个记忆工具。 它的工作原理是记忆宫殿。 对,就是卷福装逼大杀器。 滚,我去记忆宫殿遨游惹。 它不基于现实生活的场景。 而是进入角色扮演游戏里。 随便乱逛,打打怪记东西。 想象一下,你就走着走着。 然后你操起了你的碧血剑。 一刀下去,怪物喷出鲜血。 口中大叫,单词:ponder。 一刀下去,怪物没有犹豫。 捂着伤口说,释义:沉思。 一刀下去,怪物流着鲜血。


Updated 5.11

调研了可能的构建记忆宫殿的方法。 例如,曾经豆瓣的阿花城就很合适。 但是木有开源实现,自己写一个又很烦。 OpenStreetMap 是一个 GIS 的 WEB 应用,但是解析略繁琐。 我的结论是,使用 Tiled 或者现成的 TMX Libraries 来绘制 TMX 地图。 这种技术在 2D 游戏里最为常见。


Updated 5.13

午后醒来研究了下刷子和贴图,随手绘制了下一张图,感觉处于可用的状态


Updated 5.15

由于外出去看妈妈和侄女,木有大进展。 尝试用 Swift + SpriteKit 的方式来加载地图,使用的库叫 JSTiledMap。 使用了 OBJ-C 的 Header Bridge,将其导入给 Swift 使用。

Read More

import SpriteKit

class GameScene: SKScene {
    override func didMoveToView(view: SKView) {
        /* Setup your scene here */

        // load first scene tmx map
        let tiledmap = JSTileMap(named: "first-scene.tmx");

        // center map on scene's anchor point
        tiledmap.position = CGPointMake(160, 80);

        // add map to scene.
        self.addChild(tiledmap);
    }
}

但是感觉使用 Swift 写,将来写 NPC 之类的行为很难受,找了个叫 Love2D 的框架。 使用一个叫 STI 的库,可以蛮方便导入地图:

local sti = require "sti"

function love.load()
    map = sti.new("assets/first-scene.lua")
end

function love.update(dt)
    map:update(dt)
end

function love.draw()
    map:draw()
end

Updated 5.17

晚上编程时间很有限,但是单元测试不能省。

$ make test
busted src
●●●●●●●●●●●●●●●●
16 successes / 0 failures / 0 errors / 0 pending : 0.005402 seconds

Updated 5.18

为了顺便响应潮流,我打算在新项目中用 redux 来写游戏逻辑。 由于完全没有找到 redux 的 lua 实现,我必须自己手动撸一个。 好在 redux 本身并没有什么逻辑,写起来可能会很快。 另外,我决定在 redux.lua 还没撸出来之前,先写写业务逻辑,以后再整合。

具体来说,目前看起来代码像这样子:

Reducer:

function camera.reducer(state, action)
    if action.type == 'MOVE_CAMERA' then
        local dx = action.dx or 0
        local dy = action.dy or 0
        return assign(state, {
            x = state.x + dx,
            y = state.y + dy,
        })
    end
end

Component:

function camera.update(dt)
    store.dispatch({
        type = 'SET_CAMERA_POSITION',
        x = store.player.x - love.graphics.getWidth() / 2,
        y = store.player.y - love.graphics.getHeight() / 2,
    })
end

function camera.draw(children)
    -- Set camera
    love.graphics.push()
    love.graphics.rotate(-store.camera.rotation)
    love.graphics.scale(1 / store.camera.scaleX, 1 / store.camera.scaleY)
    love.grahpics.translate(-store.camera.x, -store.camera.y)

    -- Render children nodes
    if children then
        for _, child in pairs(children) do
            child()
        end
    end

    -- Unset camera
    love.grahpics.pop()
end

游戏的代码组织就是很简单的两个目录:

  • src/components: 放置绘制逻辑,具体来说,draw 函数根据全局的状态树渲染当前界面,根据监听的事件以及love2d定义的钩子调用 store.dispatch 用于触发事件。
  • src/reducers: 放置业务逻辑,具体来说,reducer 函数响应事件并生成新的状态。
  • src/store: 定义一颗全局状态树。

运行情况: