1-狀態原型-從零開始寫一個武俠冒險遊戲
從零開始寫一個武俠冒險遊戲-1-狀態原型
概述
真正的從零開始, 一段程式碼一段程式碼, 一個函式一個函式地從頭開始構思/編寫一個武俠練功冒險遊戲.
- 環境要求: Codea + iPad
先寫一個人物狀態列原型
我們這個遊戲以人物的狀態變化為核心, 一切都從這個核心出發, 所以最先編寫的就是這個人物狀態原型.
最簡狀態類原型
首先定義一下角色的狀態列:體力,內力,精力,智力,氣,血,寫個狀態類把它們表現出來. 程式碼:
-- 角色狀態類
Status = class()
function Status:init()
-- 體力,內力,精力,智力,氣,血
self.tili = 100
self.neili = 0
self.jingli = 100
self.zhili = 100
self.qi = 100
self.xue = 100
-- 申請一個 200* 300 的圖片, 用來繪製狀態
self.img = image(200, 300)
end
為方便除錯,再寫一個繪製方法, 程式碼如下:
function Status:drawUI()
-- 把所有內容先繪製到 self.img 上
setContext(self.img)
background(119, 121, 72, 255)
fill(36, 112, 111, 255)
rect(5,5,200-10,300-10)
fill(70, 255, 0, 255)
textAlign(LEFT)
text("體力: "..self.tili,50,280)
text("內力: "..self.neili,50,260)
text("精力: "..self.jingli,50,240)
text("智力: "..self.zhili,50,220)
text("氣 : "..self.qi,50,200)
text("血 : "..self.xue,50,180)
setContext()
sprite(self.img, 200,300)
end
主程式
最後是一個主程式框架:
-- 主程式框架
function setup()
displayMode(OVERLAY)
myStatus = Status()
end
function draw()
background(32, 29, 29, 255)
myStatus:drawUI()
end
把上述程式碼合起來,就是一個基本的角色狀態了.
增加狀態更新方法
角色的狀態不可能凝固不變,因此,我們需要為角色狀態類增加一個用來更新值的方法,原型除錯階段,簡單實現最基本功能就可以了:
function Status:update()
-- 更新狀態:自我修煉,日常休息,戰鬥
self.neili = self.neili + 10
end
暫時用觸控動作來觸發這個方法,在螢幕右半部分點選一次就會呼叫一次,增加觸控事件:
function touched(touch)
-- 除錯用: 點選在螢幕右側, 會觸發 Status:update() , 重新整理 self.neili 的值
if touch.x > WIDTH/2 and touch.state == ENDED then myStatus:update() end
end
現在已經可以初步跑起來了, 點選會重新整理狀態值.
增加資料視覺化:雷達圖
基本雷達圖
我們為了更直觀地瞭解人物狀態的變化, 寫一個雷達圖繪製函式, 具體除錯過程就不贅述了, 總之是先寫最簡單的骨架結構, 再一步步填充豐滿, 程式碼如下:
-- 角色技能雷達圖
function Status:raderGraph()
setContext(self.img)
pushMatrix()
pushStyle()
fill(60, 230, 30, 255)
-- 中心座標,半徑,角度
local x0,y0,r,a,s = 150,230,40,360/6,4
-- 計算右上方斜線的座標
local x,y = r* math.cos(math.rad(30)), r* math.sin(math.rad(30))
p = {"體力","內力","精力","智力","氣","血"}
axis = {t={vec2(0,r/s),vec2(0,r*2/s),vec2(0,r*3/s),vec2(0,r)},
n={vec2(-x/s,y/s),vec2(-x*2/s,y*2/s),vec2(-x*3/s,y*3/s),vec2(-x,y)},
j={vec2(-x/s,-y/s),vec2(-x*2/s,-y*2/s),vec2(-x*3/s,-y*3/s),vec2(-x,-y)},
z={vec2(0,-r/s),vec2(0,-r*2/s),vec2(0,-r*3/s),vec2(0,-r)},
q={vec2(x/s,-y/s),vec2(x*2/s,-y*2/s),vec2(x*3/s,-y*3/s),vec2(x,-y)},
x={vec2(x/s,y/s),vec2(x*2/s,y*2/s),vec2(x*3/s,y*3/s),vec2(x,y)}}
-- 用於繪製圈線的函式
function lines(t,n,j,z,q,x)
line(axis.n[n].x, axis.n[n].y, axis.t[t].x, axis.t[t].y)
line(axis.n[n].x, axis.n[n].y, axis.j[j].x, axis.j[j].y)
line(axis.x[x].x, axis.x[x].y, axis.t[t].x, axis.t[t].y)
line(axis.z[z].x, axis.z[z].y, axis.j[j].x, axis.j[j].y)
line(axis.x[x].x, axis.x[x].y, axis.q[q].x, axis.q[q].y)
line(axis.z[z].x, axis.z[z].y, axis.q[q].x, axis.q[q].y)
end
-- 平移到中心 (x0,y0), 方便以此為中心旋轉
translate(x0,y0)
-- 圍繞中心點勻速旋轉
rotate(30+ElapsedTime*10)
-- 繪製背景圓環
fill(57, 121, 189, 84)
strokeWidth(0)
ellipse(0,0,2*r/s)
ellipse(0,0,4*r/s)
ellipse(0,0,6*r/s)
ellipse(0,0,r*2)
strokeWidth(2)
-- noSmooth()
stroke(93, 227, 22, 255)
fill(60, 230, 30, 255)
-- 繪製雷達圖
for i=1,6 do
text(p[i],0,45)
line(0,0,0,r)
rotate(a)
end
-- 繪製圈線
stroke(255, 0, 0, 102)
strokeWidth(2)
for i = 1,4 do
lines(i,i,i,i,i,i)
end
end
stroke(255, 32, 0, 255)
strokeWidth(2)
smooth()
-- 設定當前各引數的值
print(values())
local t,n,j,z,q,x = 3,2,3,2,4,1
local t,n,j,z,q,x = values()
lines(t,n,j,z,q,x)
popStyle()
popMatrix()
setContext()
end
增加動態重新整理
基本的雷達圖程式碼寫完了, 現在繪製出來的還是一個靜態的雷達圖, 我們希望能根據狀態值的重新整理而實時更新雷達圖, 那麼就是把這段程式碼修改一下, 因為這段程式碼只是把 3,2,3,2,4,1
這些固定值賦給這幾個區域性變數:
local t,n,j,z,q,x = 3,2,3,2,4,1
lines(t,n,j,z,q,x)
在函式 Status:raderGraph()
內部寫一個函式, 把這幾個區域性變數 t,n,j,z,q,x
跟狀態類的各個屬性 self.tili
等關聯起來, 也就是做一個賦值:
-- 處理人物狀態值, 根據它的值大小將其縮減為 1,2,3,4 並返回
function values()
local t,n,j,z,q,x = self.tili, self.neili, self.jingli,self.zhili, self.qi, self.xue
local f = math.floor
return f(t/25),f((25+math.fmod(n,100))/25),f(j/25),f(z/25),f(q/25),f(x/25)
end
把這條語句
local t,n,j,z,q,x = 3,2,3,2,4,1
換成下面這條:
local t,n,j,z,q,x = values()
很好, 現在我們的雷達圖就可以隨著狀態值的變化而變化了
增加實時旋轉
不過這種變化還是不太明顯, 我們再增加一個旋轉效果, 增加如下語句到相應位置:
-- 圍繞中心點勻速旋轉
rotate(30+ElapsedTime*10)
最終雷達圖
這樣就會產生一個實時旋轉的效果了, 全部程式碼如下:
-- 角色狀態類
Status = class()
function Status:init()
-- 體力,內力,精力,智力,氣,血
self.tili = 100
self.neili = 90
self.jingli = 70
self.zhili = 100
self.qi = 100
self.xue = 100
self.img = image(200, 300)
end
function Status:update()
-- 更新狀態:自我修煉,日常休息,戰鬥
self.neili = self.neili + 1
end
function Status:drawUI()
setContext(self.img)
background(119, 121, 72, 255)
pushStyle()
fill(36, 112, 111, 255)
rect(5,5,200-10,300-10)
fill(70, 255, 0, 255)
textAlign(RIGHT)
text("體力: "..self.tili,50,280)
text("內力: "..self.neili,50,260)
text("精力: "..self.jingli,50,240)
text("智力: "..self.zhili,50,220)
text("氣 : "..self.qi,50,200)
text("血 : "..self.xue,50,180)
sprite("Documents:B1", 100,90)
popStyle()
setContext()
self:raderGraph()
sprite(self.img, 400,300)
end
-- 角色技能雷達圖
function Status:raderGraph()
setContext(self.img)
pushMatrix()
pushStyle()
fill(60, 230, 30, 255)
-- 中心座標,半徑,角度
local x0,y0,r,a,s = 150,230,40,360/6,4
-- 計算右上方斜線的座標
local x,y = r* math.cos(math.rad(30)), r* math.sin(math.rad(30))
p = {"體力","內力","精力","智力","氣","血"}
axis = {t={vec2(0,r/s),vec2(0,r*2/s),vec2(0,r*3/s),vec2(0,r)},
n={vec2(-x/s,y/s),vec2(-x*2/s,y*2/s),vec2(-x*3/s,y*3/s),vec2(-x,y)},
j={vec2(-x/s,-y/s),vec2(-x*2/s,-y*2/s),vec2(-x*3/s,-y*3/s),vec2(-x,-y)},
z={vec2(0,-r/s),vec2(0,-r*2/s),vec2(0,-r*3/s),vec2(0,-r)},
q={vec2(x/s,-y/s),vec2(x*2/s,-y*2/s),vec2(x*3/s,-y*3/s),vec2(x,-y)},
x={vec2(x/s,y/s),vec2(x*2/s,y*2/s),vec2(x*3/s,y*3/s),vec2(x,y)}}
-- 用於繪製圈線的函式
function lines(t,n,j,z,q,x)
line(axis.n[n].x, axis.n[n].y, axis.t[t].x, axis.t[t].y)
line(axis.n[n].x, axis.n[n].y, axis.j[j].x, axis.j[j].y)
line(axis.x[x].x, axis.x[x].y, axis.t[t].x, axis.t[t].y)
line(axis.z[z].x, axis.z[z].y, axis.j[j].x, axis.j[j].y)
line(axis.x[x].x, axis.x[x].y, axis.q[q].x, axis.q[q].y)
line(axis.z[z].x, axis.z[z].y, axis.q[q].x, axis.q[q].y)
end
-- 平移到中心 (x0,y0), 方便以此為中心旋轉
translate(x0,y0)
-- 圍繞中心點勻速旋轉
rotate(30+ElapsedTime*10)
fill(57, 121, 189, 84)
strokeWidth(0)
ellipse(0,0,2*r/s)
ellipse(0,0,4*r/s)
ellipse(0,0,6*r/s)
ellipse(0,0,r*2)
strokeWidth(2)
-- noSmooth()
stroke(93, 227, 22, 255)
fill(60, 230, 30, 255)
-- 繪製雷達圖
for i=1,6 do
text(p[i],0,45)
line(0,0,0,r)
rotate(a)
end
-- 繪製圈線
stroke(255, 0, 0, 102)
strokeWidth(2)
for i = 1,4 do
lines(i,i,i,i,i,i)
end
function values()
local t,n,j,z,q,x = self.tili, self.neili, self.jingli,self.zhili, self.qi, self.xue
local f = math.floor
return f(t/25),f((25+math.fmod(n,100))/25),f(j/25),f(z/25),f(q/25),f(x/25)
end
stroke(255, 32, 0, 255)
strokeWidth(2)
smooth()
-- 設定當前各引數的值
print(values())
-- local t,n,j,z,q,x = 3,2,3,2,4,1
local t,n,j,z,q,x = values()
lines(t,n,j,z,q,x)
popStyle()
popMatrix()
setContext()
end
-- main 主程式框架
function setup()
displayMode(OVERLAY)
myStatus = Status()
end
function draw()
background(32, 29, 29, 255)
myStatus:drawUI()
-- myStatus:raderGraph()
fill(143, 255, 0, 255)
rect(WIDTH/2,HEIGHT/2,200,200)
fill(0, 55, 255, 255)
text("修煉", WIDTH/2+100, HEIGHT/2+100)
end
function touched(touch)
if touch.x > WIDTH/2 and touch.state == ENDED then myStatus:update() end
end
把雷達圖函式載入, 執行無誤, 接下來可以選擇的方向就多了--也意味著工作量和複雜度也大大增加了.
---本章結束
相關文章
- 2-幀動畫-從零開始寫一個武俠冒險遊戲動畫遊戲
- 5-使用協程-從零開始寫一個武俠冒險遊戲遊戲
- 3-地圖生成-從零開始寫一個武俠冒險遊戲地圖遊戲
- 6-用GPU提升效能(3)-從零開始寫一個武俠冒險遊戲GPU遊戲
- 6-用GPU提升效能(1)-從零開始寫一個武俠冒險遊戲GPU遊戲
- 6-用GPU提升效能(2)-從零開始寫一個武俠冒險遊戲GPU遊戲
- 4-第一次整合-從零開始寫一個武俠冒險遊戲遊戲
- 0-開發框架Codea簡介-從零開始寫一個武俠冒險遊戲框架遊戲
- 從零開始:用REACT寫一個格鬥遊戲(一)React遊戲
- 從零開始寫一個ExporterExport
- 從零開始:用REACT寫一個格鬥遊戲(二)React遊戲
- 從零開始仿寫一個抖音App——開始APP
- 從零開始寫一個網頁網頁
- 動作冒險遊戲俠盜獵車手遊戲
- 如何從零開始寫一個網站網站
- 從零開始寫一個node爬蟲(一)爬蟲
- 從零開始編寫一個babel外掛Babel
- 從零開始寫一個Javascript解析器JavaScript
- 冒險遊戲已逝?冒險遊戲萬歲!遊戲
- 從3A遊戲中看國產武俠遊戲
- 從零開始寫JavaScript框架(一)JavaScript框架
- 從零開始構建一個vue專案 --- webpack歷險記VueWeb
- 從零開始寫一個微前端框架-沙箱篇前端框架
- 從零開始手寫一個微前端框架-渲染篇前端框架
- 從零開始開發一個 WebpackWeb
- 從零開始實現放置遊戲(一)遊戲
- 武俠遊戲,江湖告急遊戲
- [Flutter]從零開始實現一個巢狀滑動的PageView(一)Flutter巢狀View
- 武俠遊戲演變史:從“俠客英雄傳”到“只狼”遊戲
- 從零開始,如何用puppeteer寫一個爬蟲指令碼爬蟲指令碼
- 從零開始,開發一個 Web Office 套件(8):狀態管理 & 拖動滑鼠選中文字Web套件
- 【從零開始擼一個App】PKCEAPP
- 從零開始做一個SLG遊戲(一):六邊形網格遊戲
- 從零開始做一個SLG遊戲(七):遊戲系統以及配置表遊戲
- 從零開始編寫自己的JavaScript框架(一)JavaScript框架
- [Flutter]從零開始實現一個巢狀滑動的PageView(三)Flutter巢狀View
- 從零開始寫JavaScript框架(二)JavaScript框架
- [AST實戰]從零開始寫一個wepy轉VUE的工具ASTVue