Draw images on a canvas next to each other without space in flutter - flutter

I'm creating a game in flutter. I'm using a tilesheet to render tiles. I chop the image in 50x50 sections and then render them depending on their surrounding.
The tiles are rendered at the position of their corresponding "game object". In order to keep the code clean from details about converting from the game world positions and sizes to actual screen sizes my painting classes always obtain world space and then scales it up to screen space.
However, after scaling up the tiles I'm sometimes left with gaps between the tiles.
I've tried:
Placing the tiles at their appropriate screen position, without scaling the canvas first, in case the scaling produces the problem.
Adding borders around the tiles in the tilesheet in case the canvas.drawImageRect samples too many pixels.
Making the board take a size divisible by the number of tiles, in case there is a rounding error.
Drawing a subsection of the tile.
I can't seem to make the gap disappear. Do you have any suggestions?
Below is the relevant drawing code, where size and position are in world space and frameX and frameY is the positions to extract from the spritesheet.
void drawFrameAt(int x, int y, Canvas canvas, Offset position, Size size) {
var frameX = x * frameWidth;
var frameY = y * frameHeight;
var rect = Rect.fromLTWH(frameX, frameY, frameWidth, frameHeight);
var width = size.width;
var height = size.height;
var destination = Rect.fromLTWH(position.dx, position.dy, width, height);
canvas.drawImageRect(image, rect, destination, Paint());
}

Related

Math doesn't work for the size and position of Game Pieces WRT the size of their container "room"

The positions and sizes of my Game Pieces, as set by CGPoint(..) and CGRect(..), don’t make arithmetic sense to me when looked at with respect to the width and height of the surrounding container of all Game Pieces?
Let me illustrate with just one specific example –
I call the surrounding container = “room”.
One of many specific Game Pieces = “rock”.
Here’s the math
roomWidth = Double(UIScreen.main.bounds.width)
roomHeight = Double(UIScreen.main.bounds.height)
While in Portrait mode:
roomWidth = 744.0
roomHeight = 1133.0
When rotated to Landscape mode:
roomWidth = 1133.0,
roomHeight = 744.0
So far so good .. here’s the problem:
When I look at my .sks file, the width of the “rock” and its adjacent game pieces far exceeds the roomWidth; for example,
Widths of rock + paddle + tree = 507 + 768 + 998 which obviously exceeds the room’s width for either Portrait or Landscape mode – and this math doesn’t even address the separation between Game Pieces.
The final math “craziness” looks at the swift xPos values for each Game Piece as specified in my .sks file:
Room: xPos = 40,
Rock: xPos = -390,
Paddle: xPos = -259,
Tree: xPos = 224
I cannot grasp the two high negative numbers .. to me, that means the Rock and the Paddle shouldn’t even be visible .. seriously off-screen.
One significant addition = I did set the Autoresizing Mask to center horizontally and vertically
I need a serious infusion of “smarts” here.
The default anchorPoint of an sks file (SpriteKit Scene file) is (0.5, 0.5). So the origin (0, 0) of the scene is drawn at the center of the SKView. You can change the anchor point in the Attributes inspector when editing the sks file. The default means that negative coordinates not too far from the origin will be visible in the SKView.
The scene also has a scaleMode property which determines how the scene is scaled if its size doesn't match the SKView's size. The default is .fill, which means the view scales the scene's axes independently so the scene's size exactly fills the view.

Crop Image texture on WorldSpace Canvas using RectTransform on Overlay Canvas

I've been trying for several days to crop an Image texture (Board - originalImage in the code example) on WorldSpace Canvas using RectTransform(CropArea - cropArea in the code example) on Overlay Canvas.
The problem is that I can't find the correct coordinates of the cropArea on the original image.
I've tried with this:
Texture2D croppedTexture = new Texture2D((int)cropArea.rectTransform.rect.width, (int)cropArea.rectTransform.rect.height);
Texture2D originalTexture = (Texture2D) originalImage.mainTexture;
croppedTexture.SetPixels(originalTexture.GetPixels((int)cropArea.rectTransform.anchoredPosition.x, (int)cropArea.rectTransform.anchoredPosition.y, (int)cropArea.rectTransform.rect.width, (int)cropArea.rectTransform.rect.height));
croppedTexture.Apply();
resultImage.texture = croppedTexture;
But the result image is not cropped properly. It is a bit to the left and a bit down.
Does anybody have an idea how can I achieve this?
I found I have to consider so many variables. Here is a simplified version.
Need a new field: worldCanvas
var cropRectTrans = cropArea.rectTransform;
var origRectTrans = originalImage.rectTransform;
var origRectSize = origRectTrans.sizeDelta;
var pivot = origRectTrans.pivot;
Texture2D originalTexture = (Texture2D)originalImage.mainTexture;
// Scale pivot to pixel unit.
pivot.Scale(origRectSize);
// Get corners of the overlay rectangle in world space.
// The canvas is "Screen Space Overlay", so these positions are
// also the screen positions.
var cropCorners = new Vector3[4];
cropRectTrans.GetWorldCorners(cropCorners);
// Transform the left-bottom and right-top corners to the space
// of the original image. The translated position needs to be added
// with the scaled pivot, so that we can obtain the coordinates
// relative to the left-bottom corner of the image.
var cam = worldCanvas.worldCamera;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
origRectTrans, cropCorners[0], cam, out Vector2 lb);
RectTransformUtility.ScreenPointToLocalPointInRectangle(
origRectTrans, cropCorners[2], cam, out Vector2 tr);
var point = lb + pivot;
var size = tr - lb;
// Scale the position and size if the image is scaled.
var scale = new Vector2(
originalTexture.width / origRectSize.x,
originalTexture.height / origRectSize.y
);
point.Scale(scale);
size.Scale(scale);
// Finally we get the correct position and size in the original image space.
Texture2D croppedTexture = new Texture2D((int)size.x, (int)size.y);
croppedTexture.SetPixels(originalTexture.GetPixels(
(int)point.x, (int)point.y, (int)size.x, (int)size.y));
croppedTexture.Apply();
resultImage.texture = croppedTexture;

