Jump to content

  • Log In with Google      Sign In   
  • Create Account

Aardvajk

Member Since 02 Mar 2006
Offline Last Active May 02 2016 11:36 AM

#5288404 c++ should nested switch statements be avoided?

Posted by Aardvajk on 24 April 2016 - 01:43 AM

Here's one from the innards of my virtual machine for handling math operations (+, -, * and /) on an exploding number of combinations of different types. I don't think there is anything wrong with this personally, others might disagree.
 
template<class T> bool operation(State &state, const TypedValue &a, const TypedValue &b, TypedValue &c, Om::Value &res)
{
    switch(a.userType())
    {
        case Om::Type::Int:
        {
            switch(b.userType())
            {
                case Om::Type::Int: return op<T, int>(state, Om::Type::Int, a, b, c, res);
                case Om::Type::Float: return op<T, float>(state, Om::Type::Float, a, b, c, res);

                default: break;
            }

            break;
        }

        case Om::Type::Float:
        {
            switch(b.userType())
            {
                case Om::Type::Int: return op<T, float>(state, Om::Type::Float, a, b, c, res);
                case Om::Type::Float: return op<T, float>(state, Om::Type::Float, a, b, c, res);

                default: break;
            }

            break;
        }

        case Om::Type::String:
        {
            if(T::type == Addition && b.realType() == Om::Type::String)
            {
                c = TypedValue(Om::Type::String, state.allocate<StringEntity>(state.entity<StringEntity>(a.toUint()).text + state.entity<StringEntity>(b.toUint()).text));
                return true;
            }

            break;
        }

        default: break;
    }

    res = Om::ValueProxy::makeError(state, error(a.userType(), b.userType()));
    return false;
}
It is templated on structures like Add, Sub etc, so the same method can be used for all math operations via compile-time polymorphism.


#5287083 How beneficial can personal projects be?

Posted by Aardvajk on 15 April 2016 - 01:24 PM

My 2D platform game and level editor got me a job developing business software.

I wouldn't personally hire a programmer who didn't have personal projects. If all you showed me was coursework, I'd assume you lacked the passion we all share here.


#5287082 Is inheritance evil?

Posted by Aardvajk on 15 April 2016 - 01:21 PM

Of course it isn't. It's s tool that can be used or abused.

Even deep inheritance trees can be appropriate in certain domains. Look at something like Qt for example.

There is, though, a huge amount of very bad OOP out there and a great deal of confusion about the is-a and has-a relationships.

But inheritance itself is not the cause of this. Personally I blame Java :).


#5286744 How to handle a collision in a physics library and OOP?

Posted by Aardvajk on 13 April 2016 - 02:12 PM

It's pretty common for a third party physics library to use some kind of void user data pointer to allow you to link back a physics object to your game object and while this is generally a bit icky, it's not really solvable in any other general purpose way without introducing unnecessary overhead.

I tend to wrap the physics library (Bullet in my case) in my own thin wrapper that hides such activity away in a central place and makes it generally more compatible with the rest of my code. I dislike using a third party API directly in the parts of the code that just use the physics.

With the void pointer, I only ever assign one type of pointer to it, so in a way I (the programmer) do "know" the class type, even if the compiler doesn't. Rules like this are hard to treat as set in stone in the real world.

Rather than dynamic_casting to lots of different classes, can't you abstractify the things the physics needs to know about into the base class and just treat all your objects as this base inside the physics code? Seems unnecessary for the physics to need to know the exact class details for every object to me.


#5286320 Access violation reading location 0xDDDDDDDD.

Posted by Aardvajk on 11 April 2016 - 10:58 AM

Remember you are now responsible for deleting the Sprite when you are either removing it from the list or the list is destroyed, or you'll have memory leaks.

Modern smart pointers can automate this sort of thing for you.


#5277251 [BULLET] Various collision problems

Posted by Aardvajk on 21 February 2016 - 03:14 AM

Bullet's vanilla Kinematic Character Controller is far from finished and polished compared to the KCCs that ship with commercial engines. I've had to give up on it and roll my own (using the Bullet GJK and manually resolving collisions against a capsule shape) in my current Bullet project.

I keep promising to submit mine to Bullet but the problem is it is so tied up into my own wrapper system around Bullet it has hard to break it out, and it is only okay for my particular domain (Mario-style 3D platformer) and probably not of any use in any other context.

My advice - learn enough to implement your own KCC, based on Bullet's collision and ray test functionality so you can tweak it to suit your particular requirements. Not easy though - I had already implemented my own (very poor) GJK before I felt comfortable handing that over to Bullet for a stable result.

Some pointers on the way mine works - I have a capsule shape representing the character, and also constantly cast a ray down from its base to measure the distance to the floor, only applying fake gravity if the controller is above a certain threshold above the "floor" and snapping it to a fixed distance above the floor if within the threshold. This avoids the need to use any kind of friction to prevent slope sliding. I use the Bullet broadphase then the GJK pair test to get separation vectors against the world geometry for other collisions. There are some additional complications when penetrating into steep slopes that require a bit of vector math to figure out.

Massive code dump ahoy...
 
#include "Kcc.h"

