【Love2d从青铜到王者】第十篇:Love2d之类和类的继承(Classes And Inheritance)

2022年05月15日 阅读数:4
这篇文章主要向大家介绍【Love2d从青铜到王者】第十篇:Love2d之类和类的继承(Classes And Inheritance),主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

在这里插入图片描述

系列文章目录



前言

在这里插入图片描述


🍇1、类(Classes)

1️⃣.类(Classes)

  • Classes 就像蓝图。您能够用一个Classes 建立多个房屋。相似地,咱们能够从一个类中建立多个对象。
    在这里插入图片描述
    git

  • 对于Classes ,咱们将使用一个库:Classic github

在这里插入图片描述

  • 点击classic.lua而后按行的复制代码。

在这里插入图片描述

  • 转到文本编辑器,建立一个名为classic.lua而后粘贴代码。
  • 如今咱们必须require它。
function love.load()
    Object=require "classic"
end

function love.update(dt)
end

function love.draw()
end
  • 如今咱们已经准备建立一个类。建立一个名为rectangle.lua,并放入如下代码:
--! file: rectangle.lua

-- Pass Object as first argument.
Rectangle = Object.extend(Object)

function Rectangle.new(self)
    self.test = math.random(1, 1000)
end
  • 一切都会获得解释。可是首先将这段代码放入main.lua
--! file: main.lua
function love.load()
    Object = require "classic"
    --Don't forget to load the file
    require "rectangle"

    r1 = Rectangle()
    r2 = Rectangle()
    print(r1.test, r2.test)
end

function love.update(dt)
end

function love.draw()
end

在这里插入图片描述

  • 当您运行游戏时,您将看到打印了2个随机数。
  • 因此让咱们一步一步地看这段代码。首先,咱们用Rectangle = Object.extend(对象)。这使得Rectangle成为一个Classes 。这将是咱们的蓝图。与属性相反,Classes 一般用大写字符编写(所以这将是uppercase或PascalCase)
  • main.lua。咱们说r1 = Rectangle()。即便Rectangle是一个表,咱们仍然能够像调用函数同样调用它。它如何工做的是另外一个章节。可是经过调用Rectangle()它建立一个新的实例。这意味着它采用咱们的蓝图,建立一个具备全部类特性的新对象。每一个新实例都是独一无二的。
  • 为了证实这一点r1是惟一的,咱们建立另外一个名为r2。双方都有属性值 test,但他们的变量不一样。
  • 当咱们调用Rectangle(),它执行调用Rectangle.new。这就是咱们所说的构造器。
  • 参数self,是咱们正在修改的实例。若是咱们打字Rectangle.test = math.random(0, 1000),咱们将把属性赋予蓝图,而不是用蓝图建立的实例。
  • 让咱们对咱们的类进行一些更改:
--! file: rectangle.lua
Rectangle = Object.extend(Object)

function Rectangle.new(self)
    self.x = 100
    self.y = 100
    self.width = 200
    self.height = 150
    self.speed = 100
end
function Rectangle.update(self, dt)
    self.x = self.x + self.speed * dt
end

function Rectangle.draw(self)
    love.graphics.rectangle("line", self.x, self.y, self.width, self.height)
end
  • 这就是移动矩形的对象在Object 组成。除了此次咱们将运动和绘图部分的代码放在对象中。如今咱们只须要调用updatedraw进去main.lua
--! file: main.lua
function love.load()
    Object = require "classic"
    --Don't forget to load the file
    require "rectangle"

    r1 = Rectangle()
    r2 = Rectangle()
    print(r1.test, r2.test)
end

function love.update(dt)
    r1.update(r1,dt)
end

function love.draw()
    --love.graphics.print(r1.test,100,100)
    --love.graphics.print(r2.test,100,200)
    r1.draw(r1,100,200)
end

在这里插入图片描述

  • 当你运行游戏时,你会看到一个移动的矩形。
  • 因此咱们建立了一个名为Rectangle()。咱们建立了一个名为r1。因此如今r1具备功能updatedraw。咱们调用这些函数,做为第一个参数,咱们传递实例自己r1。这是什么self变成了函数。
  • 不过,咱们不得不经过,这有点烦人r1每次咱们调用它的一个函数。幸运的是,Lua对此有一个简写。当咱们使用冒号(:)时,函数调用将自动传递冒号左边的对象做为第一个参数。
--! file: main.lua
function love.load()
    Object = require "classic"
    --Don't forget to load the file
    require "rectangle"

    r1 = Rectangle()
    r2 = Rectangle()
    print(r1.test, r2.test)
end

--[[
function love.update(dt)
    r1.update(r1,dt)
end
--]]
function love.update(dt)
    r1:update(dt)
end

