Unity2D: Reduce Y of square during runtime - c#

I struggle to reduce the Y-Scale of a square, while shifting the Y-position downwards,
so the square stays in place.
It should be like a healthbar for remaining oxygen, but in a gameobject not on a canvas.
I reduce the scale of the square over time with this code:
float remainingAir = 100f;
void Start()
{
defaultY = oxygenOverlay.transform.localScale.y;
yPercent = defaultY / air;
}
float reduceFactor = newY * air;
void AdjustOxygenBar()
{
oxygenOverlay.transform.localScale = new Vector3(oxygenOverlay.transform.localScale.x, yPercent * remainingAir ,oxygenOverlay.transform.localScale.z);
}
The scale reduced from both sides of the square. How do I move the square downward each frame, so the square will only reduce from top to bottom?
Thanks on advance

Well I have tried this and it works to scale only on Y axis, however it will shrink towards the center of the object so yes you have to move it down to make the effect thats a bar thats being unfilled
void Awake ()
{
percent = 100;
}
void Update ()
{
percent -= 0.1f;
transform.localScale = new Vector3(transform.localScale.x,transform.localScale.y*percent/100,transform.localScale.z);
}

Related

How can I make a camera zoom script in c# for unity?

I want a c# script so when I hold right click it zooms in a little and when you stop holding right click it goes back to its original position.
You would first want to store the original camera z distance. (As I assume you want it to go forward in the z direction). Then you would want to have a float for the amount of tome zoom was held down. (Increase it when zooming, and decrease it when you dont click it).
Also have a target z, so it doesn't go too far
public float startZ;
public float targetZ;
public float zoomInSpeed;
public float zoomOutSpeed;
float heldDownTime;
float originalZ;
void Start()
{
startZ = transform.position.z;
}
void Update()
{
if (Input.GetKey(KeyCode.Mouse0))
{
heldDownTime += Time.deltaTime * zoomInSpeed;
}
else
{
heldDownTime -= Time.deltaTime * zoomOutSpeed;
heldDownTime = Mathf.Clamp(heldDownTime, 0, Mathf.Infinity);
}
float smoothed = System.Math.Tanh(heldDownTime);
Vector3 pos = transform.position;
transform.position = new Vector3(pos.x, pos.y, startZ + smoothed * (targetZ - startZ));
}
I basically get the time held down, then I smooth it out, so it doesn't zoom to far forward.
Let me know in the comments if you get any errors!

Sprites Auto Position and scale

