如何在LOVE2D中制作死亡动画?

How to make a death animation in LOVE2D?

我在我的游戏中为玩家和敌人创建了碰撞(碰撞并不完美,但在大多数情况下都有效),但我很难弄清楚如何为玩家创建死亡动画。

我想让玩家的飞船在敌人击中你时爆炸,我该怎么做?

这是我的播放器文件:

Player = Class{}


function Player:init(x, y, width, height)
    self.player = {}
    self.x = x
    self.y = y
    self.height = height
    self.dx = 0
    self.image = love.graphics.newImage('images/player.png')
    self.width = self.image:getWidth()
    self.fire_sound = love.audio.newSource('sounds/laser.wav', 'static')
    self.fire_sound:setVolume(.25)
    self.player_explosion = love.audio.newSource('sounds/player_explosion.wav', 'static')
    self.player_explosion:setVolume(25)
    self.cooldown = 10
    self.bullets = {}
end

function Player:update(dt)
    self.x = self.x + self.dx * dt
    if self.x <= 0 then
        self.dx = 0
        self.x = 0
    end
    if self.x >= WINDOW_WIDTH - self.width * 4 then
        self.dx = 0
        self.x = WINDOW_WIDTH - self.width * 4
    end 
end

function Player:fire()
    if self.cooldown <= 0 then
        love.audio.play(player.fire_sound)
        if BULLET_COUNTER >= 1 then
            love.audio.stop(player.fire_sound)
            love.audio.play(player.fire_sound)
            self.cooldown = 30
            bullet = {}
            bullet.x = player.x + 25
            bullet.y = player.y + 5
            table.insert(self.bullets, bullet)
            BULLET_COUNTER = 0
            return
        end
        self.cooldown = 10
        bullet = {}
        bullet.x = self.x + 25
        bullet.y = self.y + 5
        table.insert(self.bullets, bullet)
        BULLET_COUNTER = BULLET_COUNTER + 1
    end
end

function Player:render()
    love.graphics.setColor(255, 255, 255)
    love.graphics.draw(self.image, self.x, self.y, 0, 4)
end

function Player:checkCollision(enemies)
    for i,e in ipairs(enemies) do
        if e.y + e.height >= self.y and e.y <= self.y + self.height and e.x <= self.x + self.width and e.x + e.width >= self.x + self.width then
            love.audio.stop(self.player_explosion)
            love.audio.play(self.player_explosion)
            table.remove(enemies, i)
            LIVES = LIVES - 1
        end
    end
end

如果您需要,这是我的主文件:

Class = require 'class'

require 'Player'

GAME_STATE = 'start'

WINDOW_WIDTH = 720
WINDOW_HEIGHT = 900
love.window.setMode(WINDOW_WIDTH, WINDOW_HEIGHT)

SCORE = 0

LIVES = 3

PLAYER_SPEED = 300

-- map variables
map = {}
map.image = love.graphics.newImage('images/background_final.png')
map.width = 720
map.height = 900
map.music = love.audio.newSource('sounds/Battle-in-the-Stars.wav', 'static')

-- enemy variables
enemy = {}
enemies_controller = {}
enemies_controller.enemies = {}
alienImage = love.graphics.newImage('images/alien2.png')
alienship1_Image = love.graphics.newImage('images/enemyship1.png')
alienship2_Image = love.graphics.newImage('images/enemyship4.png')
enemies_controller.explosion = love.audio.newSource('sounds/explosion.wav', 'static')
enemies_controller.explosion:setVolume(.25)
spawnTimer = 0
spawnTimer_Max = 0.75
SMALL_WIDTH = 70
SMALL_HEIGHT = 70

-- star variables for warp effect
star = {}
stars_controller = {}
stars_controller.stars = {}
starSpawnTimer = 0
starSpawnTimer_Max = 0.25
STAR_WIDTH = 100
STAR_HEIGHT = 100

BULLET_COUNTER = 0

-- this function allows us to scale an image we created to a desired height and width
function getImageScaleForNewDimensions(image, newWidth, newHeight)
    local currentWidth, currentHeight = image:getDimensions()
    return ( newWidth / currentWidth ), ( newHeight / currentHeight )
end

-- check collisions for enemies and bullets
function checkCollisions(enemies, bullets)
    for i,e in ipairs(enemies) do
        for j,b in ipairs(bullets) do
            -- checks if the hitboxes for the bullet and the enemy collide
            -- if they do remove the enemy and the bullet that collided
            if b.y <= e.y + e.height and b.x > e.x and b.x < e.x + e.width then
                love.audio.stop(enemies_controller.explosion)
                table.remove(enemies, i)
                table.remove(bullets, j)
                love.audio.play(enemies_controller.explosion)
                SCORE = SCORE + 10
            end
        end
    end
