I'm using C# and Unity for a shooter game. My code works, but I'd like to tweak it. I have this on a blend tree and am using which direction the player is in to fire the bullet. The problem is, if you rapidly change directions, the player doesn't always shoot. I found this to be because the full value of 1 or -1, isn't always being achieved. If I put "less than or equal to" as opposed to "equals (==)", the bullets fire all the time as it is always "less than" at that point. Is there a different way of doing this?
Thank you in advance.
Example of my code, these are only 2 directions to save space, it is a 4 directional sprite. I apologize if the code is broken up, I don't know how to show it properly here.
if (myAnimator.GetFloat("DirectionX") == -1f)
{
shotTime = Time.time + timeBetweenShots;
GameObject b = (Instantiate(bulletLeft, shotPoint.position + -transform.right, Quaternion.identity));
b.GetComponent<Rigidbody2D>().AddForce(-transform.right * speed);
}
if (myAnimator.GetFloat("DirectionY") == 1f)
{
shotTime = Time.time + timeBetweenShots;
GameObject b = (Instantiate(bulletUp, shootUpPoint.position + transform.up, Quaternion.Euler(0, 0, 90)));
b.GetComponent<Rigidbody2D>().AddForce(transform.up * speed);
}
Sounds like your looking for discreet integer values:
int dirX = Mathf.RoundToInt(myAnimator.GetFloat("DirectionX"))
if(dirX == 1)
//etc
Related
I'm working on a game for game jam and part of it is to make platforms that move smoothly. They slow down at the ends of their movement before turning around. The platforms simply move side to side or up and down between two waypoints(which are just empty transforms). I have code that uses cosine to determine the speed which works well except it doesn't align with the waypoints, the platforms tend to slow and change direction before ever reaching the waypoints. I need a way to use the distance between the waypoints as a variable in determining how the cosine equation changes speed so that the platforms slow and reverse direction exactly at the waypoints.
Here is what I have so far:
void Side_to_side()
{
if (waypointIndex < horWaypoints.Length)
{
platformSpeed = (1f * (float)Mathf.Cos(2f * (float)Mathf.PI * 1f * totalTime));
Vector3 targetPosition = horWaypoints[waypointIndex].position;
float delta = platformSpeed * Time.deltaTime;
transform.position = Vector2.MoveTowards(transform.position, targetPosition, delta);
if (transform.position.x == targetPosition.x && transform.position.y == targetPosition.y)
{
if (waypointIndex + 1 == horWaypoints.Length)
waypointIndex = 0;
else
waypointIndex++;
}
}
else
{
waypointIndex = 0;
}
//Translate platform back and forth between two waypoints
}
As I have said this code moves the platforms in the motions i want but they don't use the waypoints as turn around points. I understand I could do away with the waypoints and just calculate how far I would like each platform to go before turning around individually but that would take time to do it for each platform whereas I'd like to quickly put down waypoint pairs for them to use and the script calculates what the perfect values would be to match the waypoint locations.
If I understand you correctly you want to move an object forth and back between exactly two positions and apply some smoothing to the movement.
I would rather use a combination of Vector2.Lerp with a Mathf.PingPong as factor and you can then apply ease in and out using additionally Mathf.SmoothStep.
This could look like e.g.
public Transform startPoint;
public Transform endPoint;
// Desired duration in seconds to go exactly one loop startPoint -> endPoint -> startPoint
public float duration = 1f;
private void Update ()
{
// This will move forth and back between 0 and 1 within "duration" seconds
var factor = Mathf.PingPong(Time.time / (2f * duration), 1f);
// This adds additional ease-in and -out near to 0 and 1
factor = Mathf.SmoothStep(0, 1, factor);
// This interpolates between the given positions according to the given factor
transform.position = Vector2.Lerp(startPoint, endPoint, factor);
}
you could of course still use cosine if necessary, basically any function that returns a value between 0 and 1. You just have to use the correct multiplier in order to achieve the desired duration in seconds.
Note: Typed on the phone and not 100% sure on the math but I hope the idea gets clear
So, here is what i have:
SteamVR's hand gameobject
3D sphere.
what i want:
The sphere to move to same direction/position as the hand does, but it to move further with a multiplier. E.g. i move the VR controller and the hand moves 1 unit. I want that the sphere moves to the same direction in a same amount of time but e.g. 2 units. how do i do this?
i tried simple
sphere.transform.position = ControllerToFollow.position +2f;
but then the sphere is always offset.
position is a Vector3, which is essentially 3 floats - you can't plus a Vector3 with a float unless you overload the + operator. Otherwise what you can do is the following:
Vector3 followPos = new Vector3(ControllerToFollow.position.x + 2f,
ControllerToFollow.position.y + 2f,
ControllerToFollow.position.z + 2f);
sphere.transform.position = followPos;
If you only want it to follow on one axis, then you can do the following:
Vector3 followPos = new Vector3(ControllerToFollow.position.x + 2f, // Follow on x Axis
ControllerToFollow.position.y, // Y axis is the same
ControllerToFollow.position.z); // X Axis is the same
sphere.transform.position = followPos;
Edit: I think I understand your problem better now. Here's a better version.
if (Vector3.Distance(sphere.transform.position, ControllerToFollow.position) >= 2f)
{
// Code that makes the sphere follow the controlling
}
Just track the movement Delta of the hand and multiply it by a certain multiplier.
At the beginning of the manipulation store
private Vector3 lastControllerPosition;
...
lastControllerPosition = ControllerToFollow.position;
then in every frame compare
var delta = ControllerToFollow.position - lastHandPosition;
// Don't forget to update lastControllerPosition for the next frame
lastControllerPosition = ControllerToFollow.position;
Now in delta you have a movement of the controller since the last frame. So you can assign it to the sphere with a multiplier using Transform.Translate
sphere.transform.Translate(delta * multiplier, Space.World);
or simply using
sphere.transform.position += delta * multiplier;
I want my object to keep moving in the target's direction forever or until it collides, the collision part I have already handled it; However, I am having problems with the movement part.
I first try to rotate my target using these lines of code
Vector2 diff = target - transform.position;
float angle = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0.0f, 0.0f, angle);
This works perfect and my object rotates in the direction I want it to.
In my Update method I have the following
if (isMoving)
{
Vector2 f = transform.forward;
transform.position = Vector3.MoveTowards(transform.position, target + Vector3.forward, speed * Time.deltaTime);
}
Now this runs but fails to accomplish the goal and I know why, it makes sense but not sure how to fix it. The object moves to the point in the correct direction but I don't want it to stop at the target, I want it to keep going.
I also tried
rb.MovePosition(rb.position + f * Time.deltaTime * speed);
rb is a rigidbody2D
as well as
rb.AddForce(rb.position + f * Time.deltaTime * speed);
But in both cases the object rotates but never moves
I also used translate and same behavior as MovePosition
P.S. It's a 2D game
After looking over the internet, I didn't find anything that really does what I am looking for, you are not able to translate a kinematic object forever (Obviously you have to handle that the object should get destroyed at some point or something, but that's not the issue). So I went ahead and decided to write my own library to make this simple. I was able to achieve my goal using the line equation. Simple I took these steps to solve my issue.
At start I get the slope between 2 points
Calculate the y-intercept
translate the object using the line equation with a fixed X value (step), every x value find the corresponding y value and translate the object to it.
Repeat step 3 in a FixedUpdate and that's it.
Of course there is more to it, handling cases where x = 0 which will give a 0 division for the slope or y = 0, etc... I solved all of that in the library. For anyone interested you can check it out here EasyMovement
If you don't want the library then here is a simple code that will do it.
//Start by Defining 5 variables
private float slope;
private float yintercept;
private float nextY;
private float nextX;
private float step;
private Vector3 direction; //This is your direction position, can be anything (e.g. a mouse click)
In the Start Method
//step can be anything you want, how many steps you want your object to take, I prefer 0.5f
step = 0.5f;
//Calculate Slope => (y1-y2)/(x1-x2)
slope = (gameObject.transform.position.y - direction.y) / (gameObject.transform.position.x - direction.x);
//Calculate Y Intercept => y1-x1*m
yintercept = gameObject.transform.position.y - (gameObject.transform.position.x * slope);
Now in FixedUpdate
//Start by calculating the nextX value
//nextX
if (direction.x > 0)
nextX = gameObject.transform.position.x + step;
else
nextX = gameObject.transform.position.x - step;
//Now calcuate nextY by plugging everything into a line equation
nextY = (slope * nextX) + yintercept;
//Finally move your object into the new coordinates
gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, new Vector3(nextX, nextY, 0), speed * Time.deltaTime);
Keep in mind this won't do the heavy lifting, there are a lot of conditions that needs to be taken into consideration.
I just want to know if I'm using vector3.slerp correctly as I have some issues.
I have set up a cube in a scene and I want it move smoothly from its current position to one being passed into by the program. Before I was trying to use the slerp I simply had my cube moving from its current point to its new point like this (as I said, the math all works):
cubeFour.transform.localPosition = new Vector3((B2*C1 - B1*C2)/delta,0,(A1*C2 - A2*C1)/delta);
But when I put it in a slerp call, my cube is no longer on the screen. This is how I'm calling it:
Vector3 targetPosition = new Vector3(lerpX, lerpY, lerpZ);
cubeFour.transform.localPosition = Vector3.Slerp(cubeFour.transform.localPosition, targetPosition, Time.deltaTime);
LerpX, LerpY & LerpZ are local variables I've set to contain the X, Y & Z of the first Vector3 I created in my first attempt.
Have I set up the slerp correctly or have I made a kerfuffle somewhere?
Slerp is best for directions, Lerp is best for positions. You should probably be using Lerp. And Time.deltaTime is almost certainly the wrong choice for t. You should be giving it a number that moves from 0 to 1 over the time that you want the cube to move, e.g.
float moveTimeInSeconds = 2;
cubeFour.transform.localPosition = Vector3.Lerp(cubeStartingPosition, targetPosition, (Time.time - startTime) / moveTimeInSeconds);
Or use MoveTowards if it makes more sense to define the speed of motion, and to move towards a target regardless of a starting point, instead of via starting and ending positions and times.
float step = speed * Time.deltaTime;
cubeFour.transform.localPosition = Vector3.MoveTowards(cubeFour.transform.localPosition, targetPosition, step);
Lerp uses a percentage to animate!
This means you must plug in a percentage, not a value near the same thing each frame.
Example Update():
var animationSpeedInSeconds=1;
var animationCounter:float=0;
function Update(){
if(animationCounter>=0 && animationCounter<=1){
animationCounter+=Time.deltaTime/animationSpeedInSeconds;
cubeFour.transform.localPosition = Vector3.MoveTowards(cubeFour.transform.localPosition, targetPosition, animationCounter);
}
}
I hope this helps!
I am trying to create a jump method in XNA, but I am facing a lot of problems, it doesn't work for me, I've been trying doing it for like 2 hours long and still no "luck". Can anybody give me a code sample, or at least a direction?
Note: I want the jump to be realistic, using gravity and such.
Thank you!
I erased all my work but here's the latest I tried, I know it shouldn't work for sure, but still..
public void Jump(GameTime gameTime)
{
float currentTime = (float)0.1;
if (position.Y == 200)
{
position.Y += velocity.Y*currentTime -gravity * (float)(Math.Pow(currentTime,2)) / 2;
}
if (position.Y == 200 + jumpHeight)
{
position.Y -= velocity.Y * currentTime - gravity * (float)(Math.Pow(currentTime, 2)) / 2;
}
}
I see that you've learned the equations of motion from your code (which I don't think was in place when I made my comment). However you're a little off, your issue is with your time variable. You're passing in your game time, but then using .1f for your time variable. What you really want for your time variable is the time since you started the jump. Further, position.Y is unlikely to ever be exactly equal to 200 or 200 + jumpHeight. It's a float (I assume), so you can never trust that it'll be a nice round number. If you want to specify an exact maximum jump height, you'll have to perform some equations before and set your velocity.Y accordingly (solve for when velocity equals 0 i.e. the top of your jump).
So, to fix your original code I think something like this will work, albeit totally untested:
public void Jump(GameTime gameTime)
{
if(jumping && position.Y > groundLevelAtPlayer) {
//Get the total time since the jump started
float currentTime = gameTime.totalTime - character.timeofjumpStart;
//gravity should be a negative number, so add it
position.Y += (velocity.Y * currentTime)
+ (gravity * ((float)(Math.Pow(currentTime, 2)) / 2));
}
else
{
jumping = false;
}
}
How exactly do you want to make your player jump? Since you mentioned realism I am assuming that you want your player to jump and move across both the X and Y axis, so that it will move along an arc(parabola if you will).
If that is what you are after, you will need to replicate projectile motion. This previous SO thread contains various methods in which you could implement such motion.
Edit:
You should be able to use the same equations presented. For vertical jumps, the angle will be 90 degrees, or pi/2 if you are working with radians. If you are pressing your direction keys, you will have to use the same equations. The angle at which you want your player to start the jump will have to be selected by yourself. Usually maximum range is obtained at an angle of 45 degrees (pi/4) assuming that the same force is used, so your option is really between 0 and 45 degrees.