Positioning UI or Camera relatively to each other (and screen border)

I'm struggling with this sort of
Screen disposition.
I want to position my Camera so that the world is positionned like in the image with the origin at bottom left. It's easy to set the orthographicSize of the camera as I know how many unit I want vertically. It is also easy to calculate the Y position of the camera as I just want it to be centered vertically. But I cannot find how to compute the X position of the camera to put the origin of the world in this position, no matter what the aspectRatio of the screen is.
It brings me two questions :
How can I calculate the X position of the camera so that the origin of the world is always as the same distance from the screen left and bottom borders ?
Instead of positioning the camera regarding the UI, should I use RenderMode Worldspace for the UI canvas. And if so, how could I manage responsiveness ?
I don't understand the second question, but regarding positioning the Camera on the X axis so that the lower left corner is always at world 0 you could do the following:
var lowerLeftScreen = new Vector3(0, 0, 10);
var pos = transform.position;
var lowerLeftScreenPoint = Camera.main.ScreenToWorldPoint(lowerLeftScreen).x;
if (lowerLeftScreenPoint > 0)
{
pos.x -= lowerLeftScreenPoint;
}
else
{
pos.x += Mathf.Abs(lowerLeftScreenPoint);
}
transform.position = pos;
Debug.Log(Camera.main.ScreenToWorldPoint(lowerLeftScreen));
Not the nicest code, but gets the job done.
Also the Z component in the Vector does not really matter for our orthographic camera.

Draw line relative to Image position and scale

I am making a game in Unity and I have a Canvas set to Screen Space - Overlay and it has that background green as you can see from the image. I also have a RawImage with the background blue as a child of the Canvas and the player will have to draw an object like a car or a house inside the RawImage.Right now, the line Instantiates in a random position on the screen even if I give it the coordinated (0, 0).
What I need help with is to find a way to convert the coordinates so I only work with the inside coordinates of the RawImage. For example, the (0, 0) coordinate I will pass to the line, has to be converted to the bottom-left corner of the RawImage. and the maximum width or height should also depend on the RawImage width and height.
Here is the CreateLine function I have for now:
public void CreateLine(int x, int y)
{
currentLine = Instantiate(linePrefab, Vector3.zero, Quaternion.identity);
currentLine.transform.parent = GameObject.Find("GameMenu(Clone)").transform; //Make the line a child of the Canvas named GameMenu
lineRenderer = currentLine.GetComponent<LineRenderer>();
lineRenderer.SetPosition(0, new Vector3(x, y, 99));
lineRenderer.SetPosition(1, new Vector3(x, y, 99));
}
Any amount of help will be greatly appreciated. Have a great day!

How can I determine the area currently visible in a scrollview and determine the center?

I have a map app where the user can place waypoints manually. I would like for them to press the waypoint button and have a waypoint placed in the center of their currently visible view on the content view.
I'm afraid you'd have to calculate it yourself. contentSize returns size of the scrolled content, contentOffset gives you the origin of the scroll view inside the content. Then with scrollView.bounds.size you can find the center of the view.
Haven't tested this, but maybe you could convert scrollView.center to your scrolled map like this:
CGPoint viewportCenterInMapCoords =
[scrollView.superview convertPoint:scrollView.center
toView:mapViewInsideScrollView];
Need to account for how zoomed it is, then I can convert the content offset to the size of the full image and add some.
/// this is the full size of the map image
CGSize fullSize = CGPointMake(13900, 8400);
/// determines how the current content size compares to the full size
float zoomFactor = size.width/self.contentSize.width;
/// apply the zoom factor to the content offset , this basically upscales
/// the content offset to apply to the dimensions of the full size map
float newContentOffsetX = self.contentOffset.x*zoomFactor + (self.bounds.size.width/2) *zoomFactor-300;
float newContentOffsetY = self.contentOffset.y*zoomFactor + (self.bounds.size.height/2) * zoomFactor-300;
/// not sure why i needed to subtract the 300, but the formula wasn't putting
/// the point in the exact center, subtracting 300 put it there in all situations though
CGPoint point = CGPointMake(newContentOffsetX,newContentOffsetY );