So for a University Project I am looking to try and change the tint of a sprite over a specific time frame. The aim is to make a set of rocks turn from grey to orange (simulating heating them up) over 5 seconds, then turn them from orange to grey again (simulating cooling them down) over the next 5 seconds.
This is done using the DirectXTK, SpriteBatch specifically, however I appear to be having some problems controlling the heating up and cooling down logic. Currently, the rocks heat up to orange, but do not cool back down.
The Update function for the rocks, along with a further HeatDelay function I am using to control the cooling down are are included below.
timeToChangeColour is initialised at 5.
void RockFade::Update(float timeDelta)
{
if ((timeDelta >= timeToChangeColour) && (heatDelay == false))
{
this->heatUp = false;
HeatDelay();
timeToChangeColour = timeDelta + 10;
}
else if ((timeDelta < timeToChangeColour) && (heatDelay == false))
{
this->heatUp = true;
}
if (heatUp)
{
this->newBlue -= 0.002f;
}
else
{
this->newBlue += 0.002f;
}
this->spriteTint = DirectX::SimpleMath::Color{ 1.0f, 1.0f, newBlue, 1.0f};
}
void RockFade::HeatDelay()
{
heatDelay = true;
Sleep(5);
heatDelay = false;
}
Any help is greatly appreciated!
The biggest conceptual problem with your code is that in the function
void RockFade::Update(float timeDelta);
You seem to assume that timeDelta will be a time difference since a specified fixed time in the past, but it is actually the time difference since the last time Update was called.
Because of this the condition
timeDelta < timeToChangeColour
seem to be always true (because it seems timeToChangeColour's value exceeds one frame time).
The first step towards achieving what you are trying to do here might be to accumulate the time, and use it as your basis, e.g.:
this->myAccumulatedTime += timeDelta; // initialize it to zero
Related
For this project i use OpenGl.
I'm trying to detect the collision between two spheres, I think it's pretty simple.
It works but sometimes (very often actually...) the collision between these two spheres is not detected, and I really don't know why...
I tried to change the algorithm of detection and it allways ends by a non detection sometimes...
void MyGlWindow::checkMoverIsHit()
{
for (size_t i = 0; i < m_container->m_movers.size(); i++)
{
if (m_container->m_ball != m_container->m_movers[i]) {
float size = m_container->m_ball->m_size + m_container->m_movers[i]->m_size;
if (size >= (m_container->m_ball->m_position - m_container->m_movers[i]->m_position).magnitude())
{
score += 10;
m_container->m_movers.erase(std::remove(m_container->m_movers.begin(), m_container->m_movers.end(), m_container->m_movers[i]), m_container->m_movers.end());
for (size_t i = 0; i < (score / 10) + 1; i++)
createMover();
reload();
}
}
}
}
I call this function in my update function
void MyGlWindow::update()
{
TimingData::get().update();
if (!run) return;
float lastFrameDuration = (float)TimingData::get().lastFrameDuration;
float duration = lastFrameDuration * 0.003;
totalTimePrecise += lastFrameDuration;
totalTimeSec = totalTimePrecise / 1000;
if (totalTimeSec > 60) {
writeBestScoreInFile();
restart();
}
if (totalTimeSec == 40)
windBlowing = true;
if (duration <= 0.0f) return;
m_container->update(duration);
if (windBlowing == true)
m_container->windBlow();
checkBallDetachFromAnchor();
checkMoverIsHit(); // !!! ITS CALLED HERE !!!
m_world->runPhysics(duration);
}
m_container is my container of movers: it contains basically all the "movers" of my scene.
m_container->m_ball is a pointer of one of these movers. It's the ball I launched to "shoot" the other movers.
After I think everything is pretty clear, ask me if something is not.
Hope someone can help me... I've done everything in my project it's the only thing bugging !
Here is a GIF, the first ball worked, the second didn't:
I finally manage to find out what was happening.
The problem is that my world is avoiding collisions. What I mean by that is: when two objects collide, they automatically bounce against each other.
This behaviour was the problem because the goal of my hunting ball is to collide against the other objects so.... randomly... it was not detecting some collisions, because it was boucing.
To fix it, I removed from my hunting ball the fact that it was iteracting with the other movers of the scene. So now it's only checking in my function checkMoverIsHit(); if it's colliding with the other movers.
It now works perfectly.
I have a thread that waits on a std::condition_variable then loops till it is done.
Im trying to slide my rect that is drawn in opengl.
Everything works fine without using a delta, But i would like my rect to slide at the same speed no matter what computer it is ran on.
At the moment it jumps about half way then slides really slow.
If i dont use my delta it does not run at the same speed if ran on slower computers.
Im not sure if i should ihave a if statement and check if time has passed then do the sliding, an not use a delta?
auto toolbarGL::Slide() -> void
{
LARGE_INTEGER then, now, freq;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&then);
while (true)
{
// Waits to be ready to slide
// Keeps looping till stopped then starts to wait again
SlideEvent.wait();
QueryPerformanceCounter(&now);
float delta_time_sec = (float)(now.QuadPart - then.QuadPart) / freq.QuadPart;
if (slideDir == SlideFlag::Right)
{
if (this->x < 0)
{
this->x += 10 * delta_time_sec;
this->controller->Paint();
}
else
SlideEvent.stop();
}
else if (slideDir == SlideFlag::Left)
{
if (this->x > -90)
{
this->x -= 10 * delta_time_sec;
this->controller->Paint();
}
else
SlideEvent.stop();
}
else
SlideEvent.stop();
then = now;
}
}
If you want your rectangle to move at a steady speed no matter what, I suggest a different approach -- instead of relying on your code executing at a particular time and causing a side effect (like x += 10) each time, come up with a function that will tell you what the rectangle's location should be at any given time. That way, no matter when your Paint() method is called, it will always draw the rectangle at the location that corresponds to that time.
For example:
// Returns the current time, in microseconds-since-some-arbitrary-time-zero
unsigned long long GetCurrentTimeMicroseconds()
{
static unsigned long long _ticksPerSecond = 0;
if (_ticksPerSecond == 0) _ticksPerSecond = (QueryPerformanceFrequency(&tps)) ? tps.QuadPart : 0;
LARGE_INTEGER curTicks;
if ((_ticksPerSecond > 0)&&(QueryPerformanceCounter(&curTicks)))
{
return (curTicks.QuadPart*1000000)/_ticksPerSecond;
}
else
{
printf("GetCurrentTimeMicroseconds() failed, oh dear\n");
return 0;
}
}
[...]
// A particular location on the screen
int startPositionX = 0;
// A clock-value at which the rectangle was known to be at that location
unsigned long long timeStampAtStartPosition = GetCurrentTimeInMicroseconds();
// The rectangle's current velocity, in pixels-per-second
int speedInPixelsPerSecond = 10;
// Given any clock-value (in microseconds), returns the expected position of the rectangle at that time
int GetXAtTime(unsigned long long currentTimeInMicroseconds)
{
const long long timeSinceMicroseconds = currentTimeInMicroseconds-timeStampAtStartPosition;
return startPositionX + ((speedInPixelsPerSecond*timeSinceMicroseconds)/1000000);
}
void PaintScene()
{
const int rectX = GetXAtTime(GetCurrentTimeMicroseconds());
// code to paint the rectangle at position (rectX) goes here...
}
Given the above, your program can call PaintScene() as seldom or as often as it wants, and your rectangle's on-screen speed will not change (although the animation will look more or less smooth, depending on how often you call it).
Then if you want the rectangle to change its direction of motion, you can just do something like this:
const unsigned long long now = GetCurrentTimeInMicroseconds();
startPositionX = GetXAtTime(now);
speedInPixelsPerSecond = -speedInPixelsPerSecond; // reverse course!
The above example uses a simple y=mx+b-style equation that provides linear motion, but you can get many different types of motion, by using different parametric equations that take a time-value argument and return a corresponding position-value.
I am currently experiencing some heavy slowdowns with my game. I have narrowed it down to something related with texture animations.
In my game there are characters that walk in 1 of 4 possible directions, they will walk up to a point, then change direction and continue walking (sort of like a tower defense game).
First i am loading the sprite frame cache like this
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("characters.plist");
This code is only run once during the life time of my application.
When the characters get loaded to the screen their animation is being set using the following code:
int direction = 0;
int number = 0;
if (this->to_x < 0) // Left
{
direction = 1;
number = 1;
}
else if(this->to_x > 0) // Right
{
direction = 2;
number = 1;
}
if (this->to_y < 0) // Down
{
direction = 0;
number = 0;
}
else if(this->to_y > 0) // Up
{
direction = 3;
number = 2;
}
int s = 0; //skin
// Set the animation
Animation *animation = Animation::create();
for (int i = 0; i < INT16_MAX; i++)
{
string frame_sprite_name = StringUtils::format("%s_%d_%d_%d.png",parameters[name].image_name.c_str(),s,number,i);
auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(frame_sprite_name);
if (frame) {
animation->addSpriteFrame(frame);
} else {
break;
}
}
// Invert the sprite when they go right
if (direction == 2) {
setFlippedX(true);
}else{
setFlippedX(false);
}
// Set the pace of the animation based on the type
if (name=="runner") {
animation->setDelayPerUnit(0.15f);
} else{
animation->setDelayPerUnit(0.3f);
}
Animate *animate = Animate::create(animation);
this->stopAllActions();
this->runAction(RepeatForever::create(animate));
What this code does is:
Check the direction
Get the sprite frame from the cache based on the direction
Run the action with repeat forever.
However this code is ran every time they change direction to set the new animation of the active characters. Also, at one time I can have around 40-50 of these characters going around.
I've noticed that after a few minutes in the game the slowdown starts to happen as soon as a new "character" is created, (since they are created in rapid succession in waves). And the slowdown also happens when the characters change in direction. So this makes me believe I am using the textures wrong.
If anyone knows how to fix this please let me know.
PD: I was thinking about the possibility of pre-loading all the animations and then just having each of the sprites that represent the characters run the corresponding animation.
You should definitely cache the animation in the AnimationCache with addAnimation and getAnimation methods.
i've been sitting here for hours now trying to figure out how collision could work for a platformer.. after doing a lot of research i found something useful in the internet.. but it doesn't work yet :/
my character seems to jump one time.. and then gets stuck a short distance above the ground
This is the function where i load my platforms from txt (by calling setupworld)
in my txt i define xstart (where the platform starts) xend (end of platform) ystart (bottom of platform) 2 unnused variables and the texture filter (0-4 atm)
each platform is then created by repeating 2x2 tiles in x direction
numblocks= number of platforms (sry for the bad variable name ^^)
number of blocks is calculated by taking the end coordinate of the platform - start coordinate and dividing by 2.0 (my platforms always have coordinates dividable by 2.. like.. 0 - 16.. or.. 8 - 16.. )
as u see.. the structure block is where all the data is saved to in setupworld() and it has nothing to do with the number of tiles displayed.. sry again for my weird names
GLvoid BuildLists()
{
texture[0]=LoadPNG("data/grass.png");
texture[1]=LoadPNG("data/gnd.png");
texture[2]=LoadPNG("data/pilz_test.png");
texture[3]=LoadPNG("data/rockwall.png");
texture[4]=LoadPNG("data/crate.png");
setupworld();
quad[0]=glGenLists(numblocks);
for(int loop=0;loop<numblocks;loop++)
{
GLfloat xstart,xend,ystart,u,v,u2,v2;
xstart=block.data[loop].xstart;
xend=block.data[loop].xend;
ystart=block.data[loop].ystart;
//u=block.data[loop].u;
//v=block.data[loop].v;
GLuint filter=block.data[loop].filter;
GLfloat blocks=(xend-xstart)/2.0f;
u=0.0f;
v=0.0f;
u2=1.0f*blocks;
v2=1.0f;
glNewList(quad[loop],GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, texture[filter]);
// Start Drawing Quads
for(int y=0;y<blocks;y++)
{
glBegin(GL_QUADS);
glTexCoord2f(u,v);
glVertex3f(xstart,ystart,-1.0f);
glTexCoord2f(u2,v);
glVertex3f(xstart+((y+1)*2.0f),ystart,-1.0f);
glTexCoord2f(u2,v2);
glVertex3f(xstart+((y+1)*2.0f),ystart+2.0f,-1.0f);
glTexCoord2f(u,v2);
glVertex3f(xstart,ystart+2.0f,-1.0f);
glEnd();
}
glEndList();
quad[loop+1]=quad[loop]+1;
}
}
This is where the key actions are processed..
DetectCollision() calls my function where i (try to) check for collisions
ymovement
ypos2=ypos; is just to remind the last position for repositioning
i jump until i reach 5.0f or a collision in y-direction is detected.. then locky turns TRUE; the else is to let my character get back to ground (cause no gravity) even when the player keeps w pressed
the same thing happens when w is not pressed.. and locky is being reset
xmovement
i add to (or subtract from) xpos for movement
as long as the character doesn't reach the border or a collision appears it should do the normal movement
if (active) // Program Active?
{
if (keys[VK_ESCAPE])
{
done=TRUE;
glDeleteTextures(1,&texture[0]);
glDeleteTextures(1,&texture[2]);
glDeleteTextures(1,&texture[1]);
}
if (keys['W'])
{
if(!locky)
{
DetectCollision();
ypos2=ypos;
ypos=ypos+0.2f;
if(ypos>=5.0f)
{
locky=!locky;
}
if(collisiony)
{
ypos=ypos2;
locky=!locky;
}
}
else
{
if(ypos>0.0f && !collisiony)
{
ypos=ypos-0.2f;
}
}
}
if (!keys['W'])
{
locky=!locky;
if(ypos>0.0f && !collisiony)
{
ypos=ypos-0.2f;
}
}
if (keys['A'])
{
if(xpos>0.0f && !collisionx)
{
xpos=xpos-0.2f;
}
}
if (keys['D'])
{
if(xpos< 50.0f && !collisionx)
{
xpos=xpos+0.2f;
xcam=xcam-0.1f;
}
}
glLoadIdentity();
glTranslatef(0,-7.0f,-25.0f);
DrawWorld(); //draws my platforms by calling the display lists compiled in build lists
DrawChar(); //draws the character
SwapBuffers(hDC);
}
Finally the code where i check for collisions
inPlatformx for checking x
is my character between left and right side of the platform being checked
-> function returns TRUE and is written into collisionx
inPlatformy for checking y
same for inPlatformy
bool inPlatformx(float xpos, BLOCK block, int i){
return xpos > block.data[i].xstart &&
xpos < block.data[i].xend;}
bool inPlatformy(float ypos, BLOCK block, int i){
return ypos > block.data[i].ystart &&
ypos < (block.data[i].ystart+0.2);
}
GLvoid DetectCollision(){
for(int i=0; i<numblocks;i++)
{
collisionx=inPlatformx(xpos,block,i);
collisiony=inPlatformy(ypos,block,i);
}
}
finally a screenshot
http://www.grenzlandzocker.de/test.png
I hope u can help me.. either fix my code or give me some tips on collisions.. since it's my first game with opengl :s
if u need any more detail or infos please ask ^^
and thanks in advance !
if (keys['W'])
{
//DetectCollision();
if(!locky)
{
ypos2=ypos;
ypos=ypos+0.2f;
if(ypos>=5.0f)
{
locky=!locky;
}
if(collisiony)
{
ypos=ypos2;
locky=!locky;
}
}
else
{
if(ypos>0.0f)
{
ypos=ypos-0.2f;
}
}
}
if (!keys['W'])
{
locky=!locky;
if(ypos>0.0f && !collisiony)
{
ypos=ypos-0.2f;
}
}
if (keys['A'])
{
//DetectCollision();
if(xpos>0.0f && !collisionx)
{
xpos2=xpos;
xpos=xpos-0.2f;
}
if(collisionx)
{
xpos=xpos2;
}
}
if (keys['D'])
{
//DetectCollision();
if(xpos< 50.0f && !collisionx)
{
xpos2=xpos;
xpos=xpos+0.2f;
xcam=xcam-0.1f;
}
if(collisionx)
{
xpos=xpos2;
}
}
THANKS :)
well i just edited the code for x movement and collision.. so it works properly.. (despite the flickering (but idc atm :) ).. i'm wondering why jumping doesn't work at all anymore.. it's just increasing till i'm stuck.. can't even get up once anymore :/
i put my detectCollision() in front of they key section.. which works for x AND y now (hopefully)..
and i also edited something in DetectCollision()
i had ystart+0.2 instead of ystart+2.0 which is the correct coordinate for the platforms top
but looks like it just got worse at y
i'm still totally confused..
oh and talking about those predefined api's and stuff.. since somebody first showed me some things with glut i tried to make the next step and initialize everything myself.. i guess detection is much easier using predefined stuff.. but i want to learn it and not just get one game to work :)
if u have any more suggestions for my code i would be really grateful.. and if u know any good books for starters till advanced lvl i would really appreciate
and yes.. i know.. display lists are deprecated since opengl 3.0 ^^
Unless I am not following your code correcty, once you reach the apex of your jump and set your locky to !locky, you start hitting your else statement, which never checks for collision. IF you are moving in the x or -x direction, you likely want to be doing this as the ground may not be in the same place as your origin of the jump.
Additionally, your locky check is checking if the ypos >= 5.0f , which will immediately be the case if you are already on some part of your game world above the 5.0 mark. You likely want this to be a variable such as limitY = ypos + 5.0f; and then check if ypos >= limitY, so it works regardless of origin.
As for the issue you are seeing now, it should be easy to debug and look at the current value of your y coordinate and see if there is anything obvious (such as not executing a final ypos -= 0.2f ) which is cause for you floating slightly above the ground after a jump. (I don't see an obvious error in the way you are doing your code, although I would not have designed it in the way you are doing it yourself.)
If you are developing this for Windows you may want to look into XNA development, which makes collision detection and resolution a lot easier.
Are you initializing locky to true or false? because all the code i can see inverts the state of locky, so depending on how the input is processed, your locky value is flipping every loop or possibly being set out of sync with your expectations.
I would recommend setting locky to true and false explicitly in the code you've shown, rather than using locky=!locky, it's clearer about the state of the system.
I am building a 3d game from scratch in C++ using OpenGL and SDL on linux as a hobby and to learn more about this area of programming.
Wondering about the best way to simulate time while the game is running. Obviously I have a loop that looks something like:
void main_loop()
{
while(!quit)
{
handle_events();
DrawScene();
...
SDL_Delay(time_left());
}
}
I am using the SDL_Delay and time_left() to maintain a framerate of about 33 fps.
I had thought that I just need a few global variables like
int current_hour = 0;
int current_min = 0;
int num_days = 0;
Uint32 prev_ticks = 0;
Then a function like :
void handle_time()
{
Uint32 current_ticks;
Uint32 dticks;
current_ticks = SDL_GetTicks();
dticks = current_ticks - prev_ticks; // get difference since last time
// if difference is greater than 30000 (half minute) increment game mins
if(dticks >= 30000) {
prev_ticks = current_ticks;
current_mins++;
if(current_mins >= 60) {
current_mins = 0;
current_hour++;
}
if(current_hour > 23) {
current_hour = 0;
num_days++;
}
}
}
and then call the handle_time() function in the main loop.
It compiles and runs (using printf to write the time to the console at the moment) but I am wondering if this is the best way to do it. Is there easier ways or more efficient ways?
I've mentioned this before in other game related threads. As always, follow the suggestions by Glenn Fiedler in his Game Physics series
What you want to do is to use a constant timestep which you get by accumulating time deltas. If you want 33 updates per second, then your constant timestep should be 1/33. You could also call this the update frequency. You should also decouple the game logic from the rendering as they don't belong together. You want to be able to use a low update frequency while rendering as fast as the machine allows. Here is some sample code:
running = true;
unsigned int t_accum=0,lt=0,ct=0;
while(running){
while(SDL_PollEvent(&event)){
switch(event.type){
...
}
}
ct = SDL_GetTicks();
t_accum += ct - lt;
lt = ct;
while(t_accum >= timestep){
t += timestep; /* this is our actual time, in milliseconds. */
t_accum -= timestep;
for(std::vector<Entity>::iterator en = entities.begin(); en != entities.end(); ++en){
integrate(en, (float)t * 0.001f, timestep);
}
}
/* This should really be in a separate thread, synchronized with a mutex */
std::vector<Entity> tmpEntities(entities.size());
for(int i=0; i<entities.size(); ++i){
float alpha = (float)t_accum / (float)timestep;
tmpEntities[i] = interpolateState(entities[i].lastState, alpha, entities[i].currentState, 1.0f - alpha);
}
Render(tmpEntities);
}
This handles undersampling as well as oversampling. If you use integer arithmetic like done here, your game physics should be close to 100% deterministic, no matter how slow or fast the machine is. This is the advantage of increasing the time in fixed time intervals. The state used for rendering is calculated by interpolating between the previous and current states, where the leftover value inside the time accumulator is used as the interpolation factor. This ensures that the rendering is is smooth, no matter how large the timestep is.
Other than the issues already pointed out (you should use a structure for the times and pass it to handle_time() and your minute will get incremented every half minute) your solution is fine for keeping track of time running in the game.
However, for most game events that need to happen every so often you should probably base them off of the main game loop instead of an actual time so they will happen in the same proportions with a different fps.
One of Glenn's posts you will really want to read is Fix Your Timestep!. After looking up this link I noticed that Mads directed you to the same general place in his answer.
I am not a Linux developer, but you might want to have a look at using Timers instead of polling for the ticks.
http://linux.die.net/man/2/timer_create
EDIT:
SDL Seem to support Timers: SDL_SetTimer