【Love2d从青铜到王者】第十三篇:Love2d之游戏:射击敌人(Game: Shoot the enemy)

x33g5p2x  于2022-05-08 转载在 其他  
字(9.3k)|赞(0)|评价(0)|浏览(370)

系列文章目录

前言

🍇一、游戏:射击敌人(Game: Shoot the enemy)

  • 让我们用目前所学的一切来创建一个简单的游戏。你可以随心所欲地阅读关于编程和制作游戏的书籍,但要真正学会,你必须亲自动手。
  • 一个游戏本质上是一堆你必须解决的问题。当你让一个有经验的程序员做PONG的时候,他不会去查a如何制作乒乓球。他们可以将PONG分成不同的问题,并且知道如何解决每一个问题。本章将向你展示如何将一个游戏分成多个任务。
  • 我们要做的游戏很简单:一个敌人在墙上反弹。我们必须拍下来。我们每射一次,敌人就跑得更快一点。当你失手时,游戏就结束了,你必须重新开始。

  • 对于这个游戏,我们将使用图像。您可以自由使用自己的图像,但我将使用这3种图像:

  • 这些图像是由kenney,他制作了许多任何人都可以在他们的游戏中使用的免费资源。看看他。
  • 让我们从3个主要回调开始,load classic我们用来模拟类的库。
function love.load()
    Object=require("classic")
    require"panda"
    panda=Panda(0,0,150)
end

function love.update(dt)
    panda:update(dt)
end

function love.draw()
    panda:draw()
end
  • 先说主界面。创建一个名为main.lua
  • 我们可以为我们所有的对象创建一个基类,但是因为这是一个非常简单的游戏,所以我们没有基类。尽管我鼓励你在本章末尾通过自己添加一个基类来改进代码。

🍈二、任务:创建一个移动的熊猫(Task: Create a moving panda)

  • 创建熊猫类别:
Panda=Object:extend()

function Panda:new(x,y,speed)
    self.x=x
    self.y=y
    self.speed=speed
    self.image=love.graphics.newImage("panda.png")
end
  • 我要把熊猫形象给我的玩家。
function Panda:draw()
    love.graphics.draw(self.image,self.x,self.y)
end
  • 接下来让我们用箭头键移动我们的熊猫。
function Panda:update(dt)
    if love.keyboard.isDown("left")
    then
        self.x=self.x-self.speed*dt
    elseif love.keyboard.isDown("right")
    then
        self.x=self.x+self.speed*dt
    end
end

function Panda:draw()
    love.graphics.draw(self.image,self.x,self.y)
end
  • 现在我们应该可以移动我们的熊猫了。让我们回到main.lua。加载我们的panda。。
function love.load()
    Object=require("classic")
    require"panda"
    panda=Panda(0,0,150)
end

function love.update(dt)
    panda:update(dt)
end

function love.draw()
    panda:draw()
end
  • 如你所见,我们可以移动我们的熊猫。但是我们的熊猫可以跳出窗外。让我们用if语句来解决这个问题。

Panda=Object:extend()

function Panda:new(x,y,speed)
    self.x=x
    self.y=y
    self.speed=speed
    self.image=love.graphics.newImage("panda.png")

    --获取图片的宽度
    self.width=self.image:getWidth()
end

function Panda:update(dt)
    if love.keyboard.isDown("left")
    then
        self.x=self.x-self.speed*dt
    elseif love.keyboard.isDown("right")
    then
        self.x=self.x+self.speed*dt
    end

    --获取窗口的宽度
    local window_width=love.graphics.getWidth()
    if self.x<0
    then
        self.x=0
    elseif self.x>window_width-self.width
    then
        self.x=window_width-self.width
    end
end

function Panda:draw()
    love.graphics.draw(self.image,self.x,self.y)
end
  • 现在修好了。我们的熊猫不能再跳出窗外了。

