起点

昆特牌之于巫师而言已从内置的 “小玩法” 脱胎成为独立的 “游戏” ,这一过程和原因网上有诸多分析,相信无需赘述。由此出发,发掘更多有潜力的 “小玩法” 加以改造的路子也不鲜见。

这其中我想到了 “钓鱼” ,玩过的游戏里,印象深的有武林群侠传、FATE黑暗史诗、火炬之光、minecraft、古剑奇谭等等,往往能令人沉迷于中不能自拔,于是有了尝试开发钓鱼游戏的想法。


思路

设计方面:

  1. 玩法。接触过的钓鱼玩法大体分三类:
    a.拟真钓鱼,从搓饵打窝调漂到挥杆溜鱼入获,极力还原真实。
    b.白盒钓鱼,即鱼作为实体可见,偏操作向
    c.黑盒钓鱼,不定时上钩的鱼和随机的收获
    本次选择做c,包括上面举的例子也都是此类的钓鱼玩法
  2. 体验。首先需要注意的是,例子游戏中的钓鱼之所以好玩,很大程度是因为其承担的产出足够有吸引力,而这种吸引力是游戏内其他系统和玩法带来的,因此我们需要提供足够的目标和吸引力,否则没有玩家愿意去钓没有价值的东西。具体内容下个版本总结。
  3. 表现。基于想提供的体验,仅使用简单2d画面和帧动画,结合特效,即可满足我们的要求。

开发方面:

短而快的开发需求,同时希望能够学多一点技能,因此选择了曾经接触又放弃的love2d引擎,希望能够在学习和使用的过程中增加对于lua、对于脚本语言、对于底层渲染逻辑的理解。

开发过程有以下总结:

  1. 对于项目结构的理解需要加强。虽说是做简单的小项目,使用严谨的所谓 “开发模式” 似乎反而降低效率(一开始就是这么想的),但是看着初版这个孤零零的main.lua文件和里面乱糟糟的function,还是觉得有点汗颜。
  2. 状态机和动画,尝试造一些简陋的轮子,勉强能用,但还是不够高效,而且非常不利于维护,对象化的思维差了很多。
  3. 资源,这块是比较顺的地方,opengameartcraftpix的免费资源都很棒,对于图集atlas的理解也更深了一些。
  4. 分发,因为想便于分享查看尝试web平台发布,官方对于web发布缺少支持,在民间支持里找到了这个并上传到网站内,可以点这里试玩,但是加载很慢,看了下源码这个工具是把love2d项目的lua代码逐字符转义,不确定是否此原因导致,但是写这篇日志时找到了另一个民间工具:https://github.com/ghoulsblade/love-webplayer,有待试用。
  5. 已知问题:想简单用加速度定期换正负号的方式做循环动画,但是方式不太对(用速度判断没用位置判断),下回修改

代码

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

标签: web, love2d

仅有一条评论

  1. [Love2d]钓鱼小游戏开发日志0.20 - Neer's Sanctuary

    [...]钓鱼小游戏开发日志0.10说明补一个日志应该不会继续做这个了,确实是代码写的太臭,完全面向过程,改动起来很难受不过只是一个习作,最终效果还好更新内容:增加读取配置代码,使用以前项目用的excel改巴改巴,用vba导出lua数据格式配置增加获取物品逻辑,钓鱼后读取配置内权重并随机掉落item,获得对应的分数增加数据持久化,自动存档,能够保存用户之前游戏的积分。这个是社区找的现成代码代码就不贴了,工程[...]

添加新评论