Jump to content

  • Log In with Google      Sign In   
  • Create Account


Trienco

Member Since 22 Aug 2001
Offline Last Active Today, 12:30 AM
-----

#5145843 What it's like to be a software engineer (video)

Posted by Trienco on 09 April 2014 - 10:01 PM

 


I don't think it's fair to make this about engineers vs. non-engineers, though.
It's just people who know the field versus people who don't. It would be exactly the same if the positions were reversed (the engineer calling the shots on marketing and asking a marketing expert to do the impossible).

 

 

True, but one of those things constantly happens in the real world, while I've never ever heard about the other.

 

My "favorite" exchange so far was something like this: "We need you to add this functionality."  "That's technically impossible."  "Well, you better make it possible, because we already sold it to the customer."

 

In fact, I got a little bit of naive hope that with reversed roles, engineers would be more likely to approach things by asking "would it be possible", rather than "do it, we don't care how" or "I don't want to hear about problems, I want solutions".




#5141171 Why are my two classes sharing variables? C++

Posted by Trienco on 22 March 2014 - 12:36 AM

If you're using Visual Studio, use a debug build and make sure to enable all the run-time checks (especially to check for out of bounds writes).

 

Finding the error would also be easier if the code wouldn't be so C-ish and cluttered.

 

-Stop declaring uninitialized variables

 

Seriously, what's the point of creating uninitialized variables and then assign stuff in the next line? Eventually you might want to start writing const correct code and that simply won't work if you stick with that. A similar thing goes for constructors. Embrace initializer lists.

 

-Don't assign values you'll never use

 

Not only are px and py in movebeam() completely pointless, they are also first assigned values and then overwritten without these values ever having been used. The function as about twice as long as it should be, only due to doing lots of pointless things.

 

-Don't declare at the top of the function, but at point of first use

 

That you way you would have noticed that n in drawbeam has become completely unused and pointless.

 

-Avoid useless clutter

 

What's the point of px and py in drawbeam?

 

-There's more types than "int"

 

alive doesn't track types of being alive (which should be an enum) or a degree of being alive. It's a bool. Why create doubt about the usage and meaning of a variable by not using the appropriate type for it?

 

-Vectors are nice

 

They would also prevent moving into a direction turning into a messy if/else-copy/paste orgy (if left and right do the same thing, why is this not one block for both?).

 

 

Finding bugs just from looking at code is a LOT easier if the code is clean and well written, without unnecessary clutter that makes everything look more complicated than it actually is. You're trying to find a bug in your code and your code being at least 3-4 times longer than it needs to be makes it at least 3 times harder to find it.

 

I can't see anything obvious that should result in the bug to describe (potentially for all the above reasons), so the obvious first step would be setting up breakpoints that trigger if the rock position is assigned a value that greater or smaller than a reasonable value, then check the call stack to see who's responsible for it.




#5134647 C++ Constructors vs. Init() Functions

Posted by Trienco on 25 February 2014 - 11:06 PM

- if you define your own constructor, the 'default' constructor, destructor and assignment operator are no longer applied from the compiler, meaning you need to write them yourself to (look up "the rule of three")

 

Unless somebody made really weird changes to the language, that's simply not true. Creating your own constructor will never prevent default implementations of anything but the default constructor.

 

The "Rule of Three " doesn't say "you must implement all of them, because the compiler doesn't create them", it says "if you need one, you probably need all three". In fact, the big problem IS that the default implementations don't do everything they should in that case.

 

Obvious example:

 


class Demo()

{

    Demo() : ptr(new Thing) {}

    ~Demo() { delete ptr; }

 

    Thing* ptr;

}

 

And you probably don't want to know how often I'm seeing this kind of thing, always hand-waved away with "nah, it's never going to be copied anyway". Unless it suddenly is and "someone" (typically me) gets to spend hours debugging and tracking down the double delete introduced months ago.

 

If the compiler actually would stop creating defaults for assignment and _copy_ constructor (which is the one relevant to the Rule of Three) the code would have the decency to stop compiling. You'd also have an army of C++ coders lynching the person that came up with it.

 

 

Another common rule is that the constructor should only do minimal work to get the object in a valid state. Any heavy lifting that isn't absolutely needed would then go into an init() function.




#5134010 rotating space ship

Posted by Trienco on 23 February 2014 - 11:04 PM

Dejaime, OpenGL is simple. The deprecated functions to modify the matrix stack simply operate on the local coordinate system/object space/whatever you like to call it. So it should be obvious why it's wrong to rotate first if your position is given in world space.

 

Not that it matters, because 3 posts from now, he will announce researching this and looking into that, disappear for a while and after a few months post the exact same code with the exact same question, showing zero progress or improvement and have half the people on the forum wonder if he's trolling us (and yet again he will ask what that means) or if he's really so completely beyond help that you'd have better luck explaining colors to a blind man.

 

To quote BSG: "All of this has happened before, and all of it will happen again." (ie. "just check his history")




#5133466 I don't get c++11.

