Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ The [rules](./rules/Deep_Future_Rules_1_6.pdf) include tables and guidelines for

## How to Play

### Play Online

Click the "Play Online" button above to play the game in your browser.

### Play Locally

- Download [soluna](https://github.com/cloudwu/soluna/releases/tag/nightly) (the game engine runtime).
- Clone the game repository.
- (Optional) For Linux users with Simplified Chinese, install the font `WenQuanYi Micro Hei`.
Expand All @@ -40,6 +46,7 @@ soluna.exe main.game
Feedback is welcome. Please include your save file when reporting issues. The save file can be found at:

- Windows: `%USERPROFILE%\Documents\My Games\deepfuture\save.txt`
- macOS | Linux: `~/.local/share/deepfuture/save.txt`
- macOS & Linux: `~/.local/share/deepfuture/save.txt`
- Web: Browser Local Storage

To share your thoughts about the game, please use Discussions.
9 changes: 8 additions & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@

## 如何游玩

### 在线体验

点击上方“在线体验”按钮,即可在浏览器中游玩游戏。

### 本地体验

- 下载 [soluna](https://github.com/cloudwu/soluna/releases/tag/nightly)(游戏引擎运行时框架)。
- 克隆本游戏仓库。
- (可选)Linux 用户如需简体中文,请安装字体 `WenQuanYi Micro Hei`。
Expand All @@ -40,6 +46,7 @@ soluna.exe main.game
游戏正在持续开发与改进中,欢迎参与测试并提供反馈。遇到问题请带上存档文件提交 issue,存档文件可在以下位置找到:

- Windows: `%USERPROFILE%\Documents\My Games\deepfuture\save.txt`
- macOS | Linux: `~/.local/share/deepfuture/save.txt`
- macOS & Linux: `~/.local/share/deepfuture/save.txt`
- Web: 浏览器 Local Storage

关于游戏内容的交流,请在 Discussions 中发帖。
4 changes: 4 additions & 0 deletions core/mouse.lua
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ function mouse.focus_region()
return focus.region
end

function mouse.focus_object()
return focus.object
end

function mouse.scroll(delta)
mouse.z = mouse.z + delta
end
Expand Down
216 changes: 216 additions & 0 deletions core/touch.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
local mouse = require "core.mouse"

local TOUCH_LONG_PRESS_FRAMES <const> = 18
local TOUCH_MOVE_THRESHOLD2 <const> = 12 * 12
-- Regions that require a confirmation tap.
local DOUBLE_TAP_REGIONS <const> = {
hand = true,
neutral = true,
homeworld = true,
colony = true,
discard = true,
deck = true,
card = true,
}

local REGION_CONFIRM_DOUBLE <const> = {
deck = true,
}

local touch = {}

local current_frame = 0
local pending_clear_focus

local function dist2(x1, y1, x2, y2)
local dx = x1 - x2
local dy = y1 - y2
return dx * dx + dy * dy
end

local state = {
active = false,
pressing = false,
double_candidate = false,
require_double = false,
moved = false,
start_frame = 0,
start_x = 0,
start_y = 0,
x = 0,
y = 0,
}

local last_tap = {
require_double = false,
object = nil,
region = nil,
x = 0,
y = 0,
}

local function clear_last_tap()
last_tap.require_double = false
last_tap.object = nil
last_tap.region = nil
last_tap.x = 0
last_tap.y = 0
end

local function store_last_tap(focus_object, region, x, y)
if focus_object then
last_tap.require_double = true
last_tap.object = focus_object
last_tap.region = region
last_tap.x = x
last_tap.y = y
return true
end
if region and REGION_CONFIRM_DOUBLE[region] then
last_tap.require_double = true
last_tap.object = nil
last_tap.region = region
last_tap.x = x
last_tap.y = y
return true
end
clear_last_tap()
end

local function reset_state()
state.active = false
state.pressing = false
state.double_candidate = false
state.require_double = false
state.moved = false
state.start_frame = 0
state.start_x = 0
state.start_y = 0
state.x = 0
state.y = 0
end

local function apply_press()
if state.pressing then
return
end
mouse.mouse_button("left", true)
state.pressing = true
state.double_candidate = false
clear_last_tap()
end

function touch.begin(x, y)
mouse.mouse_move(x, y)
state.active = true
state.pressing = false
state.moved = false
state.start_frame = current_frame
state.start_x = x
state.start_y = y
state.x = x
state.y = y
state.double_candidate = false
state.require_double = false
local region = mouse.focus_region()
if region and DOUBLE_TAP_REGIONS[region] then
state.require_double = true
end
if last_tap.require_double then
local focus_object = mouse.focus_object()
local same_object = focus_object and focus_object == last_tap.object
local same_region = (focus_object == nil and last_tap.object == nil and region ~= nil and REGION_CONFIRM_DOUBLE[region] and region == last_tap.region)
if same_object or same_region then
state.double_candidate = true
else
clear_last_tap()
end
end
end

function touch.moved(x, y)
mouse.mouse_move(x, y)
state.x = x
state.y = y
if not state.active then
return
end
if not state.moved and dist2(x, y, state.start_x, state.start_y) > TOUCH_MOVE_THRESHOLD2 then
state.moved = true
state.double_candidate = false
end
end

function touch.ended(x, y)
mouse.mouse_move(x, y)
state.x = x
state.y = y
local region = mouse.focus_region()
if state.pressing then
mouse.mouse_button("left", false)
clear_last_tap()
reset_state()
return
end
if state.active then
if not state.moved then
if state.require_double then
if state.double_candidate then
mouse.mouse_button("left", true)
mouse.mouse_button("left", false)
clear_last_tap()
pending_clear_focus = true
else
local focus_object = mouse.focus_object()
if not store_last_tap(focus_object, region, state.x, state.y) then
reset_state()
return
end
end
else
mouse.mouse_button("left", true)
mouse.mouse_button("left", false)
clear_last_tap()
end
else
clear_last_tap()
end
end
reset_state()
end

function touch.update(frame)
current_frame = frame
if pending_clear_focus then
mouse.set_focus(nil, nil)
pending_clear_focus = nil
end
if not state.active then
return
end
local region = mouse.focus_region()
local need_double = region and DOUBLE_TAP_REGIONS[region] or false
state.require_double = need_double
if need_double then
local candidate = false
if last_tap.require_double then
local focus_object = mouse.focus_object()
if focus_object and focus_object == last_tap.object then
candidate = true
elseif focus_object == nil and last_tap.object == nil and REGION_CONFIRM_DOUBLE[region] and region == last_tap.region then
candidate = true
end
end
state.double_candidate = candidate
else
state.double_candidate = false
end
if state.pressing or state.moved then
return
end
if frame - state.start_frame >= TOUCH_LONG_PRESS_FRAMES then
apply_press()
end
end

return touch
14 changes: 14 additions & 0 deletions main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ local loadsave = require "core.loadsave"
local track = require "gameplay.track"
local vbutton = require "visual.button"
local mouse = require "core.mouse"
local touch = require "core.touch"
local keyboard = require "core.keyboard"
local text = require "soluna.text"
local setting =require "core.setting"
Expand Down Expand Up @@ -155,10 +156,23 @@ function callback.mouse_scroll(x, y)
mouse.scroll(x)
end

function callback.touch_begin(x, y)
touch.begin(x, y)
end

function callback.touch_end(x, y)
touch.ended(x, y)
end

function callback.touch_moved(x, y)
touch.moved(x, y)
end

function callback.frame(count)
local x, y = mouse.sync(count)
vdesktop.set_mouse(x, y)
flow.update()
touch.update(count)
-- todo : don't flush card here
vdesktop.card_count(card.count "draw", card.count "discard", card.seen())
map.update()
Expand Down
9 changes: 8 additions & 1 deletion visual/region.lua
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,14 @@ local function draw_card(obj)
end

local function test_card(obj, mx, my)
return obj._move == nil and vcard.test(mx, my, obj.x, obj.y, obj.scale)
if obj._move then
return
end
local x, y, scale = obj.x, obj.y, obj.scale
if obj._focus_time then
x, y, scale = focus_args(obj)
end
return vcard.test(mx, my, x, y, scale)
end

function region:transfer(card, new_region)
Expand Down