🍑三、任务:创造一个移动的蛇(Task: Create a moving snake)

  • 现在让我们创建射类。创建一个名为snake.lua,并键入以下内容:
Snake=Object:extend()

function Snake:new(x,y)
    self.x=x
    self.y=y
end
  • 我要给一个蛇的形象,让它自己移动。
Snake=Object:extend()

function Snake:new(x,y)
    self.x=x
    self.y=y
    self.speed=100
    self.image=love.graphics.newImage("snake.png")
end

function Snake:update(dt)
    self.x=self.x+self.speed*dt
end

function Snake:draw()
    love.graphics.draw(self.image,self.x,self.y)
end
  • 我们需要让蛇移动到墙上,但我们先加载蛇。
function love.load()
    Object=require("classic")
    require"panda"
    require"snake"
    panda=Panda(0,0,150)
    snake=Snake(0,love.graphics.getHeight())
end

function love.update(dt)
    panda:update(dt)
    snake:update(dt)
end

function love.draw()
    panda:draw()
    snake:draw()
end
  • 好了,现在我们可以看到蛇在移动,我们可以看到它从我们的窗口移动出去。让我们确保它不会像熊猫一样移出我们的窗口。

Snake=Object:extend()

function Snake:new(x,y)
    self.x=x
    self.y=y
    self.speed=100
    self.image=love.graphics.newImage("snake.png")

    --图片高度与宽度
    self.width=self.image:getWidth()
    self.height=self.image:getHeight()
end

function Snake:update(dt)
    self.x=self.x+self.speed*dt

    --窗口宽度
    local window_width=love.graphics.getWidth()
    if self.x<0 
    then
        self.x=0
    elseif self.x+self.width>window_width
    then
        self.x=window_width-self.width
    end
end

function Snake:draw()
    love.graphics.draw(self.image,self.x,self.y)
end

  • 我们的蛇停在墙边,但我们想让它反弹回来。我们如何让它做到这一点?它撞上了右边的墙,然后呢?它应该向另一个方向移动。我们如何让它向另一个方向移动?通过更改的值speedspeed的值应该是变成什么?不应该是100而是-100。
  • 那么我们应该做什么self.speed = -100-?不,因为就像我之前说的,我们会让舌头在被击中时加速,这样它在反弹时会重设speed。相反,我们应该反转speed。因此speed成为**-speed**。换句话说,如果speed增加到120,它就会变成-120。
  • 如果它撞到左边的墙呢?在这一点上,speed是一个负数,我们应该把它变成正数。我们如何做到这一点?嗯,负乘以负等于正。所以如果我们这么说speed,此时为负数,变成**-speed**,它会变成一个正数。
Snake=Object:extend()

function Snake:new(x,y)
    self.x=x
    self.y=y
    self.speed=100
    self.image=love.graphics.newImage("snake.png")

    --图片高度与宽度
    self.width=self.image:getWidth()
    self.height=self.image:getHeight()
end

function Snake:update(dt)
    self.x=self.x+self.speed*dt

    --窗口宽度
    local window_width=love.graphics.getWidth()
    if self.x<0
    then
        self.x=0
        self.speed=-self.speed
    elseif self.x+self.width>window_width
    then
        self.x=window_width-self.width
        self.speed=-self.speed
    end
end

function Snake:draw()
    love.graphics.draw(self.image,self.x,self.y)
end

好了,我们有了一个熊猫和一个移动的蛇,现在只剩下子弹了。

🍐四、任务:能够发射子弹(Task: Be able to shoot bullets)

  • 创建一个名为bullet.lua,并编写以下代码:
Bullet=Object:extend()

function Bullet:new()
    self.image=love.graphics.newImage("bullet.png")
end

function Bullet:draw()
    love.graphics.draw(self.image)
end
  • 这个子弹应该垂直向下移动,而不是水平左右移动。
Bullet=Object:extend()

