Instantiate objects in a list - c#

I want to write a simple "point painting" code.
I have created a script which was supposed to instantiate gameobject (point) according to mouse position, but there is a 5 clone instead of 1, in a one mouse click.
void Update()
{
if (Input.GetMouseButton(0))
{
Vector3 newPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
newPos.z = 0;
Instantiate(prefab, newPos, Quaternion.identity);
}
}
how can I play with instantiate speed in update method?
or
how can I make list (ArrayList) of instantiated objects and then destroy objects (points) which has a same position?

The problem here is that u are using Input.GetMouseButton(0) which will return true in every frame while the left mouse button is held down(your machine basically is so fast that while you as a human only did a simple mouse press, your computer actually rendered 5 frames thus the 5 instatiation), in order to prevent this use Input.GetMouseButtonDown(0), which will only return true in one frame specifically when the left mouse button is pressed.
Here are the mouse button events that might be useful for you:
Returns true during the frame the user pressed the given mouse button.
Input.GetMouseButtonDown(int button);
Returns whether the given mouse button is held down or not.
Input.GetMouseButton(int button);
Returns true during the frame the user releases the given mouse button.
Input.GetMouseButtonUp(int button);

You can try this: Paint when the mouse cursor travels a certain amount of distance, like so:
public class MyPainter : MonoBehaviour {
[SerializeField, Tooltip("The prefab to paint")]
private GameObject toPaint;
[SerializeField, Tooltip("How far does the cursor have to move in order to paint the next object?")]
private float paintDistanceThreshold;
private bool isPainting;
/// <summary>
/// How much distance did the cursor travelled since last paint.
/// </summary>
private float cursorDistanceTravelledSinceLastPaint;
private Vector2 lastCursorPosition;
private Camera mainCameraRef;
private void Awake() {
isPainting = false;
// Btw, cache the main camera. Repeated calls to 'Camera.main' is expensive.
mainCameraRef = Camera.main;
cursorDistanceTravelledSinceLastPaint = 0f;
}
private void Update() {
// Mouse button pressed, start painting.
if (Input.GetMouseButtonDown(0)) {
PaintAtCurrentCursorPosition();
isPainting = true;
}
if (isPainting) {
cursorDistanceTravelledSinceLastPaint += Vector2.Distance(Input.mousePosition, lastCursorPosition);
if (cursorDistanceTravelledSinceLastPaint >= paintDistanceThreshold) {
PaintAtCurrentCursorPosition();
}
}
// Mouse button lifted, stop painting.
if (Input.GetMouseButtonUp(0)) {
isPainting = false;
}
lastCursorPosition = Input.mousePosition;
}
private void PaintAtCurrentCursorPosition() {
Vector3 newPos = mainCameraRef.ScreenToWorldPoint(Input.mousePosition);
newPos.z = 0;
Instantiate(toPaint, newPos, Quaternion.identity);
cursorDistanceTravelledSinceLastPaint = 0f;
}
}
Basically, it starts painting OnMouseDown.
When the mouse cursor travels a certain amount of distance (paintDistanceThreshold), it will paint another object.
Stops painting OnMouseUp.
Though one issue you might encounter is that when your mouse cursor intercepts a point where you have painted before, it will paint on that point again.
can I make list (ArrayList) of instantiated objects and then destroy objects (points) which has a same position?
It will mostly work if your painter is pixel/grid based. Otherwise, the coordinates needs to be rounded off for it to work accurately.
That said, most painting applications today uses pixel-based. I would highly suggest that you make your painter paint by pixel/grid rather than world coordinates.
This way, you can avoid a lot of the issues that I mentioned earlier.

Related

Keeping camera & mouse movement speeds the same on Drag in Unity3D

