使 Sprite 在 Lua 中消失
Making a Sprite Disappear in Lua
这里是 Lua 和 Love2D 的新手!我正在尝试完成我正在参加的在线课程的期末项目,我想知道如何让精灵消失。目前,我拥有它,所以玩家在一个 class 中,而与地图(如瓷砖和背景)有关的任何东西都在另一个中。我想这样写,如果玩家击中特定的方块,则该方块消失,并且计数器上升。我知道关于 cs50 gamedev course with balls 也有类似的问题,但我不太了解代码,所以我希望有人能帮助我。我的 map.lua
看起来像这样:
require 'Util'
require 'Player'
Map = Class{}
-- Storing where all the sprites are in the tile spritesheet
EMPTY = 1
LID = 2
SUSHI1 = 3
SUSHI2 = 4
-- Storing where the background should be
BACKGROUND = 1
-- Scroll speed for the camera
local SCROLL_SPEED = 200
function Map:init()
-- Storing the spritesheet
self.background = love.graphics.newImage('Graphics/platform/NEW/back2.png')
self.spritesheet = love.graphics.newImage('Graphics/platform/newplatforms/all.png')
-- Storing the width and height of each sprite AND background width and height
self.backgroundWidth = 500
self.backgroundHeight = 2000
self.tileWidth = 35
self.tileHeight = 15
-- Creating a player object so that it has access to the map properties
-- Passing in the self object for that specific reason
self.player = Player(self)
-- Table to contain all the tile sprites
self.tiles = {}
-- Table to contain all the background sprites
self.back = {}
-- Stores the map width and height
-- NOTE that these values are chosen through experimentation
self.mapWidth = 15
self.mapHeight = 133
-- Cutting the sprites of the sheet AND background
self.backgroundSprites = generateQuads(self.background, self.backgroundWidth, self.backgroundHeight)
self.tileSprites = generateQuads(self.spritesheet, self.tileWidth, self.tileHeight)
-- Setting the camera values
self.camX = 0
self.camY = self.backgroundHeight - VIRTUAL_HEIGHT
-- Setting the background tiles
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
self:setTileBackground(x, y, BACKGROUND)
end
end
-- Setting all the tiles initially to be empty
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
self:setTile(x, y, EMPTY)
end
end
-- Setting the initial floor
for x = 1, self.mapWidth do
self:setTile(x, self.mapHeight, LID)
end
------------------------------------------------- START OF MAP CREATION -------------------------------------------------
local y = 1
-- variable to help with the twist
local location = 5
while y < self.mapHeight do
-- Make sure we're at least 6 tiles away from the bottom
-- START OF EVERYTHING
if y < self.mapHeight - 1 and y > 3 then
-- FOR THE FIRST QUARTER OF THE MAP
if y > self.mapHeight * 2/3 then
for counter = 1, self.mapWidth / 2.5 do
-- As long as location isn't max, keep incrementing
-- NOTICE THE - 7 TO KEEP IT ON ONE SIDE
if location < self.mapWidth - 7 then
location = location + 1
-- If location goes to max, then reset
else
location = 1
end
-- Set the tile in the appropriate location
self:setTile(location, y, LID)
end
-- FOR THE SECOND QUARTER OF THE MAP, HARDER
elseif y < self.mapHeight * 2/3 and y > self.mapHeight * 1/3 then
for counter = 1, self.mapWidth / 2.5 do
-- As long as location isn't max, keep incrementing
if location < self.mapWidth then
location = location + 1
-- If location goes to max, then reset
else
location = 1
end
-- Set the tile in the appropriate location
-- CHANGING BETWEEN SUSHI COVERS
if (counter % 2 == 0) then
self:setTile(location, y, SUSHI1)
else
self:setTile(location, y, SUSHI2)
end
end
-- FOR THE LAST QUARTER OF THE MAP
else
for counter = 1, self.mapWidth / 2.5 do
-- As long as location isn't max, keep incrementing
if location < self.mapWidth then
location = location + 1
-- If location goes to max, then reset
else
location = 1
end
-- Set the tile in the appropriate location
-- CHANGING BETWEEN SUSHI COVERS
if (counter % 2 == 0) then
self:setTile(location, y, SUSHI1)
else
self:setTile(location, y, SUSHI2)
end
end
end
end
-- INCREMENTING SCANLINE
y = y + 4
end
end
-- Function to 'Set' what the background tiles should be in the map
function Map:setTileBackground(x, y, tile)
self.back[(y - 1) * self.mapWidth + x] = tile
end
-- Function to 'Set' what the tiles should be in the map
function Map:setTile(x, y, id)
self.tiles[(y - 1) * self.mapWidth + x] = id
end
-- Function to get the ID of the tile at a certain location
-- This passes the map in as pixel coordinates rather than tile IDs
-- The x and y here are pixel values, getting the tile at that pixel location
-- Note that getTile gets the tile as a TILE, and so needed adjustment
-- The + 1 is because pixel values would make it go back to a pixel based system, and that's
-- 0 indexed. Instead, we want it to be 1 indexed
function Map:tileAt(x, y)
return {
x = math.floor(x / self.tileWidth) + 1,
y = math.floor(y / self.tileHeight) + 1,
id = self:getTile(math.floor(x / self.tileWidth) + 1, math.floor(y / self.tileHeight) + 1)
}
end
-- Function to figure out what background tile should be in the map
function Map:getTileBackground(x, y)
return self.back[(y - 1) * self.mapWidth + x]
end
-- Function to figure out what tile should be in the map
function Map:getTile(x, y)
return self.tiles[(y - 1) * self.mapWidth + x]
end
-- Function to define what the collidables are
function Map:collides(tile)
-- Define the collidable tiles. It contains the
-- constants of the tiles that are considered solid
local collidables = {
LID, SUSHI1, SUSHI2
}
-- This is the function that will be used to check if the tile id that's under us matches
--the collidables. It's essentially saying for every key/value pair for ipairs which is
-- iterating through all the k/v pairs, and the _ just means index. We aren't using the
-- key here so it doesn't matter anyway
for _, v in ipairs(collidables) do
if tile.id == v then
return true
end
end
-- Return false if it isn't a collidable
return false
end
function Map:update(dt)
-- Updating the player
self.player:update(dt)
-- keep camera's coordinate following the player, preventing camera from
-- scrolling past 0 to the left and the map's width
self.camX = math.max(0, math.min(self.player.x - VIRTUAL_WIDTH / 2,
math.min(self.backgroundWidth - VIRTUAL_WIDTH, self.player.x)))
self.camY = math.max(0, math.min(self.player.y - VIRTUAL_HEIGHT * 0.815,
math.max(self.backgroundHeight - VIRTUAL_HEIGHT, self.player.y)))
end
function Map:render()
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
love.graphics.draw(self.background, self.backgroundSprites[self:getTileBackground(x, y)],
(x - 1) * self.backgroundWidth, (y - 1) * self.backgroundHeight)
love.graphics.draw(self.spritesheet, self.tileSprites[self:getTile(x, y)],
(x - 1) * self.tileWidth, (y - 1) * self.tileHeight)
end
end
self.player:render()
end
我的 player.lua
文件如下所示:
Player = Class{}
require 'Animation'
-- Know where everything is in the sheet
STEVEN_JUMP = 1
STEVEN_IDLE = 2
STEVEN_WALK1 = 3
STEVEN_WALK2 = 4
-- Setting the movement speed
local MOVE_SPEED = 100
-- Jump velocity, gravity velocity
local JUMP_VELOCITY = 700
local GRAVITY = 40
function Player:init(map)
-- Initializing the x and y coordinates of the character
-- NOTE that for the y to be at the bottom, we must subtract the 30 of the platform, and 30
-- of Steven himself
self.x = map.tileWidth * 5 -- Essentially 300 pixels to the right
self.y = map.backgroundHeight - 45
-- Storing the width and height of the spritesheet
self.width = 32
self.height = 30
-- The dx and dy variables
self.dx = 0
self.dy = 0
-- Easier to type this way
self.map = map
-- Storing the spritesheet for Steven
self.playerSheet = love.graphics.newImage('Graphics/platform/steven/all.png')
-- Splicing up the spritesheet
self.frames = generateQuads(self.playerSheet, self.width, self.height)
-- INITIAL STATE
self.state = 'idle'
-- DIRECTION THE CHARACTER IS FACING, DEFAULT
self.direction = 'right'
--Animation table
-- Each takes as an argument the parameters that we used in the Animation
-- function in the next page, and so it needs textures, frames, etc
self.animations = {
-- IDLE ANIMATION TABLE
-- Notice that the {} is meant to be an argument into the Animation function,
-- or class, but since it's only a table, we don't need to put ({}) but can just
-- put {}
['idle'] = Animation {
-- The texture that we'll use
texture = self.texture,
-- The frames that we're going to use
frames = {
self.frames[2]
},
-- Interval between frames
interval = 1
},
['walking'] = Animation {
texture = self.texture,
frames = {
self.frames[3], self.frames[4]
},
interval = 0.15
},
['jumping'] = Animation {
texture = self.texture,
frames = {
self.frames[1]
},
interval = 1
}
}
-- What the current animation is
self.animation = self.animations['idle']
self.currentFrame = self.animation:getCurrentFrame()
-- Checking the states, returns a function as keys
self.behaviors = {
['idle'] = function(dt)
-- JUMPING STEVEN
-- Notice how we need to create a wasPressed function as it's a one-time press
if love.keyboard.wasPressed('space') then
-- Set the velocity upwards so negative
self.dy = -JUMP_VELOCITY
-- Change the state
self.state = 'jumping'
-- Change the animation
self.animation = self.animations['jumping']
-- STEVEN MOVES
elseif love.keyboard.isDown('a') then
-- Change the direction
self.direction = 'left'
-- left movement
self.dx = -MOVE_SPEED
-- Change the state
self.state = 'walking'
-- Resetting the animation
self.animations['walking']:restart()
-- Change the animation
self.animation = self.animations['walking']
elseif love.keyboard.isDown('d') then
-- Change the direction
self.direction = 'right'
-- right movement
self.dx = MOVE_SPEED
-- Change the state
self.state = 'walking'
-- Reset the animation
self.animations['walking']:restart()
-- Change the animation
self.animation = self.animations['walking']
else
-- If we aren't pressing a or d, make him idle
self.dx = 0
end
end,
['walking'] = function(dt)
if love.keyboard.wasPressed('space') then
-- Set the velocity upwards so negative
self.dy = -JUMP_VELOCITY
self.state = 'jumping'
-- Change the animation
self.animation = self.animations['jumping']
-- STEVEN MOVES
elseif love.keyboard.isDown('a') then
-- Change the direction
self.direction = 'left'
-- left movement
self.dx = -MOVE_SPEED
-- Change the animation
self.animation = self.animations['walking']
elseif love.keyboard.isDown('d') then
-- Change the direction
self.direction = 'right'
-- right movement
-- Notice we add 80 to account for that weird slow-mo here
self.dx = MOVE_SPEED
-- Change the animation
self.animation = self.animations['walking']
else
-- If we aren't pressing a or d, make him idle
self.dx = 0
self.state = 'idle'
self.animation = self.animations['idle']
end
-- check if there's a tile directly beneath us
if not self.map:collides(self.map:tileAt(self.x, self.y + self.height)) and
not self.map:collides(self.map:tileAt(self.x + self.width - 1, self.y + self.height)) then
-- if so, reset velocity and position and change state
self.state = 'jumping'
self.animation = self.animations['jumping']
end
end,
['jumping'] = function(dt)
------------------------------------------- TO DO IF PLAYER GOES UNDER CAMERA BOTTOM ------------------------------------------------------------
-- break if we go below the surface
if self.y > self.map.backgroundHeight then
end
-- This is to change and manuever in the air
if love.keyboard.isDown('a') then
self.direction = 'left'
-- Change the moving velocity
self.dx = -MOVE_SPEED
elseif love.keyboard.isDown('d') then
self.direction = 'right'
-- Change the moving velocity
self.dx = MOVE_SPEED
end
-- Setting the y velocity
self.dy = self.dy + GRAVITY
-- check if there's a tile directly beneath us
if self.map:collides(self.map:tileAt(self.x, self.y + self.height)) or
self.map:collides(self.map:tileAt(self.x + self.width - 1, self.y + self.height)) and self.dy < 0 then
-- if so, reset velocity and position and change state
self.dy = 0
self.state = 'idle'
self.animation = self.animations['idle']
self.y = (self.map:tileAt(self.x, self.y + self.height).y - 1) * self.map.tileHeight - self.height
end
end
}
end
function Player:update(dt)
-- Calling the behaviors as a function
self.behaviors[self.state](dt)
--Updating the animation
self.animation:update(dt)
-- Get the current frame
self.currentFrame = self.animation:getCurrentFrame()
-- Changing the velocities
self.x = self.x + self.dx * dt
self.y = self.y + self.dy * dt
end
function Player:render()
-- NOTE the X scaling factor, which is -1 as in to flip if it's right
local scaleX
if self.direction == 'right' then
scaleX = 1
else
scaleX = -1
end
-- Drawing the character initially
-- NOTE the extra arguments to change the rotation and OFFSET/FLIP
-- 0 is the initial rotation, which we don't want
-- Scaling by -1 changes it to flipping to their right corner, not left, and so
-- we need to move the origin point (which is initially the top left) to the center
-- as we want it to change place wrt the origin
-- The 1 is scaling 1 by Y
-- The last 2 arguments are adding the offset of whatever its width and height are
-- ALSO need to account for the origin (since it draws it from the origin) to make
-- sure Steven isn't floating
love.graphics.draw(self.playerSheet, self.currentFrame, math.floor(self.x + self.width / 2), math.floor(self.y + self.height / 2),
0, scaleX, 1,
self.width / 2, self.height / 2)
end
我想做的是,如果玩家跳到 SUSHI2
方块上,它就会消失。
抱歉这么久 post。我真的很想尽我最大的努力,我正在尝试添加尽可能多的普通游戏,但我是 gamelogic 的新手,我不确定如何从屏幕上“删除”一个图块。我问这主要是为了稍后实现如何在敌人死亡时移除整个敌人,这样它就会有某种健康栏,当它达到 0 时,角色将不再出现在屏幕上,因为我'假设这将是相同的逻辑。或者,一旦一些子弹击中敌人,它们就会从屏幕上消失。无论如何,我们将不胜感激! (我附上了一张游戏现在的样子的图片,如果有帮助的话,我指的是哪个方块)
meow meow
您的代码似乎可以处理碰撞,我假设它可以工作,我的猜测是将您碰撞的 SHUSHI2 单元格替换为 EMPTY 网格中的单元格值,因此它会被 销毁 。假设你想在坠落时摧毁一个 SUSHI2 方块,你可以采用以下解决方案:
--> Player.behaviors.walking :
-- check if there's a tile directly beneath us
-- Let's add a local for the example
local tile_we_re_falling_on = self.map:tileAt(self.x, self.y + self.height)
if self.map:collides(tile_we_re_falling_on) or
self.map:collides(self.map:tileAt(self.x + self.width - 1, self.y + self.height)) and self.dy < 0 then
if self.dy > 0 and tile_we_re_falling_on.id == SUSHI2 then -- We're falling on a SUSHI2 block/tile
-- Overwrite the tile to EMPTY
self.map:setTile(tile_we_re_falling_on.x, tile_we_re_falling_on.y, EMPTY)
-- Increment some counter, maybe?
end
-- if so, reset velocity and position and change state
self.dy = 0
self.state = 'idle'
self.animation = self.animations['idle']
self.y = (self.map:tileAt(self.x, self.y + self.height).y - 1) * self.map.tileHeight - self.height
end
希望我理解了您的问题,希望对您有所帮助。您可能想要清理它,感觉有点老套,但展示了这个想法。
另一件事是,当您在游戏 tick 中改变世界时,其他一些代码可能会假设它没有改变,这可能会导致一些奇怪的行为。当所有更新逻辑具有 运行 而不是 in-between 更新步骤时,一种常见的做法是 延迟 在帧的 begin/end 改变世界,也就是说,您将保存 tile id (x=2, y=43) 需要更改为 EMPTY 的事实,并将在更新函数结束时应用更改。在这种情况下,我相信它会很好。
这里是 Lua 和 Love2D 的新手!我正在尝试完成我正在参加的在线课程的期末项目,我想知道如何让精灵消失。目前,我拥有它,所以玩家在一个 class 中,而与地图(如瓷砖和背景)有关的任何东西都在另一个中。我想这样写,如果玩家击中特定的方块,则该方块消失,并且计数器上升。我知道关于 cs50 gamedev course with balls 也有类似的问题,但我不太了解代码,所以我希望有人能帮助我。我的 map.lua
看起来像这样:
require 'Util'
require 'Player'
Map = Class{}
-- Storing where all the sprites are in the tile spritesheet
EMPTY = 1
LID = 2
SUSHI1 = 3
SUSHI2 = 4
-- Storing where the background should be
BACKGROUND = 1
-- Scroll speed for the camera
local SCROLL_SPEED = 200
function Map:init()
-- Storing the spritesheet
self.background = love.graphics.newImage('Graphics/platform/NEW/back2.png')
self.spritesheet = love.graphics.newImage('Graphics/platform/newplatforms/all.png')
-- Storing the width and height of each sprite AND background width and height
self.backgroundWidth = 500
self.backgroundHeight = 2000
self.tileWidth = 35
self.tileHeight = 15
-- Creating a player object so that it has access to the map properties
-- Passing in the self object for that specific reason
self.player = Player(self)
-- Table to contain all the tile sprites
self.tiles = {}
-- Table to contain all the background sprites
self.back = {}
-- Stores the map width and height
-- NOTE that these values are chosen through experimentation
self.mapWidth = 15
self.mapHeight = 133
-- Cutting the sprites of the sheet AND background
self.backgroundSprites = generateQuads(self.background, self.backgroundWidth, self.backgroundHeight)
self.tileSprites = generateQuads(self.spritesheet, self.tileWidth, self.tileHeight)
-- Setting the camera values
self.camX = 0
self.camY = self.backgroundHeight - VIRTUAL_HEIGHT
-- Setting the background tiles
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
self:setTileBackground(x, y, BACKGROUND)
end
end
-- Setting all the tiles initially to be empty
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
self:setTile(x, y, EMPTY)
end
end
-- Setting the initial floor
for x = 1, self.mapWidth do
self:setTile(x, self.mapHeight, LID)
end
------------------------------------------------- START OF MAP CREATION -------------------------------------------------
local y = 1
-- variable to help with the twist
local location = 5
while y < self.mapHeight do
-- Make sure we're at least 6 tiles away from the bottom
-- START OF EVERYTHING
if y < self.mapHeight - 1 and y > 3 then
-- FOR THE FIRST QUARTER OF THE MAP
if y > self.mapHeight * 2/3 then
for counter = 1, self.mapWidth / 2.5 do
-- As long as location isn't max, keep incrementing
-- NOTICE THE - 7 TO KEEP IT ON ONE SIDE
if location < self.mapWidth - 7 then
location = location + 1
-- If location goes to max, then reset
else
location = 1
end
-- Set the tile in the appropriate location
self:setTile(location, y, LID)
end
-- FOR THE SECOND QUARTER OF THE MAP, HARDER
elseif y < self.mapHeight * 2/3 and y > self.mapHeight * 1/3 then
for counter = 1, self.mapWidth / 2.5 do
-- As long as location isn't max, keep incrementing
if location < self.mapWidth then
location = location + 1
-- If location goes to max, then reset
else
location = 1
end
-- Set the tile in the appropriate location
-- CHANGING BETWEEN SUSHI COVERS
if (counter % 2 == 0) then
self:setTile(location, y, SUSHI1)
else
self:setTile(location, y, SUSHI2)
end
end
-- FOR THE LAST QUARTER OF THE MAP
else
for counter = 1, self.mapWidth / 2.5 do
-- As long as location isn't max, keep incrementing
if location < self.mapWidth then
location = location + 1
-- If location goes to max, then reset
else
location = 1
end
-- Set the tile in the appropriate location
-- CHANGING BETWEEN SUSHI COVERS
if (counter % 2 == 0) then
self:setTile(location, y, SUSHI1)
else
self:setTile(location, y, SUSHI2)
end
end
end
end
-- INCREMENTING SCANLINE
y = y + 4
end
end
-- Function to 'Set' what the background tiles should be in the map
function Map:setTileBackground(x, y, tile)
self.back[(y - 1) * self.mapWidth + x] = tile
end
-- Function to 'Set' what the tiles should be in the map
function Map:setTile(x, y, id)
self.tiles[(y - 1) * self.mapWidth + x] = id
end
-- Function to get the ID of the tile at a certain location
-- This passes the map in as pixel coordinates rather than tile IDs
-- The x and y here are pixel values, getting the tile at that pixel location
-- Note that getTile gets the tile as a TILE, and so needed adjustment
-- The + 1 is because pixel values would make it go back to a pixel based system, and that's
-- 0 indexed. Instead, we want it to be 1 indexed
function Map:tileAt(x, y)
return {
x = math.floor(x / self.tileWidth) + 1,
y = math.floor(y / self.tileHeight) + 1,
id = self:getTile(math.floor(x / self.tileWidth) + 1, math.floor(y / self.tileHeight) + 1)
}
end
-- Function to figure out what background tile should be in the map
function Map:getTileBackground(x, y)
return self.back[(y - 1) * self.mapWidth + x]
end
-- Function to figure out what tile should be in the map
function Map:getTile(x, y)
return self.tiles[(y - 1) * self.mapWidth + x]
end
-- Function to define what the collidables are
function Map:collides(tile)
-- Define the collidable tiles. It contains the
-- constants of the tiles that are considered solid
local collidables = {
LID, SUSHI1, SUSHI2
}
-- This is the function that will be used to check if the tile id that's under us matches
--the collidables. It's essentially saying for every key/value pair for ipairs which is
-- iterating through all the k/v pairs, and the _ just means index. We aren't using the
-- key here so it doesn't matter anyway
for _, v in ipairs(collidables) do
if tile.id == v then
return true
end
end
-- Return false if it isn't a collidable
return false
end
function Map:update(dt)
-- Updating the player
self.player:update(dt)
-- keep camera's coordinate following the player, preventing camera from
-- scrolling past 0 to the left and the map's width
self.camX = math.max(0, math.min(self.player.x - VIRTUAL_WIDTH / 2,
math.min(self.backgroundWidth - VIRTUAL_WIDTH, self.player.x)))
self.camY = math.max(0, math.min(self.player.y - VIRTUAL_HEIGHT * 0.815,
math.max(self.backgroundHeight - VIRTUAL_HEIGHT, self.player.y)))
end
function Map:render()
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
love.graphics.draw(self.background, self.backgroundSprites[self:getTileBackground(x, y)],
(x - 1) * self.backgroundWidth, (y - 1) * self.backgroundHeight)
love.graphics.draw(self.spritesheet, self.tileSprites[self:getTile(x, y)],
(x - 1) * self.tileWidth, (y - 1) * self.tileHeight)
end
end
self.player:render()
end
我的 player.lua
文件如下所示:
Player = Class{}
require 'Animation'
-- Know where everything is in the sheet
STEVEN_JUMP = 1
STEVEN_IDLE = 2
STEVEN_WALK1 = 3
STEVEN_WALK2 = 4
-- Setting the movement speed
local MOVE_SPEED = 100
-- Jump velocity, gravity velocity
local JUMP_VELOCITY = 700
local GRAVITY = 40
function Player:init(map)
-- Initializing the x and y coordinates of the character
-- NOTE that for the y to be at the bottom, we must subtract the 30 of the platform, and 30
-- of Steven himself
self.x = map.tileWidth * 5 -- Essentially 300 pixels to the right
self.y = map.backgroundHeight - 45
-- Storing the width and height of the spritesheet
self.width = 32
self.height = 30
-- The dx and dy variables
self.dx = 0
self.dy = 0
-- Easier to type this way
self.map = map
-- Storing the spritesheet for Steven
self.playerSheet = love.graphics.newImage('Graphics/platform/steven/all.png')
-- Splicing up the spritesheet
self.frames = generateQuads(self.playerSheet, self.width, self.height)
-- INITIAL STATE
self.state = 'idle'
-- DIRECTION THE CHARACTER IS FACING, DEFAULT
self.direction = 'right'
--Animation table
-- Each takes as an argument the parameters that we used in the Animation
-- function in the next page, and so it needs textures, frames, etc
self.animations = {
-- IDLE ANIMATION TABLE
-- Notice that the {} is meant to be an argument into the Animation function,
-- or class, but since it's only a table, we don't need to put ({}) but can just
-- put {}
['idle'] = Animation {
-- The texture that we'll use
texture = self.texture,
-- The frames that we're going to use
frames = {
self.frames[2]
},
-- Interval between frames
interval = 1
},
['walking'] = Animation {
texture = self.texture,
frames = {
self.frames[3], self.frames[4]
},
interval = 0.15
},
['jumping'] = Animation {
texture = self.texture,
frames = {
self.frames[1]
},
interval = 1
}
}
-- What the current animation is
self.animation = self.animations['idle']
self.currentFrame = self.animation:getCurrentFrame()
-- Checking the states, returns a function as keys
self.behaviors = {
['idle'] = function(dt)
-- JUMPING STEVEN
-- Notice how we need to create a wasPressed function as it's a one-time press
if love.keyboard.wasPressed('space') then
-- Set the velocity upwards so negative
self.dy = -JUMP_VELOCITY
-- Change the state
self.state = 'jumping'
-- Change the animation
self.animation = self.animations['jumping']
-- STEVEN MOVES
elseif love.keyboard.isDown('a') then
-- Change the direction
self.direction = 'left'
-- left movement
self.dx = -MOVE_SPEED
-- Change the state
self.state = 'walking'
-- Resetting the animation
self.animations['walking']:restart()
-- Change the animation
self.animation = self.animations['walking']
elseif love.keyboard.isDown('d') then
-- Change the direction
self.direction = 'right'
-- right movement
self.dx = MOVE_SPEED
-- Change the state
self.state = 'walking'
-- Reset the animation
self.animations['walking']:restart()
-- Change the animation
self.animation = self.animations['walking']
else
-- If we aren't pressing a or d, make him idle
self.dx = 0
end
end,
['walking'] = function(dt)
if love.keyboard.wasPressed('space') then
-- Set the velocity upwards so negative
self.dy = -JUMP_VELOCITY
self.state = 'jumping'
-- Change the animation
self.animation = self.animations['jumping']
-- STEVEN MOVES
elseif love.keyboard.isDown('a') then
-- Change the direction
self.direction = 'left'
-- left movement
self.dx = -MOVE_SPEED
-- Change the animation
self.animation = self.animations['walking']
elseif love.keyboard.isDown('d') then
-- Change the direction
self.direction = 'right'
-- right movement
-- Notice we add 80 to account for that weird slow-mo here
self.dx = MOVE_SPEED
-- Change the animation
self.animation = self.animations['walking']
else
-- If we aren't pressing a or d, make him idle
self.dx = 0
self.state = 'idle'
self.animation = self.animations['idle']
end
-- check if there's a tile directly beneath us
if not self.map:collides(self.map:tileAt(self.x, self.y + self.height)) and
not self.map:collides(self.map:tileAt(self.x + self.width - 1, self.y + self.height)) then
-- if so, reset velocity and position and change state
self.state = 'jumping'
self.animation = self.animations['jumping']
end
end,
['jumping'] = function(dt)
------------------------------------------- TO DO IF PLAYER GOES UNDER CAMERA BOTTOM ------------------------------------------------------------
-- break if we go below the surface
if self.y > self.map.backgroundHeight then
end
-- This is to change and manuever in the air
if love.keyboard.isDown('a') then
self.direction = 'left'
-- Change the moving velocity
self.dx = -MOVE_SPEED
elseif love.keyboard.isDown('d') then
self.direction = 'right'
-- Change the moving velocity
self.dx = MOVE_SPEED
end
-- Setting the y velocity
self.dy = self.dy + GRAVITY
-- check if there's a tile directly beneath us
if self.map:collides(self.map:tileAt(self.x, self.y + self.height)) or
self.map:collides(self.map:tileAt(self.x + self.width - 1, self.y + self.height)) and self.dy < 0 then
-- if so, reset velocity and position and change state
self.dy = 0
self.state = 'idle'
self.animation = self.animations['idle']
self.y = (self.map:tileAt(self.x, self.y + self.height).y - 1) * self.map.tileHeight - self.height
end
end
}
end
function Player:update(dt)
-- Calling the behaviors as a function
self.behaviors[self.state](dt)
--Updating the animation
self.animation:update(dt)
-- Get the current frame
self.currentFrame = self.animation:getCurrentFrame()
-- Changing the velocities
self.x = self.x + self.dx * dt
self.y = self.y + self.dy * dt
end
function Player:render()
-- NOTE the X scaling factor, which is -1 as in to flip if it's right
local scaleX
if self.direction == 'right' then
scaleX = 1
else
scaleX = -1
end
-- Drawing the character initially
-- NOTE the extra arguments to change the rotation and OFFSET/FLIP
-- 0 is the initial rotation, which we don't want
-- Scaling by -1 changes it to flipping to their right corner, not left, and so
-- we need to move the origin point (which is initially the top left) to the center
-- as we want it to change place wrt the origin
-- The 1 is scaling 1 by Y
-- The last 2 arguments are adding the offset of whatever its width and height are
-- ALSO need to account for the origin (since it draws it from the origin) to make
-- sure Steven isn't floating
love.graphics.draw(self.playerSheet, self.currentFrame, math.floor(self.x + self.width / 2), math.floor(self.y + self.height / 2),
0, scaleX, 1,
self.width / 2, self.height / 2)
end
我想做的是,如果玩家跳到 SUSHI2
方块上,它就会消失。
抱歉这么久 post。我真的很想尽我最大的努力,我正在尝试添加尽可能多的普通游戏,但我是 gamelogic 的新手,我不确定如何从屏幕上“删除”一个图块。我问这主要是为了稍后实现如何在敌人死亡时移除整个敌人,这样它就会有某种健康栏,当它达到 0 时,角色将不再出现在屏幕上,因为我'假设这将是相同的逻辑。或者,一旦一些子弹击中敌人,它们就会从屏幕上消失。无论如何,我们将不胜感激! (我附上了一张游戏现在的样子的图片,如果有帮助的话,我指的是哪个方块) meow meow
您的代码似乎可以处理碰撞,我假设它可以工作,我的猜测是将您碰撞的 SHUSHI2 单元格替换为 EMPTY 网格中的单元格值,因此它会被 销毁 。假设你想在坠落时摧毁一个 SUSHI2 方块,你可以采用以下解决方案:
--> Player.behaviors.walking :
-- check if there's a tile directly beneath us
-- Let's add a local for the example
local tile_we_re_falling_on = self.map:tileAt(self.x, self.y + self.height)
if self.map:collides(tile_we_re_falling_on) or
self.map:collides(self.map:tileAt(self.x + self.width - 1, self.y + self.height)) and self.dy < 0 then
if self.dy > 0 and tile_we_re_falling_on.id == SUSHI2 then -- We're falling on a SUSHI2 block/tile
-- Overwrite the tile to EMPTY
self.map:setTile(tile_we_re_falling_on.x, tile_we_re_falling_on.y, EMPTY)
-- Increment some counter, maybe?
end
-- if so, reset velocity and position and change state
self.dy = 0
self.state = 'idle'
self.animation = self.animations['idle']
self.y = (self.map:tileAt(self.x, self.y + self.height).y - 1) * self.map.tileHeight - self.height
end
希望我理解了您的问题,希望对您有所帮助。您可能想要清理它,感觉有点老套,但展示了这个想法。
另一件事是,当您在游戏 tick 中改变世界时,其他一些代码可能会假设它没有改变,这可能会导致一些奇怪的行为。当所有更新逻辑具有 运行 而不是 in-between 更新步骤时,一种常见的做法是 延迟 在帧的 begin/end 改变世界,也就是说,您将保存 tile id (x=2, y=43) 需要更改为 EMPTY 的事实,并将在更新函数结束时应用更改。在这种情况下,我相信它会很好。