function Bullet:new(x,y)
    self.image=love.graphics.newImage("bullet.png")
    self.x=x
    self.y=y
    self.speed=700
end

function Bullet:update(dt)
    self.y=self.y+self.speed*dt
end

function Bullet:draw()
    love.graphics.draw(self.image,self.x,self.y)
end
  • 在我们需要能够发射子弹。在main.lua中加载文件并创建一个表listOfBullets
function love.load()
    Object=require("classic")
    require"panda"
    require"snake"
    require"bullet"
    panda=Panda(0,0,150)
    snake=Snake(0,love.graphics.getHeight()-105)

    listOfBullets = {}
end

function love.update(dt)
    panda:update(dt)
    snake:update(dt)
end

function love.draw()
    panda:draw()
    snake:draw()
end
  • 现在我们给熊猫一个函数,当空格被按下时会产生一个子弹。
function Panda:keypress(key)
    if key=="space"
    then
        table.insert(listOfBullets,Bullet(self.x,self.y))
    end
end
  • 我们需要调用这个函数在love.keypressed回调。
function love.load()
    Object=require("classic")
    require"panda"
    require"snake"
    require"bullet"
    panda=Panda(0,0,150)
    snake=Snake(0,love.graphics.getHeight()-105)

    listOfBullets = {}
end

function love.keypressed(key)
    panda:keypress(key)
end

function love.update(dt)
    panda:update(dt)
    snake:update(dt)
end

function love.draw()
    panda:draw()
    snake:draw()
end
  • 现在我们需要遍历这个表listOfBulletsupdate/draw所有子弹。
function love.load()
    Object=require("classic")
    require"panda"
    require"snake"
    require"bullet"
    panda=Panda(0,0,150)
    snake=Snake(0,love.graphics.getHeight()-105)

    listOfBullets = {}
end

function love.keypressed(key)
    panda:keypress(key)
end

function love.update(dt)
    panda:update(dt)
    snake:update(dt)

    for k,v in ipairs(listOfBullets)
    do
        v:update(dt)
    end
end

function love.draw()
    panda:draw()
    snake:draw()

    for k,v in ipairs(listOfBullets)
    do
        v:draw()
    end
end

  • 太棒了,我们的玩家现在可以发射子弹了。

🍒五、任务:使子弹影响敌人的速度(Task: Make bullets affect the enemy’s speed)

  • 现在我们需要让蛇被子弹击中。我们给Bullet一个碰撞检测功能。
function Bullet:checkCollision(obj)
end
  • 你还知道怎么做吗?你还知道保证碰撞发生需要满足的四个条件吗?
  • 我们不是返回真假,而是增加敌人的速度。我们给予变量self_dead给子弹,我们将用它从listOfBullets中删除它。
Bullet=Object:extend()

function Bullet:new(x,y)
    self.image=love.graphics.newImage("bullet.png")
    self.x=x
    self.y=y
    self.speed=700

    self.width=self.image:getWidth()
    self.height=self.image:getHeight()
end

function Bullet:update(dt)
    self.y=self.y+self.speed*dt
end

function Bullet:draw()
    love.graphics.draw(self.image,self.x,self.y)
end

function Bullet:checkCollision(obj)

    --子弹的左右上下
    local self_left=self.x
    local self_right=self.x+self.width
    local self_top=self.y
    local self_bottom=self.y+self.height

    --蛇的左右上下
    local obj_left=obj.x
    local obj_right=obj.x+obj.width
    local obj_top=obj.y
    local obj_bottom=obj.y+obj.height

    if self_left<obj_right 
    and self_right>obj_left
    and self_top<obj_top
    and self_bottom>obj_bottom
    then
        self.dead=true
        obj.speed=obj.speed+50
    end
end
  • 现在我们需要在main.lua中调用checkCollision
function love.update(dt)
    panda:update(dt)
    snake:update(dt)

    for k,v in ipairs(listOfBullets)
    do
        v:update(dt)

        v:checkCollision(snake)
    end