function love.draw()
    --love.graphics.print(r1.test,100,100)
    --love.graphics.print(r2.test,100,200)
    --r1.draw(r1,100,200)
    r1:draw()
end

在这里插入图片描述

  • 咱们也能够用函数来作这件事。
--! file: rectangle.lua

--Lua turns this into: Object.extend(Object)
Rectangle = Object:extend()

--Lua turns this into: Rectangle.new(self)
function Rectangle:new()
    self.x = 100
    self.y = 100
    self.width = 200
    self.height = 150
    self.speed = 100
end

--Lua turns this into: Rectangle.update(self, dt)
function Rectangle:update(dt)
    self.x = self.x + self.speed * dt
end

--Lua turns this into: Rectangle.draw(self)
function Rectangle:draw()
    love.graphics.rectangle("line", self.x, self.y, self.width, self.height)
end

在这里插入图片描述

  • 咱们称之为语法糖。 Syntactic sugar
  • 让咱们添加一些参数到Rectangle:new()
--Lua turns this into: Object.extend(Object)
Rectangle = Object:extend()

--! file: rectangle.lua
function Rectangle:new(x, y, width, height)
    self.x = x
    self.y = y
    self.width = width
    self.height = height
    self.speed = 100
end

--Lua turns this into: Rectangle.update(self, dt)
function Rectangle:update(dt)
    self.x = self.x + self.speed * dt
end

--Lua turns this into: Rectangle.draw(self)
function Rectangle:draw()
    love.graphics.rectangle("line", self.x, self.y, self.width, self.height)
end
  • 有了这个咱们能够给r1r2每一个都有本身的位置和大小。
--! file: main.lua

function love.load()
    Object = require "classic"
    require "rectangle"
    r1 = Rectangle(100, 100, 200, 50)
    r2 = Rectangle(350, 80, 25, 140)
end

function love.update(dt)
    r1:update(dt)
    r2:update(dt)
end

function love.draw()
    r1:draw()
    r2:draw()
end
  • 因此如今咱们有两个移动的矩形。这就是classes如此厉害的缘由。r1r2都是同样的,但倒是独一无二的。

在这里插入图片描述

  • 另外一个让classes如此厉害的缘由是继承(inheritance)

🍈2、继承(inheritance)

1️⃣.继承(inheritance)

  • 经过继承,咱们能够扩展咱们的类。换句话说,咱们制做了蓝图的副本,并向其中添加了功能,而没有编辑原始蓝图。
    在这里插入图片描述
  • 假设你有一个怪物游戏。每一个怪物都有本身的攻击方式,它们的移动方式不一样。可是他们也会受到伤害,甚至死亡。这些重叠的特性应该放在咱们称之为超类或者基础类。他们提供了全部怪物都有的特征。而后每一个怪物的类能够扩展这个基类,并在其中添加本身的特性。
  • 让咱们建立另外一个移动的形状,一个圆形。咱们的移动矩形和圆形有什么共同之处?他们都会搬走。因此让咱们为这两个形状建立一个基类。
  • 建立一个文件名为shape.lua,并放入如下代码:
--! file: shape.lua
Shape = Object:extend()

function Shape:new(x, y)
    self.x = x
    self.y = y
    self.speed = 100
end

function Shape:update(dt)
    self.x = self.x + self.speed * dt
end
  • 咱们的基类shape如今处理运动。我应该指出基类只是一个术语。“X是Y的基类”。基类仍然和其余类同样。只是咱们使用它的方式不一样。web

  • 不管如何,如今咱们有了一个处理咱们运动的基类,咱们可使Rectangle继承shape,并移除其update代码。确保require shape在使用它以前。编程

--! file: main.lua

function love.load()
    Object = require "classic"
    require "shape"
    require "rectangle"
    r1 = Rectangle()
    r2 = Rectangle()
end
--! file: rectangle.lua
Rectangle = Shape:extend()

function Rectangle:new(x, y, width, height)
    Rectangle.super.new(self, x, y)
    self.width = width
    self.height = height
end

function Rectangle:draw()
    love.graphics.rectangle("line", self.x, self.y, self.width, self.height)
end
  • Rectangle = Shape:extend(),咱们使Rectangle继承shape
  • Shape有本身的函数,称为:new()。经过创造Rectangle:new()咱们覆盖原始函数。意味着当咱们调用Rectangle()它不会执行Shape:new()可是相反的执行Rectangle:new()
  • 可是矩形具备这样的属性super子类,这是一个类Rectangle()类是从Shape继承过来的。用Rectangle.super咱们能够访问基类的函数,并用它来调用Shape:new()
  • 咱们必须经过self做为第一个参数,不能让Lua用冒号(:)来处理,由于咱们没有把函数做为实例来调用。
  • 如今咱们须要制做一个circle类。建立一个名为circle.lua,并放入下面的代码。
--! file: circle.lua
Circle = Shape:extend()

