防止變成龍騎士的坐騎
我稍微發散一下
經常有吐槽說龍噴火不符合生物原理,消耗的能量大於捕獵獲得的獵物的能量
但是自然界有一種情況是會讓動物毫不在乎浪費能量的…那就是…求偶!
所以綜上所述龍噴火其實是爲了求偶!龍噴火的圖都相當於人類搔首弄姿引誘異性的澀圖!
如果是海龍或者陸地龍倒是可以理解
但是如果是東龍或者有翅膀的四足西方龍的話
現實裏卻恐高
會不會說出去很丟龍臉
@羽落 寫道: | 第一營養級| 植物、藻類 | 生產者 || 第二營養級| 草食動物(斑馬、兔子) | 初級消費者 || 第三營養級| 小型肉食動物(狐狸、蛇) | 次級消費者 || 第四營養級 | 中型肉食動物(狼、豹) | 三級消費者 || 第五營養級 | 頂級掠食者(虎、大白鯊、北極熊) | 四級消費者 |
這個營養級對應其實有問題,營養級並不正比於體型,頂級掠食者不等於營養級位置高。比如草原頂級掠食者主食是大型食草動物,營養級算三級。還要考慮一個物種可能喫多種獵物,屬於多個營養級。或許只有海里的大魚喫小魚相對確定一些。
背景:中世紀的實際生產力,無魔法,龍具備高智商與理性決策能力。
龍的優勢:
制空
高攻高防高機動性
優秀的野外生存能力
中世紀的無尾幾乎沒有有效的防空手段,這使得龍成爲獨立高效的戰略襲擾者。
無尾的優勢:
組織動員能力
穩定的資源生產
持續將資源轉化爲武器的能力
技術的發展與傳承
歷史上的無尾確實憑藉這些優勢在漫長的時間裏逐步主宰地球。但是,在面對龍的情況下,這些優勢會系統性失效。
農業國家的核心是耕地產出,即是食物來源也是稅基。農業的特徵單位面積產出高,但週期長,易被破壞。龍不需要直接進攻城市,只需要週期性的摧毀農田、糧倉、牲畜、水利設施,即可讓農田無法正常生產。還可以污染飲用水,直接削減無尾聚居地的生存資源。如此便可引發食物短缺,饑荒,人口流失。無尾無法在失去農田的情況下維持城市。更進一步可以打擊交通運輸、地方行政機構,造成稅收、行政、軍事失效,屆時地方將脫離中央掌控。如此,就會引發連鎖反應,饑荒、叛亂、地方割據、王權失效。
相當於遊戲剛開局就飛龍騎臉屠農,兵力和科技都發展不起來。
無尾幾乎無法組織反擊。國家的組織能力依賴穩定糧食供應,發達的交通網絡,行政與軍事的集中。而這些恰恰是龍的優先打擊目標。一旦國家嘗試集中資源(例如建設防禦工事,調集軍隊,後勤運輸),這種集中本身就成爲高價值目標。結果是越試圖組織反擊,越暴露於打擊之下。
有人提到無尾可以建造弩炮等足夠對龍造成傷害的遠程武器,但問題在於大型工程建造週期長,需要大規模的人力物力調動。而龍具備空中偵查能力,高機動性的打擊能力,可以自由選擇攻擊時間,攻擊低點,攻擊目標。這意味着主動權完全在龍的控制下。無尾的高殺傷力武器無法保證部署在正確的地點,無法確保龍進入射程,也很難在暴露後保全。
無尾的防禦成本也是無底洞。要想保證安全就必須長期維持高強度的防禦,儘可能廣泛的覆蓋核心生產區域,承擔持續的維護成本。而龍的進攻可以自由調整頻率,不可預測。無尾的資源越集中,龍的攻擊收益越高。
相當於遊戲中以高機動性的英雄單位拖住對方整支高維護費用的軍隊,拖垮對手。
在現實的中世紀框架下,一條理性、高機動、具備空中優勢的龍,本質上是一個無尾無法強制交戰、無法承受長期對抗成本、也無法系統性防禦的戰略級存在。
所以問題似乎是:中世紀的無尾究竟能不能在龍的持續戰略襲擾下維持國家存在。
最后修改: shiningdracon (2026-04-14 17:49:49)
龍族的邊境防禦部隊由志願加入的龍組成.
但是怎樣的報酬才足夠呢? 人類和龍族交界的大片不穩定地區作爲領地的獎勵嗎?
將灰色地帶收歸龍有,這樣倒也一定程度上解決了龍族內部數量增長產生的領地緊張問題
真的有龍會去幹這種風險極高的幹架工作嗎
[正在聽Art of Rally的Patience and Determination]
參考貪喫蛇遊戲