#include "maths/Vec2.h"
#include "maths/Vec3.h"
#include "maths/Matrix.h"
#include "maths/Quaternion.h"
#include "maths/Ray.h"

#include "physics/Physics.h"
#include "physics/components/Body.h"

#include "debug/DebugRender.h"

namespace
{

float minFloorDistance(float radius, const Vec3 &normal, float margin)
{
    return sphericalDistanceToNormal(radius, normal) + (margin * 2);
}

RayResult findFloor(Physics &physics, float radius, const Vec3 &base)
{
    RayResult r = physics.rayCast(Ray(base, Vec3(0, -1, 0)), 100);

    if(r.valid() && dotVectors(r.normal(), Vec3(0, 1, 0)) >= 0.8f && r.distance() < minFloorDistance(radius, r.normal(), 0.15f))
    {
        return r;
    }

    return RayResult();
}

Vec3 alignToFloor(const Vec3 &velocity, const Vec3 &normal)
{
    return transformNormal(velocity, rotationToQuaternion(Vec3(0, 1, 0), normal));
}

float lockedY(const RayResult &r, float radius, float height)
{
    return r.worldPoint().y + minFloorDistance(radius, r.normal(), 0.05f) + ((height / 2) - radius);
}

bool lockToFloor(Physics &physics, Vec3 &pos, float radius, float height)
{
    Vec3 base(pos.x, pos.y - ((height / 2) - radius), pos.z);
    RayResult r = findFloor(physics, radius, base);

    if(r.valid())
    {
        pos.y = lockedY(r, radius, height);
        return true;
    }

    return false;
}

Vec3 slopeCorrection(const Vec3 &separation)
{
    float d = dotVectors(normalizeVector(separation), Vec3(0, 1, 0));
    if(d >= 0 && d < 0.8f)
    {
        return getDownVector(separation) * vectorLength(separation);
    }

    return Vec3(0, 0, 0);
}

Vec3 separatingVector(Physics &physics, const Shape &shape, const Vec3 &at)
{
    Vec3 result = at;
    Matrix to = translationMatrix(result);

    BroadphaseResult br = physics.broadphaseAabb(shape.aabb(to).expanded(2));

    if(br.valid())
    {
        int it = 0;
        bool loop = true;

        while(it < 5 && loop)
        {
            loop = false;

            for(auto &b: br.bodies)
            {
                ConvexResult r = physics.convexIntersection(shape, to, b->shape(), b->transform());

                if(r.valid())
                {
                    result += r.separatingVector();
                    to = translationMatrix(result);

                    loop = true;
                }
            }

            ++it;
        }
    }

    return result - at;
}

}

Kcc::Kcc(float radius, float height, const Vec3 &position) : pos(position), prev(position), shape(radius, height)
{
}

void Kcc::setPosition(const Vec3 &value)
{
    pos = value;
    prev = pos;
}

void Kcc::move(Physics &physics, MoveFlags flags, const Vec3 &step, float epsilon)
{
    Vec3 tp = pos;
    prev = pos;

    bool tg = gr;

    implementMove(tp, tg, physics, flags, step);

    if(vectorLength(Vec2(tp.x, tp.z) - Vec2(pos.x, pos.z)) >= epsilon)
    {
        pos.x = tp.x;
        pos.z = tp.z;
    }

    pos.y = tp.y;
    gr = tg;
}

bool Kcc::canMove(Physics &physics, MoveFlags flags, const Vec3 &step, float epsilon) const
{
    Vec3 tp = pos;
    bool tg = gr;

    implementMove(tp, tg, physics, flags, step);

    return vectorLength(Vec2(tp.x, tp.z) - Vec2(pos.x, pos.z)) >= epsilon;
}

float Kcc::distanceToFloor(Physics &physics) const
{
    RayResult r = physics.rayCast(Ray(pos + Vec3(0, -shape.height() / 2, 0), Vec3(0, -1, 0)), 100);
    if(r.valid())
    {
        return r.distance() + (shape.radius() - minFloorDistance(shape.radius(), r.normal(), 0.01f));
    }

    return -1.0f;
}

bool Kcc::booleanIntersection(Physics &physics, const Matrix &transform, const BodyFilter &filter) const
{
    return physics.booleanIntersection(shape, transform, filter);
}

void Kcc::implementMove(Vec3 &position, bool &grounded, Physics &physics, MoveFlags flags, const Vec3 &step) const
{
    bool flying = step.y > 0;
    float hh = shape.height() / 2;

    RayResult floor = findFloor(physics, shape.radius(), position + step + Vec3(0, -(hh - shape.radius()), 0));

    Vec3 dv(step.x, 0, step.z);
    Vec3 mv = floor.valid() && !flying ? alignToFloor(dv, floor.normal()) : dv;

    mv.y = step.y;

    Vec3 sep = separatingVector(physics, shape, position + mv);

    if(!flying)
    {
        mv += slopeCorrection(sep);
    }

    position += mv + sep;

    grounded = false;
    if(step.y <= 0)
    {
        grounded = lockToFloor(physics, position, shape.radius(), shape.height());
    }
}



#5277248 Correct way of doing Mouse Picking

