diff options
| author | Eltrac <hi@guhub.cn> | 2025-04-29 13:41:03 +0800 |
|---|---|---|
| committer | Eltrac <hi@guhub.cn> | 2025-04-29 13:41:03 +0800 |
| commit | f2b8c53bb441c1ed455c0aa45b4e29305323a11f (patch) | |
| tree | 18ff6b3022e83021dd893c9bdfdfdeaa87d5ab76 | |
| parent | 9088049e3296ac1760d28bb5d68402d985988b8b (diff) | |
| parent | 565bb73eaa8c858211892044032343ce67933072 (diff) | |
Merge branch 'master' of https://github.com/BigCoke233/geek-death-project
| -rw-r--r-- | assets/css/components/_card.scss | 33 | ||||
| -rw-r--r-- | assets/css/components/_markdown.scss | 20 | ||||
| -rw-r--r-- | assets/css/components/_postlist.scss | 13 | ||||
| -rw-r--r-- | assets/css/utils/_utility.scss | 27 | ||||
| -rw-r--r-- | content/posts/从订阅制到理财观再到游戏设计.md | 107 | ||||
| -rw-r--r-- | layouts/_default/taxonomy.html | 64 | ||||
| -rw-r--r-- | layouts/cards/section.html | 12 | ||||
| -rw-r--r-- | layouts/categories/taxonomy.html | 67 | ||||
| -rw-r--r-- | layouts/partials/components/global-search.html | 13 | ||||
| -rw-r--r-- | layouts/term/term.html (renamed from layouts/_default/term.html) | 2 |
10 files changed, 247 insertions, 111 deletions
diff --git a/assets/css/components/_card.scss b/assets/css/components/_card.scss index 6bf57fcc..8308d1c6 100644 --- a/assets/css/components/_card.scss +++ b/assets/css/components/_card.scss @@ -74,6 +74,39 @@ } } +.cards-section { + display: grid; + grid-template-columns: 1fr; + gap: 1rem; + @media screen and (min-width: 768px) { + grid-template-columns: 1fr 1fr; + } + .card { + margin: 0; + h3 { + margin: 0; + } + } +} + +.cards-statistics { + margin: 1rem 0; + table tr > td:nth-child(2) { + text-align: right; + } + .number-pill { + text-align: center; + display: inline-block; + width: 1.75rem; + height: 1.75rem; + line-height: 1.75rem; + box-sizing: border-box; + border-radius: 50%; + background-color: var(--block-background-color); + font-size: 1rem; + } +} + #latest-cards { margin: 1rem 0; .latest-cards-container { diff --git a/assets/css/components/_markdown.scss b/assets/css/components/_markdown.scss index 551ce3fb..d1e1c50d 100644 --- a/assets/css/components/_markdown.scss +++ b/assets/css/components/_markdown.scss @@ -110,20 +110,16 @@ $em-text-color: #889E73; } table { - border: 1px solid $border-color; - max-width: 100%; - overflow-x: auto; border-collapse: collapse; - th { - background-color: $block-background-color - } - td { - padding: .1rem .75rem - } + border-top: 2px solid var(--border-color); + overflow-x: auto; + width: 100%; tr { - & > td:nth-child(even) { - background-color: var(--bright-background-color) - } + border-bottom: 1px solid var(--border-color); + } + td, th { + padding: 0.5rem 1rem; + line-height: 1.5; } } diff --git a/assets/css/components/_postlist.scss b/assets/css/components/_postlist.scss index da4113a2..7682dbae 100644 --- a/assets/css/components/_postlist.scss +++ b/assets/css/components/_postlist.scss @@ -131,19 +131,6 @@ } } } - .term-list-cards { - @media screen and (min-width: 768px) { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 1rem; - } - .card { - margin: 0; - h3 { - margin: 0; - } - } - } } .taxonomy-description hr { diff --git a/assets/css/utils/_utility.scss b/assets/css/utils/_utility.scss index a9907339..9b857fdb 100644 --- a/assets/css/utils/_utility.scss +++ b/assets/css/utils/_utility.scss @@ -29,22 +29,31 @@ figure { } .outbox { - display: flex; - justify-content: center; + display: flex; + justify-content: center; + width: 100%; - // Default width - width: var(--page-width); + @media screen and (min-width: 768px) { + width: calc(var(--page-width) + 10rem); + margin: 0 -5rem; + } - // Properly interpolate calc() in media queries + @media screen and (min-width: 1200px) { + width: calc(var(--page-width) + 20rem); + margin: 0 -10rem; + } + + &.small { @media screen and (min-width: 768px) { - width: calc(var(--page-width) + 5rem * 2); - margin: 0 -5rem; + width: calc(var(--page-width) + 4rem); + margin: 0 -2rem; } @media screen and (min-width: 1200px) { - width: calc(var(--page-width) + 10rem * 2); - margin: 0 -10rem; + width: calc(var(--page-width) + 10rem); + margin: 0 -5rem; } + } } .font-mono { diff --git a/content/posts/从订阅制到理财观再到游戏设计.md b/content/posts/从订阅制到理财观再到游戏设计.md index e2c6c983..3a9c5162 100644 --- a/content/posts/从订阅制到理财观再到游戏设计.md +++ b/content/posts/从订阅制到理财观再到游戏设计.md @@ -1,16 +1,18 @@ --- title: 从订阅制到理财观再到游戏设计 subtitle: 游戏《Subscriptions》设计日志 -description: -tags: -related_cards: +description: +tags: +related_cards: date: 2025-04-20T22:43:00 categories: Game++ -banner: +banner: draft: true toc: true --- +## 📅 时间轴 + ### 4 月 17 日前些日子 最近其实有两个游戏点子,第一个在上手制作之后莫名地让我丧失了热情,甚至连最简单的原型都没做完;另一个坑挖得太大,令我望而却步,可能会作为一个进展相对缓慢的主项目进行。但无论如何,我觉得我需要做一个轻巧简单、能让我快速找回创作热情的项目。 @@ -35,7 +37,7 @@ toc: true 诶?不是说好订阅的是软件吗?罢了罢了,好玩就行。 -{{< img src="https://image.guhub.cn//uPic/untitled-card-game-20250418.jpeg" >}} +{{< img src="https://image.guhub.cn/uPic/untitled-card-game-20250418.jpeg" >}} 我还用到了之前买的各种类型的骰子,除了用于决定计费条件的六面体骰子,我还用到了一个用于发放「工资」的十面体骰子(骰子上的数值是 0-90)。这两个骰子分别被称作**机会骰子**和**工资骰子**(*好奇怪的名字……*)。 @@ -47,7 +49,7 @@ toc: true 唉,还是第二天上班跟同事摸鱼的时候玩玩再说吧! -## 4 月 19 日 +### 4 月 19 日 和三个学生以及同事玩了玩,结果三次都是我输,但玩得很爽。因为计算量实在是太大了,所以一局游戏 30~50 分钟的时间里,有一半都在拿计算器算分数。不过这对游戏性的影响不算大,至少我们玩得挺上头的。 @@ -56,7 +58,7 @@ toc: true 1. 设置有「小额投资」和「大额投资」这样的卡牌,每轮都需要支付 ¥10 或 ¥50,但只要机会点数不算低,基本都是稳赚不赔(如果掷出 2,就能回本)。这样的设计其实问题不大,但投资牌的数量不多,先抽到投资牌的玩家能获得较明显的优势。 2. 设置了一张叫做「乞讨」的卡牌,可以选定一个玩家,获取其总资产的 5%。这 5% 的计算让玩家的资产全部变成了小数,而且一直在往小数点后延伸。这个还好解决,回合结束时四舍五入到小数点后两位就行了。 3. 一位一直在旁观我们游戏的学生指出,除了部分卡牌有偷窃、乞讨、换牌的效果,这更像是两个人在一起玩单机游戏。虽然**卡牌构筑**类游戏大部分都有这样的特征,而且这个游戏确实可以单人玩,但玩家之间的互动确实应该更多一些,于是我决定加入更多有互动效果的牌。 -4. 部分较强的卡牌被我设置得很昂贵,尽管买卖一开始看起来很赚,但我发现自己一回合结算下来自己竟然亏了 100…… +4. 部分较强的卡牌被我设置得很昂贵,尽管买卖一开始看起来很赚,但我发现自己一回合结算下来自己竟然亏了 100…… 玩过几局之后,我发现这其实更像是个「投资」主题的游戏,而非一开始设想的「订阅」——本以为很有策略,各种精打细算,结果还是亏钱的。尽管这可能要怪罪到扣费条件的随机性上,但现实中的投资难道不是这样吗? @@ -72,8 +74,8 @@ toc: true 最后,我加入了一些能够促进玩家之间竞争的卡牌: -1. 礼物牌:持有这张牌时,在抽牌阶段可以选择将一张牌放进对手的手牌中(前提是对方的手牌有空位,手牌上限是 5 张) -2. 鬼手牌:持有这张牌时,在抽牌阶段除了抽取牌堆中的牌,还可以从其他玩家的手牌中选取,效果发动后弃置这张牌 +1. 礼物:持有这张牌时,在抽牌阶段可以选择将一张牌放进对手的手牌中(前提是对方的手牌有空位,手牌上限是 5 张) +2. 鬼手:持有这张牌时,在抽牌阶段除了抽取牌堆中的牌,还可以从其他玩家的手牌中选取,效果发动后弃置这张牌 3. 一张纯粹的负面卡牌:有一半的概率扣除 ¥100,没有任何效果 4. 锁牌:横着放置在某张牌上,下面的这张牌无法被弃置也无法被偷取,除非先弃置锁牌(由于每轮的抽牌阶段选择弃牌就不能抽牌,而且只能弃牌一张,如果将锁加到某个玩家的一张牌上,下面这张牌至少会保留两回合) 5. …… @@ -86,4 +88,89 @@ toc: true ### 4 月 21 日 -和自己玩了几局单人游戏,试图建立对这个游戏的理解, +> 这个游戏暂定名为《Subscriptions》,试着单人玩了几局建立对自己游戏的理解,发现这游戏单人玩根本不会输,因为不会有人因为付不起卡牌费用而破产,就算调高费用也会有人保守而选择只掷骰子获胜。 +> +> 感觉是一个需要解决的问题,想到了两个方案: +> 1. 抽牌阶段必须行动,不能不抽牌也不弃牌(但这样其实也可以抽到任何牌都说自己不想要然后弃掉😣) +> 2. 单人游戏目标设置为「在最少的回合数内完成¥1000的目标」,而不只是达到目标。 +> +> 开始感受到数值设计和机制平衡的压力了~ + +——在 Telegram 群组里发表的感想 + +### 4 月 26 日 + +~~别问我为什么时间突然过了这么久。~~ + +跟一个 T 人朋友玩了迭代过后的游戏,她对更新后的抽牌方式提出了建议。她指出有问题的是这一条: + +> 如果不愿意赌也不愿意将就,或者纯粹不想让对手拿到某张牌,可以从明牌的牌堆中拿取一张放到弃牌堆,**这样做也意味着其他玩家可以抽取下面的一张牌,因为玩家在弃牌之后就没有行动机会了**。 + +她跟我说「一个玩家的回合结束之后,你把牌堆刷新一下不就行了?」。 + +好吧,看来的确是我游戏玩少了…… + +不过这又导致了另一个问题——玩家真的很容易忘记刷新牌堆这件事情啊!陪我玩的两个人因为在上周已经接触过这个游戏,新鲜感褪却之后,对频繁的计算感到有些厌倦了。我能感到他们在挑选卡片和做决策时是有体验感的,但每轮一开始做计算的部分就会让人觉得无聊。这样无聊的一局游戏最终以游戏设计者的胜利结束(我玩这个游戏第一次赢啊喂!)。 + +之前想做个资产计算器,结果没找到时间,现在想想,直接做成电子游戏应该会更好。各种数值叠加是很爽的,但如果要自己算,总归会感到厌倦。 + +### 4 月 28 日 + +一个 INFJ 朋友来找我玩,给他冲了一杯咖啡过后,我把《Subscriptions》的小纸盒掏出来和他玩了一局。有新鲜感果然还是好啊,我觉得他玩得挺起劲的。 + +对我来说,这也是非常有意思的一局游戏。最终胜利的是他,而且他获胜的方式是我从未设想过的。他通过几张牌的 combo 叠加倍率,再加上手气不错,从 400 多的资产,一次赚取了 1200,减去手中卡牌的高额扣费之后,他依然获得了胜利。 + +{{< img src="https://image.guhub.cn/uPic/2025/04/the-unexpected-win-of-subscription-20250429.jpeg" >}} + +他手上的四张牌,效果分别是: + +1. 奇遇:如果机会骰子掷出奇数,则机会 × 2 +2. 风险投资:工资变为 机会 × 工资点数 +3. 行贿:工资 × 2 +4. 大额投资:获得 机会 × 20 金钱 + +这轮他掷出的机会点数是 3,工资点数是 90,他本轮的收入就是: + +``` +90 × (3 × 2) × 2 + (3 × 2) × 20 +``` + +他还跟我讲了讲一张名为「赌徒」的卡牌设计,这张牌的效果是: + +> 若 机会 > 3,则获得 3 × 20 金钱 +> +> 若 机会 < 3,则扣除 3 × 20 金钱 + +他没有选择这张牌(事实上,玩了这么多局游戏,没有一个人选张牌,连我自己也不用),他大概把卡牌的价格也考虑在内,算了一下数学期望,说这张牌亏钱的概率比较大,就没有用。~~这就是 J 人吗,可怕,可怕。~~ + +设计这种游戏大概是需要一些数学和经济学知识的,如果我了解相关的理论的话,设计数值的时候兴许就不会这么纠结了。 + +## 🕹️ 游戏规则 + +{{< callout "先整理一下目前为止确定下来的游戏规则吧" "📋" >}} + +### 回合行动 + +1. 🎲 掷骰阶段<br/> + 玩家同时投掷「工资骰子」和「机会骰子」,先结算工资,手牌中与工资相关的卡牌在此阶段生效。 +2. 🃏 发动卡牌效果<br/> + 依序触发手中卡牌的效果。 +3. 💸 扣费阶段<br/> + 根据机会点数决定每张卡牌是否扣费,并从资产中扣除相应费用。 +4. 🗳️ 抽牌阶段<br/> + 玩家在此阶段只能行动一次,抽牌或者弃牌。 + - 玩家从两个正面向上的牌堆和一个背面向上的牌堆中抽取一张牌放入手牌 + - 或者,玩家可以弃置一张手牌 + - 如果玩家已有 5 张手牌,则不能抽牌,只能弃牌或者放弃行动 +5. 💰 结算阶段<br/> + - 如果有玩家的资产达到 ¥1000,则该玩家获胜; + - 如果有玩家的资产降到 ¥0 以下,则该玩家出局;如果其他玩家都出局,则留在场上的玩家获胜; + - 如果上述条件都不满足,则游戏继续。 + +### 卡牌 + +每张卡牌上有三种信息:价格信息、名称和效果描述。 + +价格信息由「价格」和「扣费条件」构成。价格决定了这张卡牌一次扣费多少;扣费条件决定了卡牌在某一回合是否扣费。扣费条件只与玩家在某一回合投掷的「机会点数」相关。 + +## 🎮 游戏玩法 diff --git a/layouts/_default/taxonomy.html b/layouts/_default/taxonomy.html index e4ad0753..025a63d7 100644 --- a/layouts/_default/taxonomy.html +++ b/layouts/_default/taxonomy.html @@ -4,7 +4,6 @@ {{ partial "components/postnav.html" . }} <!-- Display Tags --> - {{ if eq .Type "tags" }} <section class="taxonomy-tags"> {{ range sort .Site.Taxonomies.tags "Count" "desc" }} <a href="{{ .Page.RelPermalink }}" class="taxonomy-tags-item"> @@ -13,69 +12,6 @@ </a> {{ end }} </section> - {{ end }} - - <!-- Display Categories --> - {{ if eq .Type "categories" }} - {{ partial "components/welcome.html" . }} - {{ $featured := slice "稻草人周刊" "年终总结" "揽物日志" "极客死亡计划书" }} - <h2>周期性刊物</h2> - <section class="taxonomy-categories"> - {{ range sort .Site.Taxonomies.categories ".Count" "desc" }} - {{ if in $featured .Page.Title }} - <div class="taxonomy-categories-item"> - <h3 class="category-title"> - <a href="{{ .Page.RelPermalink }}"> - {{ with .Page.Params.icon }}<span>{{ . }}</span>{{ end }} {{ .Page.LinkTitle }} - </a> - </h3> - <p class="category-description">{{ .Page.Params.description | markdownify }}</p> - <ul class="category-articles"> - {{ range first 6 .Pages }} - <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li> - {{ end }} - </ul> - {{ if gt .Count 6 }} - <a class="category-link" - href="{{ .Page.RelPermalink }}" - >阅读所有 {{ .Count }} 篇文章</a> - {{ end }} - </div> - {{ end }} - {{ end }} - </section> - - <!-- Render Other Categories --> - <h2>文章系列</h2> - <section class="taxonomy-categories"> - {{ range sort .Site.Taxonomies.categories ".Count" "desc" }} - {{ if not (in $featured .Page.Title) }} - <div class="taxonomy-categories-item"> - <h3 class="category-title"> - <a href="{{ .Page.RelPermalink }}"> - {{ with .Page.Params.icon }}<span>{{ . }}</span>{{ end }} {{ .Page.LinkTitle }} - </a> - </h3> - <p class="category-description">{{ .Page.Params.description | markdownify }}</p> - <ul class="category-articles"> - {{ range first 6 .Pages }} - <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li> - {{ end }} - </ul> - {{ if gt .Count 6 }} - <a class="category-link" - href="{{ .Page.RelPermalink }}" - >阅读所有 {{ .Count }} 篇文章</a> - {{ end }} - </div> - {{ end }} - {{ end }} - </section> - - <p class="uncategorized-link-container"> - <a class="uncategorized-link" href="/categories/uncategorized/">查看随笔</a> - </p> - {{ end }} </article> {{ partial "footer.html" . }} {{ end }} diff --git a/layouts/cards/section.html b/layouts/cards/section.html index 61e01516..1e7254e3 100644 --- a/layouts/cards/section.html +++ b/layouts/cards/section.html @@ -1,9 +1,17 @@ {{ define "main" }} <article class="card-list"> {{ partial "header.html" . }} - <div id="cards-section"> + <div class="cards-statistics markdown-body"> + <table> + <tr> + <td>卡片数量</td> + <td><span class="number-pill">{{ len .Pages }}</span></td> + </tr> + </table> + </div> + <div class="cards-section outbox small"> {{- $cards := .Site.GetPage "section" "cards" }} <!-- 获取 "cards" 部分的内容 --> - {{- $paginator := .Paginate $cards.Pages 8 }} <!-- 对该部分内容进行分页 --> + {{- $paginator := .Paginate $cards.Pages 10 }} <!-- 对该部分内容进行分页 --> {{- range $paginator.Pages }} <div class="card" style="view-transition-name: card-{{ .File.UniqueID }}"> diff --git a/layouts/categories/taxonomy.html b/layouts/categories/taxonomy.html new file mode 100644 index 00000000..5b6748d0 --- /dev/null +++ b/layouts/categories/taxonomy.html @@ -0,0 +1,67 @@ +{{ define "main" }} +<article class="taxonomy"> + {{ partial "header.html" . }} + {{ partial "components/postnav.html" . }} + + <!-- Display Categories --> + {{ partial "components/welcome.html" . }} + {{ $featured := slice "稻草人周刊" "年终总结" "揽物日志" "极客死亡计划书" }} + <h2>周期性刊物</h2> + <section class="taxonomy-categories"> + {{ range sort .Site.Taxonomies.categories ".Count" "desc" }} + {{ if in $featured .Page.Title }} + <div class="taxonomy-categories-item"> + <h3 class="category-title"> + <a href="{{ .Page.RelPermalink }}"> + {{ with .Page.Params.icon }}<span>{{ . }}</span>{{ end }} {{ .Page.LinkTitle }} + </a> + </h3> + <p class="category-description">{{ .Page.Params.description | markdownify }}</p> + <ul class="category-articles"> + {{ range first 6 .Pages }} + <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li> + {{ end }} + </ul> + {{ if gt .Count 6 }} + <a class="category-link" + href="{{ .Page.RelPermalink }}" + >阅读所有 {{ .Count }} 篇文章</a> + {{ end }} + </div> + {{ end }} + {{ end }} + </section> + + <!-- Render Other Categories --> + <h2>文章系列</h2> + <section class="taxonomy-categories"> + {{ range sort .Site.Taxonomies.categories ".Count" "desc" }} + {{ if not (in $featured .Page.Title) }} + <div class="taxonomy-categories-item"> + <h3 class="category-title"> + <a href="{{ .Page.RelPermalink }}"> + {{ with .Page.Params.icon }}<span>{{ . }}</span>{{ end }} {{ .Page.LinkTitle }} + </a> + </h3> + <p class="category-description">{{ .Page.Params.description | markdownify }}</p> + <ul class="category-articles"> + {{ range first 6 .Pages }} + <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li> + {{ end }} + </ul> + {{ if gt .Count 6 }} + <a class="category-link" + href="{{ .Page.RelPermalink }}" + >阅读所有 {{ .Count }} 篇文章</a> + {{ end }} + </div> + {{ end }} + {{ end }} + </section> + + <p class="uncategorized-link-container"> + <a class="uncategorized-link" href="/categories/uncategorized/">查看随笔</a> + </p> +</article> +{{ partial "footer.html" . }} +{{ end }} diff --git a/layouts/partials/components/global-search.html b/layouts/partials/components/global-search.html index 5b158abe..c6d76fa8 100644 --- a/layouts/partials/components/global-search.html +++ b/layouts/partials/components/global-search.html @@ -1,4 +1,5 @@ <div id="global-search"> + <div id="global-search-close">×</div> {{ partial "components/pagefind" . }} </div> <div id="global-search-overlay"></div> @@ -37,6 +38,14 @@ bottom: 0; align-items: center; justify-content: center; + #global-search-close { + position: absolute; + top: 0; + right: 0; + padding: 0 1rem; + font-size: 3rem; + cursor: pointer; + } } #global-search #pagefind { @@ -90,6 +99,7 @@ window.addEventListener("keydown", (event) => { if (event.key === 'k' && (event.metaKey || event.ctrlKey)) { + event.preventDefault(); // Open the popup window if (search.classList.contains("shown")) { turnOff() @@ -116,5 +126,8 @@ // double-click to turn off search // in case esc and ctrl/cmd+k cannot be used search.addEventListener("dblclick", turnOff); + + const closeButton = document.getElementById("global-search-close"); + closeButton.addEventListener("click", turnOff); })(); </script> diff --git a/layouts/_default/term.html b/layouts/term/term.html index 7cab2827..7d17833a 100644 --- a/layouts/_default/term.html +++ b/layouts/term/term.html @@ -24,7 +24,7 @@ </li> {{ end }} </ul> - <div class="term-list-cards"> + <div class="term-list-cards cards-section outbox small"> {{ range where .Pages "Section" "eq" "cards" }} <div class="card"> <h3> |
