Jump to content

  • Log In with Google      Sign In   
  • Create Account

Journal of Aardvajk

Bow and Arrow beginnings [updated]

Posted by , 05 November 2016 - - - - - - · 1,512 views

I've been working a little bit on the view mode with the bow this week. Not spent a lot of time on it but Saturday morning seems to be a good time to update my journal since I have an hour to work on the game and can't really get into anything else properly, so we are only about half-way through this.

Attached Image

This is the camera view with the bow attached to the hand. The bow is just attached same as on my previous entry and there is a new animation to switch into when in this mode. Here it is set up in Charm, the model and animation editor.

Attached Image

In motion, we apply the up/down rotation from the view to the Chest rather than the Head of the character now, which moves the arm as well as the head, meaning the bow continues to point where you look.



I should say I'm entirely unhappy with the quality of the graphics here. Need a much more detailed hand for example. I'm toying with the idea of using a different model for the view mode and normal mode, although that will present difficulties of its own so it may just be we have to suck it up and build a higher-resolution model for the player. The current model is very low poly, which is fine from a distance, but this was always just a stop-gap model anyway and not the final for any game.

I need to make a decision about the arrow. Do I attach it to the other hand, and move it into position using the draw animation, then use this to inform the initial transform of the arrow when it is "fired", or do I keep the arrow completely separate and just ensure by tweaking the bow animation that the arrow rests in the right place when being drawn back?

I can see pros and cons to both approaches really. One thing that is nice is that, either way, it will be trivial to swap out the bow and the arrow meshes for other ones, so once this is working it will be easy to have a sort of Thief/Thief 2 style bow and arrow system with different bows and arrows having different abilities and powers.

It is all a bit fiddly though. I'm going to live with the crappy graphics for now until I have the actual system working the way I want. I don't think my attachment system is working quite right and need to iron out some issues there - seems the initial transform I apply to the bow in object space is somehow causing some drift in the position when in aiming mode which must be a simple enough issue to find and fix.

Sure it will all come together in the end, and it will be very satisfying to fire that first arrow into the world.

[UPDATE]

Thought it wasn't worth a new entry for this, but I've added an arrow mesh now. Threw a very quick arrow model together in Charm.

Attached Image

I decided to go down the route of attaching the arrow to the other hand, so it can be guided into place using the animation. Took some fiddling around to get it right but seems to work okay.

 

The video below shows a special external view of the animation first, then switches to what you would actually see in-game, with the camera moving to the over-the-shoulder view.



It is actually two animations, one moving from idle to the bow drawn position, then another animation all in the bow drawn position with a tiny amount of breathing added. This is the further modified by applying a portion of the up/down rotation of the camera to the Chest bone of the player.

 

To get this working, I had to add a facility to my animation system to set an animation to looping or non-looping. They were all looping before, which was wrong here as it was switching briefly back to idle then back into bow drawn when the animation event fired on the EnterBowDrawn animation.

 

It was quite scary how little I could remember about how that code worked and was quite good to revisit it. Have used it extensively for a year or two, but not actually opened the source files in almost as long :)

So the theory is now that when the player presses the Fire key, we take the current matrix being applied to the player's arrow and pass this to a system that spawns an arrow to be fired off into the world.

 

This matrix should generate both the start transform of the new arrow as well as its movement vector, since we know the arrow is pointing straight down in local space, so transforming (0, -1, 0) by the matrix should give the direction vector for the arrow as well. You can just see the green line I've added to the below.

Attached Image

Here we are taking the transform and using it to generate a vector from the tail end of the arrow ((0, 0, 0) in local space of the arrow model) and extending it out via a directional vector.

void Pc::prepareScene(SceneParams &params, float blend)
{
    KeyFrame key = machine.generateKeyFrame(blend);

    // snip

    Matrix am = data.animation.skeleton.placementTransform(data.animation.skeleton.index("Right Hand"), identityMatrix(), world);
    arrow->setTransform(am);

    Vec3 d = transformNormal(Vec3(0, -1, 0), am);
    Vec3 p = transformCoord(Vec3(0, 0, 0), am);

    debugAddLine(p, p + (d * 4), makeColor(0, 255, 0));
}
We will on the same frame just hide the player arrow and we should be ready to go.

