raspberry pi_如何在Raspberry Pi上使用LÖVE游戏引擎对游戏进行编程

raspberry pi

Raspberry Pi以向孩子介绍开源软件和编程而闻名。 Pi是负担得起的,实用的专业级计算入门,伪装成可破解的乐趣。 Mitch Resnick's Scratch (最幸运的是,它使 Pilot 2改用非开放式Adobe Air时, 由Pi Foundation分叉)是为使幼儿开始编程所做的最大努力,但是一个不可避免的问题是,有人应该毕业于在他们的拖放编程已不复存在之后。

在像Scratch这样的拖放式介绍之后,有很多候选人可以进行下一级别的编程。 有出色的PyGame ,还有一个名为Processing的Java子集,功能强大的Godot引擎等。 诀窍是找到一个框架,该框架足够容易,可以轻松地实现从拖放的即时满足过渡,但又足够复杂,可以准确地表示专业程序员一整天的实际工作。

一个特别强大的游戏引擎称为LÖVE 。 LÖVE使用脚本语言Lua ,它没有像Python那样引起人们的广泛关注,但是在现代视频游戏行业中被大量嵌入 (无论是字面意义上还是图形上)。 几乎所有主要游戏工作室都将Lua列为必备技能,它是专有的Unity和Unreal游戏引擎中的一种选择,并且它通常会在现实世界中各种意外的地方弹出。

简而言之,Lua是一种值得学习的语言,特别是如果您打算进行游戏开发。 就LÖVE引擎而言,就功能而言,它与PyGame框架一样好,并且因为它没有IDE,所以它非常轻巧,并且在某种程度上来说,它不像Godot这样简单。

更好的是,LÖVE可以在Pi上本地运行,但是它的项目可以打开并在Lua可以运行的任何平台上运行。 其中包括Linux,Windows和Mac,还包括Android甚至封闭的iOS。 换句话说,LÖVE也不是开始进行移动开发的不错平台。

Mr. Rescue, an open source game available on itch.io

Rescue先生,itch.io上的开源游戏

现在,我已经在LÖVE上卖给了您,这是从Pi上的Scratch迈出的下一步,让我们深入研究一下它是如何工作的。

安装LÖVE

像往常一样,在Raspberry Pi上安装LÖVE只是一个简单的命令:

$ sudo apt install love2d

如果您在Pi上运行Fedora,请改用dnf


   
   
$ sudo dnf install love2d

无论哪种方式,程序包管理系统都会提取Lua,SDL和LÖVE需要运行的其他依赖项。

你好,世界!

LÖVE引擎没什么可看的。 它实际上是一个框架,意味着您可以使用任何喜欢的文本编辑器。 首先要尝试的是“ hello world”程序,以确保其启动,并向您介绍Lua语言和LÖVE框架的基本语法。 打开文本编辑器,然后输入以下文本:


   
   
cwide = 520
chigh = 333

love. window . setTitle ( ' Hello Wörld ' )
love. window . setMode ( cwide, chigh )

function love. load ( )
        love. graphics . setBackgroundColor ( 177 , 106 , 248 )
        -- font = love. graphics . setNewFont ( "SkirtGirl.ttf" , 72 )
end

function love. draw ( )
love. graphics . setColor ( 255 , 33 , 78 )
        love. graphics . print ( "Hello World" , cwide / 4 , chigh / 3.33 )
end

将其另存为main.lua

可分发的LÖVE软件包只是一个标准的zip文件,扩展名为.love 。 必须始终命名为main.lua的主文件必须位于zip文件的顶层。 像这样创建它:

$ zip hello.love main.lua

并启动它:

$ love ./hello.love

Hello World

该代码非常容易理解。 cwidechigh变量是全局变量,可用于整个脚本,它们设置游戏世界的宽度和高度。 在第一个代码块(称为函数 )中,设置了背景色,在第二个函数中,“ hello world”被打印到了屏幕上。

