0
\$\begingroup\$

I want the player to select 2 points (vectors). With these 2 points a floor should be created. When these points are parallel to the x-axis it's easy, just calculate the amount of blocks needed by a simple division, loop through that amount (in x and y) and keep increasing the coordinate by the size of that block.

The trouble starts when the 2 vectors aren't parallel to an axis, for example at an angle of 45 degrees. The 2 red dots would be the player selected locations. (The blocks indeed aren't square.) enter image description here.

How do I handle the math behind this?

\$\endgroup\$
2
  • \$\begingroup\$ Is the block rotation constant(and known)? Are those two points always going to produce axis-aligned rectangle? \$\endgroup\$ Commented Jul 23, 2014 at 21:18
  • \$\begingroup\$ @Wondra, the rotation isn't constant since the player can select any 2 places (which means any angle). The two points will always produce an axis-aligned rectangle, yes. \$\endgroup\$ Commented Jul 23, 2014 at 22:45

4 Answers 4

1
\$\begingroup\$

In 2D:

The position of each block placed is {sin(theta),cos(theta)} = {x,y}. Hence at theta = 90°, the position will move only in the x-axis, by one block each time. The rotation of each block should be the same theta as well.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ This is a pretty vague answer. This is sort of how you'd find the position for one block, but it doesn't give the rotation, or how to place the other blocks or ensure the area is filled with blocks. \$\endgroup\$ Commented Jul 23, 2014 at 21:23
  • \$\begingroup\$ The rotation of the block should be the same as the angle between the two points. If the bridge width is fixed, then you would loop through the width, and find the x,y position of the block using the formula. I don't think its that vague. \$\endgroup\$ Commented Jul 23, 2014 at 23:09
  • \$\begingroup\$ This is missing too much detail to be useful. What angle is "theta"? The sine and cosine have both a range of [-1,1], which would mean the values assigned to x and y hardly change at all. \$\endgroup\$ Commented Oct 22, 2014 at 13:20
  • \$\begingroup\$ Your right the orientation/rotation should be the same as the triangle formed by the vector, but I think you should explain a bit more what angle is your theta here and how it would allow you to find the x,y position of all the blocks filling the area... maybe add some visual support ? ( my last math class was 10 years ago ... ) \$\endgroup\$ Commented Oct 22, 2014 at 14:47
0
\$\begingroup\$

You could also achieve this in a "dumb" cycle, it is not optimal but will work. Simply keep adding any block next to the current that is inside the area. Lets say you would like a list of the blocks:

Rectangle area = new Rectangle(A.x, Math.Max(B.y,B.x), A.y, Math.Min(B.y,B.x)); List<Block> blocks = new List<Block>(); Queue<Block> blockQueue = new Queue<Block>(); Block currentBlock = new Block(Point A, //...the first block corrdinates //rest vertices depends on data you didnt supply (rotation, block size etc. you can calculate that) blocks.Add(currentBlock ); blockQueue.Enqeue(currentBlock); while(!blockQueue.isEmpty) { currentBlock = blockQueue.Deqeue(); foreach(Block b in currentBlock.Neighbours)// any neighbour block, if zou dont have them, generete them { if(isInsideRect(b))// valid block? { blockQueue.Enqeue(b); blocks.Add(currentBlock); } } } //check if inside wanted area bool isInsideRect(b) { foreach(Point p in b.Vertices) if ((p.x < area.Right && p.x > area.Left) && (p.y < area.Top && p.y > area.Bottom)) return true; return false; } 
\$\endgroup\$
2
  • \$\begingroup\$ Thanks, this would technically work, but it's not what I'm looking for. It's actually a 3d world, and the models would clip inside of each other, not resulting in anything pretty. (I didn't mention the z coordinate because it's irrelevant in my problem) \$\endgroup\$ Commented Jul 23, 2014 at 22:48
  • \$\begingroup\$ Well, porting this into 3D is only adding 6 neighbours instead of 4. I am afraid there is no "smart" solution (you will have to test its for rectangle inclusion) and you will end up impementing some kind of searching algorithm one way or another. \$\endgroup\$ Commented Jul 23, 2014 at 22:58
0
\$\begingroup\$

Overview

So the algorithm is a simple fill algorithm that first finds the number of blocks needed to adequately cover the diagonal. Then it walks along this diagonal is block long increments. At each increment the fill algorithm branches out at both right angles and adds blocks so long as the center is within the box.

Also just walked though this with a few pen and paper examples so might take some refining.

The diagonal walking bit.

enter image description here

The Algorithm

Input and computing a few bit of basic info

List BoxCenterList BlockWidth BlockLength DiagonalLength = (TR - BL).lenght() DiagonalDirection = (TR - BL).Normalize() DiagonalDirectionRightAngle = new Vector2(-DiagonalDirection.Y, DiagonalDirection.X) Center = (TR + BL) / 2 

First we find the center, and then calculate the number of blocks needed to adequately cover the diagonal.

BlocksAlongDiagonal = Math.Ceiling(DiagonalLength / BlockLenght) //Number of blocks along diagonal BlockDiagonal = BlocksAlongDiagonal * BlockLenght //Length of the bridge along the diagonal 

For filling the blocks in we start in the bottom left corner along the diagonal such that the walking point is in the center of where the block should be.

StartPoint = Center - ((DiagonalDirection * BlockDiagonal) / 2) StartPoint += BlockLenght / 2 

And then we begin walking up the diagonal.

for (i in Range(BlockLenght)) BoxCenterList.Add(StartPoint) 

Branch out at a 90 degree angle and add boxes so long as the center is in the box

 TravelVector = StartPoint + (DiagonalDirection * BlockWidth) while(rectangle.contains(TravelVector)) BoxCenterList.Add(TravelVector) TravelVector += (DiagonalDirection * BlockWidth) 

Branch out at the other 90 degree angle and add boxes so long as the center is in the box

 TravelVector = StartPoint + (-DiagonalDirection * BlockWidth) while(rectangle.contains(TravelVector)) BoxCenterList.Add(TravelVector) TravelVector += (-DiagonalDirection * BlockWidth) StartPoint =+ DiagonalDirection * BlockLenght 

To use the algorithm simply take the BoxCenterList and add a box at each location rotated to align with the DiagonalDirection vector. If you want to guarantee the entire box is covered change the condition from "is the center in the box" to "is a corner in the box"

\$\endgroup\$
0
\$\begingroup\$

You said it was easy when the two vectors were aligned to the X-axis. So, first align them to the X axis, and your problem is solved! The only difficulty will be finding out whether the blocks are inside a rotated bounding box (assuming that you wanted the blocks to cover the bounding box only).

BlockMaker

Vector point1; Vector point2; // First, create an orthonormal coordinate system. Origin is point1. Vector xAxis = (point2 - point1); float dist = xAxis.length(); xAxis /= dist; Vector yAxis = xAxis.cross(0, 0, 1); yAxis.normalize(); // You will need to compute these first int blockWidth, blockHeight; BoundingBox bounds; // Diagonal of the bounding box float squareDiagonal; // Iterate along the vector from point1 to point2 for (float x = 0; x < dist; x+= blockSize) { // Iterate over the vector from the lower right corner to the upper left for (float y = -squareDiagonal * 0.5; y < squareDiagonal * 0.5; y +=blockHeight) { Vector blockPos = x * xAxis + y * yAxis + point1; // You will need to implement a function that intersects the bounds with a rotated block at the given position. if (bounds.ContainsBlock(blockPos) { // You will need to make sure this rounds properly. CreateBlock(blockPos); } } } 
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.