Marching through a voxel volume takes over a second - c#

I'm trying to raycast / raymarch through a (virtual) volume of 64^3 voxels for about 90x90 rays. The marching algorithm looks like this:
public byte[] GetVoxel(Vec3 rayStart, Vec3 direction)
{
direction.Normalize();
bool wasInside = false;
IVec3 step = new IVec3(Math.Sign(direction.x), Math.Sign(direction.y), Math.Sign(direction.z));
IVec3 p = new IVec3(rayStart);
if (step.x > 0)
p.x += 1;
if (step.y > 0)
p.y += 1;
if (step.z > 0)
p.z += 1;
Vec3 max = new Vec3(
direction.x != 0f ? Math.Abs((p.x - rayStart.x) / direction.x) : float.PositiveInfinity,
direction.y != 0f ? Math.Abs((p.y - rayStart.y) / direction.y) : float.PositiveInfinity,
direction.z != 0f ? Math.Abs((p.z - rayStart.z) / direction.z) : float.PositiveInfinity
);
Vec3 delta = new Vec3(
direction.x != 0f ? Math.Abs(1f / direction.x) : float.PositiveInfinity,
direction.y != 0f ? Math.Abs(1f / direction.y) : float.PositiveInfinity,
direction.z != 0f ? Math.Abs(1f / direction.z) : float.PositiveInfinity
);
byte[] col = new byte[4] {0,0,0,0};
byte[] newCol;
int maxSteps = voxelResolution * 2;
int k = 0;
do
{
if(max.x < max.y)
{
if(max.x < max.z)
{
p.x += step.x;
max.x += delta.x;
}
else
{
p.z += step.z;
max.z += delta.z;
}
}
else
{
if(max.y < max.z)
{
p.y += step.y;
max.y += delta.y;
}
else
{
p.z += step.z;
max.z += delta.z;
}
}
if(p.x >= 0 && p.x < voxelResolution && p.y >= 0 && p.y < voxelResolution)
{
if (!wasInside)
wasInside = true;
}
else if(wasInside)
{
break;
}
newCol = GetVoxel(p);
if(newCol[3] > 0)
col = ColorHelper.Mix(col, newCol);
k++;
}
while (col[3] <= 255 && k < maxSteps);
return col;
}
This takes over a second to perform. Shouldn't this be way faster or do I have a bottleneck?
Update:
I measured a bit and it turns out the most time is lost fetching the actual color from the voxel. I improved it already, but it still costs a total of over 300 ms:
Time total: 659
Time make: 659
Time setup: 3
Time march: 102
Time color: 318
Time update image: 0
I don't really understand where I'm missing 200 ms though. Also I'm confused why it takes so long to fetch the color for each voxel. I've updated the code and I'll include the voxel fetching method:
public void DrawImage(Vec3 camCenter, Vec3 viewDir)
{
int w = ResInternal;
int h = ResInternal;
viewDir.y *= -1;
long tSetup = 0, tTotal = 0, tMake = 0, tUpdateImage = 0, tMarch = 0, tGetColor = 0;
Stopwatch sw = new Stopwatch();
sw.Start();
if (w > 0 && h > 0)
{
int x, y;
viewDir.Normalize();
Vec3 right = Vec3.Cross(new Vec3(0, 1, 0), viewDir);
Vec3 up = Vec3.Cross(viewDir, right);
Vec3 halfS = new Vec3(w, h, 0) * 0.5f;
Vec3 loc;
for (int i = 0; i < bitmapData.Length / bpp; i++)
{
x = i % w;
y = i / w;
loc = camCenter + right * (x - w * 0.5f) + up * (y - h * 0.5f);
isoObject.GetVoxel(loc, viewDir,ref bitmapData, i * bpp, ref sw, ref tSetup, ref tMarch, ref tGetColor);
}
tMake = sw.ElapsedMilliseconds;
UpdateImage();
tUpdateImage = sw.ElapsedMilliseconds - tMake;
tTotal = sw.ElapsedMilliseconds;
}
Console.WriteLine("Time total: " + tTotal);
Console.WriteLine("Time make: " + tMake);
Console.WriteLine("Time setup: " + tSetup);
Console.WriteLine("Time march: " + tMarch);
Console.WriteLine("Time color: " + tGetColor);
Console.WriteLine("Time update image: " + tUpdateImage);
}
here is the getVoxel method:
public void GetVoxel(Vec3 rayStart, Vec3 direction, ref byte[] imgData, int index, ref System.Diagnostics.Stopwatch stopwatch, ref long timeSetup, ref long timeMarch, ref long timeColor)
{
long t = stopwatch.ElapsedMilliseconds;
direction.Normalize();
bool wasInside = false;
IVec3 step = new IVec3(Math.Sign(direction.x), Math.Sign(direction.y), Math.Sign(direction.z));
IVec3 p = new IVec3(rayStart);
if (step.x > 0)
p.x += 1;
if (step.y > 0)
p.y += 1;
if (step.z > 0)
p.z += 1;
Vec3 max = new Vec3(
direction.x != 0f ? Math.Abs((p.x - rayStart.x) / direction.x) : float.PositiveInfinity,
direction.y != 0f ? Math.Abs((p.y - rayStart.y) / direction.y) : float.PositiveInfinity,
direction.z != 0f ? Math.Abs((p.z - rayStart.z) / direction.z) : float.PositiveInfinity
);
Vec3 delta = new Vec3(
direction.x != 0f ? Math.Abs(1f / direction.x) : float.PositiveInfinity,
direction.y != 0f ? Math.Abs(1f / direction.y) : float.PositiveInfinity,
direction.z != 0f ? Math.Abs(1f / direction.z) : float.PositiveInfinity
);
byte[] col = new byte[4] {0,0,0,0};
byte[] newCol;
int maxSteps = voxelResolution * 2;
int k = 0;
timeSetup += stopwatch.ElapsedMilliseconds - t;
t = stopwatch.ElapsedMilliseconds;
do
{
if(max.x < max.y)
{
if(max.x < max.z)
{
p.x += step.x;
max.x += delta.x;
}
else
{
p.z += step.z;
max.z += delta.z;
}
}
else
{
if(max.y < max.z)
{
p.y += step.y;
max.y += delta.y;
}
else
{
p.z += step.z;
max.z += delta.z;
}
}
if(p.x >= 0 && p.x < voxelResolution && p.y >= 0 && p.y < voxelResolution)
{
if (!wasInside)
wasInside = true;
}
else if(wasInside)
{
break;
}
timeMarch += stopwatch.ElapsedMilliseconds - t;
t = stopwatch.ElapsedMilliseconds;
newCol = Root.GetVoxel(p);
if(newCol[3] > 0)
col = ColorHelper.Mix(col, newCol);
timeColor += stopwatch.ElapsedMilliseconds - t;
t = stopwatch.ElapsedMilliseconds;
k++;
}
while (col[3] <= 255 && k < maxSteps);
Buffer.BlockCopy(col, 0, imgData, index, 4);
//return col;
}
and the actual voxel fetching:
public byte[] GetVoxel(IVec3 location)
{
byte[] col = new byte[] { 0, 0, 0, 0 };
if (voxelData != null)
{
if (location.x >= 0 && location.y >= 0 && location.z >= 0 && location.x < resolution && location.y < resolution && location.z < resolution)
{
col = voxelData[location.x, location.y, location.z];
}
}
foreach(var c in children.Values)
{
if(c.Carve)
{
col[3] = (byte)(col[3] * (1f - c.GetVoxel(location)[3] / 255f));
}
}
if(col[3] < 255)
{
foreach (var c in children.Values)
{
if (!c.Carve)
{
col = ColorHelper.Mix(c.GetVoxel(location), col);
if (col[3] >= 255)
break;
}
}
}
return col;
}
I'm testing with only two layers, the root layer which is empty (voxelData is null) and one child layer with the actualy voxel data. Somehow ~300 ms are lost on a simple array fetch.