Posted by Trienco on 22 February 2014 - 12:25 AM

Random advice: if you're using VC++2013, don't try this (using int for simplicity):

vector<shared_ptr<int>> = { make_shared<int>(5), make_shared<int>(5) };

Due to some really weird bug with their initializer list, the first element of a container of shared_ptr will have the references reduced to 0 and be deleted.

 

Almost as funny as seeing their high_resolution_clock:

 

typedef system_clock high_resolution_clock;

 

No, their system clock doesn't happen to already be high resolution.




#5128331 rotating space ship

Posted by Trienco on 02 February 2014 - 10:50 PM

First, you have to translate your object so its center is at the origin. Then you rotate your object, and then you translate your object to its final destination.

 

That only works if you look at things from a "world view". Rotating (with glRotate) changes the local coordinate system of the object and the translation will move along the local coordinate system axes (just like rotation always happens around the current origin, aka. the objects position).

 

So the order in OpenGL (assuming the object is modeled around the origin) is glTranslate into position and then glRotate.

 

At least "thinking local" would seem a lot more intuitive than saying "OpenGL is doing everything backwards for some reason".

 

Of course those functions are technically deprecated and once handling matrices yourself it all boils down to multiplication order.




#5128102 Hexadecimals

Posted by Trienco on 01 February 2014 - 11:41 PM


And if you need the "0x" prefix you can do that in the string stream or insert it into the string after converting to upper case:

ss << "0x" << std::hex << myNumber; // either this
myHexString.insert( 0, "0x" ); // or this

 

Or simply:

ss << std::showbase << std::hex << myNumber;

 

Which has the distinct advantage that you don't have to manually add the 0x to every single hex value.




#5127127 Empty Array In Structures

Posted by Trienco on 28 January 2014 - 11:03 PM

Or the long overdue C++11 way:

 

char* buffer = Vec.data();

 

edit: okay, char to unsigned char means not getting rid of the cast. Which means being torn between the "proper" way of the ugly static_cast<char>() or the "evil" easy C-style cast (char*).




#5123777 Classes and use of 'New'

Posted by Trienco on 14 January 2014 - 11:09 PM

Minor nitpicks and remarks:

 

To fill the vector with default constructed objects, don't waste time writing a loop.

 

vector<Car> cars;

cars.resize(count);

 

Of course, if count is already known, you just want to do

vector<Car> cars(count);

 

 

Will do the same without any copying.

 

Rather than the unwieldy cars[cars.size()-1], just use cars.back().

 

To avoid copying, go the C++11 route:

 

Use

cars.emplace_back(100, 100);

 

rather than

cars.push_back(new Car(100, 100));




#5122991 Please check this for me. :)

Posted by Trienco on 12 January 2014 - 12:03 AM

One basic rule of thumb: "prefer non-friend non-member functions". Meaning: if there isn't a good reason for a function to be part of a class (like needing to access private members), it has no business being a member-function.

 

Unless one wants to argue that most of the C++ standard library is bad code, it's not just perfectly fine but even recommended not to stuff everything into objects "just because". Namespaces on the other hand are almost always a good idea for projects that are either complex and/or use multiple libraries.

 

Here are two examples of "C style functions":

 

//Explicitly declaring "no parameters" (in C: empty list = any number of parameters)

int function(void) { return 42; } 

 

//Skipping return and/or parameters type (C defaults to int, C++ won't compile)

function(x) { return 2*x; }




#5121315 Linear collision question

Posted by Trienco on 04 January 2014 - 11:50 PM

I follow that having two separate float values equaling the same is a low probability, but doesn't it at some point (despite how brief) have to equal a point on the line, say just before it crosses over the line. Does this mean that the update loop itself is too slow to catch the point as is?

 

Not only is it extremely unlikely that you will ever catch the exact moment of being exactly on the line, but more importantly: floats don't care about math.

 

sqrt(9.0f) * 3.0f == 4.5f * 2.0f... right? Wrong! Or at least not something you can rely on, because floats don't have infinite precision and you could easily end up comparing something like 8.999999999999999999 with 9.0000000000000001 (which are obviously NOT equal).

 

I also find it very important to be very aware of the big difference between testing for intersection and testing for collision. While intersection tests are often part of collision tests, they are also generally not sufficient, unless you make sure they are (like using fixed time steps and paying close attention to the minimum size of all objects). Only testing "does the ball intersect the wall in the new position" is useless if your ball is moving so fast that the new position is already behind the wall. You also generally don't just need to know _if_, but also _when/where_ the collision happened to correctly handle it.




#5110091 Inventory System for Noom Text Adventure Game

Posted by Trienco on 17 November 2013 - 11:19 PM

Sounds like most of all you're trying to avoid an insane mess of flags and nested if-blocks.

 

If your items are only strings and you expect to get a ton of them, you can use a std::set, but I doubt you'll come up with enough items to the point where a straight forward std::vector<string> isn't good enough.

 

