how to prevent [circle] body from sliding into 0px gaps between static bodies - physics

So I have this body that is a circle collider
and it has sometimes a big velocity
the problem is that the tiled map of the boundaries is made of small tiles
and at high velocity the body goes through it
here is my config of all bodies:
const config = {
inertia: Infinity, // do not spin
friction: 0, // X*100% stop on hit
frictionAir: 0, // X*100% slow on move
restitution: 0.5, // bounce X*100% on hit
collisionFilter: this.level.getCollisionFilter(), // default collision filter
isStatic
}
...
getCollisionFilter (key = null) {
switch (key) {
case 'fly':
return {
category: 0x0008,
mask: 0xFFFFFFF1,
group: -1
}
case 'items':
return {
category: 0x0004,
mask: 0xFFFFFFF1,
group: -1
}
case 'woda':
return {
category: 0x0002,
mask: 0xFFFFFFFF,
group: -1
}
default:
return {
category: 0x0001,
mask: 0xFFFFFFFF,
group: 0
}
}
}
```
woda means water if it's of any relevance
this is between the default and woda

The problem is that matter.js you are using has no continuous collision detection. It has been a feature request for a few years. Now that doesn't mean there is nothing you can do. There is some code in the issue description itself which is probably the cheapest way of fixing issue with going through rectangular boundaries:
It detects if a body is outside the world bounds and then reverses the velocity and translates the body back
Alternatively, this post gives a few ideas.
If you want to implement something yourself, I'll try to explain continuous collision detection algorithm.
Basically, for each moving object in your scene you have to calculate moment of next collision within the fraction of the frame 0<t0<1, then advance positions to this moment t0 within the frame, update velocities due to collision and proceed further to the next collision t0<t1<1, until you reach time of tn=1 (end of frame), making sure you don't get stuck in a the middle of the frame due to rounding of calculation or "cornered" objects. For spherical colliders, that is usually done by using capsule vs capsule (for pairs of objects) intersection and capsule vs box for the boundaries.
You can also cheat by having multiple hidden frames at a slower speed:
take highest object velocity
take smallest object collider radius
divide highest velocity by smallest radius of your colliders and get 'slowdown scale' rounded it to an integer
slow down all the objects in the scene by that integer 'slowdown scale' and update scene 'slowdown scale' times, without redrawing the screen
redraw the screen only once with result of 'slowdown scale' updates and you should get same positions as without slowdown, but respecting collisions
Good luck colliding!

Related

How to make large 2d tilemap easier to load in Unity

I am creating a small game in the Unity game engine, and the map for the game is generated from a 2d tilemap. The tilemap contains so many tiles, though, is is very hard for a device like a phone to render them all, so the frame rate drops. The map is completely static in that the only moving thing in the game is a main character sprite and the camera following it. The map itself has no moving objects, it is very simple, there must be a way to render only the needed sections of it or perhaps just render the map in once. All I have discovered from researching the topic is that perhaps a good way to do it is buy using the Unity mesh class to turn the tilemap into a mesh. I could not figure out how to do this with a 2d tilemap, and I could not see how it would benefit the render time anyways, but if anyone could point me in the right direction for rendering large 2d tilemaps that would be fantastic. Thanks.
Tile system:
To make the tile map work I put every individual tile as a prefab in my prefab folder, with the attributes changed for 2d box colliders and scaled size. I attribute each individual prefab of the tile to a certain color on the RGB scale, and then import a png file that has the corresponding colors of the prefabs where I want them like this:
I then wrote a script which will place each prefab where its associated color is. It would look like this for one tile:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Map : MonoBehaviour {
private int levelWidth;
private int levelHeight;
public Transform block13;
private Color[] tileColors;
public Color block13Color;
public Texture2D levelTexture;
public PlayerMobility playerMobility;
// Use this for initialization
void Start () {
levelWidth = levelTexture.width;
levelHeight = levelTexture.height;
loadLevel ();
}
// Update is called once per frame
void Update () {
}
void loadLevel(){
tileColors = new Color[levelWidth * levelHeight];
tileColors = levelTexture.GetPixels ();
for (int y = 0; y < levelHeight; y++) {
for (int x = 0; x < levelWidth; x++) {
// if (tileColors [x + y * levelWidth] == block13Color) {
// Instantiate(block13, new Vector3(x, y), Quaternion.identity);
// }
//
}
}
}
}
This results in a map that looks like this when used with all the code (I took out all the code for the other prefabs to save space)
You can instantiate tiles that are in range of the camera and destroy tiles that are not. There are several ways to do this. But first make sure that what's consuming your resources is in fact the large number of tiles, not something else.
One way is to create an empty parent gameObject to every tile (right click in "Hierarchy" > Create Empty"
then attach a script to this parent. This script has a reference to the camera (tell me if you need help with that) and calculates the distance between it and the camera and instantiates the tile if the distance is less than a value, otherwise destroys the instance (if it's there).
It has to do this in the Update function to check for the distances every frame, or you can use "Coroutines" to do less checks (more efficient).
Another way is to attach a script to the camera that has an array with instances of all tiles and checks on their distances from the camera the same way. You can do this if you only have exactly one large tilemap because it would be hard to re-use this script if you have more than a large tilemap.
Also you can calculate the distance between the tile and the character sprite instead of the camera. Pick whichever is more convenient.
After doing the above and you still get frame-drops you can zoom-in the camera to include less tiles in its range but you'd have to recalculate the distances then.

Circle layout with custom center coordinates

I'm building a dynamic graph with cytoscape.js over a world map generated with jVectorMap.
Starting with coordinates in LAT / LON format from json data, I can convert them in point.x / point.y over the generated map with:
var nodePoint = theMap.latLngToPoint(node.data.lat, node.data.lon)
and then I can add the new node in the graph with:
cy.add({
group: "nodes",
position: { x: nodePoint.x, y: nodePoint.y },
style: {
'background-color': node.color
},
data: {
id: node.id,
name: node.label,
customData: node.data,
}
})
This part works, but when json returns multiple nodes with the same coordinates, I would like to spread these nodes around the point with the common LAT / LON information.
I'm able to identify these nodes and apply a dedicated layout to them, but the resulting layount is located in the center of the screen / div of graph.
What I want to know is if there is a simple way to apply a Circle Layout with specific center point.
(I would like to avoid implementing the solution that I'm evaluating... i.e to build a bounding box around the center point and see what happens, (with the bounding box size that grows along with node number in the same point))
In the Wine and cheese example included in the documentation they use the bounding box to force a concentric layout around a selected node ( http://js.cytoscape.org/demos/cde4db55e581d10405f5/ ).
While you indicate you would like to avoid this solution it seems a straightforward solution. The implementation in the example is rather elegant.

XNA 2D object collision (without Tiles/Grid)

First time posting here. Tried to look for topics previously to help.
I'm using Visual Basic, but so far I've been able to follow C# and just translate into VB.
I would like collision without tiles. Smooth movement without any sort of snapping. I already have the movement down, and my sprites stop at the edges of the screen.
I've read I could use Bounds and Intersects, which I have tried. When I apply an IF statement to the arrow keys each time they are pressed, using Bounds and Intersects (I just prevent sprite movement if it is intersecting), it works for ONE key. I move left into an object, and I stop. If I apply the IF to all keys, it will work the first time. Say I move left into an object, the IF statement checks if the Intersects is true or not and acts accordingly.
Now I want to move right, away from the object. I can't since my sprite is ALREADY colliding with the object, since each arrow key is programmed to NOT move if there is Intersection. I see perfectly why this happens.
The code I currently have: (Each arrow key has the same code, altered to it)
If Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Right) And rBlockBounds.X <=
graphics.GraphicsDevice.Viewport.Width - rBlockBounds.Width = True Then
If rBlockBoundBoxBounds.Intersects(rObstructBounds) Then
rBlockBounds.X += 0
rBlockBoundBoxBounds.X = rBlockBounds.X - 1
Else
rBlockBounds.X += 1
rBlockBoundBoxBounds.X = rBlockBounds.X - 1
End If
End If
rBlockBounds is my sprite As Rectangle
rBlockBoundBoxBounds is another Rectangle (1 pixle bigger than rBlockBounds) used as a Hit Box more or less that moves with rBlockBounds, and is the thing doing the collision checking
rObstructBounds is the stationary object that I'm moving my Sprite into.
Anyone have suggestions on how I can make this work?
Since I myself program in C#, not VB I can not code your solution but instead I can explain a better way of approaching it.
What you want to do is prevent the two rectangles from ever intersecting. To do this you will need to implement a move method into your code which can check if the two tiles are colliding. Here is a C# example:
public bool MoveX(float distance) // Move Player Horizontally in this example
{
rBlockBounds.X += distance;
if(rBlockBoundBoxBounds.Intersects(rObstructBounds)
{
rBlockBounds.X -= distance;
return false;
}
return true;
}
Which essentially means that if you run into an object you will be pushed out of it. Since it occurs in one tick you won't get any jutty back-and-front animations.
And that should do what you want. You can test this out and then implement it for y-coordinates as well.
Also, you might notice I've made the function return a bool. This is optional but allows you to check if your player has moved or not.
Note if you teleport an object into another one it will cause problems so remember to implement this every time you move anything.
But that should do what you want.
Edit
Note since your objects are not in a tiled grid, you will need to move lots of time in very small steps.
Something like this:
public bool MoveX(float distance) // Move Player Horizontally in this example
{
rBlockBounds.X += distance;
if(rBlockBoundBoxBounds.Intersects(rObstructBounds)
{
rBlockBounds.X -= distance;
return false;
}
return true;
}
public bool MoveX(float distance, int repeat)
{
for(int i=0; i < repeat; i++)
{
rBlockBounds.X += distance;
if(rBlockBoundBoxBounds.Intersects(rObstructBounds)
{
rBlockBounds.X -= distance;
return false;
}
}
return true;
}
Where the second one will take multiple steps. Here is why you would use it:
MoveX(500); // Will move 500 right. Could easily skip over objects!
MoveX(5, 100); // Will move 5 right one hundred times
// ^ This will take more time but will not skip object
Similarly for yours you could do this:
MoveX(3); // If contact object will be max 3 pixels away
MoveX(1, 3); // If contact object will be max 1 pixels away
MoveX(0.5f, 6); // If contact object will be max 0.5 pixels away
Now I am guessing all your x, y positions are integers. If so you could get away doing the second call and come exactly next to each other. If not you would do the third call.
Hope this helped.

SpriteKit: How to simulate magnetic force

I am developing a game using iOS SpriteKit. I am trying to make an object in this game that will pull things towards it and the force will get greater as objects come closer to it, think of a magnet or a black hole. I've been having a difficult time figuring out what properties to change to get this nodes physicsBody to attract other nodes as they pass by.
In iOS 8 and OS X 10.10, SpriteKit has SKFieldNode for creating forces that apply to bodies in an area. This is great for things like buoyancy, area-specific gravity, and "magnets".
Watch out, though — the magneticField you get from that class is probably not what you want for the kind of "magnets" gameplay you might be looking for. A magnetic field behaves as per real-world physics at the micro level... that is, it deflects moving, charged bodies. What we usually think of as magnets — the kind that stick to your fridge, pick up junked cars, or make a hoverboard fly — is a higher-level effect of that force.
If you want a field that just attracts anything (or some specific things) nearby, a radialGravityField is what you're really after. (To attract only specific things, use the categoryBitMask on the field and the fieldBitMask on the bodies it should/shouldn't interact with.)
If you want a field that attracts different things more or less strongly, or attracts some things and repels others, the electricField is a good choice. You can use the charge property of physics bodies to make them attracted or repelled (negative or positive values) or more or less strongly affected (greater or less absolute value) by the field.
Prior to iOS 8 & OS X 10.10, SpriteKit's physics simulation doesn't include such kinds of force.
That doesn't keep you from simulating it yourself, though. In your scene's update: method you can find the distances between bodies, calculate a force on each proportional to that distance (and to whatever strength of magnetic field you're simulating), and apply forces to each body.
yes you can create magnetic force in sprite kit
-(void)didSimulatePhysics
{
[self updateCoin];
}
-(void) updateCoin
{
[self enumerateChildNodesWithName:#"coin" usingBlock:^(SKNode *node, BOOL *stop) {
CGPoint position;
position=node.position;
//move coin right to left
position.x -= 10;
node.position = position;
//apply the magnetic force between hero and coin
[self applyMagnetForce:coin];
if (node.position.x <- 100)
[node removeFromParent];
}];
}
-(void)applyMagnetForce:(sprite*)node
{
if( gameViewController.globalStoreClass.magnetStatus)
{
//if hero under area of magnetic force
if(node.position.x<400)
{
node.physicsBody.allowsRotation=FALSE;
///just for fun
node.physicsBody.linearDamping=10;
node.physicsBody.angularVelocity=10*10;
//where _gameHero is magnet fulling object
[node.physicsBody applyForce:CGVectorMake((10*10)*(_gameHero.position.x- node.position.x),(10*10)*(_gameHero.position.y-node.position.y)) atPoint:CGPointMake(_gameHero.position.x,_gameHero.position.y)];
}
}
}
remember both hero and coin body need be dynamic
Well seems like now you can since Apple introduced SKFieldNode in iOS 8.
Well you use the following code snippets to do what you're looking for, but it doesn't have attraction and repulsion properties
Body code:
let node = SKSpriteNode(imageNamed: "vortex")
node.name = "vortex"
node.position = position
node.run(SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat.pi, duration: 1)))
node.physicsBody = SKPhysicsBody(circleOfRadius: node.size.width / 2)
node.physicsBody?.isDynamic = false
node.physicsBody?.categoryBitMask = CollisionTypes.vortex.rawValue
node.physicsBody?.contactTestBitMask = CollisionTypes.player.rawValue
node.physicsBody?.collisionBitMask = 0
addChild(node)
Upon contact with the that blackhole body:
func playerCollided(with node: SKNode) {
if node.name == "vortex" {
player.physicsBody?.isDynamic = false
isGameOver = true
score -= 1
let move = SKAction.move(to: node.position, duration: 0.25)
let scale = SKAction.scale(to: 0.0001, duration: 0.25)
let remove = SKAction.removeFromParent()
let sequence = SKAction.sequence([move, scale, remove])
player.run(sequence) { [unowned self] in
self.createPlayer()
self.isGameOver = false
}
}

How to step one frame forward and one frame backward in video playback?

I need to search for some special features/patterns that might be visible in only one (or two) of many frames. The frame rate can be as slow as 25 frames per second and the video may contain over 7500 frames. I often start by scanning the video at high speed looking for a segment where I might find the feature, then rewind. I repeat this procedure while gradually reducing the playback speed, until I find a fairly small time window in which I can expect to find the feature (if it is present). I would then like to step forward and backward by single frames using key hit events (e.g. right arrow and left arrow keys) to find the feature of interest. I have managed to use HTML5 with JavaScript to control the forward speed; but, still do not know how to use the keyboard for single frame stepping forward and backward through a video. How can this be accomplished? Note, my web browser is Firefox 26 running on a Windows 7 platform.
You can seek to any time in the video by setting the currentTime property. Something like this:
var video = document.getElementById('video'),
frameTime = 1 / 25; //assume 25 fps
window.addEventListener('keypress', function (evt) {
if (video.paused) { //or you can force it to pause here
if (evt.keyCode === 37) { //left arrow
//one frame back
video.currentTime = Math.max(0, video.currentTime - frameTime);
} else if (evt.keyCode === 39) { //right arrow
//one frame forward
//Don't go past the end, otherwise you may get an error
video.currentTime = Math.min(video.duration, video.currentTime + frameTime);
}
}
});
Just a couple things you need to be aware of, though they shouldn't cause you too much trouble:
There is no way to detect the frame rate, so you have to either hard-code it or list it in some lookup table or guess.
Seeking may take a few milliseconds or more and does not happen synchronously. The browser needs some time to load the video from the network (if it's not already loaded) and to decode the frame. If you need to know when seeking is done, you can listen for the 'seeked' event.
You can check to see if the video has advanced to the next frame by checking the
targetTime += (1 / 25) // 25 fps
video.currentTime = targetTime // set the video frame
if (video.currentTime >= video.duration) { // if it's the end of the video
alert('done!');
}
if (video.currentTime == targetTime) { // frame has been updated
}