Need to design up some kind of inter-system communication for this that will extend to other things. Not sure on the details of this yet as I need to think about what else it is likely to be used for.

Thanks for stopping by as usual and hope this was of interest.




View Mode implementation and wittering

Posted by , 29 October 2016 - - - - - - · 1,119 views

Now I have a chase camera working that can be assigned to move to different targets, I've been working on a "view mode" for the player. Holding down the right-mouse button moves the camera to a shoulder-view mode so the player can look around.

Attached Image

Here I have put the camera in a position right behind the head, so that you can see in more detail that the orientation of the head changes to match the direction you are looking. You'll see this first in the video later, then it switches to the real shoulder-view mode which is just above the right shoulder but the head animation is less obvious.

To implement the head animation, I now generate my animation KeyFrame inside the PcStateMachine.

void Pc::prepareScene(SceneParams &params, float blend)
{
    KeyFrame key = machine.generateKeyFrame(blend);

    data.animation.skeleton.setKeyFrame(key);

	// snip
}
We can then generate the key frame from the animation as usual, but apply further modifications to it before we return it.

KeyFrame PcStateMachine::generateKeyFrame(float blend)
{
    KeyFrame key = data.animation.controller.keyFrame(blend, data.animation.map);

    if(curr == PcState::Looking)
    {
        key.transforms[data.animation.skeleton.index("Neck")].rotation *= axisRotationQuaternion(Vec3(-data.ang.value(blend).y, 0, 0));
    }

    return key;
}
We can save time by looking up the "Neck" index ahead of time. Bone names are set in Charm, the model editor, and are stored as part of the binary model format to avoid working directly with numeric indicies. Here we just apply an extra bit of rotation to the neck based on the accumulated angle we are looking in, which is stored in PcData::ang, a BlendVec2.

So we can do whatever we want to here, depending on the current internal state of the PcStateMachine and PcData.

The player rotates horizontally to match the angle you are looking at, and because the view down is limited, there is no need for a foot animation to show this turning action. When you release right button, the camera pulls back out and you are facing whatever direction you last looked in.

void PcStateMachine::updateLooking(GameState &state, float delta)
{
    Vec2 a = data.ang.value();
    a.x += pi();

    data.rot = FadeValue<Quaternion>(axisRotationQuaternion(Vec3(0, a.x, 0)));
}
As above, PcData::ang is the accumulator for the angle the camera is looking in and PcData::rot is a quaternion representing the direction the actual player is currently facing, so when looking, changing one updates the other.

Here is all of this in motion.



While this is a nice feature on its own for looking around in the game, it is also prepartion for the bow aiming mode I plan to tackle soon. When the player is holding a bow, view mode will include moving into a bow-drawn animation, and the arm will move with the head to point the bow at whatever point is looked at. Hopefully the position of the camera will mean I can get away with just a partial animation for aiming the bow, and the superimposing of an arrow mesh over the top. We shall see how this works out.

There are some issues at the moment with the camera intersecting the player model, and indeed have always been issues with the camera intersecting the level geometry that I haven't quite decided how to tackle yet. One approach might be to just model the camera as a sphere, and add the minimum separation vector for the sphere to the final camera position each frame but that could lead to some nasty jumps.

I don't really want to have to apply full path-finding logic to the camera. A possible solution might be to detect when the camera is jumping beyond a certain threshold and then apply a very fast fade-out/fade-in effect to cover the jump. Need to just try a few different approaches and see how they look.

 

Thanks, as always, for stopping by and I hope this was of interest to someone.




Rag Doll is back

Posted by , 23 October 2016 - - - - - - · 991 views

Just a quick post to say I've re-integrated my rag doll system back into the current iteration of the game. This is based on making a set of Bullet shapes from the current skeleton configuration on the fly, then handing control of these over to Bullet.

New feature here is that the new chase camera system then continues to follow a particular shape seamlessly when you "die".

 

Attached Image

The first half of the video below is as the player will see things, then I run through some death sequences again with some debug drawing on, so you can see the relevant shapes. While the player is alive, the large capsule is the kinematic shape that is handled manualy by the character controller system, just using Bullet to do manual intersection tests, then when in rag doll mode, Bullet is handling the whole thing.