前两个破折号( - )开头的行是注释。 在.love包中包含.ttf并取消注释setNewFont行,将以该字体显示文本。 当然,您不必使用Skirt Girl字体; 只需从FontLibrary.org获取字体并相应地调整代码即可。


   
   
$ zip hello.love main.lua SkirtGirl.ttf

并启动它:


   
   
$ love . / hello.love

基础

Scratch与专业编程语言之间的最大区别是,使用Scratch,您可以学习一些基本原理,然后随机进行探索,直到发现所有其他功能为止。

使用Lua等较低级别的编程语言,您首先学习的东西不是可以复制和粘贴以产生可玩游戏的东西。 您学习了如何使用该语言,然后查找了一些功能,这些功能可以完成您希望游戏发挥作用的动作。 除非您了解语言的工作原理,否则仍然很难进入游戏世界。

幸运的是,您可以在开始游戏时学习该语言。 在此过程中,您会选择一些技巧,以后可以重用这些技巧,以使游戏按照您希望的方式工作。

首先,您需要了解核心LÖVE引擎的三个主要功能:

  • 函数love.load()是启动LÖVE游戏时触发的函数在其他语言中称为initvoid setup()函数)。 它用于为您的游戏世界奠定基础。 函数love.load()仅执行一次,因此它仅包含在整个游戏中持续存在的代码。 它或多或少相当于“ 单击绿色标志时”块和Scratch中的“ 阶段”脚本区域。
  • 函数love.update(dt)是在游戏过程中不断更新的函数。 玩游戏时,会刷新love.update(dt)函数中的所有内容。 如果您玩过任何游戏,无论是在《弗雷迪的五夜》还是《天际》还是其他游戏中,并且您已经监视了帧速率(fps),那么随着帧跳动而发生的所有事情都将处于更新循环中(实际上不是,因为游戏不是用LÖVE制作的,而是类似更新功能的东西。
  • 函数love.draw()是使引擎实例化您在游戏的love.load()函数中创建的图形组件的函数。 您可以加载精灵或创建山峰,但如果不绘制它,则它永远不会出现在游戏中。

这三个功能是您在LÖVE中创建的任何元素的基础。 您也可以创建自己的新功能。 首先,让我们探索LÖVE框架。

精灵

“您好,世界!”的基础知识 是一个很好的起点。 相同的基本三个功能仍充当应用程序的基本框架。 但是,与在屏幕上呈现简单文本不同,这次我们使用freesvg.org中的图形创建一个sprite。

git存储库中提供了此示例的代码示例和资产。 如果要继续,请自己克隆它:


   
   
$ git clone https: // notabug.org / seth / lessons_love2d.git

LÖVE中的大多数对象都存储在数组中。 数组有点像Scratch中的列表。 它是一堆放置在普通容器中的特征。 通常,在LÖVE中创建子画面时,会创建一个数组来保存有关子画面的属性,然后在love.load中列出希望对象具有的属性。

love.draw函数中,子画面被绘制到屏幕上。


   
   
fish  = { }
cwide = 520
chigh = 333
   
love. window . setMode ( cwide, chigh )
love. window . setTitle ( ' Collide ' )
   
function love. load ( )
        fish. x    = 0
        fish. y    = 0
        fish. img  = love. graphics . newImage ( 'images/fish.png' )
end
   
function love. update ( dt )
        -- this is a comment
end
   
function love. draw ( )
        love. graphics . draw ( fish. img , fish. x , fish. y , 0 , 1 , 1 , 0 , 0 )
end

鱼的天敌是南极最恶的生物之一:企鹅。 以创建鱼精灵的方式创建企鹅精灵,并添加一个player.speed ,这是一旦我们开始设置玩家控件,企鹅将移动多少像素:


   
   
fish  = { }
player= { }
cwide = 520
chigh = 333
   
love. window . setMode ( cwide, chigh )
love. window . setTitle ( ' Collide ' )
   
function love. load ( )
  fish. x    = 0
  fish. y    = 0
  fish. img  = love. graphics . newImage ( 'images/fish.png' )
  player. x     = 100
  player. y     = 100
  player. img   = love. graphics . newImage ( 'images/tux.png' )
  player. speed = 10
end
   
function love. update ( dt )
        -- this is a comment
end
   
function love. draw ( )
        love. graphics . draw ( fish. img ,  fish. x ,  fish. y ,   0 , 1 , 1 , 0 , 0 )
        love. graphics . draw ( player. img ,player. x ,player. y , 0 , 1 , 1 , 0 , 0 )
end

为了使内容整洁,请将png文件放在images目录中。 要测试到目前为止的游戏,请压缩main.luapng文件:


   
   
$ zip game.zip main.lua -r images
$ mv game.zip game.love
$ love . / game.love

Our current cast of characters.

我们目前的角色

运动

有多种方法可以在LÖVE中实现移动,包括鼠标,操纵杆和键盘功能。 我们已经为玩家的xy位置以及玩家移动了多少像素建立了变量,因此使用if / then语句检测按键,然后使用简单的数学方法重新定义保持玩家精灵位置的变量。 :


   
   
player     = { }
fish       = { }
cwide      = 520
chigh      = 333
   
love. window . setMode ( cwide, chigh )
love. window . setTitle ( ' Collide ' )

function love. load ( )
        fish. x    = 0
        fish. y    = 0
        fish. img  = love. graphics . newImage ( 'images/fish.png' )
        player. x     = 100
        player. y     = 100
        player. img   = love. graphics . newImage ( 'images/tux.png' )
        player. speed = 10
end

function love. update ( dt )
        if love. keyboard . isDown ( "right" ) then
            player. x = player. x + player. speed

        elseif love. keyboard . isDown ( "left" ) then
            player. x = player. x - player. speed

        elseif love. keyboard . isDown ( "up" )   then
            player. y = player. y - player. speed    

        elseif love. keyboard . isDown ( "down" ) then
            player. y = player. y + player. speed
        end
end

function love. draw ( )
        love. graphics . draw ( player. img ,player. x ,player. y , 0 , 1 , 1 , 0 , 0 )
        love. graphics . draw ( fish. img , fish. x , fish. y , 0 , 1 , 1 , 0 , 0 )    
end

测试代码以确认运动是否按预期进行。 请记住在测试之前重新压缩所有文件,以免意外测试游戏的旧版本。

为了使运动更有意义,我们可以创建函数来根据按下的键来更改精灵面对的方向。 这等效于以下几种Scratch代码块:

Looking and moving in Scratch

在Scratch中寻找和移动

使用ImageMagick生成播放器精灵的翻转版本:


   
   
$ convert tux.png -flop tuxleft.png

然后编写一个函数以换出图像。 您需要两个功能:一个用于交换图像,另一个用于将其还原为原始图像:


   
   
function rotate_left ( )
        player. img = love. graphics . newImage ( 'images/tuxleft.png' )
end

function rotate_right ( )
        player. img = love. graphics . newImage ( 'images/tux.png' )
end

在适当的地方使用这些功能:


   
   
function love. update ( dt )
        if love. keyboard . isDown ( "right" ) then
            player. x = player. x + player. speed
            rotate_right ( )

        elseif love. keyboard . isDown ( "left" ) then
            player. x = player. x - player. speed
            rotate_left ( )
           
        elseif love. keyboard . isDown ( "up" )   then
            player. y = player. y - player. speed    

        elseif love. keyboard . isDown ( "down" ) then
            player. y = player. y + player. speed
        end
end

自动运动

使用与精灵x值相同的约定以及一些数学运算,可以使鱼自动在屏幕上从另一边移到另一边。 这相当于在Scratch中执行此操作:

Automated movement in Scratch

Scratch中的自动机芯

如果没有,就用LÖVE 反弹 ,而是通过检查鱼的x值是否到达屏幕的最左端( 0像素)或最右边(与画布的宽度相同)( cwide变量),则可以确定该精灵是否偏离边缘。

如果鱼在最左边,则它已到达屏幕的边缘,因此您增加了鱼的位置,迫使其向右移动。 如果鱼在最右边,则减小鱼的位置,使其向左移动。


   
   
function automove ( obj,x,y,ox,oy )
        if obj. x == cwide then
            local edgeright = 0
        elseif obj. x == 0 then
            local edgeright = 1
end

if edgeright == 1 then
            obj. x = obj. x + x
        else
            obj. x = obj. x - x
        end
    end

在这种情况下,有一系列事件很重要。 在第一个if块中,检查x的值并分配一个临时(局部)变量来指示下一步需要去哪条鱼。 然后,在第二个单独的if块中移动鱼。 为了获得加分,请尝试在if语句中全部完成,然后查看是否可以理解为什么会失败。 要获得更多的奖励积分,请查看您是否可以找出另一种移动鱼的方法。

要实现鱼的移动功能,请在love.update循环底部调用该功能:

automove(fish,1,0,fish.img:getWidth(),fish.img:getHeight() )

如果您对该脚本进行测试,您会注意到,当鱼碰到右边缘时,它会一直离开屏幕。 之所以这样做,是因为Sprite的x值基于其左上像素。 我将把它留作练习,让您确定在检查鱼的位置时应从cwide中减去什么变量。

碰撞检测

电子游戏都是关于碰撞的。 当事情相互碰撞时,无论这些事情是不幸的英雄进入了熔岩坑,还是一个坏人被法术力炸弹炸开,都应该发生。

在检测到碰撞之前,让我们决定发生碰撞时想要发生的事情。 因为您已经知道如何更改子画面的外观,所以我们将创建两个功能:一个将企鹅捕获到的鱼变成残骸中的鱼,另一个将在企鹅不在时将其恢复生命。不在。


   
   
function falive ( )
        fish. img = love. graphics . newImage ( 'images/fish.png' )
end

function fdead ( )
        fish. img = love. graphics . newImage ( 'images/fishbones.png' )
end

设置好这些功能后,就该计算碰撞了。

在Scratch中,有代码块可以检查两个Sprite是否接触。

Scratch collision

刮擦碰撞

原则上,相同的概念适用于LÖVE。 有多种检测碰撞的方法,包括HClove.physics之类的外部库,但两者之间的一个很好的折衷方案是自定义函数,用于检测精灵边界的重叠。


   
   
function CheckCollision ( x1,y1,w1,h1, x2,y2,w2,h2 )
        return x1 < x2 + w2 and
            x2 < x1 + w1 and
            y1 < y2 + h2 and
            y2 < y1 + h1
end

数学很复杂,但是如果您花一点时间考虑一下,这很有意义。 目的是检测两个图像是否重叠。 如果图像重叠,则可以说它们发生了碰撞。 这是两个 *重叠的框的示例,它们的y值示例使事情简单:

Two boxes

两盒

从函数中取出一行并处理数字:


   
   
y2   < y1 + h1
110 < 0   + 100

显然,这是一条错误的语句,因此该函数必须返回false 。 换句话说,盒子没有碰撞。

现在来看具有两个重叠框的相同逻辑:

Overlapping boxes

   
   
y2   < y1 + h1
50   < 0   + 100

这显然是正确的。 假设函数中的所有语句也都是true(如果我不愿意添加x值,它们也会是true),那么函数将返回true

要利用冲突检查,请使用if语句对其进行评估。 现在您知道,如果CheckCollision函数返回true ,则发生冲突。 CheckCollision函数是通用编写的,因此在调用它时,您需要向其提供适当的值,以便它知道哪个对象是哪个对象。

大多数值是直观的。 您需要使用LÖVE才能使用要检查碰撞的每个对象的xy位置以及对象的大小。 在这种情况下,唯一的特殊值是根据碰撞状态被换出的值。 对于那些,硬编码死鱼而不是活鱼的大小,否则在碰撞检测过程中碰撞状态将发生改变。 实际上,如果您想看到它的毛刺,可以先用错误的方式做:


   
   
if CheckCollision ( fish. x ,fish. y ,fish. img :getWidth ( ) ,fish. img :getHeight ( ) , player. x ,player. y ,player. img :getWidth ( ) ,player. img :getHeight ( ) ) then
        fdead ( )
    else
        falive ( )
    end

正确的方法是获取较小的Sprite图片的大小。 您可以使用ImageMagick做到这一点:


   
   
$ identify images / fishbones.png
images / fishbones.png PNG 150x61 [ ... ]

然后用适当的尺寸对“热点”进行硬编码:


   
   
if CheckCollision ( fish. x ,fish. y , 150 , 61 , player. x ,player. y ,player. img :getWidth ( ) ,player. img :getHeight ( ) ) then
        fdead ( )
    else
        falive ( )
end

硬编码碰撞检测区域的副作用是,当企鹅接触鱼的边缘时,鱼不会被吞噬。 为了更精确地检测碰撞,请浏览HC库或love.physics

最终代码

它不算什么游戏,但它展示了视频游戏的重要元素:


   
   
player     = { }
fish       = { }
cwide      = 520
chigh      = 333

love. window . setTitle ( ' Hello Game Wörld ' )
love. window . setMode ( cwide, chigh )

function love. load ( )
        fish. x    = 0
        fish. y    = 0
        fish. img  = love. graphics . newImage ( 'images/fish.png' )
        player. x     = 150
        player. y     = 150
        player. img   = love. graphics . newImage ( 'images/tux.png' )
        player. speed = 10
    end

function love. update ( dt )
        if love. keyboard . isDown ( "right" ) then
            player. x = player. x + player. speed

        elseif love. keyboard . isDown ( "left" ) then
            player. x = player. x - player. speed

        elseif love. keyboard . isDown ( "up" )   then
            player. y = player. y - player. speed    

        elseif love. keyboard . isDown ( "down" ) then
            player. y = player. y + player. speed
        end

if CheckCollision ( fish. x ,fish. y , 151 , 61 , player. x ,player. y ,player. img :getWidth ( ) ,player. img :getHeight ( ) ) then
            fdead ( )
        else
            falive ( )
end

automove ( fish, 1 , 0 ,fish. wide ,fish. high )
end

function love. draw ( )
        love. graphics . draw ( player. img ,player. x ,player. y , 0 , 1 , 1 , 0 , 0 )
        love. graphics . draw ( fish. img , fish. x , fish. y , 0 , 1 , 1 , 0 , 0 )    
end

function automove ( obj,x,y,ox,oy )
        if obj. x == cwide - fish. img :getWidth ( ) then
            edgeright = 0
            elseif obj. x == 0 then
            edgeright = 1
end

if edgeright == 1 then
            obj. x = obj. x + x
        else
            obj. x = obj. x - x
        end
    end

function CheckCollision ( x1,y1,w1,h1, x2,y2,w2,h2 )
        return x1 < x2 + w2 and
            x2 < x1 + w1 and
            y1 < y2 + h2 and
            y2 < y1 + h1
        end

function rotate_left ( )
        player. img = love. graphics . newImage ( 'images/tuxleft.png' )
    end

function rotate_right ( )
        player. img = love. graphics . newImage ( 'images/tux.png' )
    end

function falive ( )
        fish. img = love. graphics . newImage ( 'images/fish.png' )
    end

function fdead ( )
        fish. img = love. graphics . newImage ( 'images/fishbones.png' )
    end

在这里,您可以使用学到的原理来创作更多精彩的作品。 碰撞是视频游戏中大多数交互的基础,无论是触发与NPC的对话,管理战斗,捡起物品,引诱陷阱,还是几乎其他所有事情,因此,如果您掌握了这些,其余就是重复和肘部润滑。

因此,去制作一个视频游戏吧! 与朋友分享,在移动设备上播放,并一如既往地不断升级。

翻译自: https://opensource.com/article/17/4/how-program-games-raspberry-pi

raspberry pi

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值