I have 4 sprites with colliders, I want to auto position and scale them to the bottom of the screen evenly so they don't over lap and they are not off screen at all. I can not do this in canvas it needs to be done as gameObjects.
I also am trying to get each Sprits height to be 1/4th-1/5th depending on how it looks, that's why the code is divided by 4 down below.
How do I get them to position on the bottome and side by side?
public class AutoPosition : MonoBehaviour {
public Sprite [] goals;
public float width = Screen.width / 4;
public float height = Screen.height / 4;
// Use this for initialization
void Start () {
for (int i = 0; i < goals.Length; i++) {
goals[i]
}
}
You can use SpriteRender for the images. And position them inside of a parent GameObject. Than it is enough to simply scale and position that one Parent GameObject correctly (similar to the canvas but with normal Transform components).
public class applySize : MonoBehaviour
{
private void Apply()
{
// Get the main camera position
var cameraPosition = Camera.main.transform.position;
// This makes the parent GameObject "fit the screen size"
float height;
if (Camera.main.orthographic)
{
// Camera projection is orthographic
height = 2 * Camera.main.orthographicSize;
}
else
{
// Camera projection is perspective
height = 2 * Mathf.Tan(0.5f * Camera.main.fieldOfView * Mathf.Deg2Rad) * Mathf.Abs(cameraPosition.z - transform.position.z);
}
var width = height * Camera.main.aspect;
transform.localScale = new Vector3(width, height,1);
transform.position = cameraPosition - new Vector3(0,height*.375f, cameraPosition.z);
// Since the 4 images are childs of the parent GameObject there is no need
// place or scale them separate. It is all done with placing this parent object
}
private void Start()
{
Apply();
}
}
Using the following Scene setup
The X positions of the Sprites simply are
image1: - width * 1.5;
image2: - width * 0.5;
image3: width * 0.5;
image4: width * 1.5;
and for the four SpriteRenderers
and the colliders
Result
(with an additional call in Update)
I made the Parent position stay on Z = 0. You can change this according to your needs.
This way the colliders should now be able to interact with other objects.

How can i spawn random objects that are not overlap between specific given area?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WallsTest : MonoBehaviour
{
// using a GameObject rather than a transform
public GameObject prefab;
public Vector3 wallsStartPosition;
public float width = 0;
public float height = 1;
public float length = 2;
public Camera wallsCamera;
public float wallsArea;
void Start()
{
wallsCamera.transform.position = new Vector3(wallsStartPosition.x, wallsStartPosition.y + 100, wallsStartPosition.z - 235);
BuildWalls();
}
private void Update()
{
}
void BuildWalls()
{
for (int i = -2; i < 2; i++)
{
GameObject go = Instantiate(prefab);
go.transform.parent = transform;
Vector3 scale = Vector3.one;
Vector3 adjustedPosition = wallsStartPosition;
float sign = Mathf.Sign(i);
if ((i * sign) % 2 == 0)
{
adjustedPosition.x += (length * sign) / 2;
scale.x = width;
scale.y = height;
scale.z *= length + width;
}
else
{
adjustedPosition.z += (length * sign) / 2;
scale.x *= length + width;
scale.y = height;
scale.z = width;
}
adjustedPosition.y += height / 2;
go.transform.localScale = scale;
go.transform.localPosition = adjustedPosition;
}
}
}
For example the length is 100 so the area will be 100x100 i think.
And i have the wallsStartPosition for example 250,0,250
Now i want inside the walls area to instantiate at random position number of objects. For example 50 cubes. But they should not be overlap each other and for example the minimum gap between each other should be 5. and maximum gap as fas it can be.
But i don't understand yet how to calculate the area and position of the walls and just instantiate random objects inside.
And this is the script for spawning gameobjects at random positions in given area. In this case the area is the terrain. But i want the area to be inside the walls i create in the first script. This script is attached to the same empty gameobject like the WallsTest script.
Another problem with the SpawnObjects script is that there is no any set for the gap between the objects and if the objects too good like scale 20,20,20 some of the objects that spawn on the edge half out of the terrain.
spawn
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnObjects : MonoBehaviour
{
public Terrain terrain;
public int numberOfObjects; // number of objects to place
private int currentObjects; // number of placed objects
public GameObject objectToPlace; // GameObject to place
private int terrainWidth; // terrain size (x)
private int terrainLength; // terrain size (z)
private int terrainPosX; // terrain position x
private int terrainPosZ; // terrain position z
void Start()
{
// terrain size x
terrainWidth = (int)terrain.terrainData.size.x;
// terrain size z
terrainLength = (int)terrain.terrainData.size.z;
// terrain x position
terrainPosX = (int)terrain.transform.position.x;
// terrain z position
terrainPosZ = (int)terrain.transform.position.z;
}
// Update is called once per frame
void Update()
{
// generate objects
if (currentObjects <= numberOfObjects)
{
// generate random x position
int posx = Random.Range(terrainPosX, terrainPosX + terrainWidth);
// generate random z position
int posz = Random.Range(terrainPosZ, terrainPosZ + terrainLength);
// get the terrain height at the random position
float posy = Terrain.activeTerrain.SampleHeight(new Vector3(posx, 0, posz));
// create new gameObject on random position
GameObject newObject = (GameObject)Instantiate(objectToPlace, new Vector3(posx, posy, posz), Quaternion.identity);
newObject.transform.localScale = new Vector3(20, 20, 20);
currentObjects += 1;
}
if (currentObjects == numberOfObjects)
{
Debug.Log("Generate objects complete!");
}
}
}
My technical knowledge is limited, but you'll have to either get the script to spawn these objects every [X] amount of position ("posX += 1.0f;", or something to that effect) so that they appear in a uniform manner, or, have the script record each new object's position and use that information to calculate space away from said objects to spawn another one.
In any case, depending on the end result you're aiming for, you'll have to write how these objects operate in a given space. For example, if you have a messy room as a scene, you can have one desk that would find space in the corner of two walls, one bed alongside one wall and rubbish spawning randomly.
You can use Physics.OverlapSphere to test if two objects are overlapping. This assumes that the objects both have colliders.
Once you test this condition and it evaluates to true, I would suggest simply moving the object that overlaps and testing it again against the other objects in the scene. You can get clever with this by only testing objects you think might be close to overlapping, or overlapping.
Alternatively you can just compare every object to every other object in the scene. This would not be ideal if you have a lot of objects, because doing so would be O(n^2) complexity.
In any case you can use this function to test overlapping. Good luck.
hint: if you make the collider bigger than the object, you can place items a minimum space apart. For example if you have a cube of localSize 1,1,1 - the colider can be 5,5,5 in size and Physics.OverlapSphere will return true if the colliders overlap, demanding that the cubes be a certain space apart from each other

I need to make a sprite move horizontally for a predetermined distance, flip horizontally, and return

I'm trying to make a penguin sprite slide back and forth along platforms I have made. I have achieved this however I am really struggling to make the sprite flip horizontally once it moves back. I believe I may need to change my method of making the penguins move in order to incorporate the flip. I saw lots of threads about rotating around the Y axis but I don't know how to incorporate it. As it stands the penguins just goes back and forth always facing the positive x direction. The game is in 2D on Unity and is written in C#. Thanks for any advice. :)
using UnityEngine;
using System.Collections;
public class Enemy1 : MonoBehaviour {
private SpriteRenderer SpriteRenderer;
public float min = 2f;
public float max = 3f;
public int x = 0;
public bool facingRight = true;
// Use this for initialization
void Start()
{
min = transform.position.x;
max = transform.position.x + 27;
}
// Update is called once per frame
void Update()
{
transform.position = new Vector3(Mathf.PingPong(Time.time * 2, max - min) + min, transform.position.y, transform.position.z);
}
}
You can track the direction of your sprite and use localScale.x or flipX:
float _prevX = 0f;
...
void Update()
{
float newX = Mathf.PingPong (Time.time * 2, max - min);
transform.position = new Vector3(newX + min, transform.position.y, transform.position.z);
Vector3 scale = transform.localScale;
scale.x = newX < _prevX ? -1 : 1;
transform.localScale = scale;
_prevX = newX;
}
Another way: track when your sprite near "edge" points and "flip" only then, otherwise the first way is more general if you rotate your sprite earlier for some reasons.
Its been a while since I've messed with sprites but i think setting transform.scale.z = -1 will flip the sprite so it faces the other direction.

XNA make sprite follow the mouse pointer but with a delay?

Here I updated my code with your help.
Anyway it still does not do what is supposed to do, following the mouse pointer with a delay.
The balloon (the sprite) is flying diagonally and does not stop once the mouse pointer is met, only slows down then keeps moving and then speeds up.
I added an if condition once the balloonPosition is equal to mouse pointer, to have the velocity = 0, but that does not stop the balloon.
I added a portion of code for keeping the balloon (the sprite) in the screen.
protected override void Update(GameTime gameTime)
{
MouseState currentMouseState = Mouse.GetState();
//balloonPosition = new Vector2(currentMouseState.X, currentMouseState.Y);
//System.Windows.Input.MouseState currentMouseState = System.Windows.Input.Mouse.GetState();
// Get the current mouse position
Vector2 mousePosition = new Vector2(currentMouseState.X, currentMouseState.Y);
// Get the distance between the balloon and the mouse.
float distance = Vector2.Distance(mousePosition, balloonPosition);
// You can change the standard velocity / or the max distance to make the sprite move faster or slower.
// Currently it may move to fast or to slow for you to know a difference.
balloonVelocity = StandardVelocity * (distance/MaxDistance);
// Set the balloons position to the new velocity.
balloonPosition += balloonVelocity;
if (balloonPosition == mousePosition)
{
balloonVelocity = new Vector2(0);
}
//Keep the balloon in the screen
if (balloonPosition.X < balloon.Width / 2)
balloonPosition.X = balloon.Width / 2;
if (balloonPosition.Y < balloon.Height / 2)
balloonPosition.Y = balloon.Height / 2;
if (balloonPosition.X > Window.ClientBounds.Width - balloon.Width / 2)
balloonPosition.X = Window.ClientBounds.Width - balloon.Width / 2;
if (balloonPosition.Y > Window.ClientBounds.Height - balloon.Height / 2)
balloonPosition.Y = Window.ClientBounds.Height;
}
NewPosition = Vector2.Lerp(CurrentPosition, DesiredPosition, Speed);
Here's what I'd go with off the top of my head:
public List<Tuple<TimeSpan, Vector2>> Points { get; set; }
public Vector2 CurrentPoint { get; set; }
public void Update(GameTime gameTime)
{
Points.Add(new Tuple<TimeSpan, Vector2>(TimeSpan.FromSeconds(1), mouseCoords));
foreach(var point in Points)
{
point.Item1 -= gameTime.ElapsedTimeSpan;
if (point.Item1 < TimeSpan.Zero)point
CurrentPoint = point.Item2;
}
}
I'm pretty sure I wouldn't need to explain the code, right?
In the draw loop, you'd simply always draw the CurrentPoint
You can use a list or an array to keep the delay. Store the mouse position every 0.03125 seconds in a list. Then set timer for the delay (integer counter should work). When the delay is up start reading from the list at the same pace it was out in the list. (0.03125 in this case) and move your sprite towards that point.
Since you are looking for how to change the speed this is one way to do it.
Vector2 balloonOrigin, balloonPosition;
Vector2 balloonVelocity;
private float MaxDistance = 1920; // Reduce this value to slow down the balloon.
public static float AngleBetweenVectors(Vector2 v1, Vector2 v2) { return (float)Math.Atan2(v2.Y - v1.Y, v2.X - v1.X); }
public void test()
{
//System.Windows.Input.MouseState currentMouseState = System.Windows.Input.Mouse.GetState();
// Get the current mouse position
Vector2 mousePosition = new Vector2(currentMouseState.X, currentMouseState.Y);
// Get the distance between the balloon and the mouse.
float distance = Vector2.Distance(mousePosition, balloonPosition);
// You can change the max distance to make the sprite move faster or slower.
// Currently it may move to fast or to slow for you to know a difference.
balloonVelocity = AngleBetweenVectors(balloonPosition, mousePosition) * (distance / MaxDistance);
// Set the balloons position to the new velocity.
balloonPosition += balloonVelocity;
}

Categories