• Content count

  • Joined

  • Last visited

Community Reputation

8794 Excellent

About Khatharr

  • Rank
    Advanced Member
  1. Yes. If the lower end system can't render at 60 fps then the frame time will accumulate and you'll get multiple updates per frame to compensate.
  2. Since you're describing a 2D tiled world, I'd move away from the dt/elapsed_time approach and go with a fixed timestep. This way you can express speed in terms of "pixels per update", and just make that number a factor of your tile width. enum Direction { NONE, NORTH, SOUTH, EAST, WEST }; class Actor { Direction facing = SOUTH; int move_time = 0; int framesToCrossOneTile = 8; //(use a factor of tile width so you don't get slop) int speed = tileWidth / framesToCrossOneTile; void update() { //use a fixed timestep for this kind of game - it will make your life much easier if(move_time <= 0) { //process input Direction inputDir = getInputDirection(); if(inputDir == facing) { move_time = framesToCrossOneTile; } else { facing = inputDir; } } if(move_time > 0) { //process motion move_time--; switch(facing) { case NORTH: y -= speed; break; case OTHER_DIRS: .... break; } } } }; For a simple fixed timestep you can go to your top-level loop and do something like: const int frameDuration = 17; const int maxTimePerFrame = 200; int accumulatedTime = 0; while(game_running) { accumulatedTime += getDT(); //if the game loses focus or processing is delayed for some reason you don't //want to suddenly jump way ahead, so limit the maximum speed if(accumulatedTime > maxTimePerFrame) { accumulatedTime = maxTimePerFrame; } //update the simulation using fixed time steps as many times as necessary in //order to keep pace with the clock while(accumulatedTime >= frameDuration) { //note that "excess" time will be retained accumulatedTime -= frameDuration; update(); } draw(); } If you simply can't live with a rate that's directly divisible by the tile width then you need to do some gymnastics to keep things running smoothly. In that case you're better off setting a value indicating your end coordinate (either x or y - you don't need both) in pixels. As you move the character you check to see whether you're at or beyond that point. If so then immediately check the input to see if the motion should continue (just change the endpoint) or if you should snap the position to the desired endpoint. In that case a 'moving' bool is the better approach. Make sense?
  3. That's correct. It doesn't really bother me with 2D sprite animation, but I used this technique in a 3D rendered game and the skip was a lot more noticeable. For clarity, what you end up with is: if(move_timer <= 0) { listening to input } if(move_timer > 0) { moving }
  4. Nope. This is bat country.
  5. The default case is to work by value: void doThing(int num) { num++; } In this case 'num' is a copy of whatever you pass in when calling the function. int derp = 1; doThing(derp); //derp still equals 1 because it was a copy that got incremented If you want to be able to modify the original value then you can pass by reference: void doThingByRef(int& num) { num++; } Now 'num' is effectively a direct alias of whatever you pass in: int derp = 1; doThing(derp); //derp now equals 2 There's another case to consider... What if the thing you're passing in is large, but you don't want to modify it? You don't want to do an unnecessary copy, so you may use a reference, but that suggests that you're modifying the item within the function. In this case you could use a const reference: void doThingByConstRef(const BigThing& thing) { ??? } This lets you read 'thing' but not modify it (you'll get a compile error). These are the basics of reference semantics. Pointers are similar, but they have some additional properties: 1) A pointer is "nullable". That is, it can be set to 'nulllptr' in order to indicate that it doesn't actually point to anything. 2) A pointer is "reseatable". That is, it can be modified to point at something else. A note about pointers and constness: int* num; //the pointer can be changed and the int that it points to can be changed const int* num; //the pointer can be changed but the int that it points to can not int* const num; //the pointer can not be changed but the int that it points to can be (probably use a reference instead in this case) const int* const num; //neither the pointer or the pointed-to int can be changed (probably just use a const reference instead) Be careful about returning pointers and references from functions. If the thing that you're referring to is destroyed or moved then you end up with a dangling reference/pointer, and that's no fun at all. So the basic rule of thumb here is: Use value semantics by default. Use references when you want references. Use pointers when you want references that are reseatable and/or nullable. Cheers.
  6. DX9 attaches to an HWND during its setup. All of the controls in your window, as well as the window itself, will have an HWND. If you want to render into a square in that window then put some kind of control in the area where you want to draw and hand the HWND of that control to DX9. Refer to D3DPRESENT_PARAMETERS and device creation. Since you're using resedit you may need this: Although, if memory serves, you can just set the ID of the target control manually in resedit and then just use GetDlgItem with that ID.
  7. How do you render stuff normally?
  8. In the past I've actually done away with the "moving"/"stopped" state indicator and just checked whether the interpolation value was in the normalized range. if(move_timer > 0) { moving } else { listening to input }
  9. tl;dr, but did you disable face culling?