this question is a bit long but please bare with me.
I am working with Unity3D's newer input system, and I've been able to set up camera movement so when the user clicks the middle mouse button, they can drag the camera around along the X- & Y-axis. However, has a very parallax-y feel to it, which I am trying to avoid. From my understanding this is happening because the speed of the mouse movement & the camera movements are not the same (See, visual).
My InputController class:
public class InputController : MonoBehaviour
{
private InputControls inputControls;
[Header("Camera Movement")]
[SerializeField] CameraController cameraController;
private InputAction.CallbackContext context;
void Awake()
{
inputControls = new InputControls();
}
private void Start()
{
inputControls.Mouse.MiddleButton.started += MiddleButton_started;
}
public void MiddleButton_started(InputAction.CallbackContext ctx)
{
context = ctx;
}
private void Update()
{
bool mouseIsDown = context.performed;
if (mouseIsDown)
{
Vector2 delta = inputControls.Mouse.DeltaPosition.ReadValue<Vector2>();
cameraController.Move(delta, false);
}
}
}
My CameraController class:
public class CameraController : MonoBehaviour
{
[SerializeField] Vector2 minPosition;
[SerializeField] Vector2 maxPosition;
[SerializeField] float speed = 3;
[SerializeField] float zPosition = -10f;
private Camera mainCam;
private void Start()
{
mainCam = GetComponent<Camera>();
}
public void Move(Vector2 deltaPosition, bool convertToViewportPoint = true)
{
if (convertToViewportPoint) deltaPosition = mainCam.ScreenToViewportPoint(deltaPosition);
Vector3 moveTo = new Vector3(deltaPosition.x, deltaPosition.y, 0);
Vector3 target = transform.position - moveTo;
float clampedX = Mathf.Clamp(target.x, minPosition.x, maxPosition.x);
float clampedY = Mathf.Clamp(target.y, minPosition.y, maxPosition.y);
transform.position = Vector3.Lerp(transform.position, new Vector3(clampedX, clampedY, -10), speed * Time.deltaTime);
}
}
Now, in this version of the CameraController, the parallax-y feel might be coming from the fact that the Lerp speed is constant, whereas the speed of the mouse movement is not.
However, I've tested it with various magnitudes (ie., the magnitudes of the delta mouse position, the current mouse position, the current mouse position subtracted from the delta mouse position, etc...) with generally the same results -- either the camera moves too fast for the mouse or vice versa.
From my limited but growing understanding of trig, magnitudes represents the speed of a vector but I CANNOT get the speed of the camera movement and the speed of the mouse movement to match up. I would like for this to happen so that when the user clicks a certain point, that point generally stays under the cursor when in movement (See other visual).
Can someone help me understand how I might achieve this?
Thanks kindly.
What I did to solve this, in case anyone comes across this, is get the position of the cursor when the mouse is first clicked. We can call that dragOrigin. Then we can get the change in position as the mouse moves (polling the input through Unity's input system can be done through an Update function). Then we subtract the new mouse position from dragOrigin. Once we have that difference -- lets call it deltaPosition -- we just add it to the camera's current position.
To ensure that the speed matches that of the mouse, run the deltaPosition and the currentMousePosition through SmoothDamp to get the velocity of the change. Its magnitude will be the speed you want the camera to move.
So for example:
// Call this when the user first clicks the mouse.
// Lets assume this is part of a class that controls the camera.
public void SetDragOrigin(Vector2 mousePosition)
{
// could probably cache Camera.main for efficiency
dragOrigin = Camera.main.ScreenToWorldPoint(mousePosition);
}
// This is called in an update function of another class that deals with input.
// (Or perhaps you can simply pass the input controls to the class controlling the camera, but that's not the case here).
public void Move(Vector2 newMousePosition)
{
mousePosition = mainCam.ScreenToWorldPoint(mousePosition);
Vector2 deltaPosition = dragOrigin - mousePosition;
Vector3.SmoothDamp(deltaPosition, mousePosition, ref dragVelocity, 0.1f, 250f, Time.deltaTime);
cameraPosition += new Vector3(deltaPosition.x, deltaPosition.y, 0) * dragVelocity.magnitude * Time.deltaTime;
// anything else you want to do like clamping camera position
// ....
}
One thing to note here, is that the 5th argument of SmoothDamp is the maxSpeed. I hardcoded it in this example, but you might want to play around with it. When I did not set the maxSpeed, there was some wonky things happening to the dragVelocity over time, so it may be better to set the maxSpeed to what suits you best.

Photon Pun 2 change position with mouse

I think there is problem between Photon and mouse position. Because when I try to change position of object with keyboard it works successfully but when I try to change position with mouse it is not changing over the network. How can I change object position with mouse position over the network?
public class SpehreControl : MonoBehaviour
{
PhotonView PV;
GameObject sphere1;
GameObject bt;
// Start is called before the first frame update
void Start()
{
PV = GetComponent<PhotonView>();
sphere1 = GameObject.Find("Sphere 1");
bt = GameObject.Find("BT_1");
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButton(0) && PV.IsMine)
{
PV.RPC("RPC_MoveOnline", RpcTarget.AllBuffered);
}
}
[PunRPC]
void RPC_MoveOnline()
{
transform.position = new Vector3(Camera.main.ScreenToWorldPoint(Input.mousePosition).x,
Camera.main.ScreenToWorldPoint(Input.mousePosition).y, 0);
}
}
I think the problem in RPC function.
When you call it, every user receives only a call event with no params. It means, every user work with his own Input.mousePosition but not from the sender.
You can use params to fix this:
...
PV.RPC("RPC_MoveOnline", RpcTarget.AllBuffered, Camera.main.ScreenToWorldPoint(Input.mousePosition));
...
[PunRPC]
void RPC_MoveOnline(Vector3 worldPosition)
{
transform.position = new Vector3(worldPosition.x, worldPosition.y, 0);
}
But it's really not a very good way...
As I see, you need to synchronize the position of some objects for all users.
It's much easier to deal with PhotonView component (what your GO already has). Just drag and drop your GO Transform component to the PhotonView Observed Components field in unity inpector.
Using this, ALL changes with a transform of your local GO will automatically be synchronized for all players!
more info here
Good luck!)

