CS50 - Lua/LOVE2D - 如何在两个类之间共享相同的更新随机数变量 (Flappy Bird)

问题描述 投票:0回答:1

我正在学习 CS50 游戏开发入门课程,该课程使用 Lua 和 LOVE2D 制作游戏。我在分配代码中发现了一个错误,但我不确定如何修复它。

作业是 Flappy Bird 的克隆。如果您不熟悉,游戏中有一只鸟飞过上下管组之间的缝隙。我将在本文末尾发布代码。学生将获得完整游戏的作业代码,然后必须进行修改。我会在最后贴出代码。

这里是相关部分。在 PipePair.lua 中,我们将常量 GAP_HEIGHT 设置为 90。然后我们使用 init() 函数实例化一对管道,如下所示:

self.pipes = {
    ['upper'] = Pipe('top', self.y),
    ['lower'] = Pipe('bottom', self.y + PIPE_HEIGHT + GAP_HEIGHT)    
}

PIPE_HEIGHT 是 288,我们管道精灵的大小。

在 PlayState.lua 中。我们设置一个变量 self.y 如下:

self.lastY = -PIPE_HEIGHT + math.random(1,80) + 20

然后在更新方法中,我们将局部变量 y 设置为以下内容:

local y = math.max(-PIPE_HEIGHT + 10, math.min(self.lastY + math.random(-20, 20), VIRTUAL_HEIGHT - 90 - PIPE_HEIGHT))
self.lastY = y
table.insert(self.pipePairs, PipePair(y))

VIRTUAL_HEIGHT 为 288,与 PIPE_HEIGHT 相同。此方法的目的是将每个管道对的间隙位置更改为比最后一个间隙低 20 像素和高 20 像素之间的某处,以创建一种流。 math.max 的第一个值中的 (+10) 的目的是确保上部管道显示至少 10 个像素,以便您看到管道。 math.min 的第二个值中的硬编码值 90 应该是间隙高度。 math.min 中第二个值的目的是确保底部管道不会开始绘制在屏幕下方,因此不可见。

最后,Pipe.lua对每个管道的渲染函数如下:

love.graphics.draw(PIPE_IMAGE, self.x,
    (self.orientation == 'top' and self.y + PIPE_HEIGHT or self.y),
    0, 1, self.orientation == 'top' and -1 or 1)

这是我发现的错误。我在游戏中注意到有时底管不可见。经过测试和计算,我发现可以将底部管道的y设置为288,即虚拟屏幕高度。与顶部管道不同,底部管道未设置为在地面上方可见的最小高度。修复方法是将 PlayState 的本地 y 计算中的硬编码 90 更改为 110。但这仅在间隙高度为 90 时有效。如果间隙高度为 60,则该值需要为 80,如果间隙高度为 120,该值需要为 140.

所以问题来了。该任务要求我们随机化每个管道对中的间隙高度。我试图在 60 到 120 之间随机化。但为了避免错误,我需要为 PipePair 类和 PlayState 类提供相同的间隙高度值。随机数需要在每次更新时更改。但是我不知道在哪里放置随机数生成,该随机数生成将随每次更新而改变,并与 PipePair 和 PlayState 类共享该值。我该怎么做?

顺便说一句,我已经在多个地方发布了这个问题以进行 CS50 讨论,但没有得到任何回应,这就是我转向这里寻求帮助的原因。

以下是相关文件,减去注释:

PlayState.lua

PlayState = Class{__includes = BaseState}

PIPE_SPEED = 60
PIPE_WIDTH = 70
PIPE_HEIGHT = 288

BIRD_WIDTH = 38
BIRD_HEIGHT = 24

function PlayState:init()
    self.bird = Bird()
    self.pipePairs = {}
    self.timer = 0
    self.score = 0

    self.lastY = -PIPE_HEIGHT + math.random(80) + 20
end

function PlayState:update(dt)
    self.timer = self.timer + dt

    if self.timer > 2 then
        local y = math.max(-PIPE_HEIGHT + 10, 
         math.min(self.lastY + math.random(-20,20), VIRTUAL_HEIGHT - 90 - PIPE_HEIGHT))
        self.lastY = y

        table.insert(self.pipePairs, PipePair(y))

        self.timer = 0
    end

    for k, pair in pairs(self.pipePairs) do
        if not pair.scored then
            if pair.x + PIPE_WIDTH < self.bird.x then
                self.score = self.score + 1
                pair.scored = true
                sounds['score']:play()
            end
        end

        pair:update(dt)
    end

    for k, pair in pairs(self.pipePairs) do
        if pair.remove then
            table.remove(self.pipePairs, k)
        end
    end

    for k, pair in pairs(self.pipePairs) do
        for l, pipe in pairs(pair.pipes) do
            if self.bird:collides(pipe) then
                sounds['explosion']:play()
                sounds['hurt']:play()

                gStateMachine:change('score', {
                    score = self.score
                })
            end
        end
    end

    self.bird:update(dt)

    if self.bird.y > VIRTUAL_HEIGHT - 15 then
        sounds['explosion']:play()
        sounds['hurt']:play()

        gStateMachine:change('score', {
            score = self.score
        })
    end
end

function PlayState:render()
    for k, pair in pairs(self.pipePairs) do
        pair:render()
    end

    love.graphics.setFont(flappyFont)
    love.graphics.print('Score: ' .. tostring(self.score), 8, 8)

    self.bird:render()
end

function PlayState:enter()
    scrolling = true
end

function PlayState:exit()
    scrolling = false
end

PipePair.lua

PipePair = Class{}

local GAP_HEIGHT = 90

