I have a problem with my first isometric game. I do not know how to do to my player able to approach the edge of the wall. In this moment player maybe move about in green area.
My map:
int[,] map = new int[,]
{
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1}
};
Variables:
int TileWidth = 50;
int TileHeight = 50;
int posX = 2; // map X position
int posY = 2; // map Y position
float playerX = 2 * 50; // player X position
float playerY = 2 * 50; // player Y position
Detect wall:
public bool detectSolidTile(int x, int y)
{
if (map[y, x] == 1) return true; else return false;
}
Movemet:
posX = (int)(Math.Floor((playerX) / 50));
posY = (int)(Math.Floor(playerY / 50));
(...)
if (slide == 1 && !detectSolidTile(posX + 1, posY))
{
playerX++;
}
if (slide == 2 && !detectSolidTile(posX - 1, posY))
{
playerX--;
}
Image -> http://s16.postimg.org/cxkfomemd/tiles.jpg
What I need improve to be able to move from wall to wall?
best regards, Krzysiek
Try making all the map where you can navigate 0, and then the map where you can not 1.
When trying to make a new move check if the future position will be either a 1 or a 0. If it's 0 you let him move, otherwise you stop him.
if (slide == 1 && !detectSolidTile(posX + 1, posY))
{
playerX++;
}
This will detect the map with 1 as being outside the movable region, thus stopping it from going where you want.
Do you understand where the problem is now?
Another solution is to understand the size of the matrix, and as soon x or y reach the maximum value, you stop incrementing them. But if you want to add obstacles later on, keep with what you are doing now, but make sure 0 is for map, 1 is for outside the map.
So here is a edit for BartoszKP:
You might be right that this "!" does not fix his code, I was just explaining how he should do it.
The code I would use for his issues is slightly different.
First of all drop the playerX and playerY since it is the exact same thing as posX and posY, you just do extra calculations.
now this being said you movement algorithm would look something like this:
Variables:
int TileWidth = 50;
int TileHeight = 50;
int posX = 2; // map X position - same thing as playerX
int posY = 2; // map Y position - same thing as playerY
//posX and posY will now hold the position of your player on the map since your conversion from playerX to playerY will only work if you increment a value by 50 or more.
Detect a wall:
//if the tile at coordinates x and y is a wall I return true
//else return false
public bool detectSolidTile(int x, int y)
{
if (map[y, x] == 1) return true;
else return false;
}
Movement:
posX = (int)(Math.Floor((playerX) / 50)); //drop this you don't need it
posY = (int)(Math.Floor(playerY / 50)); //drop this too, you are using posX and posY to store locations
(...)
if (slide == 1 && !detectSolidTile(posX + 1, posY))
{
posX++;
}
if (slide == 2 && !detectSolidTile(posX - 1, posY))
{
posX--;
}
if (slide == 3 && !detectSolidTile(posX, posY+1))
{
posY++;
}
if (slide == 4 && !detectSolidTile(posX, posY-1))
{
posY--;
}
This should work quite well if you use posX and posY as the position of the player on the map.
Making 1 type of coordinate for the player and one type for the map just makes it more confusing at this point. But if you indeed need to use different coordinates for them, you should always refer to playerX and playerY when trying to calculate the movement like this:
if (slide == 1 && !detectSolidTile((int)(Math.Floor((playerX+1) / 50)) + 1, posY))
{
playerX++;
}
And this is because you are changing the value of playerX by 1 not the value of posX, and this will restrict you movement. If this is confusing let me know and I will try to explain this better.
Related
I have a cube with six vertices of form (x, y, z), in a 3D coordinate system. All information about cube is available, including vertices, edge lengths, etc.
I would like an efficient way to uniformly return n ^ 3 points, with n points on each edge, something like the coordinate system itself. An image is attached (ignore the colouring) (source: Sebastian Lague's video on marching cubes):
I've more or less been able to implement this in Python, and I'd like a C# version.
An example of what I want:
I've used a unit cube at the origin as an example, what I'm after is pseudocode or logic that works for any cube at any coordinates.
More information: I'd like to have code that works for cubes in any orientation, but failing that code that works for cubes aligned with the grid but in any position.
Thanks to Jon Skeet for the help and clarification!
/*
Input:
(0, 0, 0)
(1, 0, 0)
(1, 1, 0)
(1, 1, 1)
(0, 1, 1)
(0, 0, 1)
(0, 1, 0)
(1, 0, 1)
27 points to be generated: n = 3
3 points per edge (INCLUDING VERTICES)
Output:
(0, 0, 0)
(1, 0, 0)
(1, 1, 0)
(1, 1, 1)
(0, 1, 1)
(0, 0, 1)
(0, 1, 0)
(1, 0, 1)
(0, 0.5, 0)
(0.5, 0, 0)
(0, 0, 0.5)
(0.5, 0.5, 0)
(0.5, 0, 0.5)
(0.5, 0.5, 0.5)
(0, 0.5, 0.5)
(1, 0.5, 0)
... etc
*/
I'm using it in Unity, so answers with Vector3 and such would work too.
Some pseudocode:
// MagicPointGenerator is really what I'm after
float[][] GeneratePoints(float[][] vertices, int pointsPerEdge)
{
float[][] points = new float[(int)Math.Pow(pointsPerEdge, 3)][3];
for (int i = 0; i <= pointsPerEdge; i++)
{
for (int j = 0; j <= pointsPerEdge; j++)
{
for (int k = 0; k <= pointsPerEdge; k++)
{
points[i + j + k] = MagicPointGenerator(i, j, k);
}
}
}
return points;
}
I am making a cubic voxel game. I have chunks, world, blocks and mesh generation done, but there's one problem - I could not do the texturing.
Everything I need is just add a texture to a side of a 3D mesh (Texture of every is different!). I've seen some implementations but it's hard to read somebody else's code (I've tried to use them, but it didn't work). I've tried to do this by myself, but with no results.
Can anybody explain how to do this??
Here is my current code:
[ExecuteInEditMode]
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class Chunk : MonoBehaviour
{
private ushort[] _voxels = new ushort[16 * 16 * 16];
private MeshFilter meshFilter;
private Vector3[] cubeVertices = new[] {
new Vector3 (0, 0, 0),
new Vector3 (1, 0, 0),
new Vector3 (1, 1, 0),
new Vector3 (0, 1, 0),
new Vector3 (0, 1, 1),
new Vector3 (1, 1, 1),
new Vector3 (1, 0, 1),
new Vector3 (0, 0, 1),
};
private int[] cubeTriangles = new[] {
// Front
0, 2, 1,
0, 3, 2,
// Top
2, 3, 4,
2, 4, 5,
// Right
1, 2, 5,
1, 5, 6,
// Left
0, 7, 4,
0, 4, 3,
// Back
5, 4, 7,
5, 7, 6,
// Bottom
0, 6, 7,
0, 1, 6
};
public ushort this[int x, int y, int z]
{
get { return _voxels[x * 16 * 16 + y * 16 + z]; }
set { _voxels[x * 16 * 16 + y * 16 + z] = value; }
}
void Start()
{
meshFilter = GetComponent<MeshFilter>();
}
private void Update()
{
GenerateMesh();
}
public void GenerateMesh()
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
for (var x = 0; x < 16; x++)
{
for (var y = 0; y < 16; y++)
{
for (var z = 0; z < 16; z++)
{
var voxelType = this[x, y, z];
if (voxelType == 0)
continue;
var pos = new Vector3(x, y, z);
var verticesPos = vertices.Count;
foreach (var vert in cubeVertices)
vertices.Add(pos + vert);
foreach (var tri in cubeTriangles)
triangles.Add(verticesPos + tri);
}
}
}
mesh.SetVertices(vertices);
mesh.SetTriangles(triangles.ToArray(), 0);
meshFilter.mesh = mesh;
}
}
NOTE: This is a repost with many edits so it is focused on one problem plus has better explanation. Sorry for that.
Like your SetVertices() and SetTriangles(), you can call a SetUVs() with a list of the UV coordinates of each vertex on your texture.
The UV list size must match the vertices list size!
The UV coordinate are expressed as Vector2 with values between 0 and 1.
For example, to apply the whole texture on the front face of your cube, you have the first 4 uvs like this:
private Vector2[] cubeUVs = new[] {
new Vector2 (0, 0),
new Vector2 (1, 0),
new Vector2 (1, 1),
new Vector2 (0, 1),
...
}
...
mesh.SetUVs(0, cubeUVs);
If your texture is not a square, then it will be stretched.
You should also call RecalculateBounds() and RecalculateNormals() at the end of your GenerateMesh() method to avoid some issues later.
EDIT
If you really want different texture files for each side of the cube, then the cleanest and most performant solution for me is to set a different VertexColor for each side of your cube, eg. (1,0,0), (0,1,0), (0,0,1), (1,1,0), (1,0,1) and (0,1,1).
However, you will have to duplicate all your vertices 3 times. (because the vertex color is bound to a vertex, and each vertex of a cube belongs to 3 sides)
(You still have to set the UVs like I said previously, but each side has the whole texture instead of only a part of the texture)
Then, you will have to create a custom shader with 6 textures in inputs (one for each side).
And in the fragment function, you select the right texture color according to the vertex color.
You can for that, do some if to select the texture, but it will be not very performant:
float3 finalColor;
if(vertexColor.r > 0.5f && vertexColor.g < 0.5f && vertexColor.b < 0.5f)
{
finalColor = text2D(_TopTexture, in.uv);
}
else if(...)
{
...
}
...
Or if you want more perf (with a lot of cubes), you can instead do some multiplications to select the right texture:
float3 topTexColor = text2D(_TopTexture, in.uv) * vertexColor.r * (1.0f - vertexColor.g) * (1.0f - vertexColor.b);
float3 frontTexColor = ...;
...
float3 finalColor = topTexColor + frontTexColor + ...;
I have this function to convert Euler Angles to a rotation matrix but I would like to reverse it and get the Euler Angles when I only have the rotation matrix.
The reason for it is I want to be able to set an objects transform using a transform matrix then I would like to update that objects Euler rotation variable that is in degrees. (I have a function that calculate the rotation matrix from the transform matrix)
public static Mat4 RotMat(Vec3 _rot)
{
double rx = Math2.degToRad(_rot.x);
double[,] trmx = new double[4, 4] { { 1, 0, 0, 0 }, { 0, Math.Cos(rx), Math.Sin(rx), 0 }, { 0, -Math.Sin(rx), Math.Cos(rx), 0 }, { 0, 0, 0, 1 } };
Mat4 rmx = new Mat4(trmx);
double ry = Math2.degToRad(_rot.y);
double[,] trmy = new double[4, 4] { { Math.Cos(ry), 0, -Math.Sin(ry), 0 }, { 0, 1, 0, 0 }, { Math.Sin(ry), 0, Math.Cos(ry), 0 }, { 0, 0, 0, 1 } };
Mat4 rmy = new Mat4(trmy);
double rz = Math2.degToRad(_rot.z);
double[,] trmz = new double[4, 4] { { Math.Cos(rz), Math.Sin(rz), 0, 0 }, { -Math.Sin(rz), Math.Cos(rz), 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
Mat4 rmz = new Mat4(trmz);
return (rmx * rmy * rmz);
}
This is an attempt based on some code I found but does not always give me the expected result, it works sometimes (I know there is the gimbal lock issue with euler angles so maybe this is a futile attempt ).
public static Vec3 GetRot(Mat4 _tm)
{
Mat4 rm = GetRotMat(_tm);
double sy = Math.Sqrt(rm[0, 0] * rm[0, 0] + rm[1, 0] * rm[1, 0]);
bool singular = sy < 1e-6; // If
double x, y, z;
if (!singular)
{
x = Math.Atan2(rm[2, 1], rm[2, 2]);
y = Math.Atan2(-rm[2, 0], sy);
z = Math.Atan2(rm[1, 0], rm[0, 0]);
}
else
{
x = Math.Atan2(-rm[1, 2], rm[1, 1]);
y = Math.Atan2(-rm[2, 0], sy);
z = 0;
}
x = Math2.radToDeg(x);
y = Math2.radToDeg(y);
z = Math2.radToDeg(z);
return new Vec3(x, y, z) * -1;
}
This is the first time I'm asking in here, so bear with me :)
Well basically I have a problem with my code, and I cannot figure out what it is.
It's a city generator for a game that I'm developing. It creates a 20 x 20bitmap with the ground in brown, and a river in blue. Now I need it to generate a 3x3 block in pink, and then it should check if there is any overlap, if yes, genereate a new random position, and proceed to check if there is a blue color. My problem is that it generates the river, and the 3x3 pink block regardless of if its overlapping the blue part.
According to the code, it shouldn't be possible.. And the function that generates the city block gets called after the river is:
private void CreateCityBlock(string name, Color col) {
//This variable stops the loop
bool canGenerate = false;
//Create a loop that checks if it can generate the 3x3 block
while (!canGenerate)
{
//Create a random and generate two positions for "x" and "y"
Random rnd = new Random();
int x = rnd.Next(1, 19);
int y = rnd.Next(1, 19);
//Check if it overlaps with the river
if (!city.GetPixel(x, y).Equals(Color.Blue)||
!city.GetPixel(x - 1, y + 1).Equals(Color.Blue) ||
!city.GetPixel(x, y + 1).Equals(Color.Blue) ||
!city.GetPixel(x + 1, y + 1).Equals(Color.Blue) ||
!city.GetPixel(x - 1, y).Equals(Color.Blue) ||
!city.GetPixel(x + 1, y).Equals(Color.Blue) ||
!city.GetPixel(x - 1, y - 1).Equals(Color.Blue) ||
!city.GetPixel(x, y - 1).Equals(Color.Blue) ||
!city.GetPixel(x + 1, y - 1).Equals(Color.Blue))
{
//set the color to pink
city.SetPixel(x - 1, y + 1, col);
city.SetPixel(x, y + 1, col);
city.SetPixel(x + 1, y + 1, col);
city.SetPixel(x - 1, y, col);
city.SetPixel(x, y, col);
city.SetPixel(x + 1, y, col);
city.SetPixel(x - 1, y - 1, col);
city.SetPixel(x, y - 1, col);
city.SetPixel(x + 1, y - 1, col);
canGenerate = true;
}
}
}
The problem lies in the fact that the || (conditional-OR) operator does not evaluate any expressions if the first expression is True.
So, if the first pixel is not blue, then the rest is not evaluated, since !False equals True.
In this case, I would write a separate "checking" method to evaluate all pixels and return the result accordingly, e.g.:
// Returns true if the area overlaps a river pixel, false otherwise
private bool Overlaps(Bitmap city, int x, int y)
{
for (int cx = x - 1; cx < x + 2; cx++)
{
for (int cy = y - 1; cy < y + 2; cy++)
{
if (city.GetPixel(cx, cy).Equals(Color.Blue))
return true;
}
}
return false;
}
I've got an array of [4,4]
X is the only one I "know", the rest is calculated with a simple double for-loop.
x 0 0 0
0 0 1 0
0 1 1 0
0 1 0 0
I want a function that take this array, and rotate it 90 degrees + / - while the position of x stays the same. (It's supposed to be tetris)
x 0 0 0
1 1 0 0
0 1 1 0
0 0 0 0
I know some way to hardcode the permutations but what that wouldn't learn me anything and it's frankly quite boring.
Would appreciate the help :>
I'm not sure how exactly you intend to rotate a matrix by 90 degrees and yet still have the top left X in the top left of the rotated version, but to rotate something by 90 degrees, I'd just make a new array, swap rows and columns and flip horisontally.
int[][] start = new int[4][];
start[0] = new int[4] { x, 0, 0, 0 }
start[1] = new int[4] { 0, 0, 1, 0 }
start[2] = new int[4] { 0, 1, 1, 0 }
start[3] = new int[4] { 0, 1, 0, 0 }
int[][] rotate = new int[4][];
for (int i=0; i<4; i++) rotate[i] = new int[4];
for (int i=0; i<4; i++)
for (int j=0; j<4; j++)
rotate[i][j] = start[j][i];
Rotate finishes with:
0, 0, 0, 0,
0, 0, 1, 1,
0, 1, 1, 0,
0, 0, 0, 0,
Now this is a diagonal flip (EDIT: It just occurs to me that this will keep x in the same position: perhaps this is what you mean?), but just do a horisontal flip and it should be fine:
for (int i=0; i<4; i++)
for (int j=0; j<4; j++)
rotate[i][3-j] = start[j][i];
Rotate finishes with:
0, 0, 0, 0,
1, 1, 0, 0,
0, 1, 1, 0,
0, 0, 0, 0,
(To tilt other way: rotate[i][j] = start[j][3-i];)
:)