end


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

    love.window.setTitle('Space Attack')

    title_largeFont = love.graphics.newFont('fonts/Mario-Kart-DS.ttf', 40)
    title_smallFont = love.graphics.newFont('fonts/Mario-Kart-DS.ttf', 20)
    largeFont = love.graphics.newFont('fonts/04B_30__.TTF', 32)
    smallFont = love.graphics.newFont('fonts/04B_30__.TTF', 20)
    love.graphics.setFont(largeFont)

    player = Player(WINDOW_WIDTH / 2 - 40, WINDOW_HEIGHT - 100, 10, 10)

    map.music:setLooping(true)
    map.music:setVolume(.25)
    map.music:play()
end

function enemies_controller:spawnEnemy(x, y, n)
    enemy = {}
    enemy.x = x
    enemy.y = y
    enemy.width = SMALL_WIDTH
    enemy.height = SMALL_HEIGHT
    enemy.bullets = {}
    enemy.cooldown = 10
    -- n is a random variable that determines what type of enemy spawns
    if n == 0 then
        enemy.image = alienImage
        enemy.speed = 5
    elseif n == 1 then
        enemy.image = alienship1_Image
        enemy.speed = 6
    else
        enemy.image = alienship2_Image
        enemy.speed = 7
    end
    table.insert(self.enemies, enemy)
end

function stars_controller:spawnStars(x, y)
    star = {}
    star.x = x
    star.y = y
    star.speed = 10
    star.image = love.graphics.newImage('images/star.png')
    star.width = SMALL_WIDTH
    star.height = SMALL_HEIGHT
    table.insert(self.stars, star)
end

function love.update(dt)
    player.cooldown = player.cooldown - 1

    checkCollisions(enemies_controller.enemies, player.bullets)
    player:checkCollision(enemies_controller.enemies)


    -- checks spawn timer, if > 0 don't spawn an enemy but if it is spawn an enemy
    if spawnTimer > 0 then
        spawnTimer = spawnTimer - dt
    else
        if GAME_STATE == 'play' then
            enemies_controller:spawnEnemy(love.math.random(0, WINDOW_WIDTH - SMALL_WIDTH), 0, love.math.random(0,2))
            spawnTimer = spawnTimer_Max
        end
    end

    -- same situation as spawn timer for enemies, but this is for the warp effect
    if starSpawnTimer > 0 then
        starSpawnTimer = starSpawnTimer - dt
    else
        stars_controller:spawnStars(love.math.random(0, WINDOW_WIDTH - SMALL_WIDTH), 0)
        starSpawnTimer = starSpawnTimer_Max
    end

    -- checking user input to move left and right
    if love.keyboard.isDown('right') then
        if GAME_STATE == 'play' then 
            player.dx = PLAYER_SPEED 
        end
    elseif love.keyboard.isDown('left') then
        if GAME_STATE == 'play' then
            player.dx = -PLAYER_SPEED
        end
    else
        player.dx = 0
    end

    -- checking user input for firing function
    if love.keyboard.isDown('space') then
        if GAME_STATE == 'play' then
            player:fire()
        end
    end

    -- this removes enemies if they are too far off the scree
    -- also how the enemies move downards
    -- NEED TO ADD MOVEMENT FUNCTIONS HERE FOR DIFFERENT ENEMIES
    for i,e in ipairs(enemies_controller.enemies) do
        e.y = e.y + e.speed
        if e.y > WINDOW_HEIGHT then
            table.remove(enemies_controller.enemies, i)
        end
    end

    -- removes bullets if they travel too far off the screen
    -- this also moves the bullets upwards
    for i,v in ipairs(player.bullets) do
        if v.y < 0 then
            table.remove(player.bullets, i)
        end
        v.y = v.y - 8
    end 

    -- removes stars if they travel too far off screen
    -- moves the stars to create warp effect
    for i,s in ipairs(stars_controller.stars) do
        s.y = s.y + s.speed
        if s.y > WINDOW_HEIGHT then
            table.remove(stars_controller.stars, i)
        end
    end

    -- checks lives to determine game state
    if LIVES == 0 then
        GAME_STATE = 'end'
    end

    player:update(dt)
end

-- key pressed function so we can exit the game and start the game
function love.keypressed(key)
    if key == 'escape' then 
        love.event.quit()
    elseif key == 'enter' or key == 'return' then
        if GAME_STATE == 'start' then
            GAME_STATE = 'play'
        end
    end
end