I had all this working before so was just a case of re-writing the integration code, which happens at quite a high level so that the entire PcStateMachine code is not run once the rag doll has taken over. I just had to add some simple methods to the rag doll to extract the position of a particular shape from the current position to feed to the chase camera system.

Not much else to report at the moment. I'm going to look at working on a "view" mode next, whereby if you hold down the right mouse button, the camera mode switches to a behind-the-shoulder view and you can then rotate the player by moving the mouse and look up and down in more detail, in preparation for the bow-aiming mode but I'm not quite sure how this is going to work yet.

The player logic has become split over quite a range of areas and it is sometimes hard to know what should go where so constant refactoring is happening here.

Thanks as usual for stopping by. Your interest is much appreciated.




Mumbling about the Camera system

Posted by , 16 October 2016 - - - - - - · 2,305 views

In preparation for being able to do some stuff with the bow aiming, I've ripped out and rewritten the Camera system for the game. I've split what was one system into two classes now, ViewTransform which represents a position and orientation for a point of view with the orientation being represented by a quaternion and a Camera class which takes care of moving between a current and a target ViewTransform and providing a current view matrix based on its internal state.

 

In the video below, you can see that we have manual control of the camera while holding the right mouse button down, but pressing the N and M keys set hard-coded targets for the camera at opposite ends of the map which the camera will move to whenever those keys are pressed. All can be interrupted by the others at any point.

 

 

ViewTransform allows us to think in terms of both rotation (quaternion) and angles (x, y rotations) but keeps all its rotations stored in a quaternion to make interpolating between two ViewTransforms a breeze.

 

class ViewTransform
{
public:
    ViewTransform();
    ViewTransform(const Vec3 &pos, const Quaternion &rot);
    ViewTransform(const Vec3 &pos, const Vec2 &angle);

    Vec3 position() const;
    void setPosition(const Vec3 &value);

    Quaternion rotation() const;
    void setRotation(const Quaternion &value);

    Vec2 angle() const;
    void setAngle(const Vec2 &value);

    void flatVectors(Vec3 &look, Vec3 &right) const;

private:
    Vec3 pos;
    Quaternion rot;
};
Camera just maintains a current ViewTransform and an optional target transform and, depending on its mode, will work out the current interpolated ViewTransform between the two.

 

class Camera
{
public:
    Camera();

    enum class Mode { Manual, Tracking, Null };

    void store();
    void update(float delta);

    ViewTransform transform() const;
    ViewTransform transform(float blend) const;

    void setTransform(const ViewTransform &transform);
    void setTarget(const ViewTransform &transform);

    Mode mode() const;

    Matrix viewMatrix(float blend) const;
    Vec3 position(float blend) const;

private:
    Mode md;

    ViewTransform cur;
    ViewTransform tar;

    BlendFloat t;
};
We don't really need to go into details here. It is all quite fire-and-forget really. When the camera is in Mode::Tracking, it is moving between a current and a target position, otherwise what it returns is just based on the current position.

 

The flatVectors() method is used when the player works out what direction to move in based on the current orientation of the camera. Eventually we'll replace this with some kind of chase camera system.

 

So before I can get into the bow drawing and other combat camera activity, I think I need to get the normal chase camera system working. Not sure hwo this should work yet.

 

There is the original Tomb Raider system of the camera trying to stay behind the player at all times as the player rotates, or the newer Tomb Raider system whereby the camera stays a fixed distance from the player, but the controller controls the angle of the camera by rotating left and right and up and down, then movement is always in the direction of the camera towards the player. Not sure which is better here.

 

I'm already finding it difficult to track how this should work across all the different units that look after the player now. There is Pc which is the highest level unit that connects the player to the Entity system, the PcData unit which is owned by the Pc class and provides all the state to the PcStateMachine class which looks after switching the player into all of its different states.

 

Hard to get a good overview, especially on a weekend morning when I'm half-asleep which is when I am doing most of the work on this these days :).

 

I'll post this now and then have some time to reflect I think. Sorry if it is largely mumble. That is how it is in my head at the moment.

[LATER EDIT]

Woke up a bit as the day wore on and managed to figure out what I needed to get the basic chase camera working, as per this video:



