问题描述
Lua和Love2D的新功能在这里!我正在尝试完成我正在参加的此在线课程的最终项目,我想知道如何使精灵消失。目前,我拥有这样一个功能,即播放器属于一类,而与地图有关的任何内容(即图块和背景)都属于另一类。我要写的是,如果玩家击中一个特定的方块,则该方块消失,计数器增加。我知道关于带球的cs50 gamedev课程也存在类似的问题,但是我不太了解其中的代码,所以我希望有人可以帮助我。我的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.mapWidth do
self:setTile(x,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,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,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,SUSHI1)
else
self:setTile(location,SUSHI2)
end
end
-- FOR THE LAST QUARTER OF THE MAP
else
for counter = 1,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,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,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.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,(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),scaleX,1,self.width / 2,self.height / 2)
end
我想做到这一点,例如,如果玩家跳到SUSHI2
块上,它将消失。
很抱歉,冗长的帖子。我确实确实想尽我最大的努力,并且尝试添加与普通游戏一样多的内容,但是我是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
希望我能理解您的问题,并且可以有所帮助。您可能需要清理它,感觉有些古怪,但可以说明这个想法。
另一件事是,当您在游戏滴答声中改变世界时,其他一些代码段可能会假设其未更改,这可能会导致某些奇怪的行为。一种常见的做法是,在所有更新逻辑都已运行且不在更新步骤之间的情况下,在帧的开始/结尾推迟改变世界,即可以节省图块ID(x = 2,y = 43)需要更改为EMPTY,并在更新功能结束时应用更改。在这种情况下,我敢肯定会没事的。