function Circle:new(x, y, radius)
    Circle.super.new(self, x, y)
    --A circle doesn't have a width or height. It has a radius.
    self.radius = radius
end

function Circle:draw()
    love.graphics.circle("line", self.x, self.y, self.radius)
end
  • 因此咱们使Circle继承Shape。咱们给了xynew()函数对于ShapeCircle.super.new(self,x,y)
  • 咱们给咱们的Circle类本身的draw函数。这是你画圆的方法。圆没有宽度和高度,它们有半径。
  • 如今在main.lualoadShape.luaCircle.lua,并改变r2对于Circle
--! file: main.lua

function love.load()
    Object = require "classic"
    --Don't forget to load the file
    require "shape"

    require "rectangle"

    --Don't forget to load the file
    require "circle"

    r1 = Rectangle(100, 100, 200, 50)

    --We make r2 a Circle instead of a Rectangle
    r2 = Circle(350, 80, 40)
end

function love.update(dt)
    r1:update(dt)
    r2:update(dt)
end

function love.draw()
    r1:draw()
    r2:draw()
end

在这里插入图片描述

  • 如今当你运行游戏时,你会看到一个移动的矩形和一个移动的圆形。

🍊3、代码详细解读

  • 让咱们再看一遍全部的代码。
  • 首先,咱们加载library classic require “classic”。加载这个库会返回一个表,咱们将这个表存储在里面的对象Object。它有模拟一个类所须要的最基本的东西。由于Lua没有类,可是经过使用classic 的咱们获得了一个很是好的类的模仿。
  • 接下来咱们加载shape.lua 。在该文件中,咱们建立了一个名为Shape 。咱们将使用这个类做为基础类为Rectangle Circle 。这些类的两个共同点是它们都有一个x和y变量,而且它水平移动。这些类似之处是咱们放进去的变量在Shape
  • 接下来,咱们建立Rectanlge 类。咱们使Rectanlge 类继承基类。在里面new()函数,这构造函数,咱们调用Rectangle.super.new(self,x,y)。咱们用self做为第一个参数,因此Shape 将使用咱们蓝图的实例,而不是蓝图自己。咱们给矩形一个width height 变量,并给它一个绘制函数。
  • 接下来咱们重复上面的,除了一个圈。因此不是一个宽度和高度咱们给它一个radius 变量。
  • 既然咱们已经把classes 准备好了,咱们能够开始作了例子这些classes 。随着 r1 = Rectangle(100, 100, 200, 50) 咱们建立了类的一个类Rectanlge 。它是一个由咱们的蓝图制成的物体,而不是蓝图自己。咱们对此实例所作的任何更改都不会影响该类。咱们update draw 这个实例,为此咱们使用冒号(😃。这是由于咱们须要将实例做为第一个参数传递,冒号会让Lua为咱们作这件事。
  • 最后,咱们作一样的事情r2 ,除了咱们让它成为一个Circle

🍋4、疑惑

  • 对于一章来讲,这是不少信息,我能够想象若是你很难理解全部这些。若是你是编程新手,你须要一段时间才能理解全部这些新概念,但最终你会习惯的。我会在谈论新主题的同时,不断增长对旧主题的解释。

🍉5、总结

  • Classes 就像蓝图。咱们能够从一个类中建立多个对象。为了模拟类,咱们使用库classic。您能够用建立一个类ClassName = Object:extend()。您可使用建立类的实例instanceName = ClassName()。这将调用函数ClassName:new()。这是调用构造函数。类的每一个函数都应该以self 开始以便在调用函数时,能够将实例做为第一个参数传递。instanceName.functionName(instanceName)。咱们可使用冒号(:)让Lua替咱们作这件事。框架

  • 咱们能够用扩展一个类ExtensionName = ClassName:extend()。这使得ExtensionNameClassName的一份拷贝,以致于咱们能够在不改变ClassName的状况下添加变量。若是咱们给ExtensionName一种函数ClassName已经有了,咱们仍然能够调用原函数用extension name . super . function name(self)dom

🍋总结

以上就是今天要讲的内容,本文仅仅简单介绍了Love2d之类和类的继承(Classes And Inheritance),介绍了love2d类和类的继承的使用,与博主的lua语言文章结合更好的理解love2d的编码,若是你是一名独立游戏开发者,或者一位对游戏开发有着深厚兴趣,可是又对于unity3d,ue4等这些对于新手而言不太友好的引擎而头疼的开发者;那么如今,你能够试试Love2D。Love2D是一款基于Lua编写的轻量级游戏框架,尽管官方称呼其为引擎,但实际上它只能称得上是一个框架,由于他并无一套全面完整的解决方案。不过,这款框架上手及其容易,是学习游戏开发的初学者入门的一个良好选择。编辑器

在这里插入图片描述