<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>東方龍貪吃蛇</title>
<style>
:root {
--bg1: #0f172a;
--bg2: #1e293b;
--panel: rgba(15, 23, 42, 0.82);
--gold: #fbbf24;
--gold2: #fde68a;
--jade: #34d399;
--danger: #fb7185;
--text: #e2e8f0;
--muted: #94a3b8;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-family: "Segoe UI", "Noto Sans TC", sans-serif;
color: var(--text);
background:
radial-gradient(circle at top, rgba(251, 191, 36, 0.18), transparent 28%),
radial-gradient(circle at bottom right, rgba(52, 211, 153, 0.14), transparent 26%),
linear-gradient(180deg, var(--bg2), var(--bg1));
padding: 20px;
}
.wrap {
width: min(92vw, 760px);
background: var(--panel);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 24px;
box-shadow: 0 24px 60px rgba(0,0,0,0.35);
backdrop-filter: blur(8px);
padding: 20px;
}
.topbar {
display: flex;
gap: 12px;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.title h1 {
margin: 0;
font-size: clamp(26px, 4vw, 36px);
color: var(--gold2);
letter-spacing: 1px;
}
.title p {
margin: 6px 0 0;
color: var(--muted);
font-size: 14px;
}
.stats {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.chip {
background: rgba(255,255,255,0.06);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 999px;
padding: 10px 14px;
font-weight: 700;
font-size: 14px;
}
.chip span {
color: var(--gold2);
margin-left: 6px;
}
.game-box {
position: relative;
display: grid;
place-items: center;
}
canvas {
width: min(92vw, 640px);
height: min(92vw, 640px);
max-width: 640px;
max-height: 640px;
aspect-ratio: 1 / 1;
background:
linear-gradient(180deg, rgba(15, 23, 42, 0.94), rgba(2, 6, 23, 0.96));
border-radius: 20px;
border: 2px solid rgba(251, 191, 36, 0.25);
box-shadow: inset 0 0 40px rgba(0, 0, 0, 0.35);
}
.overlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
}
.panel {
pointer-events: auto;
text-align: center;
width: min(84%, 420px);
padding: 24px 22px;
border-radius: 22px;
background: rgba(15, 23, 42, 0.9);
border: 1px solid rgba(255,255,255,0.08);
box-shadow: 0 16px 40px rgba(0,0,0,0.4);
}
.panel h2 {
margin: 0 0 10px;
color: var(--gold2);
font-size: 28px;
}
.panel p {
margin: 8px 0;
color: var(--text);
line-height: 1.6;
}
.actions {
display: flex;
gap: 12px;
justify-content: center;
flex-wrap: wrap;
margin-top: 16px;
}
button {
border: none;
border-radius: 999px;
padding: 12px 20px;
font-size: 15px;
font-weight: 800;
cursor: pointer;
color: #0f172a;
background: linear-gradient(135deg, var(--gold2), var(--gold));
box-shadow: 0 10px 24px rgba(251, 191, 36, 0.22);
transition: transform 0.15s ease, filter 0.15s ease;
}
button:hover {
transform: translateY(-1px);
filter: brightness(1.03);
}
.ghost {
background: rgba(255,255,255,0.08);
color: var(--text);
box-shadow: none;
border: 1px solid rgba(255,255,255,0.08);
}
.footer {
margin-top: 14px;
color: var(--muted);
font-size: 13px;
text-align: center;
line-height: 1.6;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="wrap">
<div class="topbar">
<div class="title">
<h1>東方龍貪吃蛇</h1>
<p>以方向鍵或 WASD 操控龍身,吃靈珠變長,別撞到自己或牆壁。</p>
</div>
<div class="stats">
<div class="chip">分數 <span id="score">0</span></div>
<div class="chip">最高分 <span id="best">0</span></div>
<div class="chip">速度 <span id="speed">1</span></div>
</div>
</div>
<div class="game-box">
<canvas id="game" width="640" height="640"></canvas>
<div class="overlay" id="startOverlay">
<div class="panel">
<h2>開始遊戲</h2>
<p>你將操控一條東方龍在夜空中穿梭,吞食靈珠成長。</p>
<p>操作:方向鍵 / WASD</p>
<div class="actions">
<button id="startBtn">開始</button>
</div>
</div>
</div>
<div class="overlay hidden" id="gameOverOverlay">
<div class="panel">
<h2>遊戲結束</h2>
<p>本次分數:<strong id="finalScore">0</strong></p>
<p id="finalMessage">龍撞上障礙了,再試一次。</p>
<div class="actions">
<button id="restartBtn">重新開始</button>
<button class="ghost" id="closeBtn">查看畫面</button>
</div>
</div>
</div>
</div>
<div class="footer">
小提醒:每吃 4 顆靈珠,速度會提升一級。<br />
直接把這個 HTML 存成檔案後,用瀏覽器打開即可遊玩。
</div>
</div>
<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('score');
const bestEl = document.getElementById('best');
const speedEl = document.getElementById('speed');
const startOverlay = document.getElementById('startOverlay');
const gameOverOverlay = document.getElementById('gameOverOverlay');
const finalScoreEl = document.getElementById('finalScore');
const finalMessageEl = document.getElementById('finalMessage');
const startBtn = document.getElementById('startBtn');
const restartBtn = document.getElementById('restartBtn');
const closeBtn = document.getElementById('closeBtn');
const gridCount = 20;
const cell = canvas.width / gridCount;
let dragon = [];
let direction = { x: 1, y: 0 };
let nextDirection = { x: 1, y: 0 };
let orb = { x: 10, y: 10 };
let score = 0;
let best = Number(localStorage.getItem('dragonSnakeBest') || 0);
let level = 1;
let gameOver = false;
let started = false;
let frameTimer = 0;
let stepMs = 160;
let lastTime = 0;
bestEl.textContent = best;
function resetGame() {
dragon = [
{ x: 5, y: 10 },
{ x: 4, y: 10 },
{ x: 3, y: 10 },
{ x: 2, y: 10 }
];
direction = { x: 1, y: 0 };
nextDirection = { x: 1, y: 0 };
score = 0;
level = 1;
stepMs = 160;
gameOver = false;
scoreEl.textContent = score;
speedEl.textContent = level;
spawnOrb();
draw();
}
function spawnOrb() {
let valid = false;
while (!valid) {
orb = {
x: Math.floor(Math.random() * gridCount),
y: Math.floor(Math.random() * gridCount)
};
valid = !dragon.some(part => part.x === orb.x && part.y === orb.y);
}
}
function startGame() {
resetGame();
started = true;
startOverlay.classList.add('hidden');
gameOverOverlay.classList.add('hidden');
lastTime = performance.now();
frameTimer = 0;
requestAnimationFrame(loop);
}
function endGame(reason) {
gameOver = true;
started = false;
if (score > best) {
best = score;
localStorage.setItem('dragonSnakeBest', String(best));
bestEl.textContent = best;
}
finalScoreEl.textContent = score;
finalMessageEl.textContent = reason;
gameOverOverlay.classList.remove('hidden');
}
function update() {
direction = nextDirection;
const head = { ...dragon[0] };
const newHead = {
x: head.x + direction.x,
y: head.y + direction.y
};
if (
newHead.x < 0 || newHead.x >= gridCount ||
newHead.y < 0 || newHead.y >= gridCount
) {
endGame('東方龍撞上邊界了。');
return;
}
if (dragon.some(part => part.x === newHead.x && part.y === newHead.y)) {
endGame('東方龍撞到自己的龍身了。');
return;
}
dragon.unshift(newHead);
if (newHead.x === orb.x && newHead.y === orb.y) {
score += 10;
scoreEl.textContent = score;
if ((score / 10) % 4 === 0) {
level += 1;
speedEl.textContent = level;
stepMs = Math.max(70, stepMs - 12);
}
spawnOrb();
} else {
dragon.pop();
}
}
function drawBackground() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const bg = ctx.createLinearGradient(0, 0, 0, canvas.height);
bg.addColorStop(0, '#0f172a');
bg.addColorStop(1, '#020617');
ctx.fillStyle = bg;
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (let y = 0; y < gridCount; y++) {
for (let x = 0; x < gridCount; x++) {
ctx.fillStyle = (x + y) % 2 === 0 ? 'rgba(255,255,255,0.025)' : 'rgba(255,255,255,0.012)';
ctx.fillRect(x * cell, y * cell, cell, cell);
}
}
for (let i = 0; i < 24; i++) {
const sx = (i * 97) % canvas.width;
const sy = (i * 53) % canvas.height;
ctx.fillStyle = 'rgba(255,255,255,0.18)';
ctx.beginPath();
ctx.arc(sx, sy, 1.4, 0, Math.PI * 2);
ctx.fill();
}
}
function drawOrb() {
const cx = orb.x * cell + cell / 2;
const cy = orb.y * cell + cell / 2;
const glow = ctx.createRadialGradient(cx, cy, 2, cx, cy, cell * 0.45);
glow.addColorStop(0, 'rgba(253, 224, 71, 0.95)');
glow.addColorStop(1, 'rgba(253, 224, 71, 0)');
ctx.fillStyle = glow;
ctx.beginPath();
ctx.arc(cx, cy, cell * 0.48, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#fde68a';
ctx.beginPath();
ctx.arc(cx, cy, cell * 0.22, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#fbbf24';
ctx.lineWidth = 2;
ctx.stroke();
}
function drawDragon() {
dragon.forEach((part, index) => {
const px = part.x * cell;
const py = part.y * cell;
const isHead = index === 0;
if (isHead) {
const headGrad = ctx.createLinearGradient(px, py, px + cell, py + cell);
headGrad.addColorStop(0, '#fde68a');
headGrad.addColorStop(1, '#f59e0b');
ctx.fillStyle = headGrad;
roundRect(px + 3, py + 3, cell - 6, cell - 6, 10, true, false);
ctx.fillStyle = '#7c2d12';
const eyeOffsetX = direction.x === -1 ? 9 : direction.x === 1 ? cell - 13 : 10;
const eye2OffsetX = direction.x === -1 ? 9 : direction.x === 1 ? cell - 13 : cell - 14;
const eyeY = direction.y === 1 ? cell - 13 : 11;
ctx.beginPath();
ctx.arc(px + eyeOffsetX, py + eyeY, 2.3, 0, Math.PI * 2);
ctx.arc(px + eye2OffsetX, py + eyeY, 2.3, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#ef4444';
ctx.lineWidth = 2;
ctx.beginPath();
if (direction.x === 1) {
ctx.moveTo(px + cell - 4, py + cell / 2);
ctx.lineTo(px + cell + 6, py + cell / 2 - 3);
ctx.lineTo(px + cell + 9, py + cell / 2);
ctx.lineTo(px + cell + 6, py + cell / 2 + 3);
} else if (direction.x === -1) {
ctx.moveTo(px + 4, py + cell / 2);
ctx.lineTo(px - 6, py + cell / 2 - 3);
ctx.lineTo(px - 9, py + cell / 2);
ctx.lineTo(px - 6, py + cell / 2 + 3);
} else if (direction.y === -1) {
ctx.moveTo(px + cell / 2, py + 4);
ctx.lineTo(px + cell / 2 - 3, py - 6);
ctx.lineTo(px + cell / 2, py - 9);
ctx.lineTo(px + cell / 2 + 3, py - 6);
} else {
ctx.moveTo(px + cell / 2, py + cell - 4);
ctx.lineTo(px + cell / 2 - 3, py + cell + 6);
ctx.lineTo(px + cell / 2, py + cell + 9);
ctx.lineTo(px + cell / 2 + 3, py + cell + 6);
}
ctx.stroke();
ctx.strokeStyle = '#fef3c7';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(px + 8, py + 7);
ctx.lineTo(px + 11, py + 2);
ctx.moveTo(px + cell - 8, py + 7);
ctx.lineTo(px + cell - 11, py + 2);
ctx.stroke();
} else {
const t = index / dragon.length;
const bodyGrad = ctx.createLinearGradient(px, py, px + cell, py + cell);
bodyGrad.addColorStop(0, `rgba(52, 211, 153, ${0.95 - t * 0.25})`);
bodyGrad.addColorStop(1, `rgba(16, 185, 129, ${0.9 - t * 0.25})`);
ctx.fillStyle = bodyGrad;
roundRect(px + 4, py + 4, cell - 8, cell - 8, 9, true, false);
ctx.strokeStyle = 'rgba(253, 230, 138, 0.55)';
ctx.lineWidth = 1.6;
ctx.beginPath();
ctx.arc(px + cell / 2, py + cell / 2, cell * 0.18, Math.PI * 0.2, Math.PI * 1.8);
ctx.stroke();
}
});
}
function roundRect(x, y, w, h, r, fill, stroke) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.arcTo(x + w, y, x + w, y + h, r);
ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.arcTo(x, y + h, x, y, r);
ctx.arcTo(x, y, x + w, y, r);
ctx.closePath();
if (fill) ctx.fill();
if (stroke) ctx.stroke();
}
function draw() {
drawBackground();
drawOrb();
drawDragon();
}
function loop(timestamp) {
if (!started) return;
const delta = timestamp - lastTime;
lastTime = timestamp;
frameTimer += delta;
while (frameTimer >= stepMs && !gameOver) {
update();
frameTimer -= stepMs;
}
draw();
if (!gameOver) {
requestAnimationFrame(loop);
}
}
function setDirection(x, y) {
if (!started && startOverlay.classList.contains('hidden') === false) return;
if (direction.x === -x && direction.y === -y) return;
nextDirection = { x, y };
}
document.addEventListener('keydown', (e) => {
const key = e.key.toLowerCase();
if (["arrowup", "arrowdown", "arrowleft", "arrowright", "w", "a", "s", "d", " "].includes(key)) {
e.preventDefault();
}
if (!started && (key === ' ' || key === 'enter')) {
startGame();
return;
}
if (key === 'arrowup' || key === 'w') setDirection(0, -1);
else if (key === 'arrowdown' || key === 's') setDirection(0, 1);
else if (key === 'arrowleft' || key === 'a') setDirection(-1, 0);
else if (key === 'arrowright' || key === 'd') setDirection(1, 0);
});
startBtn.addEventListener('click', startGame);
restartBtn.addEventListener('click', startGame);
closeBtn.addEventListener('click', () => gameOverOverlay.classList.add('hidden'));
resetGame();
</script>
</body>
</html>
2026.3.14
確定編程語言爲Python,使用個體建模(Agent-Based Modeling, ABM),語言爲Python,框架爲Mesa。
ABM 由Agent、環境、規則、交互拓撲四大核心模塊構成,即:
1. Agent(主體)
定義:系統的基本決策單元,可對應人、企業、動物、車輛、細胞、機器人等。
核心屬性:狀態(如健康 / 感染、有錢 / 沒錢)、特徵(年齡、偏好、位置)、資源、記憶。
行爲規則:感知→決策→行動的邏輯(如 “行人靠右走”“投資者追漲殺跌”“病毒接觸傳播”),通常是有限理性的啓發式規則,而非完美最優決策。
2. 環境(Environment)
爲 Agent 提供活動空間與約束(如地理空間、網絡拓撲、資源池、物理規則)。
可靜態(如固定網格)或動態(如資源消耗、環境變化)。
3. 交互規則(Interaction Rules)
Agent 之間、Agent 與環境的互動機制(如碰撞避免、信息傳遞、交易、感染、競爭 / 合作)。
決定系統演化的核心動力。
4. 交互拓撲(Topology)
Agent 的連接 / 鄰居關係(如網格、隨機網絡、小世界網絡、無標度網絡),影響信息 / 影響的傳播範圍與速度。
第一步我計劃從地圖(Environment)開始,採用網格形式,網格大小1km*1km,總地圖大小300*300,溫度帶採用固定的形式,第一版先不考慮季節變化、天氣變化和生物羣系演替(但是有恢復和破壞)。使用雙層噪聲邏輯,柏林噪聲(Perlin Noise)生成高度,並結合緯度溫度帶與溼度噪聲來確定生物羣系,生物羣系用Whittaker 生物羣系分類模型。藉助gemini的deep search我收集到以下淨初級生產力(NPP)表格(https://gemini.google.com/share/0bcb3465a31d):
| 生物羣系 | 平均NPP (g/m²/yr) | 全球總面積 (10⁶ km²) | 全球總產出 (10⁹ t/yr) | 關鍵限制養分 |
| :---- | :-------------- | :-------------- | :--------------- | :------- |
| 熱帶雨林 | 2200 | 17.0 | 37.4 | 磷、鈉 |
| 熱帶季節林 | 1600 | 7.5 | 12.0 | 水分季節性 |
| 溫帶落葉林 | 1200 | 7.0 | 8.4 | 氮 |
| 溫帶針葉林 | 1300 | 5.0 | 6.5 | 氮、熱量 |
| 溫帶草原 | 600 | 9.0 | 5.4 | 氮、水分 |
| 北方針葉林 | 800 | 12.0 | 9.6 | 氮、熱量 |
| 稀樹草原 | 900 | 15.0 | 13.5 | 氮、水分脈衝 |
| 地中海灌叢 | 700 | 8.5 | 6.0 | 水分夏季缺失 |
| 苔原 | 140 | 8.0 | 1.1 | 氮、熱量 |
| 荒漠 | 40 - 90 | 18.0 - 42.0 | 1.6 - 1.7 | 水分、氮 |
| 極地冰原 | ~0 (宏觀) | 38.0 | ~0 | 極度低溫、液態水 |
|水 | 不計入 |--------------- | ---------------- | -------- |
現代地球的頂掠通常位於第四或第五營養級,具體取決於生態系統的複雜程度。
常規營養級劃分:
| 營養級 | 典型生物 | 角色 |
| --------- | -------------------- | ----- |
| 第一營養級| 植物、藻類 | 生產者 |
| 第二營養級| 草食動物(斑馬、兔子) | 初級消費者 |
| 第三營養級| 小型肉食動物(狐狸、蛇) | 次級消費者 |
| 第四營養級 | 中型肉食動物(狼、豹) | 三級消費者 |
| 第五營養級 | 頂級掠食者(虎、大白鯊、北極熊) | 四級消費者 |
根據林德曼效率(10%法則),能量每傳遞一個營養級損失約90%。森林的 2200 NPP 並不等於 2200 的“食物”。很大一部分是不可食用的木材,引入可食用係數(Edibility Factor, EF)。
因此得到公式:
再根據
Barbour, Michael G所著的Terrestrial plant ecology:
About 10% of NPP is consumed by biophage herbivores for typical terrestrial
vegetation. The percentage varies with vegetation: 2-3% for desert scrub or arc¬
tic/alpine tundra, 4-7% for forest, 10-15% for temperate grasslands with minimal
grazing, and 30-60% for African grasslands or grasslands managed for domesti¬
cated animals. The percentage can also fluctuate from year to year. Episodic out¬
breaks of herbivores such as tent caterpillars, locusts, budworms, rabbits, voles,
lemmings, or pathogenic microbes may raise the consumption to 50-100% of NPP.
(對於典型的陸地植被,大約10%的淨初級生產力 (NPP) 被食草性生物消耗。這個百分比因植被類型而異:沙漠灌木或北極/高山苔原爲2-3%,森林爲4-7%,放牧最少的溫帶草原爲10-15%,非洲草原或爲家畜管理的草原爲30-60%。這一百分比也可能隨年份波動。像帳篷毛毛蟲、蝗蟲、芽蟲、兔子、田鼠、旅鼠或致病微生物等食草生物的偶發性爆發,可能將消耗率提高到NPP的50-100%。)
(https://z-library.sk/book/Yv34Qpp8Om/terrestrial-plant-ecology.html)
其中有用數據有:
一級營養級到二級營養級的傳遞總效率(含EF計算後的結果):
極地冰原/苔原/荒漠:2-3%
森林:4-7%
溫帶草原:10-15%
家畜放牧的草原:30-60%
可以由此倒推EF。
結合生物羣系複雜度可以得到以下表格:
| 生物羣系 | NPP | EF | 有效可食NPP | 營養級 | 傳遞係數 | **頂掠可得能量** |
| --------- | ------- | ---- | ------- | --------- | ------ | ---------- |
| **熱帶雨林** | 2200 | 0.20 | 440 | 第五級 | 0.0002 | **0.088** |
| **熱帶季節林** | 1600 | 0.25 | 400 | 第五級 | 0.0002 | **0.080** |
| **溫帶落葉林** | 1200 | 0.30 | 360 | 第四級 | 0.002 | **0.720** |
| **溫帶針葉林** | 1300 | 0.18 | 234 | 第四級 | 0.002 | **0.468** |
| **稀樹草原** | 900 | 0.60 | 540 | 第四級 | 0.0015 | **0.81** |
| **溫帶草原** | 600 | 0.80 | 480 | 第四級 | 0.0015 | **0.72** |
| **北方針葉林** | 800 | 0.12 | 96 | 第四級 | 0.001 | **0.096** |
| **地中海灌叢** | 700 | 0.22 | 154 | 第四級 | 0.001 | **0.154** |
| **苔原** | 140 | 0.25 | 70 | 第三級 | 0.01 | **0.35** |
| **荒漠** | 65 | 0.25 | 26 | 第三級 | 0.01 | **0.163** |
| **極地冰原** | ~0 | ~0 | ~0 | — | — | **~0** |
| **水** | ~0 | ~0 | ~0 | — | — | **~0** |
但是實際現象是雨林中頂掠領地大小比草原的小十倍左右,另外具有飛行能力的龍在草原上的捕食效率可能遠大於雨林中的,因此以上模型還不完善,同時雨林的營養級和EF也還有討論餘地,待後續完善......
最近討論問題時突然興趣所至打算做個模擬程序模擬龍的種族擴散,由於隨時可能熱度消失,特建此樓記錄,以便日後重拾或其他感興趣的龍參考。
生肖的組成很明顯是陸地上的六畜和常見害獸組成,所以辰位最初應該是與其它十一個生肖不同種類的害獸,我認為是熊。首先,熊是危害更甚於虎的害獸,也是《周禮》中的六獸之一;其次,楚系簡帛的熊字和秦漢的龍字是相似的;到魏晉南北朝時期,龍、熊的發音相近,加上局勢動盪,很有可能在這個時期熊訛變為龍,至此以訛傳訛,流傳至今。
依舊做夢夢到了很好笑的劇情…… 畫成漫畫分享一下。

有 8 位朋友喜欢这篇文章:安德Endur~, 龙游踏尘, 镜中龙影, NancalaStarry, 闪耀, 箐岚, shiningdracon, 龍爪翻書
不妨追問
相比這一點,我比較好奇爲什麼人(尤其是男性)會喜歡使用黃色玩笑
但是介於和本樓的主題不太相關,我建議不用直接在這裏討論(換個地方)
這樓用來發一些AI寫的小遊戲~
仿懷舊太空射擊遊戲

<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Dragon Space Shooter</title>
<style>
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: radial-gradient(circle at top, #1a2342 0%, #090d18 55%, #03050a 100%);
color: #f3f4f6;
font-family: Arial, "Noto Sans TC", sans-serif;
}
.wrap {
text-align: center;
padding: 16px;
}
h1 {
margin: 0 0 10px;
font-size: 28px;
letter-spacing: 1px;
}
.hint {
margin: 0 0 12px;
color: #cbd5e1;
font-size: 14px;
}
canvas {
display: block;
margin: 0 auto;
border: 3px solid #7dd3fc;
border-radius: 12px;
background: linear-gradient(to bottom, #07111f, #08101a 45%, #03060d);
box-shadow: 0 0 24px rgba(125, 211, 252, 0.25);
image-rendering: pixelated;
}
.controls {
margin-top: 14px;
display: flex;
justify-content: center;
gap: 12px;
flex-wrap: wrap;
}
button {
border: none;
background: #f97316;
color: white;
padding: 10px 18px;
border-radius: 999px;
font-size: 15px;
cursor: pointer;
font-weight: bold;
box-shadow: 0 6px 14px rgba(249, 115, 22, 0.3);
}
button:hover { filter: brightness(1.08); }
.note {
margin-top: 10px;
font-size: 13px;
color: #94a3b8;
}
</style>
</head>
<body>
<div class="wrap">
<h1>🐉 Dragon Space Shooter</h1>
<p class="hint">操作:← → 移動,空白鍵發射火球</p>
<canvas id="game" width="480" height="640"></canvas>
<div class="controls">
<button id="restartBtn">重新開始</button>
</div>
<div class="note">復古 2D 太空射擊風格,單一 HTML 即可運行</div>
</div>
<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const restartBtn = document.getElementById('restartBtn');
const WIDTH = canvas.width;
const HEIGHT = canvas.height;
const keys = {
ArrowLeft: false,
ArrowRight: false,
Space: false,
};
let stars = [];
let player;
let bullets;
let enemies;
let score;
let gameOver;
let enemySpawnTimer;
let enemySpawnInterval;
let fireCooldown;
let animationId;
function resetGame() {
player = {
x: WIDTH / 2 - 20,
y: HEIGHT - 90,
width: 40,
height: 48,
speed: 5.5,
};
bullets = [];
enemies = [];
score = 0;
gameOver = false;
enemySpawnTimer = 0;
enemySpawnInterval = 42;
fireCooldown = 0;
stars = Array.from({ length: 70 }, () => ({
x: Math.random() * WIDTH,
y: Math.random() * HEIGHT,
size: Math.random() * 2 + 1,
speed: Math.random() * 1.4 + 0.6,
}));
}
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
function rectsOverlap(a, b) {
return (
a.x < b.x + b.width &&
a.x + a.width > b.x &&
a.y < b.y + b.height &&
a.y + a.height > b.y
);
}
function spawnEnemy() {
const size = 26 + Math.random() * 18;
enemies.push({
x: Math.random() * (WIDTH - size),
y: -size,
width: size,
height: size,
speed: 1.6 + Math.random() * 2.3 + Math.min(score * 0.02, 2.2),
wobble: Math.random() * Math.PI * 2,
wobbleSpeed: 0.03 + Math.random() * 0.04,
});
}
function shoot() {
bullets.push({
x: player.x + player.width / 2 - 4,
y: player.y + 8,
width: 8,
height: 18,
speed: 8.5,
});
}
function update() {
updateStars();
if (gameOver) return;
if (keys.ArrowLeft) player.x -= player.speed;
if (keys.ArrowRight) player.x += player.speed;
player.x = clamp(player.x, 0, WIDTH - player.width);
if (fireCooldown > 0) fireCooldown--;
if (keys.Space && fireCooldown <= 0) {
shoot();
fireCooldown = 10;
}
bullets.forEach((bullet) => {
bullet.y -= bullet.speed;
});
bullets = bullets.filter((bullet) => bullet.y + bullet.height > 0);
enemySpawnTimer++;
if (enemySpawnTimer >= enemySpawnInterval) {
spawnEnemy();
enemySpawnTimer = 0;
enemySpawnInterval = Math.max(18, 42 - Math.floor(score / 5));
}
enemies.forEach((enemy) => {
enemy.y += enemy.speed;
enemy.wobble += enemy.wobbleSpeed;
enemy.x += Math.sin(enemy.wobble) * 1.2;
enemy.x = clamp(enemy.x, 0, WIDTH - enemy.width);
});
for (let i = enemies.length - 1; i >= 0; i--) {
const enemy = enemies[i];
if (rectsOverlap(player, enemy)) {
gameOver = true;
break;
}
let destroyed = false;
for (let j = bullets.length - 1; j >= 0; j--) {
if (rectsOverlap(bullets[j], enemy)) {
bullets.splice(j, 1);
enemies.splice(i, 1);
score += 10;
destroyed = true;
break;
}
}
if (destroyed) continue;
}
enemies = enemies.filter((enemy) => enemy.y < HEIGHT + enemy.height);
}
function updateStars() {
for (const star of stars) {
star.y += star.speed;
if (star.y > HEIGHT) {
star.y = -star.size;
star.x = Math.random() * WIDTH;
star.size = Math.random() * 2 + 1;
star.speed = Math.random() * 1.4 + 0.6;
}
}
}
function drawBackground() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (const star of stars) {
ctx.fillStyle = '#ffffff';
ctx.fillRect(star.x, star.y, star.size, star.size);
}
}
function drawPlayer(p) {
const x = p.x;
const y = p.y;
// wings
ctx.fillStyle = '#7c3aed';
ctx.beginPath();
ctx.moveTo(x + 8, y + 22);
ctx.lineTo(x - 4, y + 40);
ctx.lineTo(x + 10, y + 36);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(x + p.width - 8, y + 22);
ctx.lineTo(x + p.width + 4, y + 40);
ctx.lineTo(x + p.width - 10, y + 36);
ctx.closePath();
ctx.fill();
// body
ctx.fillStyle = '#22c55e';
ctx.beginPath();
ctx.moveTo(x + p.width / 2, y);
ctx.lineTo(x + p.width - 2, y + 18);
ctx.lineTo(x + p.width - 7, y + 42);
ctx.lineTo(x + p.width / 2, y + p.height);
ctx.lineTo(x + 7, y + 42);
ctx.lineTo(x + 2, y + 18);
ctx.closePath();
ctx.fill();
// belly
ctx.fillStyle = '#fde68a';
ctx.beginPath();
ctx.moveTo(x + p.width / 2, y + 10);
ctx.lineTo(x + p.width - 11, y + 28);
ctx.lineTo(x + p.width / 2, y + p.height - 6);
ctx.lineTo(x + 11, y + 28);
ctx.closePath();
ctx.fill();
// horns
ctx.fillStyle = '#f59e0b';
ctx.fillRect(x + 10, y + 6, 4, 8);
ctx.fillRect(x + p.width - 14, y + 6, 4, 8);
// eyes
ctx.fillStyle = '#111827';
ctx.fillRect(x + 14, y + 18, 4, 4);
ctx.fillRect(x + p.width - 18, y + 18, 4, 4);
// fire tail glow
ctx.fillStyle = '#fb923c';
ctx.beginPath();
ctx.moveTo(x + p.width / 2, y + p.height);
ctx.lineTo(x + p.width / 2 - 6, y + p.height + 14);
ctx.lineTo(x + p.width / 2 + 6, y + p.height + 14);
ctx.closePath();
ctx.fill();
}
function drawBullets() {
bullets.forEach((bullet) => {
ctx.fillStyle = '#f97316';
ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
ctx.fillStyle = '#fde68a';
ctx.fillRect(bullet.x + 2, bullet.y - 4, bullet.width - 4, 6);
});
}
function drawEnemy(enemy) {
const x = enemy.x;
const y = enemy.y;
const w = enemy.width;
const h = enemy.height;
ctx.fillStyle = '#ef4444';
ctx.beginPath();
ctx.moveTo(x + w / 2, y);
ctx.lineTo(x + w, y + h * 0.4);
ctx.lineTo(x + w * 0.8, y + h);
ctx.lineTo(x + w * 0.2, y + h);
ctx.lineTo(x, y + h * 0.4);
ctx.closePath();
ctx.fill();
ctx.fillStyle = '#fecaca';
ctx.fillRect(x + w * 0.28, y + h * 0.34, w * 0.14, h * 0.14);
ctx.fillRect(x + w * 0.58, y + h * 0.34, w * 0.14, h * 0.14);
ctx.fillStyle = '#7f1d1d';
ctx.fillRect(x + w * 0.42, y + h * 0.54, w * 0.16, h * 0.12);
}
function drawHUD() {
ctx.fillStyle = 'rgba(15, 23, 42, 0.7)';
ctx.fillRect(12, 12, 130, 42);
ctx.strokeStyle = '#7dd3fc';
ctx.strokeRect(12, 12, 130, 42);
ctx.fillStyle = '#e2e8f0';
ctx.font = 'bold 22px Arial';
ctx.fillText('Score: ' + score, 24, 40);
}
function drawGameOver() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
ctx.fillRect(0, 0, WIDTH, HEIGHT);
ctx.fillStyle = '#fff';
ctx.textAlign = 'center';
ctx.font = 'bold 42px Arial';
ctx.fillText('GAME OVER', WIDTH / 2, HEIGHT / 2 - 24);
ctx.font = '24px Arial';
ctx.fillText('最終分數:' + score, WIDTH / 2, HEIGHT / 2 + 18);
ctx.font = '18px Arial';
ctx.fillText('按下「重新開始」再玩一次', WIDTH / 2, HEIGHT / 2 + 58);
ctx.textAlign = 'start';
}
function draw() {
drawBackground();
drawHUD();
drawBullets();
enemies.forEach(drawEnemy);
drawPlayer(player);
if (gameOver) {
drawGameOver();
}
}
function gameLoop() {
update();
draw();
animationId = requestAnimationFrame(gameLoop);
}
window.addEventListener('keydown', (e) => {
if (e.code === 'ArrowLeft' || e.code === 'ArrowRight' || e.code === 'Space') {
e.preventDefault();
}
if (e.code in keys) {
keys[e.code] = true;
}
});
window.addEventListener('keyup', (e) => {
if (e.code in keys) {
keys[e.code] = false;
}
});
restartBtn.addEventListener('click', () => {
resetGame();
});
resetGame();
cancelAnimationFrame(animationId);
gameLoop();
</script>
</body>
</html>
有 2 位朋友喜欢这篇文章:shiningdracon, 闪耀
無論是在遊戲還是各類文娛作品中,人與西方龍的史詩鬥爭已經成了難以避免的經典橋段,極具濃烈的象徵意味.但我想,人並不能單純爲了斬殺而戰鬥.
我想寫這一切的一切的前傳,想搞清楚龍這個種族的特殊性到底從何而來;即便只能做到片面的.
基於我當下的能力,以及市場對魔幻題材作品的需求的見解,我認爲一種可行的方式是,僅構建人與龍兩個種族之間的故事.只寫兩個種族,能降低寫作的難度,讓讀者更着重於關注這兩族的關係.
要想讓兩界都滿意依然是很有挑戰性的,但如果能寫好將很有意義.
目前是想以小故事的方式呈現,從創世開始,終點是近未來.
[正在聽電臺司令的Codex]
Furry目前的通俗意思是“擬人化動物及喜歡他們的羣體”。而擬人化anthropomorphism
的定義很簡單,把人類的情感及特徵賦予非人事物。
相信你已經有了答案
最后修改: 蓝羽龙 (2026-05-04 11:32:07)
如題
可以收集碎片時間,記錄靈感。樓層內容之間不一定相關。
最后修改: Sherixs (2026-03-06 21:18:29)
[↑] @shiningdracon 寫道: 另外可以參看:一些涉及Otherkin的社會研究 …
還有學術期刊,文化龍就是不一樣
毫無疑問,選2.
龍和福瑞這兩個概念,到底誰先誕生的
當然是龍先誕生了 只是龍也可以由福瑞的畫風呈現
搞清楚輩分
最后修改: Sherixs (2026-03-05 18:40:44)
補充一些原文翻譯
在我們 2011年至2022年間進行的25項研究中,我們發現:
4.4%—16.5% 的獸迷認同自己是 therian
3.6%—13.9% 的獸迷認同自己是 otherkin這意味着,從定義上來說,大多數獸迷並不是 therian。
同樣,也很有可能 許多 therian(如果不是大多數)並不會認爲自己是獸迷。畢竟,這兩個羣體圍繞着不同的核心概念而組織:
獸迷(furries):喜歡擬人化動物角色的粉絲
therian:在全部或部分意義上認同自己爲非人類存在的人爲了說明這一點,我們的調查數據還顯示:
65% 的 therian 表示他們經常或幾乎總是認同自己爲某種非人類物種
而在獸迷中只有 11% 有這種情況同時:
86% 的 therian 表示自己感覺“不到100%的人類”
在獸迷中這一比例只有 30%在另一項針對 therian 的開放式研究中(Gerbasi 等,2017),我們請參加大會的參與者用自己的話描述以下術語的含義:
furry
therian
otherkin我們分析了大約 500條描述,統計每種描述中某些詞語出現的頻率。
在描述 furries 時,最常見的詞包括:
anthro(擬人)—93次
fan / fandom(粉絲 / 粉絲文化)—57次
enjoy(享受)—56次
community(社羣)—36次
cartoon(卡通)—33次
art / artistic(藝術)—26次這些詞語加起來佔描述 furries 所使用全部詞彙的 6%。
相比之下,在描述 therian 或 otherkin 時,上述詞語幾乎完全沒有出現,
唯一的例外是 “community(社羣)” 僅出現了一次。相反:
“spirit(靈魂/精神)”
在 therian 描述中出現 47次
在 otherkin 描述中出現 18次“soul(靈魂)”
在 therian 描述中出現 9次
在 otherkin 描述中出現 4次“trapped(被困住)”
在 therian 與 otherkin 描述中各出現 7次“belief / believing(信念 / 相信)”
在 therian 描述中出現 9次
在 otherkin 描述中出現 22次簡而言之:
furries 與 therians 在概念上確實存在重疊,因爲兩個羣體都對非人類動物感興趣。但這種興趣的性質以及其表現形式可能完全不同。通常來說:
therianthropy / otherkin 身份常常與 靈性、“被困在錯誤身體裏”的感覺 相關聯而:
furry 身份更常與 娛樂、藝術、粉絲文化、社羣 相關。因此:
雖然一些 therian 可能同時也是獸迷,一些獸迷也可能是 therian,但:
大多數獸迷並不是 therian,而且很可能大多數 therian 也不是獸迷。
在我們 2011年至2022年間進行的25項研究中,我們發現:
4.4%—16.5% 的獸迷認同自己是 therian
3.6%—13.9% 的獸迷認同自己是 otherkin這意味着,從定義上來說,大多數獸迷並不是 therian。
同樣,也很有可能 許多 therian(如果不是大多數)並不會認爲自己是獸迷。畢竟,這兩個羣體圍繞着不同的核心概念而組織:
獸迷(furries):喜歡擬人化動物角色的粉絲
therian:在全部或部分意義上認同自己爲非人類存在的人爲了說明這一點,我們的調查數據還顯示:
65% 的 therian 表示他們經常或幾乎總是認同自己爲某種非人類物種
而在獸迷中只有 11% 有這種情況同時:
86% 的 therian 表示自己感覺“不到100%的人類”
在獸迷中這一比例只有 30%在另一項針對 therian 的開放式研究中(Gerbasi 等,2017),我們請參加大會的參與者用自己的話描述以下術語的含義:
furry
therian
otherkin我們分析了大約 500條描述,統計每種描述中某些詞語出現的頻率。
在描述 furries 時,最常見的詞包括:
anthro(擬人)—93次
fan / fandom(粉絲 / 粉絲文化)—57次
enjoy(享受)—56次
community(社羣)—36次
cartoon(卡通)—33次
art / artistic(藝術)—26次這些詞語加起來佔描述 furries 所使用全部詞彙的 6%。
相比之下,在描述 therian 或 otherkin 時,上述詞語幾乎完全沒有出現,
唯一的例外是 “community(社羣)” 僅出現了一次。相反:
“spirit(靈魂/精神)”
在 therian 描述中出現 47次
在 otherkin 描述中出現 18次“soul(靈魂)”
在 therian 描述中出現 9次
在 otherkin 描述中出現 4次“trapped(被困住)”
在 therian 與 otherkin 描述中各出現 7次“belief / believing(信念 / 相信)”
在 therian 描述中出現 9次
在 otherkin 描述中出現 22次簡而言之:
furries 與 therians 在概念上確實存在重疊,因爲兩個羣體都對非人類動物感興趣。但這種興趣的性質以及其表現形式可能完全不同。通常來說:
therianthropy / otherkin 身份常常與 靈性、“被困在錯誤身體裏”的感覺 相關聯而:
furry 身份更常與 娛樂、藝術、粉絲文化、社羣 相關。因此:
雖然一些 therian 可能同時也是獸迷,一些獸迷也可能是 therian,但:
大多數獸迷並不是 therian,而且很可能大多數 therian 也不是獸迷。
另外可以參看:一些涉及Otherkin的社會研究
有 1 位朋友喜欢这篇文章:龍爪翻書
壞了,計算飛行升力時好像算少了一個零,按正確的計算就算速度達到50m/s都不太飛得起來......