Related

Trying to position all chunks for distinct LoD levels

Well, my question is pretty simple to understand, I'm trying to create a grid of chunks but on each step, I want to double the distance of a chunk.
Then, this is the code I have:
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class DrawLoDTest : MonoBehaviour
{
private List<Vector3> initialChunks;
public int chunkSize = 16;
public int lodLevels = 2;
public int width = 16;
public int height = 16;
private Color[] colorList;
// Start is called before the first frame update
private void Start()
{
}
// Update is called once per frame
private void Update()
{
}
private void Init()
{
if (initialChunks != null && initialChunks.Count > 0)
return;
colorList = new[] { Color.blue, Color.green, Color.yellow, Color.cyan, Color.magenta, Color.grey };
Debug.Log("Init test!");
initialChunks = new List<Vector3>(16 * 16);
for (var i = 0; i < width * height; i++)
{
var x = i % width;
var y = i / width;
initialChunks.Add(new Vector3(x * chunkSize - width * chunkSize / 2, 0, y * chunkSize - height * chunkSize / 2));
}
//Debug.Log(string.Join(Environment.NewLine, initialChunks.Select(v => v.ToString())));
}
private void OnDrawGizmos()
{
Init();
Gizmos.color = Color.red;
foreach (var chunk in initialChunks)
{
Gizmos.DrawWireCube(chunk, Vector3.one * chunkSize);
}
var ww = 0;
var ww2 = 0;
var sum = 0;
var halfChunkSize = chunkSize / 2;
var halfWidth = width * halfChunkSize;
var halfHeight = height * halfChunkSize;
for (var i = 1; i <= lodLevels; i++)
{
if (ww > 0)
++ww2;
var pow = (int)Mathf.Pow(2, i);
var w = width / pow;
var h = height / pow;
Gizmos.color = colorList[i - 1];
var oddSum = ww * chunkSize * pow;
for (var x = -1 - ww2; x <= w + ww2; x++)
{
for (var n = 0; n <= 1; n++)
{
var sign = n == 0 ? -1 : 1;
var chunk = new Vector3(
halfWidth - x * chunkSize * pow - halfChunkSize,
0,
halfHeight * sign - halfChunkSize - chunkSize * 2 * sign + oddSum * sign + sum * sign);
chunk.x -= pow * halfChunkSize;
for (var j = i + 1; j >= i; j--)
{
chunk.z += chunkSize * (int)Mathf.Pow(2, j) / 2 * sign;
}
Gizmos.DrawWireCube(chunk, Vector3.one * chunkSize * pow);
}
}
// TODO
if ((w + ww2 * 2 + 2) / 2 % 2 != 0)
{
Debug.Log($"[{i}, {ww}, {ww2}] W: {w} + {ww2} * 2 = {w + ww2 * 2} + 2 = {w + ww2 * 2 + 2} / 2 = {(w + ww2 * 2 + 2) / 2}");
if (ww == 0)
{
--i;
++ww;
}
else
{
ww = 0;
sum += oddSum;
}
}
else
{
if (ww2 > 0)
ww2 = 0;
}
}
}
}
A little bit of explanation:
First, I load a 16x16 chunk grid (initialChunks).
Then, I start a loop foreach lod level (I'm testing it for 6 levels).
Then, foreach axis I iterate its position.
Then, in a nested loop foreach axis I give a sign (a loop for 0 to 1, that converts into -1 and 1 for the sign).
Then, and this is the more complex thing, if the following row/column has an odd number of elements then I try to match the current row/column by doubling it, in that way non of the following corner will be half of the previous one, like the image below:
I have two main problems:
For some reason, sum and oddSum variables has the wrong input.
At certain levels, (for i >= 5) the logic is broken.

C# playing sound from one speaker at a time

I am trying to play sound from one speaker/earphone at a time. So I zero out the values for one side. but it is not working.
in a wav file the even values play from the right speaker/ hearphone and the old from the left right ?
so why it is not working
here is my code:
public override int Read(byte[] buffer, int offset, int sampleCount)
{
if (position == 0 && onetimeflag == false)
{
n2 = 0;
onetimeflag = true;
}
if (n2 >= Bufferlength && stopflag == false)
{
Dispose();
return 0;
}
float temp1;
for (int i = 0; i < (sampleCount / 4); i++)
{
if (Frequency_switch == true)
{
temp1 = (float)(Amplitude * Math.Sin(Math.PI * Frequency * n2 / 44100D));
Frequency_switch = false;
}
else
{
temp1 = (float)(Amplitude2 * Math.Sin((Math.PI * Frequency2 * n2) / 44100D));
Frequency_switch = true;
}
byte[] bytes = BitConverter.GetBytes(temp1);
buffer[i * 4 + 0] = bytes[0];
buffer[i * 4 + 1] = bytes[1];
buffer[i * 4 + 2] = bytes[2];
buffer[i * 4 + 3] = bytes[3];
tempSample++;
n2++;
}
return sampleCount;}} }
I am using the NAudio library
here is how I play the sound:
private void button1_Click(object sender, EventArgs e)
{
Play(1, 240, 0);
}
binaural_beats BBeats;
WaveOut waveout;
void Play(double Amp, double Left, double Right)
{
BBeats = new binaural_beats();
BBeats.Amplitude = Amp;
BBeats.Amplitude2 = Amp;
BBeats.Frequency = Left;
BBeats.Frequency2 = Right;
BBeats.Bufferlength = 44100 * 2 * 3;// will play for 3 sec
waveout = new WaveOut();
WaveChannel32 temp = new WaveChannel32(BBeats);
temp.PadWithZeroes = false;
waveout.Init(temp);
waveout.Play();
}

