View previous topic - View next topic |
Author |
Message |
tunginobi Wandering Minstrel
Joined: 13 Dec 2005 Posts: 91
|
Posted: Wed Feb 15, 2006 6:57 am Post subject: |
[quote] |
|
Quote: | I just wish I could do everything right the first time and not waste so much on failing and starting over. |
I've been programming for years, and if I've only learned one thing, it's that getting things right the first time is a very rare experience (unless the problem is small).
At times like this, you need to step back. Turn off your computer, and instead of going through a constant loop of staring at your formulas and tweaking them in the hope that they'll fix themselves, start your thinking from the bottom. Make a new set of formulas for your variables that you believe should work.
The tweak-'n'-pray "tactic" has never worked in my experience. Rethinking always has. Don't be afraid to take a break now and then, you'll usually come out more productive in the end.
|
|
Back to top |
|
|
LeoDraco Demon Hunter
Joined: 24 Jun 2003 Posts: 584 Location: Riverside, South Cali
|
Posted: Wed Feb 15, 2006 8:51 am Post subject: |
[quote] |
|
Rainer Deyke wrote: | My advice would be not to worry too much about organization at this point, and especially don't worry too much about LeoDraco's suggestions. |
My, aren't we in a good mood? Very cheery and friendly. Granted: organization concerns can bog down development --- the old "analysis paralysis" nonsense --- and having some sort of prototype is probably more important than making sure it is planned right. I shall even concede that as his original post was a cry for help in getting a particular subsystem to work, any discussion about organization is off-topic, and should therefore be frowned upon. (As such, I offer apologies for the faux pas commited above.) However, organization --- even at such an early stage --- is still important, and allowing certain constructs to continue when they could be replaced with better designed alternatives (which I shall concede is not necessarily the case in my post) is moderately negligent; he asked for help, and while my advice was off-topic, it certainly is relevant to his project.
Quote: | Division is plenty fast enough - if you can do perspective texture mapping (which requires one division per pixel) in software on a 486, you won't even notice a couple of divisions per tile. |
As true as that may be --- personally, I have never found simple operations to be much of a hassle in my projects; I often wonder if regurgitating that old myth is even still valid these days --- the question remains: why is a calculation being performed when it need not be? As far as I could tell from my brief perusal of his code, those expressions using the divisions were immutable at the point where they were being used; why waste cycles for no real gain in function?
Quote: | Enumerations aren't always the best tool for the job, but they're syntactically lightweight and they work. |
And they lead to code that is, from an object-oriented perspective, irrational: they do not provide enough information about the types they convey; a proper object passed to a method or stored as member data contains more information about the type of the data than the enumerations do. Depending upon how the object hierarchy is written, it can be just as syntactically lightweight --- as far as client utilization is concerned --- as enumerations are, although that is certainly not the case with the code in Gardon's project.
Quote: | Especially stay away from the CartesianPoint template - that's overabstraction, which can lead to just as much code bloat as underabstraction. |
Perhaps once the code from the templates has been generated by the compiler; however, in a system utilizing multiple types of tuples, the template I presented leads to a maximal amount of code reuse with a minimal amount of maintainability or redundancy. In such a situation, only one class need be maintained, rather than two or more. Granted, for a simplistic system involving only a single coordinate system, the template is overabstracted; as it was, I was never seriously condoning its use --- it was merely another alternative to the curiousity found in his code. I also realize that better alternatives exist for representing tuples that are both more dynamic and more succinct.
Quote: | And never ever use a floating point variable when an integer will do. |
I find this absolutely amusing to the point of absurdity once it has been paired with your comments about division: depending upon the size of the float and of the integer, the float might take an equal, if not smaller, amount of space than the integer will in memory, and with modern FPUs, assuming your above argument is valid, there should be little noticable difference in performance. True, there does exist an issue of precision when using floating point variables, but I'm not entirely sure that was the point of your comment.
Quote: | And no, this is not template metaprogramming. It's just generic programming, aka programming with templates. Metaprogramming implies writing actual code which is executed at compile time. |
My bad? Sorry for throwing out a buzzword? You want a cookie?
Even if my code was not, strictly speaking, template metaprogramming, your response here is not entirely accurate, at least as far as generic programming goes within languages which do not support templates --- to date, Java and pre .NET 2.0 C# being two examples --- which hold a very clear distinction between the two. _________________ "...LeoDraco is a pompus git..." -- Mandrake
|
|
Back to top |
|
|
Rainer Deyke Demon Hunter
Joined: 05 Jun 2002 Posts: 672
|
Posted: Wed Feb 15, 2006 11:07 am Post subject: |
[quote] |
|
LeoDraco wrote: | I find this absolutely amusing to the point of absurdity once it has been paired with your comments about division: depending upon the size of the float and of the integer, the float might take an equal, if not smaller, amount of space than the integer will in memory, and with modern FPUs, assuming your above argument is valid, there should be little noticable difference in performance. True, there does exist an issue of precision when using floating point variables, but I'm not entirely sure that was the point of your comment. |
The point is that floating point variables add significant additional complexity which must be carefully managed in order to avoid subtle bugs. For example, it is rarely meaningful to compare floating point numbers for equality, since the same set of operations, performed in a slightly different order, can produce similar but non-equal results.
|
|
Back to top |
|
|
zenogais Slightly Deformed Faerie Princess
Joined: 10 Jan 2006 Posts: 34
|
Posted: Wed Feb 15, 2006 1:55 pm Post subject: |
[quote] |
|
Gardon: Just wanted to let you know that I'm 17 as well, and have also had no formal training. In reference to the SDL_PollEvent problem, you could do a while loop and then send events to all your listeners(of course you'd have to implement listeners, but it would be worth it) like so:
Code: |
SDL_Event event;
...
while ( SDL_PollEvent( &event ) ) {
PostEvent(event.type, event);
}
|
The way SDL_PollEvent is defined, it returns 1 as long as there are events in the queue, once there are none it returns 0 as you can find out here. Hopefully this helps you out, and it will prevent any weird event stuff from occurring.
And in regards to floating point comparisons, you can always use the epsilon compare technique (not sure what it's called):
Code: |
const float EPSILON = 0.01F;
int AreEqual(float& f1, float& f2) {
float relativeError = fabs((f1 - f2) / f2);
if ( relativeError < EPSILON ) {
return true;
}
return false;
}
|
|
|
Back to top |
|
|
RuneLancer Mage
Joined: 17 Jun 2005 Posts: 441
|
Posted: Wed Feb 15, 2006 4:57 pm Post subject: |
[quote] |
|
Hmm... premature optimization is the root of all evil. At this point, getting a working algorithm up should be a FAR more pressing matter than worrying about wether a division eats up enough cycles to be worth optimizing out.
In fact, worry about wether a division is going to slow down things or not is micro-optimization. An excellent way to waste time (unless we're dealing with a tight loop, such as one that's applied to every pixel every frame. Which is not the case.) For that matter, modern processors can handle divisions practically as fast as any other operation. Rendering your code less intuitive over something so trivial is a bad idea. Especially considering that we're dealing with new blood here, not a seasoned veteran who can read through complex code like plain english (yet...?)
In other words, don't sweat the petty things. Right now, an algorithm is more important than micro-optimizing your code.
(For that matter, algorithms have a FAR more important impact on execution time.) _________________ Endless Saga
An OpenGL RPG in the making. Now with new hosting!
|
|
Back to top |
|
|
Gardon Scholar
Joined: 05 Feb 2006 Posts: 157
|
Posted: Wed Feb 15, 2006 9:16 pm Post subject: |
[quote] |
|
Thanks lancer, and that makes perfect sense.
As for the input thing:
while (SDL_PollEvent(....
I don't trust that. What if the user decides to consistently click, move, and rotate the mouse? The input will always be true, delaying the program.
Jason
|
|
Back to top |
|
|
RuneLancer Mage
Joined: 17 Jun 2005 Posts: 441
|
Posted: Wed Feb 15, 2006 9:25 pm Post subject: |
[quote] |
|
Yes, in those cases, you're going to deal with a program constantly handling events without ever giving control back to your app.
One option is to handle both potential events AND the game loop in the while(). Not sure how SDL does it, but with Windows you can have your while() loop poll for events and loop until it hits a WM_QUIT message. The game loop is placed in this loop.
An even better solution is to simply seperate the game loop entirely from your event handling by placing it in a thread. GameDev.net had an article about it. The previous solution can cause events to pile up if they enter the event queue faster than the app can deal with them (for instance, if your game loop runs slowly). Having them in a seperate thread, on the other hand, means your game can take as much time as it wants and the event thread will still clean out the event queue.
Mind you, handling threads can be a little difficult. Read up on synchronization mechanisms (messages, semaphores, critical sections, mutexes...) if you plan on doing it, but you should stay away from multithreading until you're comfortable with the basics. _________________ Endless Saga
An OpenGL RPG in the making. Now with new hosting!
|
|
Back to top |
|
|
Rainer Deyke Demon Hunter
Joined: 05 Jun 2002 Posts: 672
|
Posted: Wed Feb 15, 2006 10:14 pm Post subject: |
[quote] |
|
RuneLancer wrote: | An even better solution is to simply seperate the game loop entirely from your event handling by placing it in a thread. GameDev.net had an article about it. The previous solution can cause events to pile up if they enter the event queue faster than the app can deal with them (for instance, if your game loop runs slowly). Having them in a seperate thread, on the other hand, means your game can take as much time as it wants and the event thread will still clean out the event queue. |
In practice, it is simply not possible for the user to send enough events to even slow down the main program, so this "problem" is a complete non-issue.
However, in SDL, only the main thread can handle events and only the main thread can render to the screen. Therefore using separate threads is not an option. Even if it was an option, it wouldn't solve the problem, it would only make it worse (by not giving enough CPU time to event handling).
'while (SDL_PollEvent(' is the one and only correct approach here.
|
|
Back to top |
|
|
Gardon Scholar
Joined: 05 Feb 2006 Posts: 157
|
Posted: Wed Feb 15, 2006 10:27 pm Post subject: |
[quote] |
|
Isn't multi-threading possible through sdl_mixer?
Anyway, here's my new code. My brain's cleared, and I think I pretty much have it. All I have to do now is detect why my program isn't running (maybe an index error). If you guys wouldn't mind, critique my code and maybe try to help me see why it isn't running.
Code: | void Map::Draw()
{
m_currentTile = (int)((m_cameraX / m_tileSize) + (m_cameraY / m_tileSize) + 100); // gets the current tile (index) //from a pointer, m_mapIndexes
double offsetX = m_cameraX % m_tileSize; // determind offsets from camera position
double offsetY = m_cameraY % m_tileSize;
if (offsetX >= m_tileSize) ////////// ////////// ////////// /////////
offsetX = 0; //////Set offsets to 0 if they are above the tile marker or below it
////////// //////// //////////////// ////////////
if (offsetX <= 0)
offsetX = 0;
if (offsetY >= m_tileSize)
offsetY = 0;
if (offsetY <= 0)
offsetY = 0;
for (int i = 0; i < (m_screenHeight / m_tileSize) + 2; i++) // draw y tile, using +2 as partial tile add-ons
{
for (int j = 0; j < (m_screenWidth / m_tileSize) + 2; i++) // same as above, but draw x tile
{
m_source.x = m_tiles[m_mapIndexes[m_currentTile]].x + offsetX; // the m_mapIndexes[m_current.... gets the
// value (tile number) for the tile to blit
m_source.y = m_tiles[m_mapIndexes[m_currentTile]].y + offsetY;
m_source.w = m_tileSize - offsetX; // width to blit is the tile size - the offset
m_source.h = m_tileSize - offsetY;
m_destination.x = offsetX + m_source.w; // the destination of the tile, which is used with offsets/sources
m_destination.y = offsetY + m_source.h;
m_destination.w = m_source.w; // m_source.w updates every time m_currentTile is incremented, so it'll
// always change each call
m_destination.h = m_source.h;
m_graphics->DrawBitmap(m_bitmap, m_source, m_destination);
m_currentTile += 1;
}
m_currentTile += 100;
}
} |
I increment, decrement, or do nothing with the camera position based on input. If the movement is to the right, the m_cameraX variable is incremented by an amount. That value is then applied to above to calculate the current tile, which in turn is used for blitting.
Let me know what's wrong,
Jason
|
|
Back to top |
|
|
RuneLancer Mage
Joined: 17 Jun 2005 Posts: 441
|
Posted: Wed Feb 15, 2006 11:13 pm Post subject: |
[quote] |
|
Rainer Deyke wrote: | However, in SDL, only the main thread can handle events and only the main thread can render to the screen. |
No kidding? :o That sucks. Though I can understand why it wouldn't be possibly to split them up without problems, after giving it a bit of thought. I didn't know that, heh.
The purpose of splitting up the game and the message handler is more of a performance-related one, though. You simply can't use PeekMessage without throwing in a Sleep() otherwise you're using up 100% of the CPU (and though it's not a problem for most users, full-load heats up mine considerably and is something I try to avoid.) As for GetMessage(), it halts execution until a message enters the message queue. Great for apps, but crap for games due to obvious reasons (unless it's a card game or something like that.)
In a seperate thread, you can make use of GetMessage() and have a near-0% CPU usage. This just leaves your game thread to deal with. You can give the user the option to lock the framerate to a certain amount and avoid heating up the user's bedroom by 5'C after a half hour of gaming. ;) DWI, for instance, does this, and I think it's the best thing since sliced bread because anything over 45 FPS is totally unnoticeable. On the other hand, letting it run at full speed just means background apps run at a snail's pace and my case vent enough heat to notice after extended playtime.
(If you're wondering, I have a Prescott chip, which generates (and is made to handle) a lot of heat. It's ok in winter, but a problem in the summer. Particularly with a small, well-isolated, windowless room. I'm considering watercooling it someday, as a fan just blows over 50'C of heat through the case and into my room non-stop. :) Which, believe it or not, is a normal temp for this particular chip when running at 100% cpu...)
I do believe you're right about not sending enough events to slow down the program. Unless your message queue runs abnormally slow or is coded like crap, it should be able to shift out messages fast enough not to interfere. I do have my doubts, but I've never seen it occure in my programs and haven't heard anyone else making particular mention of it. So, you're most likely right.
Totally off-topic post, sorry. :D _________________ Endless Saga
An OpenGL RPG in the making. Now with new hosting!
Last edited by RuneLancer on Wed Feb 15, 2006 11:15 pm; edited 1 time in total
|
|
Back to top |
|
|
Rainer Deyke Demon Hunter
Joined: 05 Jun 2002 Posts: 672
|
Posted: Wed Feb 15, 2006 11:14 pm Post subject: |
[quote] |
|
Gardon wrote: | Isn't multi-threading possible through sdl_mixer? |
SDL_mixer has nothing to do with multithreading. SDL itself has multithreading support, but only the main thread can render to the screen or handle events. Anyway, multithreading cannot help you.
Quote: | Let me know what's wrong, |
The function you posted isn't so much buggy as borderline gibberish - it's clear that you yourself do not understand how it is supposed to work. What's wrong is that you aren't paying attention and that you aren't using the code I gave you. Here it is again. It works.
Code: | void Map::Draw(int x_offset, int y_offset)
{
int min_x = std::max(0, x_offset / m_tileSize);
int max_x = std::min(m_mapWidthTileCount,
(x_offset + m_screenWidth + m_tileSize - 1) / m_tileSize);
int min_y = std::max(0, y_offset / m_tileSize);
int max_y = std::min(m_mapHeightTileCount,
(y_offset + m_screenHeight + m_tileSize - 1) / m_tileSize);
for (int y = min_y; y < max_y; ++y) {
for (int x = min_x; x < max_x; ++x) {
int tile = m_mapIndexes[x * m_mapHeightTileCount + y]
SDL_Rect source = m_tiles[tile];
SDL_Rect dest = {
x * m_tileSize - x_offset,
y * m_tileSize - y_offset,
tileSize,
tileSize,
};
m_graphics->DrawBitmap(m_bitmap, source, dest);
}
}
}
void Map::Draw()
{
Draw(m_cameraX, m_cameraY);
}
|
|
|
Back to top |
|
|
Gardon Scholar
Joined: 05 Feb 2006 Posts: 157
|
Posted: Wed Feb 15, 2006 11:17 pm Post subject: |
[quote] |
|
Can you update it with comments and such for me to see why you're using stuff like STL's maxes and min functions?
Jason
|
|
Back to top |
|
|
Gardon Scholar
Joined: 05 Feb 2006 Posts: 157
|
Posted: Wed Feb 15, 2006 11:37 pm Post subject: |
[quote] |
|
And no, it doesn't work, you're flippen retarted.
I can't scroll at all, it just shifts the map over one tile, only letting me scroll 1 tile in any direction.
Jason
|
|
Back to top |
|
|
RuneLancer Mage
Joined: 17 Jun 2005 Posts: 441
|
Posted: Wed Feb 15, 2006 11:50 pm Post subject: |
[quote] |
|
Gardon wrote: | And no, it doesn't work, you're flippen retarted. |
Bite not the hand that feeds you. If he's a retard because you can't make his code work, I'd love to hear what that makes you for not knowing where to even begin. ;) No offense man, just saying, take it easy. Programming requires patience and you're bound to run into snags.
His code IS supposed to scroll tile by tile... if you don't pass it the right parameters. m_cameraX and m_cameraY are the position of the camera in pixels, not in tiles. It's your job to move the camera pixel per pixel when the player crosses from tile to the next, and to call the function every pixel.
Otherwise you're going to have to deal with tile by tile scrolling. The camera won't smoothly "slide" from one tile to the next on its own...
With TOTAL disregard to the game loop, you should do something like this...
Code: | for(int i = 0; i < tileSizeX; i++)
Draw(m_cameraX + i, m_cameraY);
m_cameraX += tileSizeX; |
Voila! You moved 1 tile to the right. Just plug in the variables you're using and incorporate it in your game loop instead of doing something so linear and you're set. _________________ Endless Saga
An OpenGL RPG in the making. Now with new hosting!
Last edited by RuneLancer on Wed Feb 15, 2006 11:53 pm; edited 1 time in total
|
|
Back to top |
|
|
zenogais Slightly Deformed Faerie Princess
Joined: 10 Jan 2006 Posts: 34
|
Posted: Wed Feb 15, 2006 11:52 pm Post subject: |
[quote] |
|
Gardon: He's using std::max (not part of the STL), which rounds the value to the nearest whole number. He's only doing this because dividing any two values does not always result in a whole number (pretty basic stuff, but I figured I'd add it in anyway). As for the way it scrolls, his code could be very easily modified to do per-pixel scrolling, which seems to be what you're looking for.
|
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|