enter image description here
I can't describe the problem thoroughly because I don't know rhythm game terms.
In the picture
The white cube Note represents the object which the player needs to hit on time.
The green rectangle Line is the representation of the timing. When the Note perfectly lines up with the Line is when the player presses a button to hit the note.
Now the problem is, I cannot seem to find a way to make the Note perfectly line up with the Line using Mathf.Lerp while it still reaches the end.
void GenerateBeat()
{
if (timeItems.Count == 0)
return;
if (timeItems.Peek() <= currentBeatPosition + BeatLookForwardValue)
{
Debug.Log("Item instantiated, Spawned At : " + currentBeatPosition + " Will reach 0 at : " + timeItems.Peek());
GameObject obj = Instantiate(tempSpawnObject);
obj.transform.SetParent(parentObject.transform);
existingBeats.Add(obj);
existingBeatsTime.Add(currentBeatPosition);
timeItems.Dequeue();
}
}
void MoveBeat()
{
// if (timeItems.Count == 0)
// return;
for (int i = 0; i < existingBeats.Count; i++)
{
NoteBeatline beatline = existingBeats[i].GetComponent<NoteBeatline>();
Vector2 StartingPos = new Vector2(0, 800f);
Vector2 EndPos = new Vector2(0, 0);
float offset = (endTime[i] - existingBeatsTime[i]) / 3;
float time = Mathf.InverseLerp(existingBeatsTime[i], endTime[i] + offset, currentBeatPosition);
beatline.Image.rectTransform.anchoredPosition = Vector2.Lerp(StartingPos, EndPos, time);
}
}
[Edit]
Sorry for the lack of clarification.
I'm trying to synchronise Notes by adding extra value to the endTime because existingBeatsTime (keeps track of the time at which the object is spawned) can vary depending on how great BeatLookFOrwardValue is.currentBeatPosition represents how long in beat time has passed since the start of the song, so I cannot manipulate the value.
the endTime value is always a constant, set by me
and items in timeItems are identical to the items in endTime.
the whole background colour of dark cyan is currently 800 units
and the y position of the green horizontal line is 600
so that the Notes can perfectly line up with the green line
when
float time = Mathf.InverseLerp(existingBeatsTime[i], endTime[i] + offset, currentBeatPosition);
is 0.75f.
I did more research and experiment after I posted this,
and found out
float offset = (endTime[i] - existingBeatsTime[i]) / 3;
somehow synchronises the Notes, but I don't understand how.
Please feel free to comment on my explanation.
This is my first time posting a question on StackOverflow and explaining my coding problem to someone else.
I will try to provide more information if it is still lack.
"Currently, Notes reach the end when currentBeatPosition == endTime.
But I want to make them reach the Line when currentBeatPosition == endTime"
So, they are lerping across the correct distance? They are just doing it a bit too fast yeah? So to fix it you can increase the total time over which they are lerping. So they reach the line at endTime and reach the end a little bit later.
get the ratio, distance from start to end / distance from start to line
Multiply the total time they are lerping over by this ratio.
I've finally fixed the synchronisaton problem.
I found out that there's Mathf.LerpUnclamped() which can extrapolate the return value. So I had to change
beatline.Image.rectTransform.anchoredPosition = Vector2.Lerp(StartingPos, EndPos, time);
to
beatline.Image.rectTransform.anchoredPosition = Vector2.LerpUnclamped(StartingPos, EndPos, time);
this. Since it can extrapolate I was able to set the endPos to the position of the green line.
Additionally, I also had to make my own Mathf.InverseLerp() which will be the unclamped version of Mathf.InverseLerp().
public static float InverseLerpUnclamped(float startValue, float maxValue, float inbetweenValue)
{
return (inbetweenValue - startValue) / (maxValue - startValue);
}
Finally, I could simply get it working by these two lines of code.
float time = Tools.InverseLerpUnclamped(existingBeatsTime[i], endTime[i], currentBeatPosition);
beatline.Image.rectTransform.anchoredPosition = Vector2.LerpUnclamped(StartingPos, EndPos, time);
Related
I have a Vector2 Lerp statement:
Vector2.Lerp(spawnPos, target, position);
The position variable is a number between 0 and 1, and for all intents and purposes, it increments over time. Think of the way I'm tracking position as a "playhead," like in music or animation, where a cursor moves from left to right as the playback continues.
I want the object to continue moving after it reaches its target, at the same EXACT speed, just infinitely in a direction. I've tried to change the target to the direction multiplied by the distance between the spawn point, but I still can't figure out how to get the correct speed.
A slightly easier answer for you: Instead of using Vector2.Lerp and calculating everything, just use Vector2.LerpUnclamped and throw in any value of t you want!
Thanks to Llama's comment, I was able to calculate the speed of a Lerp.
First, record the start and end time of the interpolation, and whether or not the interpolation has completed (position >= 1). Then, if it hasn't finished, lerp as normal. If it HAS finished, note the end time, calculate the speed and direction in which to move, and increment Transform.position by that value.
bool finished = false;
// Since I'm using AudioSettings.dspTime, I need to use double.
// Most forms of telling time in Unity will use float
double startTime;
double endTime;
void Start()
{
// This is what I am using for my game,
// but you can use any way of telling time that Unity/C# provides.
startTime = AudioSettings.dspTime;
}
void Update()
{
if(!finished)
{
// interpolate
transform.position = Vector2.Lerp(spawnPos, targetPos, position);
if(position >= 1)
{
// Record our end time
endTime = AudioSettings.dspTime;
finished = true
}
} else {
// How long it took to lerp
double lerpTime = endTime - startTime;
// How far we lerped
float distance = Vector2.Distance(spawnPos, targetPos);
// The speed to further move
float speed = distance / (float)lerpTime;
// The direction in which to move
Vector2 direction = (targetPos - spawnPos).normalized;
// Continue moving
transform.position += (Vector3)direction * speed * Time.deltaTime;
}
}
I'm trying to write a function to handle movement within a game I'm programming. What I have nearly works, but there are a couple situations where it breaks down.
I've coded up a minimal demonstrative example, presented below. In this example, I'm trying to calculate the travel of an object, represented by a point, and movement vector. This object's movement path is checked against a collection of polygons, which are broken down into line segments for testing. When this object collides with a line segment, I want it to slide along that segment (rather than stop or bounce away).
To do this, I check along my intended path for collisions, and if I find an intersection, I do a new test from that intersection point along the path of the line segment I've collided with, with the magnitude of the remainder of movement.
The problem arises when we slide along a line segment into a "pocket". Often times, the collision check will pass on both of the line segments that form the pocket, and the object will slip through. Because I'm travelling parallel to one of the line segments, and I'm intersecting with both line segments at an end points, I believe this issue is caused by floating point error. Whether or not it slips through, is caught, or is caught once and then slips through on the second check seems to be totally random.
I'm calculating intersection using a simple algorithm I found here: https://stackoverflow.com/a/20679579/4208739, but I've tried many other algorithms as well. All exhibit the same problems.
(Vector2 is class provided by the Unity library, it just holds x and y coordinates as floats. The Vector2.Dot function just calculates the dot product).
//returns the final destination of the intended movement, given the starting position, intended direction of movement, and provided collection of line segments
//slideMax provides a hard cap on number of slides allowed before we give up
Vector2 Move(Vector2 pos, Vector2[] lineStarts, Vector2[] lineEnds, Vector2 moveDir, int slideMax)
{
int slideCount = 0;
while (moveDir != Vector2.zero && slideCount < slideMax)
{
pos = DynamicMove(pos, lineStarts, lineEnds, moveDir, out moveDir);
slideCount++;
}
return pos;
}
//returns what portion of the intended movement can be performed before collision, and the vector of "slide" that the object should follow, if there is a collision
Vector2 DynamicMove(Vector2 pos, Vector2[] lineStarts, Vector2[] lineEnds, Vector2 moveDir, out Vector2 slideDir)
{
slideDir = Vector2.zero;
float moveRemainder = 1f;
for (int i = 0; i < lineStarts.Length; i++)
{
Vector2 tSlide;
float rem = LineProj(pos, moveDir, lineStarts[i], lineEnds[i], out tSlide);
if (rem < moveRemainder)
{
moveRemainder = rem;
slideDir = tSlide;
}
}
return pos + moveDir * moveRemainder;
}
//Calculates point of collision between the intended movement and the passed in line segment, also calculate vector of slide, if applicable
float LineProj(Vector2 pos, Vector2 moveDir, Vector2 lineStart, Vector2 lineEnd, out Vector2 slideDir)
{
slideDir = new Vector2(0, 0);
float start = (lineStart.x - pos.x) * moveDir.y - (lineStart.y - pos.y) * moveDir.x;
float end = (lineEnd.x - pos.x) * moveDir.y - (lineEnd.y - pos.y) * moveDir.x;
if (start < 0 || end > 0)
return 1;
//https://stackoverflow.com/a/20679579/4208739
//Uses Cramer's Rule
float L1A = -moveDir.y;
float L1B = moveDir.x;
float L1C = -(pos.x *(moveDir.y + pos.y) - (moveDir.x + pos.x)*pos.y);
float L2A = lineStart.y - lineEnd.y;
float L2B = lineEnd.x - lineStart.x;
float L2C = -(lineStart.x * lineEnd.y - lineEnd.x * lineStart.y);
float D = L1A * L2B - L1B * L2A;
float Dx = L1C * L2B - L1B * L2C;
float Dy = L1A * L2C - L1C * L2A;
if (D == 0)
return 1;
Vector2 inter = new Vector2(Dx / D, Dy / D);
if (Vector2.Dot(inter - pos, moveDir) < 0)
return 1;
float t = (inter - pos).magnitude / moveDir.magnitude;
if (t > 1)
return 1;
slideDir = (1 - t) * Vector2.Dot((lineEnd - lineStart).normalized, moveDir.normalized) * (lineEnd - lineStart).normalized;
return t;
}
Is there some way to calculate collision that isn't susceptible to this sort of problem? I imagine I can't totally eradicate floating point error, but is there a way to check that will at least guarantee I collide with ONE of the two line segments at the pocket? Or is there something more fundamentally wrong with going about things in this way?
If anything is unclear I can draw diagrams or write up examples.
EDIT: Having reflected on this issue more, and in response to Eric's answer, I'm wondering if converting my math from floating point to fixed point could solve the issue? In practice I'd really just be converting my values (which can fit comfortably in the range of -100 to 100) to ints, and then performing the math under those constraints? I haven't pieced all the issues together quite yet, but I might give that a try. If anyone has any information about anything like that, I'd be appreciative.
You have a line that, ideally, is aimed exactly at a point, the endpoint of a segment. That means any error in calculation, no matter how small, could say the line misses the point. I see three potential solutions:
Analyze the arithmetic and design it to ensure it is done with no error, perhaps by using extended-precision techniques.
Analyze the arithmetic and design it to ensure it is done with a slight error in favor of collision, perhaps by adding a slight bias toward collision.
Extend the line segment slightly.
It seems like the third would be easiest—the two line segments forming a pocket could just be extended by a bit, so they cross. Then the sliding path would not be aimed at a point; it would be aimed at the interior of a segment, and there would be margin for error.
I am currently working on a dynamic skybox. My skybox is composed of 3 separate scripts:
CustomList ,CustomListEditor., TOD.CS
CustomList.cs has class that stores variables for what each variable will be at a specific time. Example: time, cloud color horizon color ect.
CustomListEditor.cs is a custom inspector to set values and Add/Remove them to a list of Times of Day (TOD).
TOD.cs is where am calculating time passing and lerping variables from one TOD to another.
The problem I am currently having: I am unable to evenly lerp each TOD. basically the problem I am having is that my lerp is not running smoothly between each Time of Day and is instead having portions that run slower and some that run faster. I Acknowledge this is a Math problem and I am not entirely sure how to go about getting the correct equation to make this work properly.
if anyone could help that would be amazing. Here is an i drew up of time and the separate time of days. keep in mind the TOD's could be placed anywhere in time so the number values are not definite in the example.
<!-- language: lang-c# -->
public float TODspeed = 0.02
private float currentValue = 0.00f
public int TODindex = 0;
public Color horizon;
void Start()
{
GetTarget = new SerializedObject(this.GetComponent<CustomList>());
ThisList = GetTarget.FindProperty("MyList"); // Find the List in our script and create a refrence of it
SerializedProperty MyListRef = ThisList.GetArrayElementAtIndex(TODindex);
SerializedProperty myHorizon = MyListRef.FindPropertyRelative("horizon");
horizon = myHorizon.colorValue;
}
void Update()
{
//Grab serialized properties from my List
//MyListRef is getting a reference of the current TOD
SerializedProperty MyListRef = ThisList.GetArrayElementAtIndex(TODindex);
//NextListRef is getting a reference of the next TOD that we will be lerping to.
SerializedProperty NextListRef = ThisList.GetArrayElementAtIndex(TODindex + 1);
SerializedProperty myTime = NextListRef.FindPropertyRelative("time");
//mixTime is supposed to be my equation for the speed of the times of day. I presume that this code is incorrect and I have no idea how to fix it.
float mixTime = TODspeed * (myTime.floatValue - MyListRef.FindPropertyRelative("time").floatValue);
//This is where I lerp my TOD variables, so long as CurrentValue ,which is the game time, is less than the next TOD's time value.
if (currentValue < myTime.floatValue)
{
currentValue += (Time.deltaTime*TODspeed);
horizon = Color.Lerp(horizon, nextHorizon.colorValue, mixTime);
this.GetComponent<CustomList>().atmosphereGradient.SetColor("_BottomColor", horizon);
}
// if game time is greater than my next TOD's time variable, It will compare the TODIndex to what would be the last TOD in the script. If it is smaller than the last TOD it will incriment , If it is bigger or equal to it, it will restart to time of days.
if (currentValue >= myTime.floatValue)
{
int compareValue = ThisList.arraySize - 2;
if (TODindex < compareValue)
{
TODindex++;
}
else if (TODindex >= compareValue)
{
TODindex = 0;
currentValue = 0.00f;
}
}
}
Your problem is in the line
horizon = Color.Lerp(horizon, nextHorizon.colorValue, mixTime);
you allways interpolate between the current value and the target value => the difference between those is everytime smaller => the "fading" gets slower an slower in time.
What you want to do instead is a constant fading between the original and the target value. I don't see where horizon is declared but you should instead store the original Color outside of Update e.g. as startColor and than change your line to
horizon = Color.Lerp(startColor, nextHorizon.colorValue, mixTime);
Note: I don't completely understand the rest of your code but as I understood your problem was mostly the lerping effect so I assumed that the rest works fine.
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.
I have a PID controller running on a robot that is designed to make the robot steer onto a compass heading. The PID correction is recalculated/applied at a rate of 20Hz.
Although the PID controller works well in PD mode (IE, with the integral term zero'd out) even the slightest amount of integral will force the output unstable in such a way that the steering actuator is pushed to either the left or right extreme.
Code:
private static void DoPID(object o)
{
// Bring the LED up to signify frame start
BoardLED.Write(true);
// Get IMU heading
float currentHeading = (float)RazorIMU.Yaw;
// We just got the IMU heading, so we need to calculate the time from the last correction to the heading read
// *immediately*. The units don't so much matter, but we are converting Ticks to milliseconds
int deltaTime = (int)((LastCorrectionTime - DateTime.Now.Ticks) / 10000);
// Calculate error
// (let's just assume CurrentHeading really is the current GPS heading, OK?)
float error = (TargetHeading - currentHeading);
LCD.Lines[0].Text = "Heading: "+ currentHeading.ToString("F2");
// We calculated the error, but we need to make sure the error is set so that we will be correcting in the
// direction of least work. For example, if we are flying a heading of 2 degrees and the error is a few degrees
// to the left of that ( IE, somewhere around 360) there will be a large error and the rover will try to turn all
// the way around to correct, when it could just turn to the right a few degrees.
// In short, we are adjusting for the fact that a compass heading wraps around in a circle instead of continuing
// infinity on a line
if (error < -180)
error = error + 360;
else if (error > 180)
error = error - 360;
// Add the error calculated in this frame to the running total
SteadyError = SteadyError + (error * deltaTime);
// We need to allow for a certain amount of tolerance.
// If the abs(error) is less than the set amount, we will
// set error to 0, effectively telling the equation that the
// rover is perfectly on course.
if (MyAbs(error) < AllowError)
error = 0;
LCD.Lines[2].Text = "Error: " + error.ToString("F2");
// Calculate proportional term
float proportional = Kp * error;
// Calculate integral term
float integral = Ki * (SteadyError * deltaTime);
// Calculate derivative term
float derivative = Kd * ((error - PrevError) / deltaTime);
// Add them all together to get the correction delta
// Set the steering servo to the correction
Steering.Degree = 90 + proportional + integral + derivative;
// We have applied the correction, so we need to *immediately* record the
// absolute time for generation of deltaTime in the next frame
LastCorrectionTime = DateTime.Now.Ticks;
// At this point, the current PID frame is finished
// ------------------------------------------------------------
// Now, we need to setup for the next PID frame and close out
// The "current" error is now the previous error
// (Remember, we are done with the current frame, so in
// relative terms, the previous frame IS the "current" frame)
PrevError = error;
// Done
BoardLED.Write(false);
}
Does anyone have any idea why this is happening or how to fix it?
It looks like you are applying your time base to the integral three times.
Error is already the accumulated error since the last sample so yo don't need to multiply deltaTime times it. So I would change the code to the following.
SteadyError += error ;
SteadyError is the integral or sum of error.
So the integral should just be SteadyError * Ki
float integral = Ki * SteadyError;
Edit:
I have gone through your code again and there are several other items that I would fix in addition to the above fix.
1) You don't want delta time in milliseconds. In a normal sampled system the delta term would be one but you are putting in a value like 50 for the 20Hz rate this has the effect of increasing Ki by this factor and decreasing Kd by a factor of 50 as well. If you are worried about jitter then you need to convert delta time to a relative sample time. I would use the formula instead.
float deltaTime = (LastCorrectionTime - DateTime.Now.Ticks) / 500000.0
the 500000.0 is the number of expected ticks per sample which for 20Hz is 50ms.
2) Keep the integral term within a range.
if ( SteadyError > MaxSteadyError ) SteadyError = MaxSteadyError;
if ( SteadyError < MinSteadyError ) SteadyError = MinSteadyError;
3) Change the following code so that when error is around -180 you do not get a step in error with a small change.
if (error < -270) error += 360;
if (error > 270) error -= 360;
4) Verify Steering.Degree is receiving the correct resolution and sign.
5) Lastly yo can probably just drop deltaTime all together and calculate the differential term the following way.
float derivative = Kd * (error - PrevError);
With all of that your code becomes.
private static void DoPID(object o)
{
// Bring the LED up to signify frame start
BoardLED.Write(true);
// Get IMU heading
float currentHeading = (float)RazorIMU.Yaw;
// Calculate error
// (let's just assume CurrentHeading really is the current GPS heading, OK?)
float error = (TargetHeading - currentHeading);
LCD.Lines[0].Text = "Heading: "+ currentHeading.ToString("F2");
// We calculated the error, but we need to make sure the error is set
// so that we will be correcting in the
// direction of least work. For example, if we are flying a heading
// of 2 degrees and the error is a few degrees
// to the left of that ( IE, somewhere around 360) there will be a
// large error and the rover will try to turn all
// the way around to correct, when it could just turn to the right
// a few degrees.
// In short, we are adjusting for the fact that a compass heading wraps
// around in a circle instead of continuing infinity on a line
if (error < -270) error += 360;
if (error > 270) error -= 360;
// Add the error calculated in this frame to the running total
SteadyError += error;
if ( SteadyError > MaxSteadyError ) SteadyError = MaxSteadyError;
if ( SteadyError < MinSteadyError ) SteadyError = MinSteadyError;
LCD.Lines[2].Text = "Error: " + error.ToString("F2");
// Calculate proportional term
float proportional = Kp * error;
// Calculate integral term
float integral = Ki * SteadyError ;
// Calculate derivative term
float derivative = Kd * (error - PrevError) ;
// Add them all together to get the correction delta
// Set the steering servo to the correction
Steering.Degree = 90 + proportional + integral + derivative;
// At this point, the current PID frame is finished
// ------------------------------------------------------------
// Now, we need to setup for the next PID frame and close out
// The "current" error is now the previous error
// (Remember, we are done with the current frame, so in
// relative terms, the previous frame IS the "current" frame)
PrevError = error;
// Done
BoardLED.Write(false);
}
Are you initializing SteadyError (bizarre name...why not "integrator")? If it contains some random value on start-up it might never return to near zero (1e100 + 1 == 1e100).
You might be suffering from integrator windup, which ordinarily should go away, but not if it takes longer to diminish than it does for your vehicle to complete a full rotation (and windup the integrator again). The trivial solution is to impose limits on the integrator, though there are more advanced solutions (PDF, 879 kB) if your system requires.
Does Ki have the correct sign?
I would strongly discourage the use of floats for PID parameters because of their arbitrary precision. Use integers (maybe fixed point). You will have to impose limit checking, but it will be much more sane than using floats.
The integral term is already accumulated over time, multiplying by deltaTime will make it accumulate at a rate of time-squared. In fact since SteadyError is already erroneously calculated by multiplying error by deltaTime, that is time-cubed!
In SteadyError, if you are trying to compensate for an aperiodic update, it would be better to fix the aperiodicity. However, the calculation is flawed in any case. You have calculated in units of error/time whereas you want just error units. The arithmentiaclly correct way to compensate for timing jitter if really necessary would be:
SteadyError += (error * 50.0f/deltaTime);
if deltaTime remains in milliseconds and the nominal update rate is 20Hz. However deltaTime would be better calculated as a float or not converted to milliseconds at all if it is timing jitter you are trying to detect; you are needlessly discarding precision. Either way what you need is to modify the error value by the ratio of nominal time to actual time.
A good read is PID without a PhD
I'm not sure why your code isn't working, but I'm almost positive you can't test it to see why, either. You might inject a timer service so you can mock it out and see what's happening:
public interace ITimer
{
long GetCurrentTicks()
}
public class Timer : ITimer
{
public long GetCurrentTicks()
{
return DateTime.Now.Ticks;
}
}
public class TestTimer : ITimer
{
private bool firstCall = true;
private long last;
private int counter = 1000000000;
public long GetCurrentTicks()
{
if (firstCall)
last = counter * 10000;
else
last += 3500; //ticks; not sure what a good value is here
//set up for next call;
firstCall = !firstCall;
counter++;
return last;
}
}
Then, replace both calls to DateTime.Now.Ticks with GetCurrentTicks(), and you can step through the code and see what the values look like.