It was quite a lot easier than I expected actually. You'll see I've opted for the version where the player controls the rotation with the mouse and the direction the player runs in is relative to whatever direction the camera is currently facing. Feels quite nice and natural.

Using the targetting system here, so there is a small delay between the player moving and the camera tracking actually leads to a nice smoothing out of the camera motion which I personally find quite pleasing.

I'm going to fiddle about a bit more with this, see what else I can do with this system. Been meaning to get round to getting the chase camera working for months though, so a significant step here.

Thanks for stopping by.




All Kitted Up

Posted by , 07 October 2016 - - - - - - · 1,067 views

Attached Image

 

Decided to take a break from player/world interactions and look at something I've never tried before, namely attaching objects like weapons to the player skeleton.

 

 

The implementation took a bit of messing around and educated guesswork to get it right. Because my game has my own hand-rolled implementation of a skeleton animation system, I was able to extend the Skeleton interface to support this.

class Skeleton
{
public:
    // snip

    void setKeyFrame(const KeyFrame &key);
    const MatrixPalette &palette() const;

    Vec3 bindPosition(uint index, const Matrix &world) const;

    Matrix placementTransform(uint index, const Matrix &offset, const Matrix &world) const;

	// snip
};
With the new placementTransform() method, you pass in the index of the bone (which can be first looked-up by name), an initial offset matrix to apply to the weapon mesh in its local space and the current world matrix of the player. The result is the matrix you need to set as the transform on the weapon.

 

So, for example, inside the player character's code, we create the bow mesh on startup and add a scene node linking the bow mesh to the scene. You can have as many scene nodes linked to the same mesh as you wish in my system, each with its own transform and visibility status and so on.

 

We can then use the above Skeleton::placementTransform() method to assign the bow's scene node the correct transform inside of the player's prepareScene() method.

void Pc::prepareScene(SceneParams &params, float blend)
{
    KeyFrame key = data.animation.controller.keyFrame(blend, data.animation.map);

    data.animation.skeleton.setKeyFrame(key);

    Matrix world = rotationMatrixFromQuaternion(data.rot.value(blend)) * translationMatrix(pos.value(blend) + data.settings.positionOffset);

    mesh->setTransform(world);
    mesh->setPalette(data.animation.skeleton.palette());

    uint leftHand = data.animation.skeleton.index("Left Hand");
    Matrix initialLeft = translationMatrix(Vec3(-0.1f, 0.05f, 0));

    bow->setVisible(true);
    bow->setTransform(data.animation.skeleton.placementTransform(leftHand, initialLeft, world));
}
So we take the current interpolated KeyFrame from the animation controller and apply this to the player's Skeleton which then generates a matrix palette for the shader skinning. But we can also now query the Skeleton for the placement matrix for the left hand, for example, and apply this to the scene node representing the bow.

 

The placementTransform() method is implemented quite simply.

Matrix Skeleton::placementTransform(uint index, const Matrix &offset, const Matrix &world) const
{
    return offset * translationMatrix(bindPosition(index, identityMatrix())) * palette()[index] * world;
}
First we do the local offset transform on the object in local space. The bindPosition() method returns the position of the bone in the bind pose, which is multipled by the relevant matrix from the skinning palette to move it to the current KeyFrame position. Then finally we multiply the result by the overall world matrix of the character.

 

For simplicity, the weapon meshes are defined with their local origin being the middle of the point at which they are held and rotated so that they match the player in bind pose. We can then tweak this transform with a hardcoded offset matrix to get the position looking visually correct, moving them slightly depending on which hand is holding them for example.

 

The big challenge, of course, is coming up with animations for attacking, drawing the bow and so on that look good. My 3D model editor, Charm, has a pretty comprehensive animation system for creating these, but my lack of artistic talent is working against me here. Still, we'll see how it goes. Need to decide on how the combat system is going to work before I can do this anyway.

 

Hope this was of interest to someone. This project is almost entirely hand-rolled due to my coding masochism so if there are any specific aspects of this project that people would like to know more about, please just let me know.

 

Thanks, as always, for stopping by.








December 2016 »

S M T W T F S
    123
45678910
11 121314151617
18192021222324
25262728293031

Recent Entries

Recent Entries