Unity Moving Player along X-axis

I am trying to create a player movement along the x-axis based on finger position.
What I need to Happen: Not multi-Touch. I want it so a player can put a single finger down and grab that position. Then check to see if the player dragged finger along screen on x-axis and move player left or right based off where they dragged finger from first touch.
So if they touch the screen and if drag left: move left by speed and if it changes to drag right move right by speed.
Any help would be Awesome.
The easiest way would be to stored first touch position and then compare the X with that position:
public class PlayerMover : MonoBehaviour
{
/// Movement speed units per second
[SerializeField]
private float speed;
/// X coordinate of the initial press
// The '?' makes the float nullable
private float? pressX;
/// Called once every frame
private void Update()
{
// If pressed with one finger
if(Input.GetMouseButtonDown(0))
pressX = Input.touches[0].position.x;
else if (Input.GetMouseButtonUp(0))
pressX = null;
if(pressX != null)
{
float currentX = Input.touches[0].position.x;
// The finger of initial press is now left of the press position
if(currentX < pressX)
Move(-speed);
// The finger of initial press is now right of the press position
else if(currentX > pressX)
Move(speed);
// else is not required as if you manage (somehow)
// move you finger back to initial X coordinate
// you should just be staying still
}
}
`
/// Moves the player
private void Move(float velocity)
{
transform.position += Vector3.right * velocity * Time.deltaTime;
}
}
WARNING: this solution will only work for devices with touch input available (because of Input.touches use).
using the code #programmer provided in this answer: Detect swipe gesture direction
You can easily detect the direction you are swiping/dragging. Replace the Debug
void OnSwipeLeft()
{
Debug.Log("Swipe Left");
}
void OnSwipeRight()
{
Debug.Log("Swipe Right");
}
With functions that move your character. If you use RigidBody to move your character you can use https://docs.unity3d.com/ScriptReference/Rigidbody.MovePosition.html. If its a normal object, you can move it by tweaking the transform.position.
If you need more information on how to move rigidbody\normal objects let me know what type of game you have and more details on how you set up the player.

A better way to detect the cursor?

Goal: Detect when the cursor has entered a defined radius of the player.
Hello, I am in the process of trying to replicate the combat system from a game called CrossCode. The idea is that when the cursor is within a certain radius of the player, I will be able to switch to melee combat, and back to ranged once the cursor leaves this radius.
I have implemented one way I thought it could be done, however it feels slow or unreliable and I just wanted to know if there are any other methods I could possibly look into to achieve a smoother result.
Here is what I've done
attached to the player
void Update()
{
attackStyleSwitchRadius = colRef.radius;
playerCenter = colRef.transform.position;
if(Physics2D.OverlapCircle(playerCenter, attackStyleSwitchRadius, cursor))
{
meleeMode = true;
rangeMode = false;
}
else
{
meleeMode = false;
rangeMode = true;
}
}
And on a small 2D object I have this script so that it follows the cursor position.
void Update()
{
pos = Input.mousePosition;
gameObject.transform.position = Camera.main.ScreenToWorldPoint(pos);
}
when the small object enters the overlap circle it changes the bools around.
You can remove the collision detection overhead by doing something like this instead;
void Update ()
{
attackStyleSwitchRadius = colRef.radius;
playerCenter = colRef.transform.position;
var mouse = Input.mousePosition;
mouse.z = Vector3.Distance(Camera.main.transform.position, playerCenter);
var range = Vector2.Distance(Camera.main.ScreenToWorldPoint(mouse), playerCenter);
var inside = range < attackStyleSwitchRadius;
meleeMode = inside;
rangeMode = !inside;
}
Cursor
Make an object, name it cursor.
Add a small collider to the cursor object.
Add a script to the cursor object so its always at the mouses location.
Melee range zone
Add a GameObject as child of the player, name it MeleeRangeZone.
Add a collider to it, set it to be a Trigger. The size of this collider will be the players melee range,
Add a rigidbody to it so that collisions can be detected, but set the rigidbody to not rotate or change its position.
Add a script to the object and use the OnTriggerEnter and OnTriggerExit methods to detect whether or not the cursor has entered your melee zone.
You can now use the OnTriggerEnter and OnTriggerExit methods to switch between the players attack modes, meaning that when the cursor enters it changes to melee and when it exit it changes to ranged.
You can fire the ray to detect the location the cursor should have like this:
public LayerMask RaycastCollidableLayers;
public RaycastHit Hit;
public float CheckDistance = 200f;
public Transform Cursor;
void PerformRaycast(){
//Set up ray
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//Fire ray
Physics.Raycast(ray, out Hit, CheckDistance + 0.1f, RaycastCollidableLayers);
if (Hit.collider == null)
{
//Debug.Log("Raycast hit nothing");
return;
}
else //Ray hit something
{
//Move cursor to Hit.point;
Cursor.position = Hit.point;
}
}

Constant animation hapenning when moving

I have the following code, but i'm having some problems. Every time update is called, the character move to the point i give him to. But i just give him a point when i click with the mouse on the ground, the problem starts when i try to make it animate the character.
If i pass the value of the animation on the clickToMove() method it'll always play that animation even if we aren't moving. And if i place clickToMove inside the "if clicked" the character will teleport and not move towards. I can't think in a way to do the animation properly, only when the object is moving, and goes back to idle when it's stopped, even if the clickToMove() is playing all the time.
using UnityEngine;
using System.Collections;
public class ClickScript : MonoBehaviour
{
public float moveSpeed;
public float minDistance;
Vector3 mouseClick; //Creates a variable to save the constant of the hit from raycast
private Animator anim;
private Rigidbody rigidB;
// Use this for initialization
void Start()
{
anim = GetComponent<Animator>();
rigidB = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate()
{
if (Input.GetMouseButtonDown(1))//If clicked
{
clickPosition(); //Gets the click position
}
if (Vector3.Distance(transform.position, mouseClick) > minDistance) //If the click distance is bigger than the minimal
{
//It is allways moving, but since there's no click position it doesn't move when not clicked
clickToMove();
}
}
void clickPosition()//This function throw a raycast on the ground and save the position on mouseClick to make the char move to there
{
RaycastHit clickHit; //creates a constant with the infos from the raycast
Ray mouseClickPosition = Camera.main.ScreenPointToRay(Input.mousePosition); //creates a constant to save the mouse position
if (Physics.Raycast(mouseClickPosition, out clickHit, 100.00f))//throw a raycast returning the mouse position and more infos
{
Debug.Log("Click at " + clickHit.point); //Show where were clicked
mouseClick = clickHit.point;//mouseClick receive the position of the click
}
}
void clickToMove() //this function make the player look at the click and move to mouseClick
{
mouseClick.y = transform.position.y; //get rid of the y to fix rotation bugs
transform.LookAt(mouseClick);//look at the poit you clicked
transform.position = Vector3.MoveTowards(transform.position, mouseClick, moveSpeed * Time.deltaTime);//move to the clickpoint
}
}
How about this way?
bool _isAnimating = false;
// Update is called once per frame
void FixedUpdate()
{
if (Input.GetMouseButtonDown(1))//If clicked
{
clickPosition(); //Gets the click position
//start animation here!!!
//animator.SetBool("bWalk", false);
//and set animation state to true
_isAnimating = true;
}
if (Vector3.Distance(transform.position, mouseClick) > minDistance)
{
clickToMove();
}
else if(_isAnimating)
{
//turn off the animation here!!!
//animator.SetBool("bStop", false);
//and set to false
_isAnimating = false;
}
}

Categories

Resources