Why is my dragon fractal incomplete [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I have translated the code from javascript to c# which can be found by going to this excellent demo at http://fractal.qfox.nl/dragon.js
My translation is intended to produce just a single dragon upon clicking the button but I think I have missed something in my version.
See the Wikipedia article: Dragon Curve for more information.
Incomplete dragon fractal output:
Code:
public partial class MainPage : UserControl
{
PointCollection pc;
Int32[] pattern = new Int32[] { 1, 1, 0, 2, 1, 0, 0, 3 };
Int32[] position = new Int32[] { 0, 0, 0, 0, 0, 0, 0, 0 };
Boolean toggle;
Char r = default(Char);
Int32 distance = 10; // line length
Int32 step = 100; // paints per step
Int32 skip = 10; // folds per paint
Double x = 0;
Double y = 0;
Int32 a = 90;
public MainPage()
{
InitializeComponent();
}
private void btnFire_Click(object sender, RoutedEventArgs e)
{
x = canvas.ActualWidth / 3;
y = canvas.ActualHeight / 1.5;
pc = new PointCollection();
var n = step;
while (--n > 0)
{
List<Char> s = getS(skip);
draw(s);
}
Polyline p = new Polyline();
p.Stroke = new SolidColorBrush(Colors.Red);
p.StrokeThickness = 0.5;
p.Points = pc;
canvas.Children.Add(p);
}
List<Char> getS(Int32 n)
{
List<Char> s1 = new List<Char>();
while (n-- > 0) s1.Add(getNext(0));
return s1;
}
void draw(List<Char> s)
{
pc.Add(new Point(x, y));
for (Int32 i = 0, n = s.Count; i < n; i++)
{
pc.Add(new Point(x, y));
Int32 j;
if (int.TryParse(s[i].ToString(), out j) && j != 0)
{
if ((a + 90) % 360 != 0)
{
a = (a + 90) % 360;
}
else
{
a = 360; // Right
}
}
else
{
if (a - 90 != 0)
{
a = a - 90;
}
else
{
a = 360; // Right
}
}
// new target
if (a == 0 || a == 360)
{
y -= distance;
}
else if (a == 90)
{
x += distance;
}
else if (a == 180)
{
y += distance;
}
else if (a == 270)
{
x -= distance;
}
// move
pc.Add(new Point(x, y));
}
}
Char getNext(Int32 n)
{
if (position[n] == 7)
{
r = getNext(n + 1);
position[n] = 0;
}
else
{
var x = position[n] > 0 ? pattern[position[n]] : pattern[0];
switch (x)
{
case 0:
r = '0';
break;
case 1:
r = '1';
break;
case 2:
if (!toggle)
{
r = '1';
}
else
{
r = '0';
}
toggle = !toggle;
break;
}
position[n] = position[n] + 1;
}
return r;
}
}
I cleaned up the code, and tried to get how the pattern and position arrays should work to produce the correct sequence, but I couldn't figure it out. The last item in the pattern array is for example never used...
There is however a simpler method implementing the getNext method using just a counter:
bool getNext() {
cnt++;
return (cnt & ((cnt & -cnt) << 1)) != 0;
}
I have used that method before (about 20 years ago), and I found this implementation on the dragon curve wikipedia page.
The cleaned up code with this getNext implementation looks like this:
public partial class MainPage : UserControl {
PointCollection pc;
int cnt = 0;
int distance = 10; // line length
int steps = 1024; // number of paints
int x = 0;
int y = 0;
int a = 90;
public MainPage() {
InitializeComponent();
}
private void btnFire_Click(object sender, RoutedEventArgs e) {
x = (int)(canvas.ActualWidth / 3);
y = (int)(canvas.ActualHeight / 1.5);
pc = new PointCollection();
draw(getS(steps));
Polyline p = new Polyline();
p.Stroke = new SolidColorBrush(Colors.Red);
p.StrokeThickness = 0.5;
p.Points = pc;
canvas.Children.Add(p);
}
List<bool> getS(int n) {
List<bool> s1 = new List<bool>();
while (n-- > 0) {
s1.Add(getNext());
}
return s1;
}
void draw(List<bool> s) {
pc.Add(new Point(x, y));
foreach (bool z in s) {
a = (a + (z ? 90 : 270)) % 360;
// new target
switch (a) {
case 90: x += distance; break;
case 180: y += distance; break;
case 270: x -= distance; break;
default: y -= distance; break;
}
// move
pc.Add(new Point(x, y));
}
}
bool getNext() {
cnt++;
return (cnt & ((cnt & -cnt) << 1)) != 0;
}
}

How can I get my collision to be more solid?

I'm working on a game in C# with XNA and I've been learning program in C# thanks to Nick Gravelyn's tutorials, but I've hit a snag. While I'm using Nick's collision system, I'm not using his player code. I'm using one that's based on a tutorial by Fatso784 that I've modified. So, as a result, I'm having trouble making my modified version of the collision system work properly. I've got it to the point that it pushes the player out of certain tiles, but I need it to be more solid because the player is still able walk through walls occasionally. I'm pretty sure I'm handling the collision wrong, but it could be that the collision is a little mushy. So here's the relevant code from my player class, the move code:
public void Move()
{
pos.X = bounds.X;
pos.Y = bounds.Y;
offsetPos.X = bounds.Width;
offsetPos.Y = bounds.Height;
if (frameCount % delay == 0)
{
switch (direction)
{
case "stand":
if (sideCollide == "none")
{
Equalize(2);
}
else if (sideCollide == "left")
{
speed += 1f;
}
else if (sideCollide == "right")
{
speed -= 1f;
}
bounds.X += (int)speed;
if (frameCount / delay >= 8)
frameCount = 0;
srcBounds = new Rectangle(frameCount / delay * 64, 0, 64, 64);
break;
case "left":
if (sideCollide != "left")
{
if (speed > -maxspeed)
{
speed -= acceleration;
}
else if (speed < -maxspeed)
{
speed -= acceleration;
speed += drag;
Equalize(2);
}
speed += friction;
}
bounds.X += (int)speed;
if (frameCount / delay >= 4)
frameCount = 0;
srcBounds = new Rectangle(frameCount / delay * 64, 64, 64, 64);
break;
case "right":
if (sideCollide != "right")
{
if (speed < maxspeed)
{
speed += acceleration;
}
else if (speed > maxspeed)
{
speed += acceleration;
speed -= drag;
Equalize(2);
}
speed -= friction;
}
bounds.X += (int)speed;
if (frameCount / delay >= 4)
frameCount = 0;
srcBounds = new Rectangle(frameCount / delay * 64, 64, 64, 64);
break;
case "up":
if (speed > -4 && speed < 4)
srcBounds.Y = 128;
else
srcBounds.Y = 64;
if (srcBounds.Y == 0 || srcBounds.Y == 128)
{
if (jumpCount < 2)
{
if (frameCount / delay >= 9)
frameCount = 0;
}
else if (jumpCount > 2 && jumpCount <= 10)
{
if (frameCount / delay > 3)
frameCount = 2 * delay;
}
else if (jumpCount > 10 && jumpCount <= 18)
{
if (frameCount / delay > 5)
frameCount = 4 * delay;
}
else if (jumpCount > 18)
{
if (frameCount / delay >= 9)
frameCount = 0;
}
srcBounds = new Rectangle(frameCount / delay * 64, 128, 64, 64);
}
else if (srcBounds.Y == 64)
{
if (frameCount / delay >= 4)
frameCount = 0;
if (jumpCount <= 10)
srcBounds = new Rectangle((frameCount / delay) / 2 * 64, 64, 64, 64);
else
srcBounds = new Rectangle(frameCount / delay * 64, 64, 64, 64);
}
if (jumpCount == 0)
startY = bounds.Y;
bounds = new Rectangle(bounds.X + (int)speed,
(jumpCount - 10) * (jumpCount - 10) - 100 + startY, 64, 64);
jumpCount++;
if (bounds.Y > startY)
{
bounds.Y = startY;
direction = "stand";
jumpCount = 0;
}
break;
}
}
frameCount++;
}
And the collision code:
public void CollideOutside(TileMap tilemap)
{
Point cell = Engine.PointCell(PlayerCenter);
Point? upLeft = null, Up = null, upRight = null, Right = null, downRight = null, Down = null, downLeft = null, Left = null;
if (cell.Y > 0)
{
Up = new Point(cell.X, cell.Y - 1);
}
if (cell.Y < tilemap.collisionMap.HeightinPixels)
{
Down = new Point(cell.X, cell.Y + 1);
}
if (cell.X > 0)
{
Left = new Point(cell.X - 1, cell.Y);
}
if (cell.X < tilemap.collisionMap.WidthinPixels)
{
Right = new Point(cell.X + 1, cell.Y);
}
if (cell.X > 0 && cell.Y > 0)
{
upLeft = new Point(cell.X - 1, cell.Y - 1);
}
if (cell.X < tilemap.collisionMap.WidthinPixels - 1 && cell.Y > 0)
{
upRight = new Point(cell.X + 1, cell.Y - 1);
}
if (cell.X > 0 && cell.Y < tilemap.collisionMap.HeightinPixels - 1)
{
downLeft = new Point(cell.X - 1, cell.Y + 1);
}
if (cell.X < tilemap.collisionMap.WidthinPixels - 1 && cell.Y < tilemap.collisionMap.Height - 1)
{
downRight = new Point(cell.X + 1, cell.Y + 1);
}
if (Up != null && tilemap.collisionMap.GetCellIndex(Up.Value) == 1)
{
Rectangle rect = Engine.CreateCell(Up.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
}
}
if (Down != null && tilemap.collisionMap.GetCellIndex(Down.Value) == 1)
{
Rectangle rect = Engine.CreateCell(Down.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
}
}
if (Right != null && tilemap.collisionMap.GetCellIndex(Right.Value) == 1)
{
Rectangle rect = Engine.CreateCell(Right.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
speed = -1f;
sideCollide = "right";
}
else
{
sideCollide = "none";
}
}
if (Left != null && tilemap.collisionMap.GetCellIndex(Left.Value) == 1)
{
Rectangle rect = Engine.CreateCell(Left.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
speed = 1f;
sideCollide = "left";
}
else
{
sideCollide = "none";
}
}
if (upLeft != null && tilemap.collisionMap.GetCellIndex(upLeft.Value) == 1)
{
Rectangle rect = Engine.CreateCell(upLeft.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
}
}
if (upRight != null && tilemap.collisionMap.GetCellIndex(upRight.Value) == 1)
{
Rectangle rect = Engine.CreateCell(upRight.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
}
}
if (downLeft != null && Left != null && tilemap.collisionMap.GetCellIndex(downLeft.Value) == 1)
{
Rectangle rect = Engine.CreateCell(downLeft.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
speed = 1f;
sideCollide = "left";
}
}
if (downRight != null && Right != null && tilemap.collisionMap.GetCellIndex(downRight.Value) == 1)
{
Rectangle rect = Engine.CreateCell(downRight.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
speed = -1f;
sideCollide = "right";
}
}
if (Right == null && Left == null)
{
sideCollide = "none";
}
}
public Rectangle Boundary
{
get
{
Rectangle rect = bounds;
rect.X = (int)pos.X;
rect.Y = (int)pos.Y;
return rect;
}
}
So how can I improve the collision?
This answer is mostly in response to Tim's answer - because he's given very much the wrong approach. (Your question is a very large code dump, I can't really play spot-the-error with that much code.)
The trick with collision detection - the way the "real" physics engines do it - is to always treat your objects as solids. You always - each frame - check objects for interpenetration, and then separate them if they interpenetrate.
If you only test for moving across the boundary of an object you are going to miss collisions. This includes any approach where you attempt to predict and avoid a collision by snapping onto the surface. If you do this, you are just asking for floating-point precision errors to let you slip inside objects.
EDIT: of course, your code all seems to be integer-based (Point and Rectangle). So at least floating-point precision should not be an issue. But maybe you have a < where you should have a <= or something to that effect?
(Also you're using strings in a lot of places where you very much should be using enumerations.)

XNA 2D TileEngine Mouse clicking issue

My problem is that clicks only get registers on the lower right corner and in some cases not even there it seems to get worse the longer you stray from the 0.0 and the likes the worse it gets.
public void Render(SpriteBatch B, Camera C)
{
Vector2 firstSquare = new Vector2(C.Position.X / 32, C.Position.Y / 32);
int firstX = (int)firstSquare.X;
int firstY = (int)firstSquare.Y;
Vector2 squareOffset = new Vector2(C.Position.X % 32, C.Position.Y % 32);
int offsetX = (int)squareOffset.X;
int offsetY = (int)squareOffset.Y;
for (int y = 0; y < 16; y++)
{
for (int x = 0; x < 26; x++)
{
Tile T = GetTile(x + firstX, y + firstY);
if (T == null)
{
continue;
}
T.RenderWithCamera(B,new Vector2((x*32)-offsetX,(y*32)-offsetY));
}
}
public void CheckClick(float mx, float my,Camera C)
{
Vector2 firstSquare = new Vector2(C.Position.X / 32, C.Position.Y / 32);
int x = (int)firstSquare.X;
int y = (int)firstSquare.Y;
Vector2 squareOffset = new Vector2(C.Position.X % 32, C.Position.Y % 32);
int offsetX = (int)squareOffset.X;
int offsetY = (int)squareOffset.Y;
int vx = (int)mx / 32;
int vy = (int)my / 32;
float x1 = vx + x;
float y1 = vy + y;
int maxX, maxY;
maxX = C.Width / 32;
maxY = C.Height / 32;
Console.WriteLine("MAX_X:" + maxX + "MAX_Y:" + maxY);
Tile T = GetTile(x1, y1);
Rectangle A = new Rectangle((int)mx, (int)my, 1, 1);
if (T == null)
{ Console.WriteLine("No Tile found"); return; }
if (T.IsInside(A))
{
Console.WriteLine("Not inside?");
Tile S = null;
S = new Wall((int)x1, (int)y1, 0);
if (S != null)
{
tiles.Add(S);
tiles2[(int)T.pos.X, (int)T.pos.Y] = S;
}
}
Console.WriteLine("Clicked Tile at X:" + T.pos.X + "Y:" + T.pos.Y);
}
public bool IsInside(Rectangle B) // TILE
{
Rectangle rectA = new Rectangle((int)Last_pos.X, (int)Last_pos.Y, icon.Width, icon.Height);
Console.WriteLine("A:" + rectA.X + "A.y:" + rectA.Y + "B.X:" + B.X + "B.Y:" + B.Y);
if(rectA.Intersects(B))
{
return true;
}
else
return false;
}
Here's how I like to handle clicking a tilemap.
int xTile = Math.floor((Mouse.X + CameraBounds.left) / Tile.width);
int yTile = Math.floor((Mouse.Y + CameraBounds.top) / Tile.height);

Categories

Resources