Posted by Aardvajk on 21 February 2016 - 03:04 AM

If it helps, this is the code I use to compute a ray for picking (Direct3D9)
 
Ray Ray::compute(const Vec2 &pos, const Vec2 &size, const Matrix &view, const Matrix &proj)
{
    float w = size.x;
    float h = size.y;

    float sx = pos.x;
    float sy = pos.y;

    Vec3 v;
    v.x = (((2.0f * sx) / w ) - 1) / proj._11;
    v.y = -(((2.0f * sy) / h) - 1) / proj._22;
    v.z =  1.0f;

    Matrix m = inverseMatrix(view);

    Ray ray;

    ray.dir.x = v.x*m._11 + v.y*m._21 + v.z*m._31;
    ray.dir.y = v.x*m._12 + v.y*m._22 + v.z*m._32;
    ray.dir.z = v.x*m._13 + v.y*m._23 + v.z*m._33;
    ray.pos.x = m._41;
    ray.pos.y = m._42;
    ray.pos.z = m._43;

    ray.dir = normalizeVector(ray.dir);

    return ray;
}
pos is the mouse position on the screen, size is the width/height of the viewport. The ray returned has pos and dir and is in world frame. Matrix is just a typedef for D3DXMATRIX, Vec2 a typedef for D3DXVECTOR2 and Vec3 is a typedef for D3DXVECTOR3.


#5277009 c++ copy all data from parent class?

Posted by Aardvajk on 19 February 2016 - 01:13 PM

Could the OP give some more detail of what they are trying to achieve here? Something is badly wrong or maybe misunderstood about how C+++ works here I think.


#5269623 Criticism of C++

Posted by Aardvajk on 06 January 2016 - 08:36 AM

I'm afraid I found most of Mr Blow's justifications for his new language to be based on very strawman arguments. For example, when justifying his new ownership semantics, he says something like "Of course, you could use std::vector but nobody I know does that." Maybe his argument applies more against C, where templates are not available and ugly macro hackery or unsafe void pointers are the only way to write generic containers.

I take the point from the above poster about allocating two buffers in a single block of memory, but be fair, it isn't at all difficult to do this in C++ either.

I write languages for fun and there is always the temptation to think that your own could be useful to others, but its about so much more than a good language, as has been discussed. Its about existing codebase, existing developer skills and training, amount of learning resource available, availability of compilers etc.

I'm personally very happy working in C++11 and C++17 looks like its going to be cool too. I like the philosophy of don't implement something in the language that can be implemented in a third party language.

I'm well aware C++ has its issues, don't get me wrong, but as a familiar user, they very rarely cause me any problems.


#5266229 GUI elements whose positions depend on one another

Posted by Aardvajk on 14 December 2015 - 03:52 AM

The source code may be hard to follow, but I find Qt's layout systems hard to beat in terms of using them. I spend all day writing GUI-based applications, dialog boxes etc and I can't remember the last time I had to think about what specific position a control had to be in. You just describe the layout purely in terms of relationships and it all just works, including resizing and so on.

If I had to work without Qt in a GUI application again, the very first thing I'd do is try to replicate the layout system.


#5266227 how to search for a entity in a scene graph using c++ ?

Posted by Aardvajk on 14 December 2015 - 03:39 AM

How To Ask Questions The Smart Way


#5265108 Why didn't somebody tell me?

Posted by Aardvajk on 06 December 2015 - 02:21 AM

I still do a lot of old school debugging by pasting

MyDebug() << __PRETTY_FUNCTION__ << __LINE__;

throughout a file, then running it to find the crash point. Building our work exe with debugging info enabled takes ages and this is a quick way to find a crash point, although have been bitten by re-ordering issues like this.


#5264710 Did You Break in at an Older Age?

Posted by Aardvajk on 03 December 2015 - 01:56 AM

I should say I'm not a game programmer professionally, I write business software, but I got the gig purely as a result of a portfolio of hobby games writing I had been doing for twenty years or so and did my first day as a professional programmer at the ripe old age of 37.

Worked unrelated jobs (sales, business development, employment consultancy) for all my previous life, all while writing games for fun in my spare time and hanging around this website.

It can be done, you just have to get lucky with a gig. My current boss and colleagues are all also self-taught, passionate programmers which helps a lot. I doubt I would have got a job with a large company without a qualification or relevant experience.


#5261868 Need help with beginning game programming with C language

Posted by Aardvajk on 13 November 2015 - 01:57 AM

A couple of weeks, no programming before and they want you to use C? Wow.

Most people spend at least the first few months with C at the command line doing simple prints and input reads, just learning the nuances of the language.

I feel for you. Good luck. Sounds like your instructor has a strange approach.


#5261867 Model View Projection matrices

Posted by Aardvajk on 13 November 2015 - 01:54 AM

As has been pointed out, but will say again, model and projection matrices should have nothing to do with the camera. The camera should provide a view matrix. That's it.

An individual object should provide its own world matrix to be moved from model space to world space, and the projection matrix is likely to just be a constant for the lifetime of the game.

All the camera should be concerned with is using its position and orientation to provide a view matrix to take world positions to view space.




PARTNERS