Your events sound a lot like growing tables and I'd probably try to model them just as such. Things will be relatively flexible if you go look into std::bind (or boost::bind if you're stuck with the old standard).

 

It would all boil down to create conditions, a result and going through that table. For simplicity, let's assume all condition functions take a Player*.

 

bool hasDefeatedDragon(Player* p) { return p->dragonSlayerFlag; }
bool hasItem(Player* p, const string& item) { return find(p->inventory.begin(), p->inventory.end(), item) != p->inventory.end(); }
bool healthIsBelow(Player* p, int threshold) { return p->health < threshold; }
 
typedef std::function<bool, Player*> ConditionFunc;
 
struct EventTableEntry
{
   EventTableEntry(ConditionFunc f1, ConditionFunc f2, ConditionFunc f3, Event event);
 
  //You can use a list or template the number of preconditions if needed or use a dummy condition "ignore" that always returns true as filler
  ConditionFunc conditions[3];
  Event event;   
}
 
//Now why use std::bind? Because for this to work, all functions need to be called in the same way. Bind allows you to set certain parameters at construction time of the function object, so you won't have to pass it as a parameter when you actually call it.
 
EventTableEntry eventTable[] =
{
   EventTableEntry(isHealthy, std::bind(hasItem, _1, "sword"), ignore, spawnSkeleton);
   EventTableEntry(...);
};
 
Event* getAppropriateEvent()
{
   for(auto e : eventTable)
   {
        if (e.condition[0](player) && e.condition[1](player) && e.condition[2](player)) return &e.event;
   }
   return nullptr;
}

 

It's all crude pseudo code and taking some shortcuts, but might demonstrate the idea as such.




#5101179 "built-in loop" question

Posted by Trienco on 13 October 2013 - 10:32 PM

The place to start is to learn and gain actual experience and knowledge as a programmer, which (as already mentioned) will usually take a few years before you move from "trial & error" coding to really understanding how and why it works. You can argue "you don't need to understand how an engine works to drive a car", but you're not aiming at driving (as a user, who doesn't care how a program works), you're aiming at building. Using pre-made parts doesn't free you from the requirement of understanding how they work together.

 

There is nothing wrong with making "pretend" tutorials, where you try to clearly explain how things work. As long as you DO try to explain it and research it until you have a good understanding of it as well (rather than just parroting what you read online). Yet, those tutorials should probably never leave your local hard drive, because I can guarantee you that one or two years from now, you will look at them and feel embarrassed about the kind of nonsense you made up to explain stuff (after all, you gave the best example yourself... that other guy is incomplete and superficial at best and flat out wrong and misleading... not even sure if "at worst" or "on average" is more appropriate).




#5100706 How do I use multithreading?

Posted by Trienco on 11 October 2013 - 10:13 PM

 

Don't detach, so you can call join right before you absolutely need the thread to be finished (which will automatically block until the thread is done, without requiring any silly contraptions of flags and condition variables and inter-thread communication non-sense).

I think he wants the main thread to still be running the interactive game loop for as long as is needed for this background thread to complete, and only once it's complete does the main thread make use of the results.

 

That would of course be a cleaner solution, but in the end, it requires an actual plan what to do if you ever run into this situation (and how much longer this processing might take). If we are talking about something that should almost never happen and the delay is maybe 2s or less, is it worth the extra complexity to... well, what would you do? Show a loading screen or some kind of "don't worry, I'm still alive"-swirly icon thing?

 

If the main thread should continue, even when the data is needed and not ready, I'd be lazy and just go with std::async so I can query if the returned std::future is done yet (or wait for it with a timeout). While a primitive flag should be thread-safe, as long as one thread is only checking and the other is only eventually setting it, actually waiting for it (for example with a short timeout) would require adding a condition variable, a mutex and the flag, just to basically reinvent what is already there.




#5100433 How do I use multithreading?

Posted by Trienco on 10 October 2013 - 10:00 PM

Ever since the days of boost::thread (and std::thread is almost exactly the same) has there be no reason to introduce crutches like static member functions (or any other kind of "forwarding" function). When passing a member function to std::thread, the first parameter is automatically considered the object instance.

 

Having the SIG parameter for the function is pointless and redundant (ALL non-static member functions are being passed an instance, even if the language is hiding it). As a result, the call would have had to be 

 

std::thread(&SOLARSYSTEMIMAGEGENERATOR::ImageGenThread,this,this)

 

In other words, do as Paradigm Shifter already said and remove the pointless SIG parameter, then your original call should work just fine.

 

You are also still detaching the thread, which makes me wonder why you even bother making it a member? Read up on what detach does. You will have zero control over your thread and the thread-object will not be linked to the actual thread anymore. Don't detach, so you can call join right before you absolutely need the thread to be finished (which will automatically block until the thread is done, without requiring any silly contraptions of flags and condition variables and inter-thread communication non-sense).

 

If you want it to be nicely encapsulated, you could use std::future as well, but since you have no return value and don't need to carefully query "are we there yet", it has no benefit over starting your thread and calling join by the time you finally need that data.






PARTNERS