function PipePair:init(y)
    self.scored = false

    self.x = VIRTUAL_WIDTH + 32

    self.y = y

    self.pipes = {
        ['upper'] = Pipe('top', self.y),
        ['lower'] = Pipe('bottom', self.y + PIPE_HEIGHT + GAP_HEIGHT)
    }

    self.remove = false
end

function PipePair:update(dt)
    if self.x > -PIPE_WIDTH then
        self.x = self.x - PIPE_SPEED * dt
        self.pipes['lower'].x = self.x
        self.pipes['upper'].x = self.x
    else
        self.remove = true
    end
end

function PipePair:render()
    for l, pipe in pairs(self.pipes) do
        pipe:render()
    end
end

管道.lua

Pipe = Class{}

local PIPE_IMAGE = love.graphics.newImage('pipe.png')

function Pipe:init(orientation, y)
    self.x = VIRTUAL_WIDTH + 64
    self.y = y

    self.width = PIPE_WIDTH
    self.height = PIPE_HEIGHT

    self.orientation = orientation
end

function Pipe:update(dt)

end

function Pipe:render()
    love.graphics.draw(PIPE_IMAGE, self.x, 
    (self.orientation == 'top' and self.y + PIPE_HEIGHT or self.y), 
    0, 1, self.orientation == 'top' and -1 or 1)
end

main.lua(不确定是否真的相关):

push = require 'push'
Class = require 'class'
require 'StateMachine'

require 'states/BaseState'
require 'states/CountdownState'
require 'states/PlayState'
require 'states/ScoreState'
require 'states/TitleScreenState'

require 'Bird'
require 'Pipe'
require 'PipePair'

WINDOW_WIDTH = 1280
WINDOW_HEIGHT = 720

VIRTUAL_WIDTH = 512
VIRTUAL_HEIGHT = 288

local background = love.graphics.newImage('background.png')
local backgroundScroll = 0

local ground = love.graphics.newImage('ground.png')
local groundScroll = 0

local BACKGROUND_SCROLL_SPEED = 30
local GROUND_SCROLL_SPEED = 60

local BACKGROUND_LOOPING_POINT = 413

function love.load()
    love.graphics.setDefaultFilter('nearest', 'nearest')

    math.randomseed(os.time())

    love.window.setTitle('Fifty Bird')

    smallFont = love.graphics.newFont('font.ttf', 8)
    mediumFont = love.graphics.newFont('flappy.ttf', 14)
    flappyFont = love.graphics.newFont('flappy.ttf', 28)
    hugeFont = love.graphics.newFont('flappy.ttf', 56)
    love.graphics.setFont(flappyFont)

    sounds = {
        ['jump'] = love.audio.newSource('jump.wav', 'static'),
        ['explosion'] = love.audio.newSource('explosion.wav', 'static'),
        ['hurt'] = love.audio.newSource('hurt.wav', 'static'),
        ['score'] = love.audio.newSource('score.wav', 'static'),

        ['music'] = love.audio.newSource('marios_way.mp3', 'static')
    }

    sounds['music']:setLooping(true)
    sounds['music']:play()

    push:setupScreen(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, WINDOW_WIDTH,  WINDOW_HEIGHT, {
        vsync = true,
        fullscreen = false,
        resizable = true
    })

    gStateMachine = StateMachine {
        ['title'] = function() return TitleScreenState() end,
        ['countdown'] = function() return CountdownState() end,
        ['play'] = function() return PlayState() end,
        ['score'] = function() return ScoreState() end
    }
    gStateMachine:change('title')

    love.keyboard.keysPressed = {}

    love.mouse.buttonsPressed = {}
end

function love.resize(w, h)
    push:resize(w, h)
end

function love.keypressed(key)
    love.keyboard.keysPressed[key] = true

    if key == 'escape' then
        love.event.quit()
    end
end

function love.mousepressed(x, y, button)
    love.mouse.buttonsPressed[button] = true
end

function love.keyboard.wasPressed(key)
    return love.keyboard.keysPressed[key]
end

function love.mouse.wasPressed(button)
    return love.mouse.buttonsPressed[button]
end

function love.update(dt)
    backgroundScroll = (backgroundScroll + BACKGROUND_SCROLL_SPEED * dt) % BACKGROUND_LOOPING_POINT
    groundScroll = (groundScroll + GROUND_SCROLL_SPEED * dt) % VIRTUAL_WIDTH

    gStateMachine:update(dt)

    love.keyboard.keysPressed = {}
    love.mouse.buttonsPressed = {}
end

function love.draw()
    push:start()

    love.graphics.draw(background, -backgroundScroll, 0)
    gStateMachine:render()
    love.graphics.draw(ground, -groundScroll, VIRTUAL_HEIGHT - 16)

    push:finish()
end
random lua cs50 love2d
1个回答
0
投票

'随机数需要在每次更新时改变。 但是我不知道在哪里放置随机数生成,该随机数生成将随每次更新而改变,并与 PipePair 和 PlayState 类共享该值。 我该怎么做?'

例子

-- rand.lua
-- Lua 5.1 needs math.randomseed() first
math.randomseed(math.random(math.floor(os.time() * os.clock())))
-- 6 out of 49
local lotto = {} -- Construct a Table
-- Fill it with Numbers you wish to use randomly
for i = 1, 49 do
  table.insert(lotto, i)
end
-- Take six Numbers randomly
for i = 1, 6 do
  local getone = table.remove(lotto, math.random(1, #lotto))
  print(getone)
end
-- Above table.remove() makes sure number is Unique
-- Until table is empty
© www.soinside.com 2019 - 2024. All rights reserved.