[Love2d]钓鱼小游戏开发日志0.10
起点
昆特牌之于巫师而言已从内置的 “小玩法” 脱胎成为独立的 “游戏” ,这一过程和原因网上有诸多分析,相信无需赘述。由此出发,发掘更多有潜力的 “小玩法” 加以改造的路子也不鲜见。
这其中我想到了 “钓鱼” ,玩过的游戏里,印象深的有武林群侠传、FATE黑暗史诗、火炬之光、minecraft、古剑奇谭等等,往往能令人沉迷于中不能自拔,于是有了尝试开发钓鱼游戏的想法。
思路
设计方面:
- 玩法。接触过的钓鱼玩法大体分三类:
a.拟真钓鱼,从搓饵打窝调漂到挥杆溜鱼入获,极力还原真实。
b.白盒钓鱼,即鱼作为实体可见,偏操作向
c.黑盒钓鱼,不定时上钩的鱼和随机的收获
本次选择做c,包括上面举的例子也都是此类的钓鱼玩法 - 体验。首先需要注意的是,例子游戏中的钓鱼之所以好玩,很大程度是因为其承担的产出足够有吸引力,而这种吸引力是游戏内其他系统和玩法带来的,因此我们需要提供足够的目标和吸引力,否则没有玩家愿意去钓没有价值的东西。具体内容下个版本总结。
- 表现。基于想提供的体验,仅使用简单2d画面和帧动画,结合特效,即可满足我们的要求。
开发方面:
短而快的开发需求,同时希望能够学多一点技能,因此选择了曾经接触又放弃的love2d引擎,希望能够在学习和使用的过程中增加对于lua、对于脚本语言、对于底层渲染逻辑的理解。
开发过程有以下总结:
- 对于项目结构的理解需要加强。虽说是做简单的小项目,使用严谨的所谓 “开发模式” 似乎反而降低效率(一开始就是这么想的),但是看着初版这个孤零零的main.lua文件和里面乱糟糟的function,还是觉得有点汗颜。
- 状态机和动画,尝试造一些简陋的轮子,勉强能用,但还是不够高效,而且非常不利于维护,对象化的思维差了很多。
- 资源,这块是比较顺的地方,opengameart和craftpix的免费资源都很棒,对于图集atlas的理解也更深了一些。
- 分发,因为想便于分享查看尝试web平台发布,官方对于web发布缺少支持,在民间支持里找到了这个并上传到网站内,可以点这里试玩,但是加载很慢,看了下源码这个工具是把love2d项目的lua代码逐字符转义,不确定是否此原因导致,但是写这篇日志时找到了另一个民间工具:https://github.com/ghoulsblade/love-webplayer,有待试用。
- 已知问题:想简单用加速度定期换正负号的方式做循环动画,但是方式不太对(用速度判断没用位置判断),下回修改
代码
local charaAnim
local counTime=0
local catchtime=0
function testBatch(fileName,w,h,texW,texH,col,row)
tex=love.graphics.newImage(fileName)
quad={}
for i=1,row do
for j=1,col do
table.insert (quad,love.graphics.newQuad((j-1)*w,(i-1)*h,w,h,texW,texH))
end
end
--创建512个需要绘制的图片
mySprite = love.graphics.newSpriteBatch(tex,3)
end
function drawBatch(x,y)
for i=1,6 do
for j=1,3 do
--84,108为图块的宽和高,864为图片的高
mySprite:add(quad[j],math.ceil(j%8-1)*64+(i-1)*64,math.ceil(j/8-1)*64,0,2,2,0,0,0,0)
end
end
love.graphics.draw(mySprite,x,y)
end
function love.load()
tempa =-2
tempv =0
state="idle"
boat=love.graphics.newImage("Boat.png")
cloud1=love.graphics.newImage("1.png")
cloud2=love.graphics.newImage("2.png")
cloud3=love.graphics.newImage("3.png")
cloud4=love.graphics.newImage("4.png")
print(a)
cloudx=0
cloudx1=-50
cloudx2=-15
animetion = anime('Fisherman_idle.png',1,4,0.2,48) --初始化一个动画
animetion1 = anime('Fisherman_fish.png',1,4,0.2,48) --初始化一个动画
animetionBubble = anime('fishing_bobbles.png',2,2,0.25,24)
animetionFish = anime('fish_catch.png',2,2,0.25,24)
animetionCatch = anime('Fisherman_hook.png',1,6,0.1,48)
displayW,displayH = love.window.getMode() --获得窗口尺寸
testBatch('Water.png',32,32,96,96,3,1)
end
function love.mousepressed(x, y, button, istouch)
if button == 1 and state=="idle" then -- Versions prior to 0.10.0 use the MouseConstant 'l'
state="fishing"
elseif button == 1 and (state=="fishing" or state=="bubble" )then
state="idle"
elseif button == 1 and state=="fish" then
state="catch"
end
end
function fishingAnimManager()
if state=="fishing" then --点击鼠标左键开始动画
charaAnim=animetion1
animetionBubble.stop()
elseif state=="idle" then--不点击时恢复最初状态
charaAnim=animetion
animetionBubble.stop()
elseif state=="fish" then--不点击时恢复最初状态
charaAnim=animetion1
animetionFish.start()
animetionBubble.stop()
elseif state=="bubble" then--不点击时恢复最初状态
charaAnim=animetion1
animetionBubble.start()
animetionFish.stop()
elseif state=="catch" then--不点击时恢复最初状态
charaAnim=animetionCatch
animetionBubble.stop()
animetionFish.stop()
end
charaAnim.start()
charaAnim.update()
animetionBubble.update()
animetionFish.update()
end
function love.update(dt)
if state=="fishing" or state=="fish" or state=="bubble" then
if counTime==0 then
counTime=1+love.timer.getTime()
end
if love.timer.getTime()>=counTime then
local rnd =math.random(1,7)
if rnd>=1 and rnd<4 then
state="bubble"
animetionBubble.reset()
counTime=love.timer.getTime()+1
elseif rnd>=4 and rnd<7 then
state="fishing"
counTime=love.timer.getTime()+1
elseif rnd>=7 then
state="fish"
animetionFish.reset()
counTime=love.timer.getTime()+1
end
end
end
if state=="catch" then
if catchtime==0 then
catchtime=0.6+love.timer.getTime()
end
if love.timer.getTime()>=catchtime then
state="idle"
catchtime=0
counTime=0
end
end
fishingAnimManager()
if math.abs(tempv)>10 then
tempa = -tempa
end
tempv = tempv + dt * tempa
cloudx = cloudx + dt * tempv/2
cloudx1 = cloudx1 - dt * tempv
cloudx2 = cloudx2 + dt * tempv
end
function love.draw()
love.graphics.draw(cloud1,0,0,0,1,0.8)
love.graphics.draw(cloud2,cloudx,0,0,1,0.8)
love.graphics.draw(cloud3,cloudx1,0,0,1,0.8)
love.graphics.draw(cloud4,cloudx2,0,0,1,0.8)
drawBatch(cloudx/2-1,192)
charaAnim.draw(120,100)
love.graphics.draw(boat,190,168,0,-2,2)
if state=="bubble" then
animetionBubble.draw(185,175)
end
if state=="fish" then
animetionFish.draw(185,175)
end
end
function anime(aniName,aniRow,aniCol,aniGap,aniSize)
local image = love.graphics.newImage(aniName)
local imageW,imageH = image:getDimensions()
local imageList = {}
local timeList = {} --播放间隔时间
for i=1,aniRow do
for j=1,aniCol do
imageList[i+j-1] = love.graphics.newQuad((j-1)*aniSize-1,(i-1)*aniSize-1,aniSize,aniSize,imageW,imageH)
timeList[i+j-1] = aniGap
end
end
local play = false --播放标记(是否在播放)
local now = 1 --当前帧
local nowTime --当前时间
if #imageList ~= #timeList then
error("image num ~= time num") --提示你图片数量和时间间隔数量是不一致的
end
local function reset()
now = 1
nowTime = love.timer.getTime() + timeList[now] --获取当前时间
end
return {
start = function() --开始播放
if not play then --如果已经开始播放,再次调用时将不再有效
play = true
reset()
end
end,
stop = function() --停止播放
play = false
end,
reset = function() --重置播放
reset()
end,
update = function() --更新播放
--仅当
if play and love.timer.getTime() >= nowTime then
now = now + 1
if now > #imageList then
reset() --重置
else
nowTime = love.timer.getTime() + timeList[now] --获取下一帧的时间
end
end
end,
draw = function(x,y) --绘制
love.graphics.draw(image,imageList[now],x,y,0,2,2)
end
}
end
[...]钓鱼小游戏开发日志0.10说明补一个日志应该不会继续做这个了,确实是代码写的太臭,完全面向过程,改动起来很难受不过只是一个习作,最终效果还好更新内容:增加读取配置代码,使用以前项目用的excel改巴改巴,用vba导出lua数据格式配置增加获取物品逻辑,钓鱼后读取配置内权重并随机掉落item,获得对应的分数增加数据持久化,自动存档,能够保存用户之前游戏的积分。这个是社区找的现成代码代码就不贴了,工程[...]