I am trying to make a game which "kind of" simulates the shooting of the "worms" game. The player can choose the position (circular) of an object and then, the force that is applied to the object should move in the direction its pointing towards. I tried using the AddForce(transform.right) code, but it would just go to the right. (2D BoxCollider and RigidBody2D)
Then comes the hard part, making the player choose the force by charging the power. When the player holds down the "f" key, I want the power to go up to a certain point. Once it reaches that point, I want it to go down again and then up again, so the player can choose the power he wants. I have no idea how to go about this.
It's been awhile since I've did Unity coding, so there may be some minor errors with my syntax but it should give you an idea of how to accomplish this. Your best bet for the loop is to use a coroutine to not block the main thread.
in Update() check for 'on key down' for F and start this coroutine:
IEnumerator Cycle()
{
float max = 10.0f;
float min = 1.0f;
float interval = 0.5f;
do
{
for(int i=min;i<max;i++)
{
PowerValue = i;
yield return new waitforseconds(interval);
if(!input.getkey(f))
break;
}
for(int i=max;i>min;i--)
{
PowerValue = i;
yield return new waitforseconds(interval);
if(!input.getkey(f))
break;
}
} while(input.getkey(f));
}
And back in update() use that powerValue with getKeyUp(f)
And here is PowerValue setup as a parameter that prevents code from setting the max and min outside of a 1 to 10 range (configurable)
private float powerValue = 1.0f;
public float PowerValue
{
get { return powerValue; }
set {
if(value>10f)
powerValue=10f;
else if (value<1f)
powerValue=1f;
else
powerValue=value;
}
}
Related
Hello I did the Brackeys Tutorial and I am trying to make my own game off of it and the first thing i wanted to do was a restart screen and for that i need the score but if the cube falls off it still goes forward so i need the z value of the cube when it falls of the edge
What do you mean?
If you just want to save the float value of a transform, use something like
float z = cube.transform.position.z;
When setting the transform, you need to use a whole Vector3; you can't just change one value.
cube.transform.position = Vector3(cube.transform.position.x, cube.transform.position.y, z);
Ok. According to your comment,
bool checkForY = true;
GameObject cube;
float cubeZ;
void Update()
{
if (checkForY)
{
if (cube.transform.position.y < 0)
{
cubeZ = cube.transform.position.z;
checkForY = false;
}
}
}
This should work. You might want to rename "cubeZ" to whatever you're using it for, though.
I'm new to Unity and C# in general, so excuse my terminology(or lack thereof)...
I have succeeded -with the help of a friend, to credit where its due- in making a platform go up a certain amount after one frame of collision with the player! The only problem is that, now, I can't seem to get it moving down again... Said friend challenged me to make it go up, stay airborne for a certain amount of time, then go back down.
Here is a snippet of my working code that makes it go up.
bool HaveCollided = false; //Collision checker boolean
void Update()
{
Vector3 up = lifter * Time.deltaTime;
if (HaveCollided != true || transform.position.y >= 5)
{
return;
}
}
void OnCollisionEnter(Collision collision) //Makes HaveCollided true at collision event
{
if (collision.gameObject.GetComponent<Playertag>() != null) //don't use GetComponent in Update()
{
HaveCollided = true;
}
So if my logic is right, I'd need to nest another if statement inside the one where the condition is: HaveCollided != true || transform.position.y >= 5 which should be:
if (newTime == Time.deltaTime * CertainAmount && transform.position.y >= 1) //make platform go down until y position is equal to 1
{
//make platform go down
Debug.Log("reached");
transform.position = transform.position - up;
}
But it's not working. It doesn't even seem to reach the part that would make the platform descend. I literally do not know where to go from here...
Based on your comment I made a few revisions to make the platform movement a bit smoother. I also made it so the same function can be used for both the upward and downward motion.
using UnityEngine;
using System.Collections;
[SerializeField] private float timeToMovePlatform = 0.0f; // time it takes the platform to get from 1 point to another
[SerializeField] private float timeToRestAtPeak = 0.0f; // time that the platform rests at the top of its movement
[SerializeField] private float platformYOffset = 0.0f; // offset the platform moves from its origin point to float upward
private Coroutine movingPlatform = null; // determines if the platform is currently moving or not
private void OnCollisionEnter(Collision col)
{
// add a tag to your player object as checking a tag at runtime vs. a GetComponent is faster
if(col.gameObject.tag == "Player")
{
// only trigger when we are not currently moving
if(movingPlatform == null)
{
// start our coroutine so the platform can move
movingPlatform = StartCoroutine(MovePlatform(true));
}
}
}
/// <summary>
/// Moves this object up or down depending on the parameter passed in
/// </summary>
/// <param name="moveUpward">Determines if this object is currently moving upward or not</param>
private IEnumerator MovePlatform(bool moveUpward)
{
// store our start position
Vector3 startPos = transform.position;
// build our goal position based on which direction we are moving
Vector3 goalPos = new Vector3(startPos.x, startPos + (moveUpward ? platformYOffset : -platformYOffset), startPos.z);
// set our current time
float currentTime = 0.0f;
while(currentTime <= timeToMovePlatform)
{
// lerp the position over the current time compared to our total duration
transform.position = Vector3.Lerp(startPos, goalPos, currentTime / timeToMovePlatform);
// update our timer
currentTime += Time.deltaTime;
// need to yield out of our coroutine so it does not get stuck here
yield return null;
}
// just in case there are any floating point issues, set our position directly
transform.position = goalPosition;
// when we are moving upward, make sure to stop at the peak for the set duration
if(moveUpwards)
{
yield return WaitForSeconds(timeToRestAtPeak);
// once we are done waiting, we need to move back downward
StartCoroutine(MovePlatform(false));
}
else
{
// we finished moving downward, so set our coroutine reference to false
// so the player can set the platform to move again
movingPlatform = null;
}
}
Fair warning, I did not test this code it is more a direction I would take for your situation. Before doing anything, add a tag to your player. If you are unsure what tags are, check out the docs. Be sure to give the player the tag Player so that the code will work as expected.
You will notice the first three variables are Serialized but are private. By doing this, it allows for Unity to show them in the inspector but not allow other scripts to touch them.
To learn more about Coroutines, check out the docs and for Lerps, I enjoy this blog post. Let me know if this works for you and/or you have any questions.
Your best bet is to add colliders and use isTrigger. Seed a time and if it's not triggered within that time period raise an event.
I'm making a small game in Unity and part of it it's that glass balls spawn every few seconds and they follow a path composed of targets, and the prefab has these targets specified:
Prefab picture
And here is the code:
public class move_to_target : MonoBehaviour
{
public GameObject[] target;
public float speed;
int current = 0;
float radius_target = 1;
// Update is called once per frame
void Update()
{
if (Vector3.Distance(target[current].transform.position, transform.position) < radius_target)
{
current = Random.Range(0, target.Length);
if (current >= target.Length)
{
current = 0;
}
}
transform.position = Vector3.MoveTowards(transform.position, target[current].transform.position, Time.deltaTime * speed);
}
}
So, whenever the ball spawns, it should go for the 1st target, then 2nd and finally the 3rd, but when I load the game, all the balls go to the horizon without stopping.
The problem seems to solve itself when I put the ball/fairy prefab in the scene and load the targets in the scene instead of the prefabs but that isn't the ideal solution.
How can I make it so the balls go to the targets in the scene?
Don't have enough rep to comment but this looks like it should work, what do you see if you Debug.Log(target[current].transform.position)?
If you don't need the target game object references, you could store Vector3[]'s instead.
A couple of things: You're randomizing your target every single update frame, so there is actually no progression from one target to the next in any kind of order. Is that intentional?
Also, you're moving the ball transform only when its distance is less than (<) a certain value. It seems more likely that you should be moving the ball as long as its distance is greater than (>) that value. Are you trying to go from a distance of greater than 1, to a distance of less than / equal to one?
If that's the case, maybe something like (untested):
public List<Transform> target = new List<Transform>();
public float speed;
int current = 0;
float radius_target = 1;
void Update()
{
if (Vector3.Distance(target[current].transform.position, transform.position) > radius_target)
{
transform.position = Vector3.MoveTowards(transform.position, target[current].transform.position, Time.deltaTime * speed);
} else {
current++;
if (current == target.Count)
{
current = 0;
}
}
}
But by this method the ball will seek to return to target[0] after target[2] (or whatever is the last one) and keep going forever in a loop. If you want to stop after reaching the last target you'd want to only execute this whole block if the current target < target.Count without returning to zero as it currently does.
And finally, your radius threshold of 1 could either work or not work, depending on how these targets are set up in the scene. This whole approach only works if they are all more than one unit (or radius_target units) away from each other.
I currently learn unity3d and start to create an endless game, and I want to add score by a distance that player has traveled on + x axis, so I want to calculate only how far the player traveled on + x axis.. how to calculate it?
this is my scripts
public class Score : MonoBehaviour
public float distance;
public Transform player;
private float score = 0f;
public Text scoreText;
void Awake()
{
distance = Vector3.Distance(player.position, transform.position);
}
void Update()
{
if (distance > player.transform.position.x)
{
score = distance ++;
scoreText.text = distance.ToString();
}
}
}
You can have something like this to get you started. I set it to 0.1 distance to get +1 score but that number can be anything of course.
private const float DISTANCE_REQUIRED_FOR_1_POINT = 0.1f;
private Vector3 previousPlayerPosition;
private float distanceSinceLastScore;
public Transform player;
private float score = 0f;
public Text scoreText;
void Awake()
{
//At the start save the start position.
previousPlayerPosition = player.position;
}
void Update()
{
//Calculate the distance travvelled since last update.
distanceSinceLastScore += player.position.x - previousPlayerPosition.x;
//Set the previous position the current.
previousPlayerPosition = player.position;
int scoreToAdd = 0;
while (distanceSinceLastScore > DISTANCE_REQUIRED_FOR_1_POINT)
{
//Calculate how many points to add in this update. (Likely always 1 or none)
++scoreToAdd;
distanceSinceLastScore -= DISTANCE_REQUIRED_FOR_1_POINT;
}
if (scoreToAdd > 0)
{
score += scoreToAdd;//Add to the total score.
scoreText.text = score.ToString();//refresh the text display.
}
}
To be honest, you gave very little information about the game. But I will try to come up with some possible scenarios and solutions.
First of all, you stated that this is an endless game, then I don't know what distance are you calculating between the player and a point. So, your code didn't make much sense to me, please explain if I'm missing something.
Now, you said you want to calculate the score based on the distance that the player has traveled on + x-axis. So, take a look at this code:
float previousPlayerX;
public Transform player;
private float score;
void Awake()
{
previousPlayerX= player.position.x;
score = 0;
}
void Update()
{
if (previousPlayerX < player.position.x)
{
score += player.position.x - previousPlayerX;
previousPlayerX = player.transform.position.x
}
}
This code will increase the score as long as the player is running to +x. If the player stops or even turns back, the score will not be updated. Also, note that if your starting position is 0, then you don't need to subtract the two positions to add the score, you can simply go ahead and say score = player.position.x and it should give you the same result. Furthermore, I would implement this code in a coroutine with a little bit of wait time to avoid possible bugs maybe.
Now, let's think about another scenario. I don't think the character doesn't go to infinity in endless run games, generally, the character object is stable and you kinda make that illusion of endless flow. So, let's say your character's position is not changing actually, but in the game, it seems like your character is running non-stop. In such a case, you may want to increase the score based on the time passing.
private float score;
void Awake()
{
score = 0;
StartCoroutine(UpdateScore());
}
IEnumerator UpdateScore()
{
while(true)
{
score += 1;
yield return new WaitForSeconds(1);
}
}
As you can see in the second code, I'm just assuming that my character runs non-stop and I'm just increasing the score by 1 every second. You can do it in every half a second, you can increase the score by multiplying with a speed value or you can put an if statement and don't increase the score if the character is stunned for example. So, it's all up to you.
I hope that answer helps and gives you a general idea. Let me know in the comments if you have any other questions related to this.
I am a new student working on a class project. I have 1 script attached to the camera in my only scene. I want the camera to pause over the 1st object, scroll to the 2nd object and pause then scroll to the 3rd object and pause then end. Putting this code in the UPDATE, the camera never stops. Here in the START, it hesitates around 15 sec and then it goes right to the last object, then the function stops. Note the delay set for 10 seconds. I tried putting the code in a function and calling the function from START… but no good. What am I doing wrong? HELP ME OB1....
One more thing... Is START the best place to play sound?
using UnityEngine;
using System.Collections;
// I want the camera to pause over the 1st object, scroll to the 2nd object and pause
// then scroll to the 3rd object and pause then end. Putting this code in the UPDATE
// the camera never stops. Here in the START, it hesitates around 15 sec and then it
// goes right to the last object, then the function stops. Note the delay set for 10
// seconds.
public class CameraControl : MonoBehaviour
{
public float speed; // How fast to move the camera
public int moves; // How many moves to make
public float MyWait; // How long to pause over object
// Use this for initialization
void Start()
{
StartCoroutine(MyDelay());
for (int y = 1; y <= 2; y++) // go to the next two objects
{
for (int i = 1; i <= moves; i++) // Move the camera to the next position
{
Camera.main.transform.Translate(new Vector3(1.0f, 0.0f, 0.0f) * speed * Time.deltaTime);
Debug.LogFormat("moves = {0} ", i);
}
StartCoroutine(MyDelay());
}
}
IEnumerator MyDelay()
{
yield return new WaitForSeconds(10.0f);
}
}
Try placing this code on your camera and place all the game objects you'd like the camera to move to in the Objects list. If you'd like the camera to be a little further back so it can see the object, create a new Vector3 instead of simply giving the exact position and then give that new Vector3 the x, y and z of the iterating object and then add distance to which ever axis you'd like for the camera to be distanced from the object.
public float MyWait = 5; // How long to pause over object
public float speed = 5f; // How fast to move the camera
public List<GameObject> Objects; //List of each object for the camera to go to
void Start()
{
StartCoroutine(MoveToObject(0));
}
IEnumerator MoveToObject(int iteratingObject)
{
//Wait for however many seconds
yield return new WaitForSeconds(MyWait);
bool atDestination = false;
//Move the camera until at destination
while (!atDestination)
{
yield return new WaitForFixedUpdate();
transform.position = Vector3.MoveTowards(transform.position, Objects[iteratingObject].transform.position, Time.deltaTime * speed);
if (transform.position == Objects[iteratingObject].transform.position)
atDestination = true;
}
//Continue iterating until moved over all objects in list
if(iteratingObject != Objects.Count - 1)
StartCoroutine(MoveToObject(iteratingObject + 1));
}
I think you're going to need to put some code in the Update function for this to work smoothly.
Time.deltaTime will only really make sense in an Update function, using it here and trying to do everything in the Start function won't work. Also setting the Translate transform will instantly set the position to the given value. Look up linear interpolation (lerp).
I would suggest you have a member that you use to track the current state, i.e. which object you're looking at, but an Enum of states might be easier to read.
Then you can keep a member for how long you've been in that state, which you can increase in the Update.
Then within the Update you can check whether it is time to change state or update your moving camera.
Good luck!