function love.draw()

    -- checks gamestate and if it is
    if GAME_STATE == 'start' then
        -- draw the warp effect
        for _,s in pairs(stars_controller.stars) do
            local scaleX, scaleY = getImageScaleForNewDimensions(s.image, STAR_WIDTH, STAR_HEIGHT)
            love.graphics.draw(s.image, s.x, s.y, 0, 2, 4)
        end

        -- draw the player 
        player:render()

        love.graphics.setColor(200, 0, 200, 255)
        love.graphics.setFont(title_largeFont)
        love.graphics.print('WELCOME TO SPACE ATTACK!', WINDOW_WIDTH / 2 - 290, WINDOW_HEIGHT / 2)
        love.graphics.setFont(title_smallFont)
        love.graphics.print('press ENTER to begin!', WINDOW_WIDTH / 2 - 110, WINDOW_HEIGHT / 2 + 100)
    end

    if GAME_STATE == 'play' then
        -- draw the map
        love.graphics.setColor(255, 255, 255)
        local map_width, map_height = getImageScaleForNewDimensions(map.image, map.width, map.height)
        love.graphics.draw(map.image, 0, 0, 0, map_width, map_height)

        -- draw the enemies
        for _,e in pairs(enemies_controller.enemies) do
            local scaleX, scaleY = getImageScaleForNewDimensions(e.image, SMALL_WIDTH, SMALL_HEIGHT)
            love.graphics.draw(e.image, e.x, e.y, 0, scaleX, scaleY)
        end

        -- draw the warp effect
        for _,s in pairs(stars_controller.stars) do
            love.graphics.draw(s.image, s.x, s.y, 0, 1, 4)
        end

        -- draw the player
        player:render()

        -- draw the bullets
        love.graphics.setColor(255, 255, 255)
        for _,v in pairs(player.bullets) do
            love.graphics.rectangle('fill', v.x, v.y, 10, 10)
        end

        displayScore()
        displayLives()
    end

    if GAME_STATE == 'end' then
        love.audio.stop()
        love.graphics.setColor(200, 0, 200, 255)
        love.graphics.setFont(title_largeFont)
        love.graphics.print('GAME OVER!', WINDOW_WIDTH / 2 - 120, WINDOW_HEIGHT / 2)
        love.graphics.setFont(title_smallFont)
        love.graphics.print('score  ' .. tostring(SCORE), WINDOW_WIDTH / 2 - 60, WINDOW_HEIGHT / 2 + 50)
    end
end

function displayScore()
    if GAME_STATE == 'play' then
        love.graphics.setColor(0, 255, 0, 255)
        love.graphics.setFont(largeFont)
        love.graphics.print('Score: ' .. tostring(SCORE), WINDOW_WIDTH / 2 - 130, 10)
    end
end

function displayLives()
    if GAME_STATE == 'play' then
        love.graphics.setColor(255, 0, 0, 255)
        love.graphics.setFont(smallFont)
        love.graphics.print('Lives: ' .. tostring(LIVES), WINDOW_WIDTH - 150, 10)
    end
end 

I want the player's ship to explode when the enemies hit you, how would I go about this?

我假设您问的是创建爆炸的实际视觉效果。 LÖVE 的 particle system 具有创建此类动画/效果的所有功能,但如果您刚刚开始,可能会有点矫枉过正。

一个简单的替代方法是移除玩家的飞船并用爆炸的动画精灵替换它。您可以使用 library 来为您处理动画代码,或者仅将其用作您自己的动画代码的参考点。

动画通常由多个帧或图像组成,这些帧或图像按顺序显示。例如。一个非常简单的动画可能如下所示:

  1. 帧:小爆炸
  2. 帧:爆炸变大
  3. 帧:爆炸再次变小
  4. 帧:烟雾出现
  5. 帧:烟雾消失,动画结束

这些帧中的每一个都将包含在一个大图像或 spritesheet 中。

在 LÖVE 中你必须 load the spritesheet and divide it into its frames by using quads:

local spritesheet = love.graphics.newImage("animation.png")

-- Create a quad for each frame in the spritesheet.
-- Here we assume that each frame is a 16x16 square inside of the spritesheet.
local animation = {
    love.graphics.newQuad(0, 0, 16, 16, spritesheet:getDimensions()),
    love.graphics.newQuad(16, 0, 16, 16, spritesheet:getDimensions()),
    -- more frames
}

-- To display the animation we draw one quad each frame and then update the index variable.
-- Of course in a real game you'd add a delay between each frame and check for the boundaries 
-- of the array and so on.
local i = 1
function love.draw()
    love.graphics.draw(spritesheet, animation[i], 50, 50)
    i = i + 1
end

这不是一个完美的例子,但我希望它展示了动画如何工作的一般概念。