I've been having trouble implementing an algorithm to shift my textures given their positions and the cameras position. The first two pictures in the image explain what I'm trying to accomplish, but I can't figure out how to move them accordingly. I had created a program once upon a time that did this, but I've gone and lost it. Any ideas?
If it helps any, the Cameras/Viewports width and height are the same as the textures' width and height. The goal is the get them to shift positions, giving the illusion of an infinite plane. (With out having to draw an infinite plane, lol.)
You do not really need to move your regions, enough to decide where to draw them. Lets assume you have a terrain containing N*M blocks (in this case N=M=2), each of them are size of A*A (in this case the screen hase the same size, but this doesn't matter), and the Tiles are continously following each other.
int LeftColumn = Camera.X / A; // let it round to nearest lower int
int TopRow = Camera.Y / A;
LeftColumn = LeftColumn % N; // Calculate the first tile
TopRow = TopRow % M;
for (int i = LeftColumn+N; i < LeftColumn+2*N; i++)
for (int l = TopRow+M; l < TopRow+2*M; l++)
// you may check here if the tile is visible or not based on the screen size
{
Tile[i % N, l % M].Draw(i*A, l*A); // Or do whatever you like
}
Is this clear?
After a couple hours of trial and error, I finally figured out how to get the regions/textures/rectangles to move accordingly. For those who want the solution,
if ((int)Math.Abs(region.X - camPos.X) > region.Width * 2)
{
region.X += region.Width * 2;
}
if (camPos.X < region.X - region.Width)
{
region.X -= region.Width * 2;
}
if ((int)Math.Abs(region.Y - camPos.Y) > region.Height * 2)
{
region.Y += region.Height * 2;
}
if (camPos.Y < region.Y - region.Height)
{
region.Y -= region.Height * 2;
}
Where camPos is the camera position, and region is the region/texture/rectangle/whatever.
This code works for a 4 square region (2 regions by 2 regions). To change for more regions, simply change all the *2s to *3s or *4s for a 9 square region and 16 square region, respectively.
Related
I'm trying to make an "Explosion effect on a grid", and I need an algorithm that will allow me to do the following:
Note: The grid represents a List<List>, and I'm trying to filter out the red dots
So we start off with a given grid with black dots (in our case, black dots represent solid points on our grid, and red dots represent the points we remove from the list)
Eventually, our ractangle transformed into this random shape with holes on the edges (blue area)
My Attempt:
The Problem:
Sometimes the radius of my star/circle shape is pretty big and the output doesn't give me that "explosion" effect I'm looking for (basically, an unpredictable output), plus it really limits the shape.
Do you have any ideas or know of some mathematical algorithms that can help? Thanks for reading! :)
Sorry if I wasn't clear enough, but this is basically what I'm looking for:
This is straightforward approach to get template:
using System;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
int size = 10;
var grid = GetExplosionTemplate(size, new Random(),1);
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
Console.Write(grid[i + j * size] ? "X" : "O");
}
Console.WriteLine();
}
}
private static bool[] GetExplosionTemplate(int size, Random rnd = null, float explosionRoughness = 0)
{
var grid = new bool[size * size];
var rr = (size + 1) / 2f;
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
var cellId = i + j * size;
var r = Math.Sqrt(Math.Pow(i - size / 2, 2) + Math.Pow(j - size / 2, 2)) + rnd?.NextDouble()*explosionRoughness ?? 0;
grid[cellId] = r > rr;
}
}
return grid;
}
}
}
Roughness above 1 will give scattered inside explosion, below will give more round explosion. Value around 0.5 to 1.5 is great looking for both even/non-even values. You can play around to make it better looking, honestly for explosion physics I rather choose this roughness based on material in cell (sand penetration is better than stone, for example), cause you don't want fully fledged physics where you calculate explosion power traveling across weighted by resistance cells (for example, explosion in cave will travel along empty paths and slightly destruct environment, rather than create vacuum in radius)
Another simple approach to actually simulate explosion physics is to use recursion. You start at center with explosion power equal to some value, than as you travel wide, each cell will consume some part of that power (and may be destroyed in process), than equaly emits left part of its power to adjacent cells (even visited, so you simulate explosion wave). This way it will be more realistic in terms of materials. You can even simulate partially empty cell from resistance materials (like, iron fence, it is resistant but emits better and destroy everything around)
I am using Point Cloud Free Viewer to visualize Point Clouds in Unity. It has a script and it parses .off files and creates meshes without triangulating. However, the code creates multiple meshes since its index format is 16bit. I modified the code for utilizing 32 bit format and i have a mesh with 2 million points:
What i want to do is creating a grid like geometry and color this point cloud based on point density. I want to find a rough volume of this point cloud by multiplying differences between max and min x,y,z values and divide this volume into equal boxes. Each of these boxes will be colored based of how many points they contain. I would be happy if someone can offer me a lead. I tried KDTree approach but it is a bit slow since i have 2 million points. I also tried sorting points before creating the mesh but it takes too much time as well. Is there a way to traverse mesh vertices based on the location without visiting all vertices considering they are indexed randomly? I believe i am looking for a solution like mesh.bounds.contains() but i do not know if a method like spatial search exists.
Not really, a full solution, more a hint towards a direction I would pursue: divide your vertex pool into smaller groups first, I.e into cubes (seperate meshes maybe), precalculate this, then you only have to search within a much smaller region, after an initial search for a set of cubes that neighbour (or touch) your region.
It sounds to me like you want an octree.
First, load all of the points into memory (2 million points really isn't that many - assuming doubles, that's 2,000,000 * 3 * 8 bytes ~= 45 MB). While you are parsing the file and loading the points into memory, record the min and max x, y, and z coordinates. You can then build your octree which bounds that volume in N*LogN. Then, for each of your grid volumes, you can very quickly query the tree to get only the points in that region. I'm pretty sure this is the most efficient way to do what you want.
I would suggest checking the quadtree article for its implementation of queryRange to see how this would be done. An octree is just a 3-d implementation of a quadtree, so the underlying code is more or less the same (with each node containing 8 children instead of 4).
For those who might visit this question later i found a really fast solution based on Nico's comment. I am traversing whole points by parsing my scan file using this script
for (int i = 0; i < numPoints; i++)
{
buffer = sr.ReadLine().Split();
points[i] = new Vector3(float.Parse(buffer[0]) , float.Parse(buffer[1]) , -float.Parse(buffer[2]) );
//Finding minX, minY, minZ
if (points[i].x < minX)
minX = points[i].x;
if (points[i].y < minY)
minY = points[i].y;
if (points[i].z < minZ)
minZ = points[i].z;
//Finding maxX, maxY, maxZ
if (points[i].x > maxX)
maxX = points[i].x;
if (points[i].y > maxY)
maxY = points[i].y;
if (points[i].z > maxZ)
maxZ = points[i].z;
}
Here is my and variables i use with itFindPointIndex function.
deltaX = maxX - minX;
deltaY = maxY - minY;
deltaZ = maxZ - minZ;
gridCountX = Mathf.CeilToInt(deltaX / gridSize);
gridCountY = Mathf.CeilToInt(deltaY / gridSize);
gridCountZ = Mathf.CeilToInt(deltaZ / gridSize);
Resolution = gridCountX * gridCountY * gridCountZ;
Histogram = new int[Resolution];
int FindPointIndex(Vector3 point)
{
//Finds the grid index of the point
int index = Mathf.FloorToInt((point.x - minX) / gridSize) + ((Mathf.FloorToInt((point.z - minZ) / gridSize)) * gridCountX)
+ Mathf.FloorToInt((point.y - minY) / gridSize) * gridCountX * gridCountZ;
if (index < 0)
{
index = 0;
}
return index;
}
Then i can traverse the points again to increment index for each of them to see how many points each grid holds like this:
for (int i = 0; i < numPoints; i++)
{
Histogram[FindPointIndex(points[i])]++;
}
At the end using this histogram i can color the point cloud with another loop.
I am drawing on canvas based on device movement, I want to draw different characters in canvas based on mobile movement.
Currently its working, but I want to find time difference and i want to detect pause, pause means when user is not trying to draw and user is not moving mobile phone, so that Application ca assume that now user want to draw next character.
How to find pause in accelerometer values. Any logic? Also tell me how i can smooth accelerometer values, so that user can draw lines without noise.
I cannot help with the accelerator part, but for the noise in the data, here is one approach using Weighted Moving Average.
The basics are simple:
Find out how many points before current you want to use for smoothing
Calculate a weight based on length, f.ex. if length is 5 then the weight = 1+2+3+4+5 = 15
Iterate each data point starting from length of weight (you can start at 1 and cut the weighting short - below I'll demo the latter approach)
For point current - 5 multiply with 1/15, for current - 4 multiply with 2/15 and so forth. The sum is stored as value for this point, repeat for the next value points
Live demo
Below is a demo (enter full page to see all graphics). I wrote it in JavaScript so it could be shown live here in the answer. I think you should have little problem converting it into the language you're using (which is not stated).
Move the slider to increase number of points to weight. You can run the data through several passes to smooth even more. The original data is a sinus curve with noise jitter. With many points you can see the curve smooths to replicate this. Just using 9-10 points length over 2 passes will give a good result with very little time delay:
var ctx = document.querySelector("canvas").getContext("2d"),
rng = document.querySelector("input"),
val = document.querySelector("span"),
data = [], scale = 30;
// generate sinus wave with noise jitters
for(var i = 0; i < ctx.canvas.width; i += 2)
data.push(Math.sin(i*0.1) * Math.random() + Math.random())
// draw initial smoothed curve (length=1, no smoothing)
drawWMA();
// calculate moving average
function drawWMA() {
var len = +rng.value, // get smoothing length (number of previous points)
dataa = [], datab = [], // pass A and B arrays
weight = 0; // calc weight based on length
val.innerHTML = len;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.beginPath();
// calc weight
for(var i = 1; i <= len; i++) weight += i; // add range together [1, length]
// plot original data at top of canvas
plot(data, 30);
// PASS 1: Calc new smoothed array
dataa = calcWMA(data, len, weight);
// plot smoothed curve
ctx.fillText("FIRST PASS:", 0, 100);
plot(dataa, 120);
// PASS 2 (optional)
datab = calcWMA(dataa, len, weight);
ctx.fillText("SECOND PASS:", 0, 190);
plot(datab, 210);
ctx.stroke(); // render plots
}
function calcWMA(data, len, weight) {
var i, t, datao = [];
// calc new smoothed array
for(i = 0; i < data.length; i++) { // iterate from length to end of data
var v = 0; // calc average value for this position
for(t = 0; t < len; t++) { // [1, len]
if (i-t >= 0)
v += data[i-t] * ((t+1) / weight); // weight previous values based on -delta
}
datao.push(v); // store new value
}
return datao
}
function plot(data, y) {
ctx.moveTo(0, y + data[0]*scale);
for(i = 1; i < data.length; i++) ctx.lineTo(i * 2, y + data[i]*scale);
}
rng.onchange = rng.oninput = drawWMA;
<label>Points to consider: <input type="range" min=1 max=50 value=1></label><span>1</span><br>
<canvas width=600 height=300></canvas>
A different approach would be to use a Savitzky–Golay filter which gives a similar result, but not "sacrifice" any points at the end (moving average will push forward or crop at the end).
I've got quite a lot of code here, but it's relatively straightforward.
This is all snippets from different classes, all references are right, but I think I've done a math-based error somewhere and I can't find it. It always finds a collision on the y axis a pixel before it should. I haven't tried it with different X axis positions but it seems to fall past blocks next to it fine.
The struct "mapSection" just contains two Vector2s- A top-left block and bottom-left block coordinate.
tileManager.def_ts is the default tile width and height (32). The player's size is 32x64.
The toWorldSpace function does nothing right now other than return so that's not the problem.
When I say block coordinate I mean which index the block is in the tile array (Ex 0, 0 is the first block, 0, 1 is the second block on the Y axis, 1, 3 is 1 block in on the X axis and 3 on the Y axis, I do not mean actual pixels.)
From tile engine class:
public mapSection toMapMinMax(Vector2 position, Vector2 size)
{
position = toWorldSpace(position);
position.X = (float)Math.Floor(position.X / tileManager.def_ts);
position.Y = (float)Math.Floor(position.Y / tileManager.def_ts);
size.X = (float)Math.Floor(size.X / tileManager.def_ts);
size.Y = (float)Math.Floor(size.Y / tileManager.def_ts);
return new mapSection(position, position + size);
}
public bool collision(Vector2 screenPosition, Vector2 size)
{
mapSection mapCollisionPossibilities = toMapMinMax(screenPosition, size);
for (int y = (int)mapCollisionPossibilities.topLeft.Y; y <= mapCollisionPossibilities.bottomRight.Y; y++)
{
for (int x = (int)mapCollisionPossibilities.topLeft.X; x <= mapCollisionPossibilities.bottomRight.X; x++)
{
if (x >= 0 && y >= 0 && y < tiles.Count && x < tiles[y].Count)
{
if (tileManager.tileTypes[tiles[y][x]].collideable == true)
{
return true;
}
}
}
}
return false;
}
And this is the code from the player class:
if (!tEngine.collision(position + new Vector2(0, 1), new Vector2(32, 64)))
{
position.Y += 1;
}
I add "Vector2(0, 1)" because I want to see if there's a collision a pixel further down; so that he falls until he hits something. It's very basic right now but it's only to test the collision engine, which isn't working.
There's a picture of the error. You can see the player is a pixel too high.
In the picture, "X:" is the top-left block coordinate on X axis, "X2:" is the bottom-right block coordinate on the X axis, and same with "Y:" and "Y2: except Y axis. They're read from the mapSection directly.
If anyone can notice why this is happening, it would be massively appreciated.
Thanks.
If you cannot understand any section of the code just post in the comments and I'll be happy to explain, or if you think I've been a bit too unspecific in some area of this post.
EDIT: For the tile coordinates issue, your toMapMinMax code should be more like this:
EDIT2: have subtracted (1, 1) from bottomRight, since it is a size we are adding.
public mapSection toMapMinMax(Vector2 position, Vector2 size)
{
Vector2 topLeft = position;
Vector2 bottomRight = position + size - new Vector2(1, 1);
topLeft.X = (float)Math.Floor(topLeft.X / tileManager.def_ts);
topLeft.Y = (float)Math.Floor(topLeft.Y / tileManager.def_ts);
bottomRight.X = (float)Math.Floor(bottomRight.X / tileManager.def_ts);
bottomRight.Y = (float)Math.Floor(bottomRight.Y / tileManager.def_ts);
return new mapSection(topLeft, bottomRight);
}
Also, I was wrong in my above comment; you do want <= signs in your two for loops, because most of the time you will be checking 6 tiles.
for the off-by-one-pixel issue:
In order for you to see the character off by some amount of pixels, the draw code and the collision code must be different. If they were identical, for example if they were both off by 15 pixels (you collide 15 pixels too early, but you are also drawing 15 pixels ahead), you wouldn't see any change.
The 1 pixel gap indicates a 1 pixel difference between the draw coordinate calculation and the collision coordinate calculation. This 1 pixel difference is most likely caused by differences in rounding, probably that you are calling Math.Floor in the collision code, but are not rounding the coordinates in the draw code. (I would guess you are probably just passing the position Vector2 straight to the SpriteBatch.Draw method).
I'm working with ImageSharp to do some basic image editing in my UWP app, and one of the things I need to do is to crop the image to a circle (you can assume the image is already a square).
I couldn't find a Clip API that worked with anything else that rectangles, so I came up with the following snippet:
// Image is an Image<Argb32> instance
image.Mutate(context =>
{
context.Apply(target =>
{
double half = target.Height / 2.0;
unsafe
{
fixed (Argb32* p = target.GetPixelSpan())
for (int i = 0; i < target.Height; i++)
for (int j = 0; j < target.Width; j++)
if (Math.Sqrt((half - i).Square() + (half - j).Square()) > half)
p[i * target.Width + j] = default;
}
});
});
NOTE: that Square method is just an extension that takes a double and returns its squared value.
Now, this works fine, and it's reasonably fast as I'm working with small enough images (say, <= 250 pixels for each axis). This snippet simply sets each pixel that falls outside of the circle with radius height / 2, centered at the center of the image, to a transparent pixel.
I wonder though if there wasn't another more intuitive method to do the same thing, that I just missed.
Thank you for your help!