2017-07-31 05:57:10

So, after further research, I've figured out some things.
Assuming that I am using a framrate-based timestep, and I want something to move, I would use the following:
position.x = velocity.x*DT (delta time).
position.y = velocity.y*DT I will need my speeds to be different based on shots chosen, so in that case, from what I have read, that would look something like this:
velocity.x = acceleration.x*DT
velocity.y = acceleration.y*DT
So now my question is, how do I calculate DT correctly?  From the wy I understand it, DT is how much
time is left between when frames are completed, and you'd do something like:
current time minus previous time = DT
How exactly would I calculate this in BGT?  If I'm supposed to get the system time in milliseconds, is there a way to do that?  Then, how do I determine the amount of time since frame 1 finished and frame 2 commenced?  Any help appreciated.  Thanks.

JLove

2017-07-31 07:53:02

The purpose of the clock object is to keep the amount of time which passes constant, so you can just use the delay property (or delay×0.001, if you need it in seconds, which you generally do). If you want to be more precise, use a separate timer (if, for example, you have excessive lag), and use its elapsed property (×0.001, to get seconds), then restart the timer.
I'd rather just leave it to the clock, until lag becomes an issue, but if you want to focus on accurate time, an extra timer to track how much time really passes would be better.

Example:

 clock fps(50); 
timer time;

// (etc...) 

