I have 2 classes, In one class, I have code for position of object1 changing with time and in class2, I have code for object2 changing with time, the positions are changing continuously at different rates. Now, I want to figure out if the two objects collide, but how do I get their positions that are changing at difference of less tahn a second, is their any shortcut or efficient method to do that?
Here is how object1 and object 2 are changing their positions:
object 1:
self:setRotation( self:getRotation() + math.random(5,7) )
object2:
x = 215 + math.cos(angle)*195
y = 130 + math.sin(angle)*115
Both of these are part of 2 different classes. I need to use them in a third lua file where I am checking for the collisions, so how can I get x and y value of both of these as soon as it changes and pass them to a new function to check for collisions
I have 2 classes, In one class, I have code for position of object1 changing with time and in class2, I have code for object2 changing with time, the positions are changing continuously at different rates. Now, I want to figure out if the two objects collide, but how do I get their positions that are changing at difference of less tahn a second, is their any shortcut or efficient method to do that?
Here is how object1 and object 2 are changing their positions:
object 1:
self:setRotation( self:getRotation() + math.random(5,7) )
object2:
x = 215 + math.cos(angle)*195
y = 130 + math.sin(angle)*115
Both of these are part of 2 different classes. I need to use them in a third lua file where I am checking for the collisions, so how can I get x and y value of both of these as soon as it changes and pass them to a new function to check for collisions
Here is how I tried to use Collision detection using TNT
--> let's say I group all my 3 clock hands, these are rotated around an anchor point so x and y remain the same, but they have some width extending,
--> My player is moving in an ellipsis and it's position is changing with time(only when the player jumps, it's not on floor)
Requirement--> what I really want is whenever the player touches any of the clock hands, youLoose method(not given in the code) shall be called, now to achieve this, here is what I did:
and the collision can be anywhere across the length of any of the clock hands,(so basically this part is what I am not getting)
I checked collision as soon as x and y of player changed,here is the code:
attaching the image as well
x = 215 + math.cos(angle)*195
y = 130 + math.sin(angle)*115
for i = 1, groupA:getNumChildren() do
local sprite2 = groupA:getChildAt(i)
local oBoxToObox = tntCollision.oBoxToObox
if i == 1 then
a = 97
b = 11
elseif i == 2 then
a = 206
b = 64
else
a = 120
b = 10
end
local pointToObox = tntCollision.pointToObox
tntCollision.setCollisionAnchorPoint(0, 0)
if oBoxToObox(x,y, 36, 40, cute.anim[self.frame]: getRotation(),sprite2:getX(), sprite2:getY(), a ,b, sprite2:getRotation()) then
youLoose()
end
end
If the objects have volume you need to test if their boundaries cross, quite complicated, and you should use either Box2d or TNT Collision. Both integrated to Gideros (although TNT is a separate download). TNT Collision is only collision, no physics, so likely to be faster but not necessarily so, you would have to compare.
Otherwise (no volume, ie just point collisions), you can just test the x coordinate of each object; if almost identical, then check the y coord; if almost identical you have a collision, otherwise you don't.
Related
I have a problem I just cannot solve, and after a week it's really winding me up.
Background.
I'm placing items onto a circle using basic trig. The number of items can change dynamically, and they are spaced around the circle equally.
The items rotate around the circle, and the speed of rotation changes to be in sync with a BPM (Beats Per Minute) clock. This clock can change at any time.
The problem I'm having is that the items seem to be placed randomly on the circle, not equally spaced in order (see image 1). They'll appear out of order even though it's a basic for loop that places them. I think they may in face be in order, but the rotation values may be off making them look like they are in an odd order.
The second issue is that when the number of items reduces, the speed of rotation increases (it shouldn't) and if the number increases, the speed slows.
So I expect an issue with my trig function. I'm showing the complete code here but can simplify if it'll help.
What have I tried?
I've tried simplified versions without the graphical output, and the numbers all seem to make perfect sense. The radians between items is correct, the placement looks correct. It all looks correct, but it isn't.
The code.
--the variables
orbitalCircle.xPos = x or 0
orbitalCircle.yPos = y or 0
orbitalCircle.circleDiameter = diameter or 10
orbitalCircle.numberOfNotes = number_of_notes
orbitalCircle.spaceBetweenNotes = (360 / number_of_notes)
orbitalCircle.beatsPerSecond = (beats_per_minute / 60)
orbitalCircle.currentRotation = 0
orbitalCircle.framesPerSecond = frames_per_second or 15
orbitalCircle.framesPerFullRotation = (orbitalCircle.numberOfNotes/orbitalCircle.beatsPerSecond)+orbitalCircle.framesPerSecond
orbitalCircle.degreesPerFrame = 360 / orbitalCircle.framesPerFullRotation
orbitalCircle.newRotationValue = orbitalCircle.currentRotation + orbitalCircle.degreesPerFrame
orbitalCircle.sequenceData = sequence_data
--the function that updates the sequence data and therefore the number of items on the circle
function orbitalCircle.updateNotes(sq)
orbitalCircle.sequenceData = sq
orbitalCircle.numberOfNotes = (#sq)
orbitalCircle.spaceBetweenNotes = (360 / orbitalCircle.numberOfNotes)
end
--the function that calculates the new rotation value of the item to be placed on the circle
function orbitalCircle.tick()
orbitalCircle.spaceBetweenNotes = (360 / number_of_notes)
orbitalCircle.framesPerFullRotation = (orbitalCircle.numberOfNotes/orbitalCircle.beatsPerSecond)*orbitalCircle.framesPerSecond
orbitalCircle.degreesPerFrame = (360 / orbitalCircle.framesPerFullRotation)
orbitalCircle.newRotationValue = (orbitalCircle.currentRotation + orbitalCircle.degreesPerFrame)
if orbitalCircle.newRotationValue > 360 then
orbitalCircle.currentRotation = 0
else
orbitalCircle.currentRotation = orbitalCircle.newRotationValue
end
end
--finally the function that places the items onto the circle
function orbitalCircle.redraw()
screen.circle(orbitalCircle.xPos, orbitalCircle.yPos, orbitalCircle.circleDiameter)
screen.stroke()
for i=1, (#orbitalCircle.sequenceData) do
if orbitalCircle.sequenceData[i] > 0 then
screen.circle(
math.cos(math.rad(orbitalCircle.newRotationValue)+(orbitalCircle.spaceBetweenNotes*i))*orbitalCircle.circleDiameter + orbitalCircle.xPos,
math.sin(math.rad(orbitalCircle.newRotationValue)+(orbitalCircle.spaceBetweenNotes*i))*orbitalCircle.circleDiameter + orbitalCircle.yPos,
map(orbitalCircle.sequenceData[i], 5, 128, 0.5, 4)
)
end
end
end
end
I'd expect that the items would be:
equally spaced no matter the amount (that works)
in order (they appear not to be)
the speed of rotation should remain fixed unless the BPM changes (this doesn't happen)
I'm lost!
Let us take a closer look at the drawing.
screen.circle(
math.cos(math.rad(orbitalCircle.newRotationValue)+(orbitalCircle.spaceBetweenNotes*i))*orbitalCircle.circleDiameter + orbitalCircle.xPos,
math.sin(math.rad(orbitalCircle.newRotationValue)+(orbitalCircle.spaceBetweenNotes*i))*orbitalCircle.circleDiameter + orbitalCircle.yPos,
map(orbitalCircle.sequenceData[i], 5, 128, 0.5, 4)
)
What is the angle that is being drawn here? It is the argument to math.cos and math.sin (I will ignore the scaling and the translation that is applied afterwards):
math.rad(orbitalCircle.newRotationValue)+(orbitalCircle.spaceBetweenNotes*i)
So... it is the neRotationValue converted to radians and added to that the space between notes. This one is defined as 360 / number_of_notes, so it is in degrees. Adding a radians and degrees most likely does not produce the expected result.
So, what exactly do you mean with the following?
I've tried simplified versions without the graphical output, and the numbers all seem to make perfect sense.
I want to detect pixel-perfect collisions between 2 sprites.
I use the following function which I have found online, but makes total sense to me.
static bool PerPixelCollision(Sprite a, Sprite b)
{
// Get Color data of each Texture
Color[] bitsA = new Color[a.Width * a.Height];
a.Texture.GetData(0, a.CurrentFrameRectangle, bitsA, 0, a.Width * a.Height);
Color[] bitsB = new Color[b.Width * b.Height];
b.Texture.GetData(0, b.CurrentFrameRectangle, bitsB, 0, b.Width * b.Height);
// Calculate the intersecting rectangle
int x1 = (int)Math.Floor(Math.Max(a.Bounds.X, b.Bounds.X));
int x2 = (int)Math.Floor(Math.Min(a.Bounds.X + a.Bounds.Width, b.Bounds.X + b.Bounds.Width));
int y1 = (int)Math.Floor(Math.Max(a.Bounds.Y, b.Bounds.Y));
int y2 = (int)Math.Floor(Math.Min(a.Bounds.Y + a.Bounds.Height, b.Bounds.Y + b.Bounds.Height));
// For each single pixel in the intersecting rectangle
for (int y = y1; y < y2; ++y)
{
for (int x = x1; x < x2; ++x)
{
// Get the color from each texture
Color colorA = bitsA[(x - (int)Math.Floor(a.Bounds.X)) + (y - (int)Math.Floor(a.Bounds.Y)) * a.Texture.Width];
Color colorB = bitsB[(x - (int)Math.Floor(b.Bounds.X)) + (y - (int)Math.Floor(b.Bounds.Y)) * b.Texture.Width];
if (colorA.A != 0 && colorB.A != 0) // If both colors are not transparent (the alpha channel is not 0), then there is a collision
{
return true;
}
}
}
//If no collision occurred by now, we're clear.
return false;
}
(all the Math.floor are useless, I copied this function from my current code where I'm trying to make it work with floats).
It reads the color of the sprites in the rectangle portion that is common to both sprites.
This actually works fine, when I display the sprites at x/y coordinates where x and y are int's (.Bounds.X and .Bounds.Y):
View an example
The problem with displaying sprites at int's coordinates is that it results in a very jaggy movement in diagonals:
View an example
So ultimately I would like to not cast the sprite position to int's when drawing them, which results in a smooth(er) movement:
View an example
The issue is that the PerPixelCollision works with ints, not floats, so that's why I added all those Math.Floor. As is, it works in most cases, but it's missing one line and one row of checking on the bottom and right (I think) of the common Rectangle because of the rounding induced by Math.Floor:
View an example
When I think about it, I think it makes sense. If x1 is 80 and x2 would actually be 81.5 but is 81 because of the cast, then the loop will only work for x = 80, and therefore miss the last column (in the example gif, the fixed sprite has a transparent column on the left of the visible pixels).
The issue is that no matter how hard I think about this, or no matter what I try (I have tried a lot of things) - I cannot make this work properly. I am almost convinced that x2 and y2 should have Math.Ceiling instead of Math.Floor, so as to "include" the last pixel that otherwise is left out, but then it always gets me an index out of the bitsA or bitsB arrays.
Would anyone be able to adjust this function so that it works when Bounds.X and Bounds.Y are floats?
PS - could the issue possibly come from BoxingViewportAdapter? I am using this (from MonoExtended) to "upscale" my game which is actually 144p.
Remember, there is no such thing as a fractional pixel. For movement purposes, it completely makes sense to use floats for the values and cast them to integer pixels when drawn. The problem is not in the fractional values, but in the way that they are drawn.
The main reason the collisions are not appearing to work correctly is the scaling. The colors for the new pixels in between the diagonals get their colors by averaging* the surrounding pixels. The effect makes the image appear larger than the original, especially on the diagonals.
*there are several methods that may be used for the scaling, bi-cubic and linear are the most common.
The only direct(pixel perfect) solution is to compare the actual output after scaling. This requires rendering the entire screen twice, and requires the scale factor more computations. (not recommended)
Since you are comparing the non-scaled images your collisions appear to be off.
The other issue is movement speed. If you are moving faster than one pixel per Update(), detecting per pixel collisions is not enough, if the movement is to be restricted by the obstacle. You must resolve the collision.
For enemies or environmental hazards your original code is sufficient and collision resolution is not required. It will give the player a minor advantage.
A simple resolution algorithm(see below for a mathematical solution) is to unwind the movement by half, check for collision. If it is still colliding, unwind the movement by a quarter, otherwise advance it by a quarter and check for collision. Repeat until the movement is less than 1 pixel. This runs log of Speed times.
As for the top wall not colliding perfectly: If the starting Y value is not a multiple of the vertical movement speed, you will not land perfectly on zero. I prefer to resolve this by setting the Y = 0, when Y is negative. It is the same for X, and also when X and Y > screen bounds - origin, for the bottom and right of the screen.
I prefer to use mathematical solutions for collision resolution. In your example images, you show a box colliding with a diamond, the diamond shape is represented mathematically as the Manhattan distance(Math.Abs(x1-x2) + Math.Abs(y1-y2)). From this fact, it is easy directly calculate the resolution to the collision.
On optimizations:
Be sure to check that the bounding Rectangles are overlapping before calling this method.
As you have stated, remove all Math.Floors, since, the cast is sufficient. Reduce all calculations inside of the loops not dependent on the loop variable outside of the loop.
The (int)a.Bounds.Y * a.Texture.Width and (int)b.Bounds.Y * b.Texture.Width are not dependent on the x or y variables and should be calculated and stored before the loops. The subtractions 'y-[above variable]` should be stored in the "y" loop.
I would recommend using a bitboard(1 bit per 8 by 8 square) for collisions. It reduces the broad(8x8) collision checks to O(1). For a resolution of 144x144, the entire search space becomes 18x18.
you can wrap your sprite with a rectangle and use its function called Intersect,which detedct collistions.
Intersect - XNA
I might be stupid or something. But, I'm having a hard time with this. I usually find examples of code but it just confuses me. Unfortunately there isn't any good tutorial for this. I been using Lua for almost a year so I kinda have experience. Help would be extremely appreciate!
Basically I want to learn how to make rectangle jump up and then go back down.
For a single block that you control, you essentially need to store it's gravity and figure out a nice acceleration for it.
currentGravity = 0;
gravity = 1;
Then in the loop, you have to check if it's on ground using some collision detection. You want to add the gravity acceleration to currentGravity:
currentGravity = currentGravity + gravity
Then, you add it to the current y axis of the block:
YAxis = YAxis + currentGravity
Once you land, make sure to set gravity to 0. Also be sure to keep setting it to 0 to ensure you don't fall through the ground (as you kept adding to gravity no matter what.)
if not inAir() then
currentGravity = 0
end
And, of course, to jump, set currentGravity to a negative number (like 20) (if that's how you made the gravity work.)
Here's a collision detection function I made for Love2D:
function checkCollision(Pos1,Size1,Pos2,Size2)
local W1,H1,W2,H2 = Size1[1]/2,Size1[2]/2,Size2[1]/2,Size2[2]/2
local Center1,Center2 = {Pos1[1]+W1,Pos1[2]+H1},{Pos2[1]+W2,Pos2[2]+H2}
local c1 = Center1[1]+(W1) > Center2[1]-W2
local c2 = Center1[1]-(W1) < Center2[1]+W2
local c3 = Center1[2]+(H1) > Center2[2]-H2
local c4 = Center1[2]-(H1) < Center2[2]+H2
if (c1 and c2) and (c3 and c4) then
return true
end
return false
end
It assumes the position you gave it is the center of the block. If the box is rotated it won't work. You'll have to figure out how to make it work with walls and the like. And yes, it's ugly because it's very old. :p
I am following the Sprite Kit guide, and in the scene editor it asks me to set the Category Mask to 32 and Collision Mask to 11. How are these numbers related?
The Category bit mask tells Sprite-Kit what sort of object this is.
The Collision bit mask tells Sprite Kit what objects this object
collides with (i.e. will hit and bounce off).
The ContactTest bit mask tells Sprite-Kit what contacts you want to
be notified about i.e. when this object touches another object.
Collisions are handled automatically by the Sprite-Kit game engine; contacts are handled by your code - when a contact happens that you are interested in, your code (didBeginContact'for Swift 2,'didBegin(contact:) for Swift 3 and later) is called.
You need to think of these bitmasks in binary and for simplicity, we'll start with simple category bit masks, whereby each object in your scene belongs to only one category.
E.g. in your scene you have a player, a player-missile, an enemy and the screen-edge. We'll assume that the bit masks are 8-bit instead of 32-bit. Think of each number as a range of 8 binary digits (8 bits) each of which is a 0 or 1.
The objects in your scene have to have unique categories, so we'll assign them as follows:
player.categoryBitMask = 00000001 (1 in decimal)
playerMissile.categoryBitMask = 00000010 (2 in decimal)
enemy.categoryBitMask = 00000100 (4 in decimal)
screenEdge.categoryBitMask = 00001000 (8 in decimal)
If you use numbers that are, in decimal, something other than a power of 2 (1, 2, 4, 8, 16, 32, 64, 128 etc) then more than 1 bit will be set in the category bit mask which complicates things (it means that this object belongs to multiple categories) and your code has to get more complicated.
Now think about what bounces off what (the collisions). Let's say everything bounces off everything else except the missile goes through the screen edge.
The collision bit masks for each object consists of the bits that represent the objects that this object collides with i.e.:
player.collsionBitMask = 00001111 (15 in decimal) (the bits for all other objects are set)
playerMissile.collisionBitMask = 00000111 (7) (all object EXCEPT screenEdge)
enemy.collisonBitMask = 00001111 (15) (everything)
screenEdge.collisonBitMask = 00000000 (0) (collides with nothing)
Now we think about which object interactions we are interested in. We want to know when:
player and enemy touch
enemy and player touch or the enemy and the player's missile touch.
This is represented by:
player.contactTestBitMask = 00000100 (4) (the enemy's categoryBitMask)
enemy.contractTestBitMask = 00000011 (3) (the player's categoryBitMask combined with the missile's categoryBitMask))
Note that if you want to know when A and B touch, it's enough just to have A's contactTestBitMask (CTBM) to include B's categoryBitMask; you don't have to have B's CTBM set to A's category too. But if you want them to bounce off each other, then each object's collisionBitMask must include the other's categoryBitMask. If A's collisonbitMask includes B's category, but not vice versa, then when the 2 collide, A will bounce off but B will be unaffected by it.
For your specific example, (Category Mask to 32 and collision mask to 11), the categoryBitMask is 32 which is 00100000 (sticking with only 8 bits). The collisionBitMask is 11, which is 8 + 4 + 1 so in binary this is '00001101' which means it collides with objects with a categoryBitMask of 8, 4 or 1, so I assume that there are objects in your scene with these categoryBitMasks.
By default everything bounces off everything else i.e. the collisionBitMask is all '1's i.e. b'111111..' and nothing notifies of contacts with anything else i.e. contactTestBitMask is all '0's.
Also - all of this applies to physicsBodies, not nodes.
I'm new to Corona and looking for a little help manipulating moving objects:
Basically I want a set up where when I can click on a moving object, a dialog box will pop up giving me the option to change the speed of the object and the vector of travel. I'm pretty sure I can figure out the event handling and the dialog but I'm stuck on simply changing the direction of travel to the new vector
in a simple example, I have a rect moving up the screen as follows:
obj1 = display.newRect(500, 800, 10, 40)
transition.to(obj1,{x=500, y = 100, time = 40000})
I know I can change the speed by adjusting the time, but if I use
obj1:rotate(30)
to turn the object 30 degrees, how do I make it travel in the new direction?
Should I be using physics - linear impulse for example, instead of transitions?
Apologies if this is a stupid question but I have searched without success for a solution.
This sounds like what you are trying to do. You would have to modify bits to fit your code but this is a working example. So if you copy it to a new main.lua file and run it you can see how it works. (Click to rotate obj).
local obj = display.newRect(50,50, 10, 40)
local SPEED = 1
local function move(event)
obj.x = obj.x + math.cos(math.rad(obj.rotation)) * SPEED
obj.y = obj.y + math.sin(math.rad(obj.rotation)) * SPEED
end
local function rotate(event)
obj.rotation = obj.rotation + 45
end
Runtime:addEventListener("enterFrame", move)
Runtime:addEventListener("tap", rotate)
Basically I used the "enterFrame" event to 'move' the rectangle, by recalculating the x and y of the objects location using its rotation (which is easy enough to modify) every frame.