I am working on a tile-based game. However, due to things such as furniture my map has multiple layers. I have (for the time being) created a square to represent my player. In order to stop my player walking on furniture, I need to make a function that checks for the layer. How do I do that? (Supposing I need to check the layer on the tile to the immediate right of my player)
Pseudo-code ideas:
function checkLayers()
for every layer in map
if layer == "furniturelayer" then
stop player
end
end
end
EDIT: I have found a possible way to do it, but it does not work. I have an array containing the GID of all tiles that are collidable. I am then looping through all layers and checking if the tile has that GID. Code:
function gCheckGID(gMap, gLayer, tileX, tileY)
tilex = gMap.layers[gLayer]:get(tileX, tileY)
return tilex.id
end
function gCheckMovement(gMap, gArray, gTileX, gTileY)
local retVal = true
local layerArray = gMap.layers
local layers = table.getn(layerArray)
for layerCounter = 1, layers, 1 do
currGID = gCheckGID(gMap, layerArray[layerCounter], gTileX, gTileY)
for gidCounter = 1, table.getn(gArray), 1 do
if currGID == gArray[gidCounter] then
retVal = false
break
end
end
end
return retVal
end
I can then use an if statement to get the result and determine whether to move my character or not.
I assume you are using the Tiled library "Simple Tiled Implementation"? If so, I am the author. I have just recently added full collision support to STI using love.physics (Box2D). If you want to create a layer that is entirely collidable (such a sa furniture layer), then all you need to do is add a custom property to your layer in Tiled called "collidable" and set the value to "true".
Tiled now has a collision editor that can be used to add collision data to individual tiles in a tileset. STI also supports this out of the box with no custom properties required.
For more information about STI, check out the LOVE forum thread here.
Related
can someone help me on how show i move the NPCs through a path, like in the tds game?. I have tried this
local function move()
-- source is an array with all the positions it has to go to
for i=1,#source,1 do
-- This is in case the MoveTo takes more than 8 seconds
local itreached = false
while itreached == false do
npc.Humanoid:MoveTo(source[i].Position)
wait()
npc.Humanoid.MoveToFinished:Connect(function()
itreached = true
end)
end
end
end
and it works to an extend , that when i approach the npc it somehow falls and lags , otherwise if i just run it without a player it works just fine. Are there other techniques, like lerp or tween? I tried using lerp, but i couldn't move the whole model.
video showing the problem
You are running into an issue with network ownership. The Roblox engine decides who is responsible for calculating the positions of objects based on some calculation around who is closest to the object and who has a strong enough machine to do the calculation. For example, desktop computers and laptops tend to have a wider sphere of influence than mobile devices. Anyways, when you walk close it the NPCs, there is a handoff of ownership, and that is causing the NPCs to fall over. So to fix it, you need to call SetNetworkOwner(nil) on the NPC's PrimaryPart so that the part is owned by the server.
npc.PrimaryPart:SetNetworkOwner(nil)
Also, if you want to clean up your code, you can make it entirely driven by events. Once you tell it to start moving, it will select the next target once it arrives.
local targetPos = 1
local function move()
npc.Humanoid:MoveTo(source[targetPos].Position)
end
-- listen for when the NPC arrives at a position
npc.Humanoid.MoveToFinished:Connect(function(didArrive)
-- check that the NPC was able to arrive at their target location
if not didArrive then
local errMsg = string.format("%s could not arrive at the target location : (%s, %s, %s)", npc.Name, tostring(targetPos.X), tostring(targetPos.Y), tostring(targetPos.Z))
error(errMsg)
-- do something to handle this bad case! Delete the npc?
return
end
-- select the next target
targetPos = targetPos + 1
-- check if there are any more targets to move to
if targetPos <= #source then
move()
else
print("Done moving!")
end
end)
Could someone help me change this script into a "mesh" dropper?
wait(2)
workspace:WaitForChild("PartStorage")
while true do
wait(1.5) -- How long in between drops
local part = Instance.new("Part",workspace.PartStorage)
part.BrickColor=script.Parent.Parent.Parent.DropColor.Value
part.Material=script.Parent.Parent.Parent.MaterialValue.Value
local cash = Instance.new("IntValue",part)
cash.Name = "Cash"
cash.Value = 5 -- How much the drops are worth
part.CFrame = script.Parent.Drop.CFrame - Vector3.new(0,1.4,0)
part.FormFactor = "Custom"
part.Size=Vector3.new(1.2, 1.2, 1.2) -- Size of the drops
part.TopSurface = "Smooth"
part.BottomSurface = "Smooth"
game.Debris:AddItem(part,20) -- How long until the drops expire
end
First and foremost, there's a website specifically for Roblox questions: scriptinghelpers.org. I suggest you use it in the future.
Now that that is out of the way...
It's not very hard to add a mesh to any part. You just have to know what kind of mesh you want, what you want its properties to be, and if applicable, the texture you'll use.
Since meshes are an instance, I'd suggest creating a new mesh instance as a child of your part, and giving it the properties you want. This can be accomplished rather easily with the code below.
local mesh = Instance.new("SpecialMesh", part) -- Create the mesh as a child of 'part'
mesh.MeshType = Enum.MeshType.Sphere -- Sets the mesh's MeshType. If you'd like a mesh type other than a sphere, use the corrosponding MeshType Enum, http://wiki.roblox.com/index.php?title=API:Enum/MeshType
mesh.Scale = Vector3.new(1.2,1.2,1.2) -- this will set scale to 1.2 on all axis
mesh.MeshID = nil -- If you're using a FileMesh, replace nil with the mesh ID, otherwise, you can just remove this line
There are also other properties, such as Offset, TextureID, and VertexColor, which you can read more about on the official wiki page for the SpecialMesh instance.
I am making a roguelike in Love2D as a hobby project. My approach is to try and use as much of the native capabilities of Lua and the Love2D (0.10.1) API as possible, without relying on fancy libraries like middleclass or HUMP, so as to learn more about the language.
After reading PiL's chapters on OOP and seeing the power there, I decided to set up a Mob class (using metamethods to emulate class functionality) that encompasses the players, monsters, and other NPCs (anything that can move). So, far, it's working beautifully, I can create all kinds of instances easily that share methods and all that stuff. But there's a lot of things I don't know how to do, yet, and one of them is holding my prototype up from further progress.
Setting up collision with the map itself wasn't too bad. My maps are tables full of tables full of integers, with 0 being the floor. The game draws "." and "#" and "+" and such to denote various inanimate objects, from each table. Player 1 moves using the numpad, and their position is tracked by dividing their raw pixel position by 32 to create a grid of 32x32 "tiles". Then, inside love.keypressed(key), I have lines like:
if key == "kp8" and currentmap[player1.grid_y - 1][player1.grid_x] == 0 then
player1.grid_y = player1.grid_y - 1
and so on, with elseifs for each key the player can press. This prevents them from walking through anything that isn't an open floor tile in the map itself.
But, I'm trying to implement some kind of "collision detection" to prevent MOBs from walking through each other and to use in writing the rules for combat, and this is trickier. I had a method in place to calculate the distance between mobs, but I'm told this might eventually cause rounding errors, plus it had to be written for each combination of mobs I want to test, individually.
What I'd like to know is: Is there a known (preferably elegant) way to get all instances of a particular class to pass some number of values to a table?
What I'd like to do is "ask" every Mob on a given map where they are, and have them "report" self.grid_x and self.grid_y to another layer of map that's just for tracking mobs (1 if self.is_here is true, 0 if not, or similar), that gets updated every turn. Then, I could implement collision rules based on coordinates being equal, or maybe a foo.is_here flag or something.
I have only vague ideas about how to proceed, however. Any help would be appreciated, including (and maybe especially) feedback as to a better way to do what I'm trying to do. Thanks!
A simple idea is to store "who is here" information for every cell of the field and update this information on every move of every object.
function create_game_field()
-- initialize a table for storing "who is here" information
who_is_here = {}
for y = 1,24 do
who_is_here[y] = {}
for x = 1,38 do
who_is_here[y][x] = 0
end
end
end
function Mob:can_move(dx, dy)
local u = currentmap[self.y + dy][self.x + dx]
local v = who_is_here[self.y + dy][self.x + dx]
if u == 0 and v == 0 then
return true
else
end
end
function Mob:move(dx, dy)
-- update "who is here"
who_is_here[self.y][self.x] = 0
self.x, self.y = self.x + dx, self.y + dy
who_is_here[self.y][self.x] = 1
end
function Mob:who_is_there(dx, dy) -- look who is standing on adjacent cell
return who_is_here[self.y + dy][self.x + dx] -- return mob or nil
end
function Mob:roll_call()
who_is_here[self.y][self.x] = 1
end
Usage example:
-- player1 spawns in at (6,9) on the grid coords
player1 = Mob:spawn(6,9)
-- player1 added to who_is_here
player1:roll_call()
Then, in love.keypressed(key):
if key == "kp8" and player1:can_move(0, -1) then
player1:move(0, -1)
end
There are a few ways you could get all your instances data but one of the simpler ones is probably to have them all be added to a table when they are created. Providing you add the entire table for that instance, all the values will update in the main table because it acts like a collection of pointers.
function mob:new( x, y, type )
self.x = 100
self.y = 200
self.type = type
-- any other declarations you need
table.insert(allMobs, self)
return self
end
Here we insert all the mobs into the table 'allMobs'. Once we have that we can simply iterate through and get all our coordinates.
for i, v in ipairs(allMobs) do
local x, y = v.x, v.y
-- Do whatever you need with the coordinates. Add them to another table, compare
-- them to others, etc.
end
Now we have a table with all our mobs in it and a way to access each of their positions. If you have any further inquiries then let me know.
I've been working with the built-in Resize function in Roblox Studio and have been using it to expand the Top Surface of multiple Parts in order to form a wall-like structure.
The only problem that has arisen when using this method is that the surface of the wall created is not even: Some Parts are higher than others.
I later discovered that this problem is due to the fact that the built-in Resize function only takes integers as it's second parameter (or "expand-by" value). Ideally I need the Parts to have the ability expand by any Real Number.
Are there any alternatives to the built-in Resize function that allow one to resize a Surface by any Real Number?
Yes, this is possible, but it actually requires a custom function to do so. With some fairly basic math we can write a simple function to accomplish such a task:
local Resize
do
local directions = {
[Enum.NormalId.Top] = {Scale=Vector3.new(0,1,0),Position=Vector3.new(0,1,0)},
[Enum.NormalId.Bottom] = {Scale=Vector3.new(0,1,0),Position=Vector3.new(0,-1,0)},
[Enum.NormalId.Right] = {Scale=Vector3.new(1,0,0),Position=Vector3.new(1,0,0)},
[Enum.NormalId.Left] = {Scale=Vector3.new(1,0,0),Position=Vector3.new(-1,0,0)},
[Enum.NormalId.Front] = {Scale=Vector3.new(0,0,1),Position=Vector3.new(0,0,1)},
[Enum.NormalId.Back] = {Scale=Vector3.new(0,0,1),Position=Vector3.new(0,0,-1)},
}
function Resize(p, d, n, c)
local prop = c and 'Position' or 'CFrame'
p.Size = p.Size + directions[d].Scale*n
p[prop] = p[prop] + directions[d].Position*(n/2)
return p.Size, p[prop]
end
end
Resize(workspace.Part, Enum.NormalId.Bottom, 10, false) --Resize workspace.Part downards by 10 studs, ignoring collisions
If you're interested more on how and why this code works the way it does, here's a link to a pastebin that's loaded with comments, which I felt would be rather ugly for the answer here: http://pastebin.com/LYKDWZnt
just starting to play around with the awesome corona sdk.
I started building a simple shooter game.
I have the following code :
-- Global Variables
local shot = audio.loadSound('shot.mp3')
local bg = display.newImage('bg.png')
local shoot = {}
local Main = {}
local Init = {}
local bullets = display.newGroup()
function update()
if(bullets.numChildren ~= 0) then
for i = 1, bullets.numChildren do
bullets[i].y = bullets[i].y - 8
-- Destroy Offstage Bullets
if(bullets[i].y < (-bullets[i].height-5)) then
-- bullets[i]:removeSelf()
bullets:remove(bullets[i])
display.remove(bullets[i])
return
end
end
end
end
-- Initialisation functions
function Init ()
display.setStatusBar(display.HiddenStatusBar)
local movieclip = require('movieclip')
local physics = require('physics')
physics.start()
physics.setGravity(0, 0)
end
function shoot:tap(e)
for i = 1, 15 do
local bullet = display.newImage('bullet.png')
bullet.x = 150
bullet.y = 470
bullet.name = 'bullet'
physics.addBody(bullet)
bullets.insert(bullets, bullet)
end
audio.play(shot)
end
-- Main routine
function Main ()
Init()
bg:addEventListener('tap', shoot)
Runtime:addEventListener('enterFrame', update)
end
Main()
For now it 'works'; but when the bullet comes of the screen the whole 'game' slows down and I can clearly see that each bullet is removed which slows down the game.
Maybe i'm not doing it right; also tried the :removeSelf() function; same results.
I was facing the same problem...And got the soln for this:
you are removing objects using for loop:
if you remove objects in for loop say: you deleted object at index 1, then object 2 moves to object 1...so when it loops to object to it wont check object 2(bcoz its moved to object 1's place and you are checking object 3)
for j = 1, buttonGroup.numChildren do
buttonGroup[1]:removeSelf(); --this removes all childrens
end
for j = 1, buttonGroup.numChildren do
buttonGroup[j]:removeSelf(); --this removes alternative childrens
end
I hope its useful
I fought for a long long time with object removal for my game which uses a lot of tabbed views. The solution I found was to use "= nil", ":removeSelf()" and ".alpha = 0" on all objects which need removing. If they are all added to the same group, and nothing else is in it, that could be used too, but doesn't always work for various reasons as to how groups are set up behind the scenes.
It would seem what you've done there is remove the contents of "bullets" but that's just a reference, so where you say each bullet is being removed, it's actually only being dropped from the array - the object itself still exists and needs to be nil'd in order to prevent a memory leak and a slowing of the app (you will probably have found that each bullet slows the app more, right?)
Add this condition after your removes and you should be set:
if(not(bullet == nil)) then
bullet.alpha = 0;
bullet:removeSelf();
bullet = nil;
end
its easier to simply create a table like this
local bulletCache = {}
Then in your bullet creation code add
table.insert(bulletCache, myBulletObject)
then in your exit code and/or your destroy code say
for i = 1, #bulletCache do
--[[
--Below is not needed but just to keep your code consitant
pcall(function()
bullet.alpha = 0
end)
--]]
pcall(function()
bullet:removeSelf()
end)
pcall(function()
bullet = nil
end)
end
First of all, never try to execute any kind of loop in GameLoop. It does drop fps of game, because it takes usually more memory.
Now, it seems that you just want to destroy bullets after disappearing from the screen and you are using physics too, so why you are not taking advantage of that?
Here are the steps you should follow. (If you find any query or difficulty about it then ask me)
1.Draw a Static Physical Line little bit above the screen. Let say y is -20.
local _yLimit = -20
local _limitLine = display.newLine(0,_yLimit,display.contentWidth,_yLimit)
_limitLine.anchorX = 0
_limitLine.anchorY = 0
2.Add all bullets as a physical object.
3.Apply force at the Bottom Center of bullet, rather then transforming it. [Assuming that bullet have rectangular physical shape, otherwise decide the equilibrium point of the shape].
4.Check for collisions with "collision" event listener.
5.Destroy bullets on collision
Thats so simple :)
Let me know if you still have problems regarding this.