void step()  {
// (be sure to restart the timer at the beginning of play, so the intro, etc, doesn't cause any huge first leaps!)

double dt=time.elapsed*0.001; 
time.restart();
//update values here.
fps.tick();
看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2017-07-31 22:44:15

@CAE,
I'm not sure that a fixed, constant time step as the clock provides will work in my case.  The problem that I am wondering about is whether every moving object's speed will be stuck according to that FPS rate.  Obviously, I'd want my players to move faster or slower, depending on individual stats, strengths, and weaknesses, and I'd want my ball to move faster or slower, based on type of shot chosen as well as player stats, i.e., player strength.  I'm assuming that I cannot have independent frame rates for players, balls, etc.  It seems to me that doing that would simply be causing the same problem that I had before.  So if I use the fixed timestep that the clock provides, am I still able to make some objects move faster than others, based on parameters outside of the timestep?

JLove

2017-07-31 23:16:35

Yes. That's where the velocity, acceleration, etc in your first post come in. x+=velocity.x×dt, etc.
I think you'd want the fixed framerate for the case you've described, since using the extra timer to be perfectly accurate would probably put you right back where you started. If you use a fixed framerate, even if one instance lags and the other doesn't, they should still wind up with the same, deterministic outcome.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2017-08-01 05:02:48

@CAE,
Ok, so my next question:  There is an update function in the clock object.  Do I update player/ball movement there, or do I still do it in the original move functions I've created?  The update function looks like it just resets the timer once the delay point is reached.  So would I add in movement each time that occurs, like this?
if (time.elapsed>=delay)
{
//Move the ball here.
Or, do I just use the original move function I created?  I'm sorry for all of the questions.  I'm not trying to be difficult.  I'm sure I seem stupid, but believe me, that's not the case.  Once I totally figure this out I will be off and rolling.  I don't mind rewriting the entire move code if that's what it takes.  I just want to make sure that I get it correct.  I want to totally understand this timestep thing, and then I can start playing around with the vectors and associated math until I am satisfied.  The good thing about this is that it is forcing me to take another look at trig, which we didn't cover enough at the school for the blind.  In any case, like I said, I apologize.  Be patient with me, please.  I'll figure it out.  It's the principal of the thing now, lol.

2017-08-01 06:03:22

I'd use the function you created, and just let the clock provide the framerate control.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2017-08-01 18:25:46

@CAE,
So, if I am wrong, please correct me.  If I understand correctly, I should remove the associated timers I have in the existing move code that control each axis, and then replace it with something like this:
Globally:
clock C;
Then, in the move code:
if(C.update()
move(x, y, z);
I'm also unsure exactly where to place the math, i.e., DT, velocity, etc.  I wonder if I should incorporate it into the move code already there, or should I create a totally separate function, and then in the move code do something like this:
if(C.update())
{
math();
move(x, y, z);
}
I'm assuming that given the timestep, the ball should not move unless update is true.  So how much of that did I get wrong?  Lol.

2017-08-02 00:41:46

Eh, it'd go better like this:

// global:
clock c;

//game loop:
c.tick();

//update.

double dt=c.delay*0.001;
x = x + velocity_x*dt;
y = y + velocity_y*dt;
//if you have acceleration:
velocity_x += acceleration_x*dt;
velocity_y += acceleration_y*dt;

You can save time on movement calculations by using vectors, since bgt's vectors overload the arithmetic operators, but the above has the same effect.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2017-08-02 01:32:35

@CAE,
Ok.  Am I correct in assuming that using a vector moves the number of cords shown inside of it?  In other words:
vector V(1, 2, 3);
Would then move the ball one square on the x axis, 2 on y, and 3 on z.  So if you started at 1,1,3, you'd now be at 2,3,6.  Is that correct?  The thing is, let's say that I hit shot A with low strength, level 1.  The ball should not travel as far as it would if I hit the same shot with hard strength, say level 3.  The harder I hit the ball, the further it should travel.  Plus, the angle of shot can also vary.  So is there a way to code it so that the vectors are calculated automatically based on shot strength and angle?  In other words, I don't want to have to code each vector in manually, i.e.:
if(strength == 1)
{
if(degrees == 0)
{
vector V(0, 1, 1);
if(degrees = 45)
vector V(1, 1, 1);
}
}
if(strength == 2)
{
if(degrees == 0:
{
vector V(0, 3, 1);
...
}
}
You get the point.  There has to be a better, easier, definitely less pain in the ass, lol, way to code it so that the calculations are done automatically, which would allow for less restrictive movement as well.
Again, I apologize for all of the questions.  I just really want to get this right.

2017-08-02 04:04:19

This is where trigonometry comes in. Also, when you're dealing with 3d, it gets more complicated, depending on what you're aiming for.
The simplest way to get a vector of a certain magnitude, at a certain angle, is:
vector v(mag*cosine(angle), mag*sine(angle));
However, I'm having a hard time remembering how exactly angle and strength are supposed to work in your case. If, for example, you want constant airtime, and are using the strength to determine how far the ball goes during that time, you'd just use a constant for the z component. If you're using strength to affect the z velocity as well, things get more complicated.
If you're wanting constant airtime, though, you might do something like this:
// set the velocity:
angle = 3.14159 * angle_in_degrees / 180; // the trig functions expect radians, so convert.
vector v(strength*cosine(angle), strength*sine(angle), initial_z_velocity);

// in update:
position += v * dt; // the vector object applies these to x, y, and z.
v.z -= gravity * dt;
Here, I put the coordinates into a vector (position), so you can add and subtract all 3 at once. Dt is still a normal double, since you can only multiply and divide vectors by single numbers.
I hope this is more helpful than confusing sad

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2017-08-02 19:34:05

@CAE,
Actually, less confused than I thought I'd be.  Starting to make sense now.  Ok, in terms of Z, that axis is for height.  So strength affects it insomuch as when the harder the ball is hit, the slower it's going to fall, unless you basically were to hit it straight down.  If I hit a baseball softly, it's going to move a little forward, but not far, since it's going to pop up into the air, but fall to the ground rather quickly.  However, if I crack the shit out of the ball, it's gonna go higher, stay in the air longer, and go over the wall for a home run.
I think at this point, what is most confusing me is where to put all of the math-related things, and exactly where to check them.  I've got a ball object and a player object.  The player object contains the movement code for the player, the method for shots, and the timers that were originally associated with them, which at this point are being scrapped in favor of the FPS system.  The ball object contains the move code for the ball and the timers associated with that, which again, are being scrapped in favor of the FPS system.  The ball object also contains the method that deals with what happens when the ball lands.
It seems most logical to me that both player and ball movement should be done with vectors.  Please feel free to disagree if you think that I am wrong.  But if, indeed, both player and ball are going to use vectors and associated math, it then makes the most logical sense to me to create a math object.  It seems to me that doing it that way would cut down on redundant code, since both movement of player and ball are governed by the same math.  It should also allow for the math functions to be called from anywhere more readily if necessary.  For purposes of updating, I have a CheckEvents function that checks for user input, status of Booleans, etc.  So perhaps I would do something like:
if(C.update())
{
math();
//update player position;
//update ball position;
}
Is any of that correct, or am I just totally a moron and way off track?  Or perhaps I'm headed in the right direction, but maybe I'm wrong about some things, and there's a better, easier way to do it?  Thanks.

JLove

2017-08-02 23:16:53

That seems right, yeah. Most of the math happens when a movement starts, such as hitting the ball; the rest is letting velocity and gravity take their course.
I suppose the question is how much of the strength goes into height, vs x/y. If it affects all of them—the most realistic way, I suppose—then you have 3d angles to worry about, and that can get more complicated very quickly. IF the player only controls the x/y angle and the strength, then there's a constant angle of elevation, which is much easier to deal with. That'd probably mean you'd want to do lots of tests until you find the best angle of elevation, but it'd mean you'd only have to add a little more to the velocity calculation.

I haven't worked with this much, but i think it goes like this, where theta is the x/y angle, and phi is the angle of elevation, both in radians:
vector v(strength*cosine(theta)*cosine(phi), strength*sine(theta)*cosine(phi), strength*sine(phi));
So if phi is 0, it reduces to 2d, and if phi is pi/2 (90dg), it's straight up, and everything between is somewhere in the middle.
If it helps, the sine and cosine of pi/4 (45dg) are the same (around 0.707), so if you know for sure that you want to use 45dg angles, you might be able to take some shortcuts. If that makes things more confusing, just ignore this part.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2017-08-09 19:01:41

@CAE,
I've created a script that I want to contain all of my math functions that are going to be used across the code.  I want to be able to call the math functions from anywhere else in the code and just plug in the relevant parameters.  I don't want to have to repeat code.  For example, I've created a function that will convert radians to degrees, and one to convert degrees to radians.  I'm going to need ones to add, subtract, multiply and divide vectors, and one that will calculate the magnitude of vectors.  If I remember correctly, the formula is A^2+B^2 = C^2 for 2d, and A^2+B^2+C^2 for 3d magnitude calculations.  I want to be able to make these calculations on the fly, so I need to figure out a way to make it so that they will take values from any vector.  In other words, I want the functions to be generic and able to perform calculations on any vector I pass it as a parameter.  For example, like this, magnitude calculation:
float GetMag(vector)
{
return mag = square_root(vector.A*A+B*B+C*C);
}
Then, in other code I can just say:
GetMag(velocity), or GetMag(direction), GetMag(Whatever), etc.  I should be able to do the same with the other arithmetic operations as well, like float Add(vector), float sub(vector), etc.  Am I doing that correctly, or is there a different way to implement that?
Next question.  I have implemented the ability for the player to choos the angle of his shot...anywhere from 0 degrees straight ahead to 90 degrees to the right, and from 270 degrees to the left, through 359 degrees back to straight ahead.  So let's say as a player I want a shot of 25 degrees...not straight ahead, but not directly diagonally, or maybe I want a sharper angle across the grid, say 75 degrees...not directly straight to the right, but more than diagonally.  So once I choose, how do I then have the ball move at that actual angle?  Let's say I'm mad because you just scored on me, so now I want you to have to run your ass off for the ball, so let's say I choose 75 degrees.  A 45-degree angle, or 0.78552 radians, would be a 1:1 ratio, x to y movement.  With a 75-degree angle, or 1.3092 radians, the ball would move more along x than y, but would still move on both axes.  Having both of those numbers, what is the best way of incorporating that into a vector to tell the ball to move at that angle, and have it calculate exactly how much to move along x and y to accomplish that?  Thanks.

JLove

2017-08-09 20:56:41

For your first question: yes, you can do that. BGT's vectors contain a lot of this functionality, though. Saying v3=v1+v2 is equivalent to saying v3.x = v1.x+v2.x; v3.y=v1.y+v2.y; v3.z=v1.xz+v2.z
If I understand your second question correctly, that's where you'd use the trig functions.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2017-08-09 22:13:37 (edited by JLove 2017-08-09 22:16:50)

@CAE,
Is there a way for me to see exactly which functions are already available in the vector object, so that I'm not writing code that is already there?

2017-08-09 23:19:58

Check the manual,. The vector object is under foundation layer -> object reference. I think it's just addition, subtraction, multiplication, division, and length.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2017-08-10 03:20:40

I didn't see any of the basic operations...addition, subtraction, etc...just length.

2017-08-10 14:17:05

In the main chapter on vectors, it says that the vector object uses operator overloading to enable use of the arithmetic operators, like +, *, etc.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2017-08-11 03:29:57 (edited by JLove 2017-08-11 03:42:32)

@CAE,
Ok, the clock either isn't working correctly, DT isn't being returned correctly, or I am one dumb ass moron, lol:
class clock
{
timer time;
uint frame = 0;
double delay = 5;
double DT = time.elapsed*0.001;
in void tick(), I added a line to tell me what DT was each time the time ticked off:
void tick()
{
double elapsed=time.elapsed-delay+1;
if(time.elapsed >= 1000)
{
speaker.speak(time.elapsed + ", " + DT + ".");
time.restart();
}
time.resume();
wait((elapsed>=delay) ? 1 : delay-elapsed);
frame++;
}

When I execute, I get the following:
time.elapsed, 1004, DT, 0
time.elapsed, 1005, DT, 0
time.elapsed,  1002, DT, 0
Always 0 for DT, no matter what the elapsed is.
Also, a couple of other questions.  Could you explain this line of code, please?
wait((elapsed>=delay) ? 1 : delay-elapsed);
Second question.  In void tick, you say this:
if(time.elapsed >= 1000)
time.restart();
But then, you say in update:

bool update()
{
if (time.elapsed>=delay) {
time.restart();
So if it's restarting every time it hits delay, which in this case is 20 (1000.0/50), how does it ever reach 1000?

2017-08-11 05:33:01

The if(time.elapsed>1000) bit should not happen. If that was in the version I posted (I'm not seeing it on my copies), it was probably to prevent it from getting stuck for debugging something long ago.
The reason dt isn't reporting right is that you defined it as a member variable based on the timer, and the time between the timer starting and dt being defined is less than a millisecond. You'd want to define dt either when setting delay (if you want a fixed dt), or before restarting the timer (if it's based on the timer). I generally just define dt when calling the game's step/update/tick method, and pass it around from there.
The line wait((elapsed>=delay) ? 1 : delay-elapsed); uses the ternary operator. It's one of those things that isn't intuitive if you aren't familiar with it, but saves time when you are.
Basically, this:
a= (b) ? c : d;
is the same as:
if (b) a=c
else a=d;
It's just a sort of shorthand.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2017-08-13 22:24:39 (edited by JLove 2017-08-13 22:42:56)

@CAE,
Two things right quick.  First, I found an old thread here where you gave us access to a script you wrote for BGT with a whole lot of math functions.  I tried downloading it, but the link that was given is now dead.  Do you still have it, and if so, can I have access to it please?
Second thing:  I think that at the moment my main issue is that I am trying to figure out the best way to structure this with respect to the changes in the way I am handling movement, and I'm trying to figure out the most efficient, best way to implement DT.  I've read so many conflicting opinions, so I would greatly appreciate some advice from an actual dev who has actually worked with these concepts in the past.
The way things are structured now, when the game starts, the factors that impact things are continuously monitored within a function called check events.  This function does things like monitor for keyboard input,
takes care of retrieving info from packets, etc.So with respect to DT, updating movement, etc., do I add the lines for updating position, velocity, etc. of my vectors here, or do I do that within the actual ball object?  Or, would I do it in the function that sets initial state and starts the game?  I.e.:
void StartMatch()
{
//set initial values
//Restart the game clock
//do any other crap for before-game setup.
//load the ambience sounds, and then:
ambience.play_looped();
while(true)
{
CheckEvents();
B.position += B.velocity*DT; /*I'm assuming that I can just use the entire velocity vector at once, instead of the more verbose:
B.position.x += B.velocity.x*DT;
B.position.y += B.velocity.y*DT;
B.position.z += B.velocity.z*DT;
wait(5);
}
}
Or, do I place the updating of positions and such in the clock.update method, since that's where the clock is reset for the next frame?
bool update()
if (time.elapsed>=delay)
{
B.position += B.velocity*DT; user.position += user.velocity*DT;
time.restart();
time.resume();
return true;
}
return false;
}
Where do I actually call the tick mothod in the clock object?  Do I do it in checkevents, so that each time it is checked, tick is called again?  Or, do I do it each time the position is actually updated? 
And where should I put the actual calculations on the associated movement vectors of the ball and the player?  Should I do that in my math.bgt script, or should I do it like this:
class ball
{
float x, y, z;
int slot;
Spin spin;
bool tossing = false;
bool moving = false;
bool rising = false;
bool choosing = false;
ball()
{
vector position(0, 0, 0);
vector velocity(0, 0, 0)
}

ball(position, velocity, int slot)
{
this.slot = slot;
}

void move()
{
//vector calculations here.
//update movement position here.
}
I apologize again for being such a pain in the ass.  I feel like a moron at the moment because I'm forced to ask all of these questions.  But like I said in a different topic post, I am determined to finish this, and I am not giving up.  I'm stuck at the moment because I am unsure of exactly how to structure this so that it is the most efficient, done right, and structured right so that I'm not forced to rewrite this again, and so that the quality can be the best I can make it.  And in that vein, please do not hesitate to point out flaws in my code and tell me where I'm wrong.  I have no problem with being shown where I'm incorrect.  I might be annoyed that I am forced to totally restructure so much, but on the flip side, I am enjoying the fact that I am learning at the same time.  I think that once I figure out where to put the tick calls and where to actually update positions, etc., and where to actually put the mathematical calculations on the associated movement vectors and behaviors, i.e., what happens when the ball bounces, etc., resultant of mathematical calculations, I can make some headway.  I am sure I'll have more questions in the future, and I am sure that some of them might be stupid, but at least once I get a handle on this part I can actually move forward and make some progress.  I also want to thank you for being willing to put up with the pain in the ass questions and for being willing to help.  You are the only one who has responded to my questions.  I must admit that I am a little surprised by that fact.  I would have thought that I would have seen advice and support from more than one dev in this community, given the nature of accessibility in the mainstream market, and given that we all share a love for gaming.  I'd think that we should support one another's development projects and try to help one another as best we can, since every project that is completed benefits the entire community.  But that's neither here nor there.  I just wanted you to know that your help, patience, and willingness to share your knowledge  are greatly appreciated.

JLove

2017-08-13 23:20:04 (edited by CAE_Jones 2017-08-13 23:27:19)

I don't think I can repost the math script right now. If I can find a more permanent way to host my BGT includes, I will try.
How to structure things comes down to how it's used. Strictly speaking, you can organize things in a variety of ways. Mostly though, I like to organize things like...
(And the sample in your post seems mostly similar. And yeah, your first line regarding position was correct.)

  • Write code Design objects as though they will be reused in a different context. This means that object methods should be things the object can do either in all contexts, or frequently enough that it makes sense as an object method. In this case, that means the movement is probably best in the ball class.

  • Anything that involves multiple actions that might reasonably need repeating elsewhere, but is not inherently bound to a single object, should be in a function. I fail at this far too often.

  • If it can have things done to it, or if it has multiple properties and you can have multiple instances of it, it should have its own class.

  • The end result is that the game itself only handles that which is unique to that game, rather than things which similar games would have in common—everything else is in included classes or functions. So you shouldn't need to modify the clock class directly, and instead just tell it to tick at either the end or beginning of a frame (the difference might be relevant for fast-paced online games, but in general they're effectively equivalent).

  • I don't like the trend for every little thing to have its own class/function. (Java standards tend to be particularly awful about making absolutely everything into a class hierarchy, even if—nay, especially if—each level contains a single class.) However, I do tend to separate things based on what they're ab. So I'll usually have a function for handling key presses, a function for handling input from the network, another for joysticks, and in theory, these should all call a more abstract inpinput function where the command doesn't care about how it was called, only who called it. (In practice, I tend to filter joysticks and network through the keyboard functions, but this is prone to weird things happening.)

So I'd probably outline what you've described something like:

#include "clock.bgt"

class ball {
    vector position, velocity;
    // etc.
    void move (double dt) {
        this.position = this.position + this.velocity*dt;
        // gravity, etc.
    }
    void set_velocity(double magnitude, double angle) ;ing{
        // or however angles work.
    }
}

void update () {
    fps.tick();
    ball.move(dt);
    // etc
}

void handle_keys () {
    // keyboard stuff.
}

void update_network () {
    // network stuff. This should probably handle passive stuff; key presses should probably be sent when they happen, if needed.
}

clock fps (50);
double dt=fps.delay*0.001;
Ball ball; // I think I gave the class and the instance in update the same name by mistake earlier... hmm

void main () {
    // setup, loop, etc.
}
Keep in mind, though, that these are more guidelines than anything. I do find that trying to isolate parts as if they are real-world concepts or items helps, but I often wind up with lots of game-specific blocks anyway. It helps to remember that you might want to reuse something in a later project, and organize accordingly, but this isn't always necessary and is sometimes more trouble than it's worth.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2017-08-13 23:57:59

Hello, may i ask some things too?
This topic got my interest cause my current problem is with movimentation.
I was studying the shooter engine by Qtot, mainly the movimentation function. But there's a thing that i'm not able to solve. The inverse percetage formula, wish is like this:
def inverse_percentage(what, percent):
    return 100.0 / 100.0 / what * percent
Why 100/100? I saw a lot of call to this function on the movimentation code, but i'm not able to understand. About the libraries i only have math.bgt and geom.bgt if is what you're talking about, i still used a lot when i had all of then.
Sorry for my english, big_smile

2017-08-14 00:01:22

About hosting includes on a more permanent way, have you tried google drive, media fire or some sort of hosting services? I use google drive a lot for sharing links when i got blocked on dropbox.

2017-08-14 04:01:03

So am I correct in assuming that I should place the geometric/trigonometric/other math calculations in void move(double DT)?  The reason I started creating a math.bgt script was because I was hoping that I could simply place the concrete and immutable math formulae in one place, then just pass any vector, angle, etc. to them and get results on the fly, if that makes sense.  However, I'm not sure that that is possible.  Let's say that I put the formula to get magnitude in the math.bgt script:
float GetMag(float x, float y, float z)
{
return mag = square_root(vector.x*x + vector.y*y + vector.z*z));
}
I could see a problem where I've got a vector velocity(x, y, z), and vector position(x, y, z).  Let's say I want to find the magnitude.  I'd want to just be able to do this in the code:
GetMag(velocity), GetMag(position), etc.
But the problem is, don't the variables have to match correctly?  In other words, you couldn't have in the math code the traditional formula of:
float GetMag(float A, float B, float C)
{
return mag = square_root(whateverVectorName.x*x+y*y+z*z);
}
In other words, I want it to be a generic function that can take any vector.  But if I make my vectors x, y, z, I can't use A*A, B*B, etc., correct?I was hoping to be able to do things like that in case I ever wanted to use these things for a future project.