end
  • 接下来我们需要销毁已经self_dead的子弹。
function love.load()
    Object=require("classic")
    require"panda"
    require"snake"
    require"bullet"
    panda=Panda(0,0,150)
    snake=Snake(0,love.graphics.getHeight()-105)

    listOfBullets = {}
end

function love.keypressed(key)
    panda:keypress(key)
end

function love.update(dt)
    panda:update(dt)
    snake:update(dt)

    for k,v in ipairs(listOfBullets)
    do
        v:update(dt)

        --每颗子弹检查是否与敌人有碰撞
        v:checkCollision(snake)

        --如果子弹的属性是self_dead的,那么这是真的
        if v.dead==true
        then
            --从列表中删除它
            table.remove(listOfBullets,k)
        end
    end
end

function love.draw()
    panda:draw()
    snake:draw()

    for k,v in ipairs(listOfBullets)
    do
        v:draw()
    end
end
  • 最后要做的是当我们错过敌人时重启游戏。我们需要检查子弹是否在屏幕外。
function Bullet:update(dt)
    self.y=self.y+self.speed*dt

    --如果子弹不在屏幕上
    if self.y>love.graphics.getHeight()
    then
        --重新开始游戏
        love.load()
    end
end

  • 让我们来测试一下。你可能会注意到,当你击中向左移动的敌人时,它会减速。这是因为此时敌人的速度是负数。所以通过增加数量,敌人的速度会慢下来。为了解决这个问题,我们需要检查敌人的速度是否是负数。

Bullet=Object:extend()

function Bullet:new(x,y)
    self.x=x
    self.y=y
    self.speed=700
    self.image=love.graphics.newImage("bullet.png")

    self.width=self.image:getWidth()
    self.height=self.image:getHeight()
end

function Bullet:update(dt)
    self.y=self.y+self.speed*dt

    --如果子弹不在屏幕上
    if self.y>love.graphics.getHeight()
    then
        --重新开始游戏
        love.load()
    end
end

function Bullet:draw()
    love.graphics.draw(self.image,self.x,self.y)
end

function Bullet:checkCollision(obj)

    --子弹的左右上下
    local self_left=self.x
    local self_right=self.x+self.width
    local self_top=self.y
    local self_bottom=self.y+self.height

    --蛇的左右上下
    local obj_left=obj.x
    local obj_right=obj.x+obj.width
    local obj_top=obj.y
    local obj_bottom=obj.y+obj.height

    if self_left<obj_right and
         self_right>obj_left and
         self_top<obj_bottom and
         self_bottom>obj_top
    then
        self.dead=true

        ---增加蛇的速度
        if obj.speed>0 
        then
            obj.speed=obj.speed+50
        else
            obj.speed=obj.speed-50
        end
    end
end

  • 我们的游戏到此结束。或者是?你应该试着自己给游戏添加功能。或者做一个全新的游戏。只要你坚持学习,坚持做游戏,都没关系!

🍌六、总结

  • 一个游戏本质上就是一堆需要解决的问题。

🍋总结

以上就是今天要讲的内容,本文仅仅简单介绍了Love2d之碰游戏:射击敌人(Game: Shoot the enemy),介绍了游戏:射击敌人(Game: Shoot the enemy)与及碰撞检测(Detecting collision)的深层使用,与博主的lua语言文章结合更好的理解love2d的编码,如果你是一名独立游戏开发者,或者一位对游戏开发有着深厚兴趣,但是又对于unity3d,ue4等这些对于新手而言不太友好的引擎而头疼的开发者;那么现在,你可以试试Love2D。Love2D是一款基于Lua编写的轻量级游戏框架,尽管官方称呼其为引擎,但实际上它只能称得上是一个框架,因为他并没有一套全面完整的解决方案。不过,这款框架上手及其容易,是学习游戏开发的初学者入门的一个良好选择。

相关文章