I want to draw a rectangle on a form in C#. I read and found this article. Are there any samples or tutorials available ? The article was not very helpful.
The article you linked appears to be C++, which may explain why it didn't help you much.
If you create events for MouseDown and MouseUp, you should have the two corner points you need for a rectangle. From there, it's a matter of drawing on the form. System.Drawing.* should probably be your first stop. There are a couple of tutorials linked below:
Drawing with Graphics in WinForms using C#
Draw a rectangle using Winforms (StackOverflow)
Graphics Programming using C#
You need this 3 functions and variables:
private Graphics g;
Pen pen = new System.Drawing.Pen(Color.Blue, 2F);
private Rectangle rectangle;
private int posX, posY, width, height;
Second you need to make a mouse down event:
private void pictureCrop_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
posX = e.X;
posY = e.Y;
}
}
Third, you need to implemente the mouse up event:
private void pictureCrop_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
if (e.X > posX && e.Y > posY) // top left to bottom right
{
width = Math.Abs(e.X - posX);
height = Math.Abs(e.Y - posY);
}
else if (e.X < posX && e.Y < posY) // bottom right to top left
{
width = Math.Abs(posX - e.X);
height = Math.Abs(posY - e.Y);
posX = e.X;
posY = e.Y;
}
else if (e.X < posX && e.Y > posY) // top right to bottom left
{
width = Math.Abs(posX - e.X);
height = Math.Abs(posY - e.Y);
posX = e.X;
}
else if (e.X > posX && e.Y < posY) // bottom left to top right
{
width = Math.Abs(posX - e.X);
height = Math.Abs(posY - e.Y);
posY = e.Y;
}
g.DrawImage(_bitmap, 0, 0);
rectangle = new Rectangle(posX, posY, width, height);
g = pictureCrop.CreateGraphics();
g.DrawRectangle(pen, rectangle);
}
And to ensure that when you resize or move the form the rectangle will be there:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics graph = e.Graphics;
graph.DrawImage(_bitmap, 0, 0);
Rectangle rec = new Rectangle(posX, posY, width, height);
graph.DrawRectangle(pen, rec);
}
Related
I created a level menu manager where you swipe from one screen to the next horizontally, and it worked great. Until I realized I had to change the canvas to scale with screen size in order to preserve the layout for various devices. Now, the panels resize. Which is what I want, however it means the swipe no longer works since the panels stretch and thin to accommodate yet their position does not change. They might overlap now, or have big gaps in between. See photo examples. Is there anything I can do? I cannot for the life of me figure out how to calculate where their new position should be based on screen size and move them there using the left and right rect transform properties. It sounds easy but the math just does not math in all my efforts. Been tearing my hair out over this all day.
Code for my page swiper:
public class PageSwiper : MonoBehaviour, IDragHandler, IEndDragHandler
{
private Vector3 panelLocation;
public float percentThreshold = 0.2f;
public float easing = 0.5f;
int currentChild;
Player player;
void Start()
{
player = PlayerData.GetPlayerData();
currentChild = player.lastPanel;
panelLocation = transform.position;
panelLocation += new Vector3(-Screen.width * (currentChild-1), 0, 0);
transform.position = panelLocation;
}
public void OnDrag(PointerEventData data){
float difference = data.pressPosition.x - data.position.x;
if ((currentChild == 9 && difference < 0) || (currentChild == 1 && difference > 0))
{
transform.position = panelLocation - new Vector3(difference, 0, 0);
}
}
public void OnEndDrag(PointerEventData data){
float percentage = (data.pressPosition.x - data.position.x) / Screen.width;
if (Mathf.Abs(percentage) >= percentThreshold){
Vector3 newLocation = panelLocation;
int panelCount = transform.childCount - 1;
if (percentage > 0 && currentChild < panelCount){
newLocation += new Vector3(-Screen.width, 0, 0);
currentChild += 1;
}else if(percentage < 0 && currentChild > 1){
newLocation += new Vector3(Screen.width, 0, 0);
currentChild -= 1;
}
transform.position = newLocation;
panelLocation = newLocation;
} else {
transform.position = panelLocation;
}
}
}
Before, right next to each other for perfect swipe:
After example 1, wider screen size:
After example 2, thinner screen size:
I am looking to scale a orthographic camera in unity 2d to screen size.
When you edit your game you orient the camera in a way you want it to be, view all your objects etc.
But then when you maximise it your camera zooms out showing maybe other things you don't want to show
Images for example
Edit Mode View
Maximised
Thank you if you can answer my question
Best Regards
Dawid
Attach the following component to your camera. Make sure to set the target aspect ratio in the inspector (16/9 for example).
using UnityEngine;
[ExecuteAlways]
[RequireComponent(typeof(Camera))]
public class ViewportScaler : MonoBehaviour
{
private Camera _camera;
[Tooltip("Set the target aspect ratio.")]
[SerializeField] private float _targetAspectRatio;
private void Awake()
{
_camera = GetComponent<Camera>();
if (Application.isPlaying)
ScaleViewport();
}
private void Update()
{
#if UNITY_EDITOR
if (_camera)
ScaleViewport();
#endif
}
private void ScaleViewport()
{
// determine the game window's current aspect ratio
var windowaspect = Screen.width / (float) Screen.height;
// current viewport height should be scaled by this amount
var scaleheight = windowaspect / _targetAspectRatio;
// if scaled height is less than current height, add letterbox
if (scaleheight < 1)
{
var rect = _camera.rect;
rect.width = 1;
rect.height = scaleheight;
rect.x = 0;
rect.y = (1 - scaleheight) / 2;
_camera.rect = rect;
}
else // add pillarbox
{
var scalewidth = 1 / scaleheight;
var rect = _camera.rect;
rect.width = scalewidth;
rect.height = 1;
rect.x = (1 - scalewidth) / 2;
rect.y = 0;
_camera.rect = rect;
}
}
}
I'd like to expand on #sean-carey 's very useful answer.
I modified his code in order to add a min and max aspect ratio, so the viewport will be full screen in between those two aspects, and will pillarbox when < min and letterbox when > max
using UnityEngine;
[ExecuteAlways]
[RequireComponent(typeof(Camera))]
public class ViewportController : MonoBehaviour
{
private Camera _camera;
[Tooltip("Set the target aspect ratio.")]
[SerializeField] private float _minAspectRatio;
[SerializeField] private float _maxAspectRatio;
private void Awake()
{
_camera = GetComponent<Camera>();
if (Application.isPlaying)
ScaleViewport();
}
private void Update()
{
#if UNITY_EDITOR
if (_camera)
ScaleViewport();
#endif
}
private void ScaleViewport()
{
// determine the game window's current aspect ratio
var windowaspect = Screen.width / (float) Screen.height;
// current viewport height should be scaled by this amount
var letterboxRatio = windowaspect / _minAspectRatio;
var pillarboxRatio = _maxAspectRatio / windowaspect;
// if max height is less than current height, add letterbox
if (letterboxRatio < 1)
{
SetRect(1, letterboxRatio, 0, (1-letterboxRatio)/2);
}
// if min height is more than current height, add pillarbox
else if (pillarboxRatio < 1)
{
SetRect(pillarboxRatio, 1, (1-pillarboxRatio)/2, 0);
}
// full screen
else
{
SetRect(1, 1, 0, 0);
}
}
private void SetRect(float w, float h, float x, float y)
{
var rect = _camera.rect;
rect.width = w;
rect.height = h;
rect.x = x;
rect.y = y;
_camera.rect = rect;
}
}
Using Unity 2018.3
This camera script allows the user to zoom in and out and move the camera with touch around.
On Start() the script takes the cameras current position and saves it as the out of bounds limit. So if the player is zoomed in and moves the camera to the side, the camera will stop when it reaches the bounds limit.
My problem is that currently the user can zoom out all they want, causing the camera to get shaky as the script is trying to relocate the camera but it doesn't stop the user from increasing the orthographicSize.
How do I limit the user from zooming out passed the out of bound limit it got on Start()?
public class ControlCamera : MonoBehaviour
{
private Vector2?[] oldTouchPositions = {
null,
null
};
private Vector2 oldTouchVector;
private float oldTouchDistance;
private Vector3 bottomLeft;
private Vector3 topRight;
private float cameraMaxY;
private float cameraMinY;
private float cameraMaxX;
private float cameraMinX;
public float maxZoom;
public float minZoom;
private void Start()
{
// Set max camera bounds
topRight = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(GetComponent<Camera>().pixelWidth, GetComponent<Camera>().pixelHeight, -transform.position.z));
bottomLeft = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(0, 0, -transform.position.z));
cameraMaxX = topRight.x;
cameraMaxY = topRight.y;
cameraMinX = bottomLeft.x;
cameraMinY = bottomLeft.y;
}
private void Update()
{
// No touches
if (Input.touchCount == 0)
{
oldTouchPositions[0] = null;
oldTouchPositions[1] = null;
}
// 1 Touch
else if (Input.touchCount == 1)
{
if (oldTouchPositions[0] == null || oldTouchPositions[1] != null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = null;
}
else
{
Vector2 newTouchPosition = Input.GetTouch(0).position;
transform.position += transform.TransformDirection((Vector3)((oldTouchPositions[0] - newTouchPosition) * GetComponent<Camera>().orthographicSize / GetComponent<Camera>().pixelHeight * 2f));
oldTouchPositions[0] = newTouchPosition;
}
// 2 touches or more
} else {
if (oldTouchPositions[1] == null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = Input.GetTouch(1).position;
oldTouchVector = (Vector2)(oldTouchPositions[0] - oldTouchPositions[1]);
oldTouchDistance = oldTouchVector.magnitude;
} else {
Vector2 screen = new Vector2(GetComponent<Camera>().pixelWidth, GetComponent<Camera>().pixelHeight);
Vector2[] newTouchPositions = {
Input.GetTouch(0).position,
Input.GetTouch(1).position
};
Vector2 newTouchVector = newTouchPositions[0] - newTouchPositions[1];
float newTouchDistance = newTouchVector.magnitude;
transform.position += transform.TransformDirection((Vector3)((oldTouchPositions[0] + oldTouchPositions[1] - screen) * GetComponent<Camera>().orthographicSize / screen.y));
GetComponent<Camera>().orthographicSize *= oldTouchDistance / newTouchDistance;
transform.position -= transform.TransformDirection((newTouchPositions[0] + newTouchPositions[1] - screen) * GetComponent<Camera>().orthographicSize / screen.y);
oldTouchPositions[0] = newTouchPositions[0];
oldTouchPositions[1] = newTouchPositions[1];
oldTouchVector = newTouchVector;
oldTouchDistance = newTouchDistance;
// --------------------------------------------------------------->>
// Control Zoom In
if (GetComponent<Camera>().orthographicSize > minZoom)
{
//
}
// Control Zoom Out
if (GetComponent<Camera>().orthographicSize < maxZoom)
{
//
}
// --------------------------------------------------------------->>
}
}
// Check if camera is out-of-bounds, if so, move back in-bounds
topRight = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(GetComponent<Camera>().pixelWidth, GetComponent<Camera>().pixelHeight, -transform.position.z));
bottomLeft = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(0, 0, -transform.position.z));
if (topRight.x > cameraMaxX)
{
transform.position = new Vector3(transform.position.x - (topRight.x - cameraMaxX), transform.position.y, transform.position.z);
}
if (topRight.y > cameraMaxY)
{
transform.position = new Vector3(transform.position.x, transform.position.y - (topRight.y - cameraMaxY), transform.position.z);
}
if (bottomLeft.x < cameraMinX)
{
transform.position = new Vector3(transform.position.x + (cameraMinX - bottomLeft.x), transform.position.y, transform.position.z);
}
if (bottomLeft.y < cameraMinY)
{
transform.position = new Vector3(transform.position.x, transform.position.y + (cameraMinY - bottomLeft.y), transform.position.z);
}
}
}
You should not use GetComponent repeatedly especially not in Update or any repeatedly called method as this creates a lot unnecessary overhead. Instead get it once
private Camera camera;
private void Awake()
{
camera = GetComponent<Camera>();
}
and reuse that reference -> Everywhere replace GetComponent<Camera>() width camera
If my understanding is correct, orthographicSize is half of the height of the camera in world units.
Since you already get topRight and bottomLeft in world coordinates you should be able to calculate an orthographicSize
maxZoom = (CameraMaxY - CameraMinY) / 2.0f;
however, if anyway you want the original zoom to be the max zoom you could also simply store the original zoom like
maxZoom = camera.orthographicSize;
And later you can simply clamp the value like
camera.orthographicSize = Mathf.Clamp(
camera.orthographicSize * oldTouchDistance / newTouchDistance,
minZoom,
maxZoom);
-> no need for extra if checks
I am working on a project. I want to take a picture from gallery of android device.
1. How can i take a picture from gallery of android device?
2. How can i Crop the picture selected circle portion in unity3d?
You can use below code for cropping image. I only pass Texture2D and set centre and radius automatically according to texture; but you can pass them manually if you want to.
Texture2D RoundCrop (Texture2D sourceTexture) {
int width = sourceTexture.width;
int height = sourceTexture.height;
float radius = (width < height) ? (width/2f) : (height/2f);
float centerX = width/2f;
float centerY = height/2f;
Vector2 centerVector = new Vector2(centerX, centerY);
// pixels are laid out left to right, bottom to top (i.e. row after row)
Color[] colorArray = sourceTexture.GetPixels(0, 0, width, height);
Color[] croppedColorArray = new Color[width*height];
for (int row = 0; row < height; row++) {
for (int column = 0; column < width; column++) {
int colorIndex = (row * width) + column;
float pointDistance = Vector2.Distance(new Vector2(column, row), centerVector);
if (pointDistance < radius) {
croppedColorArray[colorIndex] = colorArray[colorIndex];
}
else {
croppedColorArray[colorIndex] = Color.clear;
}
}
}
Texture2D croppedTexture = new Texture2D(width, height);
croppedTexture.SetPixels(croppedColorArray);
croppedTexture.Apply();
return croppedTexture;
}
I have an orthographic camera and would like to implement a zoom feature to a specific point. I.e., imagine you have a picture and want to zoom to a specific part of the picture.
I know how to zoom in, the problem is to move the camera to a position that has the desired zone in focus.
How can I do so?
The camera's orthographicSize is the number of world space units in the top half of the viewport. If it's 0.5, then a 1 unit cube will exactly fill the viewport (vertically).
So to zoom in on your target region, center your camera on it (by setting (x,y) to the target's center) and set orthographicSize to half the region's height.
Here is an example to center and zoom to the extents of an object. (Zoom with LMB; 'R' to reset.)
public class OrthographicZoom : MonoBehaviour
{
private Vector3 defaultCenter;
private float defaultHeight; // height of orthographic viewport in world units
private void Start()
{
defaultCenter = camera.transform.position;
defaultHeight = 2f*camera.orthographicSize;
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Collider target = GetTarget();
if(target != null)
OrthoZoom(target.bounds.center, target.bounds.size.y); // Could directly set orthographicSize = bounds.extents.y
}
if (Input.GetKeyDown(KeyCode.R))
OrthoZoom(defaultCenter, defaultHeight);
}
private void OrthoZoom(Vector2 center, float regionHeight)
{
camera.transform.position = new Vector3(center.x, center.y, defaultCenter.z);
camera.orthographicSize = regionHeight/2f;
}
private Collider GetTarget()
{
var hit = new RaycastHit();
Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit);
return hit.collider;
}
}
hope you find this code example useful, should be a copy / paste.
Note: this script assume it's attached to the camera object, otherwise you should adjust the transform to the camera object reference.
private float lastZoomDistance = float.PositiveInfinity; // remember that this should be reset to infinite on touch end
private float maxZoomOut = 200;
private float maxZoomIn = 50;
private float zoomSpeed = 2;
void Update() {
if (Input.touchCount >= 2) {
Vector2 touch0, touch1;
float distance;
Vector2 pos = new Vector2(transform.position.x, transform.position.y);
touch0 = Input.GetTouch(0).position - pos;
touch1 = Input.GetTouch(1).position - pos;
zoomCenter = (touch0 + touch1) / 2;
distance = Vector2.Distance(touch0, touch1);
if(lastZoomDistance == float.PositiveInfinity) {
lastZoomDistance = distance;
} else {
if(distance > lastZoomDistance && camera.orthographicSize + zoomSpeed <= maxZoomOut) {
this.camera.orthographicSize = this.camera.orthographicSize + zoomSpeed;
// Assuming script is attached to camera - otherwise, change the transform.position to the camera object
transform.position = Vector3.Lerp(transform.position, zoomCenter, Time.deltaTime);
} else if(distance < lastZoomDistance && camera.orthographicSize - zoomSpeed >= maxZoomIn) {
this.camera.orthographicSize = this.camera.orthographicSize - zoomSpeed;
transform.position = Vector3.Lerp(transform.position, zoomCenter, Time.deltaTime);
}
}
lastZoomDistance = distance;
}
}