I am building a infinite vertical platformer for mobile platforms using Unity3D. I am using the accelerometer to move the character left and right on the screen.
if (Input.acceleration.y > -0.2f && Input.acceleration.y < 0.2f) {
maxSpeed = 17;
}
if (Input.acceleration.y > -0.5f && Input.acceleration.y < -0.2f) {
maxSpeed = 25;
}
if (Input.acceleration.y > 0.2f && Input.acceleration.y < 0.5f) {
maxSpeed = 25;
}
if (Input.acceleration.y > -0.7f && Input.acceleration.y < -0.5f) {
maxSpeed = 25;
}
if (Input.acceleration.y > 0.5f && Input.acceleration.y < 0.9f) {
maxSpeed = 25;
}
if (Input.acceleration.y < -0.9f) {
maxSpeed = 40;
}
if (Input.acceleration.y > 0.9f) {
maxSpeed = 40;
}
Basically the farther the device is tilted the faster the character moves. I'm pretty sure there is a way better way to write this code but I'm pretty terrible at math and I can't figure it out. Any suggestions on cleaning this up a bit?
5 Answers 5
I know absolutely nothing about c# or unity3d, so if there's a language specific assist, I have no idea about it!
I notice each condition checks Input.acceleration.y
, so that's one bit of information that repeats. I also notice we have three speeds, yet we have seven conditionals!
First of all, the negatives are confusing. Find the absolute value first.
I'm going to assume a number followed by an "f" means float. So maybe we need something like:
float acceleration = Math.Abs(Input.acceleration.y);
Great, now it's going to be easier to handle this!
Now all we need is a simple check like so:
if (acceleration < 0.2f) {
maxSpeed = 17;
} else if (acceleration < 0.9f) {
maxSpeed = 25;
} else {
maxSpeed = 40;
}
Your original numbers were a little weird, but if you meant for such a strange pattern, correct me!
-
\$\begingroup\$ This looks quite nice, but won't get the same result for e.g -0.2f \$\endgroup\$Heslacher– Heslacher2014年07月31日 06:16:55 +00:00Commented Jul 31, 2014 at 6:16
-
\$\begingroup\$ What do you mean? If the acceleration is -0.2f, then find the absolute value: 0.2f. Plug this in and you get a
maxSpeed
of 25. In the code, it actually omits -0.2f, which is what I meant by "strange pattern"! \$\endgroup\$Alex L– Alex L2014年07月31日 06:19:27 +00:00Commented Jul 31, 2014 at 6:19 -
\$\begingroup\$
In your code, you actually omit -0.2f
-> not me but the OP \$\endgroup\$Heslacher– Heslacher2014年07月31日 06:20:19 +00:00Commented Jul 31, 2014 at 6:20 -
\$\begingroup\$ Sorry @Heslacher, I was thinking you were the OP replying! I've been up for a while ;) \$\endgroup\$Alex L– Alex L2014年07月31日 06:21:41 +00:00Commented Jul 31, 2014 at 6:21
Here is your number line:
...<-40->| |<-25->|<--25-->|<-17->|<-17->|<--25-->|<----25----->|<-40->...
-0.9 -0.7 -0.5 -0.2 0 +0.2 +0.5 +0.9
The first likely bug that I see is that the ranges are discontinuous. For example, if Input.acceleration.y
is exactly 0.5, then none of the cases applies.
Once you fix that bug, you can simplify the number line to the following equivalent:
...<-40->| |<------25----->|<-----17---->|<---------25--------->|<-40->...
-0.9 -0.7 -0.2 +0.2 +0.9
The next likely bug is that the two sides are asymmetrical, and there is a strange gap between -0.9 and -0.7. Perhaps you meant to fill that in with maxSpeed = 25
? I'll assume you meant...
...<-40->|<---------25--------->|<-----17---->|<---------25--------->|<-40->...
-0.9 -0.2 +0.2 +0.9
Since the entire number line from -∞ to +∞ is covered, you should be able to avoid the double-ended inequality comparisons, and instead chain them with else-ifs. Or, if you like more compact expressions, you could use ternary operators:
float absY = Input.acceleration.y < 0 ? -Input.acceleration.y : Input.acceleration.y;
maxSpeed = (absY < 0.2f) ? 17
: (absY < 0.9f) ? 25
: 40;
The first line could also be written using Math.Abs()
, but I chose to write it this way to avoid converting the float
to a double
.
You're missing some cases, for example what should happen when y = 0.5
? Or -0.9f < y < -0.7
?
I think this is valid representation of your current code:
y: -inf -0.9f -0.7f -0.5f -0.2f 0.2f 0.5f 0.9f +inf
m: 40 ? ? ? 25 ? 25 ? 17 ? 25 ? 25 ? 40
Based on this diagram, the code posted in @AlexL's answer is likely what you want to achieve. If you're trying to do something else, please post another question with more details :)
Also I favourite Alex L
's answer, her is an alternative way
The first 5 if conditions
are checking if the given Input.acceleration.y
is between two float values.
So we can extract the between
part to an extension method like
public static Boolean Between(this float num, float lower, float upper)
{
return lower < num && num < upper;
}
we assign the value of Input.acceleration.y
to a variable, first for readability and second this property only needs to be read only once.
float accelerationY = Input.acceleration.y;
next we are using the Between() method
if (accelerationY.Between(-0.2f, 0.2f))
{
maxSpeed = 17;
}
else if (accelerationY.Between(-0.5f, -0.2f)
|| accelerationY.Between(0.2f, 0.5f)
|| accelerationY.Between(-0.7f, -0.5f)
|| accelerationY.Between(0.5f, 0.9f))
{
maxSpeed = 25;
}
else if (accelerationY < -0.9f || accelerationY>0.9f)
{
maxSpeed = 40;
}
-
2\$\begingroup\$ If you want to preserve the original behaviour (in a bug-compatible way), this is the way to go. \$\endgroup\$200_success– 200_success2014年07月31日 07:38:51 +00:00Commented Jul 31, 2014 at 7:38
Do you actually want the movement speed to be incremental? From the way you've phrased your question I get the impression that you actually want a linear gradient of movement speed with the tilt level of the device.
Here's an alternative option if this if what you actually want.
public class CharacterMover : MonoBehaviour
{
//Declare the max speeds at which the player can move left and right
private float maxLeftXAxisSpeed = -20f, maxRightXAxisSpeed = 20f;
//Speed assigned for in-game movement
private float moveXAxisSpeed = 0f;
void Update()
{
//If the device is tilting
if(Input.acceleration.y != 0)
{
moveXAxisSpeed = ConvertBetweenRanges(Input.acceleration.y, -1f, 1f, maxLeftXAxisSpeed, maxRightXAxisSpeed);
}
//you would want to assign the transform of the gameobject to the moveXAxisSpeed here
}
//This is an extension method to convert between two ranges of float values
private float ConvertBetweenRanges(float oldValue, float oldMin, float oldMax,
float newMin, float newMax)
{
float newValue = (((oldValue - oldMin) * (newMax - newMin))/(oldMax - oldMin) + newMin);
return newValue;
}
}
I would suggest making the ConvertBetweenRanges method an extension method of the float class so that you can call it from anywhere. How to do that is a different question!