# Kerndog73

Member

9

147 Neutral

• Rank
Newbie

• Interests
Programming

## Social

• Github
kerndog73
• Steam
ftw.kerndog73
1. ## Designing levels for a 2D puzzle platformer

Since originally posting this I've finished the platformer and I've started a new game. I found that the physics engine got in the way. There were a few puzzles that I wasn't able to create because of physics and lack of complexity in the game mechanics. This new game will have all the things! Basically, I'm going to take a box pushing game like this cinematic masterpiece and add in some mechanics similar to Minecraft Redstone. Using these new mechanics I can create puzzles like "press this button 4 times to move this box out of the way". There will be lasers that act a bit like trip wires. The kind of lasers that surround the golf ball sized diamond in sky movies. The player will have to push mirrors around to divert the laser to open a door (piston door). Maybe a piston pushes the mirror and the piston is activated by something. This way I can add stages to the level. Like "push the box into the pressure plate to open the door" then "press these buttons in sequence to move this mirror" then "go get that box you pushed into the pressure plate and push it into this other pressure plate". This was difficult in the platformer because of the size of the level. In a platformer, you have to waste a lot of space moving the player around. Also, logic was hidden in the platform. There are AND gates and XOR gates and NOT gates all over the place but the player can't see them, so the player has to guess what they are supposed to do. In the new game, the player can see the logic gates and think about what they should do, rather than guess. Dramolion, I like the mirrors idea and the destructible box idea sounds interesting. Some more ideas for game mechanics would be appreciated as I convert the whiteboard scribbles into C++.
2. ## Designing levels for a 2D puzzle platformer

I agree with everything you said. The levels are a single screen. I've found that similar games also have a static camera. A side-scrolling camera is for exploration and adventure. I spent about a week on the level editor but I never actually ended up using it. Currently, I use a scripting language called jsonnet which compiles into json. Using a scripting language allows the levels to be configurable. If I were to use a level editor to make level 9, I wouldn't be able to quickly change the numbers. With a scripting language, all I have to do is type the numbers into a file, recompile the level and then reload the level and the numbers change right before my eyes. Using a level editor might be a little faster but putting the levels into the computer but that is not the bottleneck. Designing the level takes much longer than putting it into the computer so the level editor won't save time anyway. The level editor is rather difficult to use. It's not too much different to typing into a file. The user just types into some very nice looking forms that validate input rather than a text file with a compiler that gives some less helpful error messages. The first 5 or so levels are actually exactly as you described. I've taught the player all of the mechanics of the game in the levels I have already created. Pressing R will instantly reload the level so the player doesn't have to wait around and get frustrated. Also, the level is actually reloaded directly from the file (not cached) so level testing is super quick. There are fours ads for books about game design right below my initial post.
3. ## Designing levels for a 2D puzzle platformer

The Problem I'm creating a 2D puzzle platformer and I'm having a little trouble creating the levels. I've created 10 levels and they're kind of boring. I was aiming for difficult puzzles that get the player thinking. The levels I've created aren't difficult, they're just long-winded. The player just looks at the level for a few moments and then thinks "Oh, so I just have to do this, this and then this". The longest levels take about 10 seconds of thinking and 3 minutes of running around. I'm not sure if just bad at making puzzles or there is a flaw in the design of the game. The Game Design Each level is kind of like a machine that the player must manipulate to create a path to the exit. The player can do all of this: toggle switches hold down buttons push boxes collect keys open locks with keys trigger laser sensors All of these things are inputs into the machine that is the level. There are also entities that take input. These entities can take multiple inputs and perform a logic operation on them. For example, a door can be open if switch 2 is on NOR switch 3 is on. The entities that can be activated by inputs are: moving platforms laser emitters doors Is there anything wrong with this? Does it lend itself to fun levels? Example: level 7 I think this level is the most fun of all the levels I have made because it is the least obvious what the player must do. The player might look at the button above (bottom left) and just see what it does. The player presses the button and a box moves. "So all I have to do is press all the buttons?". The player jumps up to the next closest button (top left) but it doesn't do anything. "Wait, what?". The player will then jump around pressing buttons before realizing "Oh, the buttons have to be pressed in order". Then the door opens and the exit is accessible. Example: level 9 This level is easy and long-winded the player must toggle all of the switches from 0 to 9. Unlike level 7, if they make a mistake, they must reload the level. Most consecutive numbers are on opposite levels so the player has to spend a lot of time waiting for the elevator and traveling on the elevator. I can easily change the numbers by just editing 2 lines of a script so I could make it less long-winded. Conclusion I can't seem to be able to create levels that are any more fun than level 7. Is the design of my game flawed or am I just bad at making levels? Can anyone offer me some tips on making difficult levels for puzzle games? Can anyone offer me a few ideas for entities that might make the game more fun? Does anyone have any ideas for complex machines that I could build that are fun to interact with? Thank you for reading this monster of a post. I'd love to hear your suggestions.
4. ## When should fonts be rendered?

@Happy SDE I thought my current approach would decrease start-up time. Isnt loading an image faster than rendering glyphs onto a texture?
5. ## When should fonts be rendered?

In my system I have a tool that renders fonts and creates an image file and an atlas file which my game engine then loads. Is this the right way to do things? Should I render the fonts at runtime instead?
6. ## Skeletal Animation with ASSIMP

IT WORKS! (For real this time) The reason only the first boneID boneWeight pair were being sent to the shader is because i was using an array attribute. I looked at the man page for glVertexAttribPointer and the size parameter can only be 1, 2, 3 or 4. So its only surposed to be used with a vector and i was using an array. The elements of an array have separate locations so when i was calling glGetAttribLocation i was getting the location of the first element in the array so when so the other elements never got enabled by glEnableVertexAttribArray so they were being set to 0. So a quick and easy solution is to replace the arrays with vectors and everything works fine but a proper solution is to use an array and make some additional calls to glVertexAttribPointer and glEnableVertexAttribArray. I'm glad I struggled through this problem because I learnt a lot about OpenGL.
7. ## Skeletal Animation with ASSIMP

I just ran Kaiser Johan's shader code and it produces the same results as mine did but then i ran this mat4 boneTransform = bones[boneID[0]] * boneWeight[0]; And i produced the same result. So then i ran this mat4 boneTransform = bones[boneID[0]]; And it also produced the same result. So final i ran this mat4 boneTransform = bones[boneID[0]] * boneWeight[1]; And the screen was red so I've come to the conclusion that the boneWeight array is a 1 followed by three 0's. This explains the jagged ness near joints because the bones arent mixing.
8. ## Skeletal Animation with ASSIMP

When i try that the shader program fails to link. The info log doesnt tell me why. Thats strange! Maybe my Intel HD Graphics 5000 has a limit to the size of vertex shader input? Thanks for your suggestion.
9. ## Skeletal Animation with ASSIMP

Its not over yet. I noticed that Bob's arms were a bit jagged and at first i thought it was just the mesh but i looked closly and i saw right angles where there shouldnt be right angles. I loaded up NightWing doing gangnam style and it had the same problem. There must be something wrong with the bone weights or maybe the vertex shader.
10. ## Skeletal Animation with ASSIMP

IT WORKS! The problem was in the makeMat function. I was multiplying the matricies in the wrong order. Here's the new working makeMat function. glm::mat4 makeMat(const glm::vec3 &translation, const glm::quat &rotation, const glm::vec3 &scaling) { //scaling rotation translation return glm::translate({}, translation) * glm::scale( glm::mat4_cast(rotation), scaling ); } I'm pretty sure this is multiplying scaling, then rotation, then translation (but I was pretty sure about the last one as well!). Am I right?
11. ## Skeletal Animation with ASSIMP

I'm trying to play a skeletan animation with ASSIMP and I can't quite get it to work. I've been stuck on this for about a week and I've got it looking pretty close to what it should. It's a big improvment over a tangled up mess. I've attached a video of what it looks like as well as a screenshot in bind pose. It's strange how the bind pose is higher up. This is what it should look like Translation seems to be the problem. Could I be multiplying the matricies in the wrong order? Is the skinning shader inccorrect? Here's the vertex shader #version 410 const uint MAX_BONES_PER_VERTEX = 4; const uint MAX_BONES = 128; uniform mat4 model; //transpose(inverse(model)) uniform mat4 transInvModel; uniform mat4 mvp; uniform mat4 bones[MAX_BONES]; in vec3 pos; in vec3 normal; in vec2 texturePos; in uint boneID[MAX_BONES_PER_VERTEX]; in float boneWeight[MAX_BONES_PER_VERTEX]; out vec3 fragPos; out vec3 fragNormal; out vec2 fragTexturePos; void main() { mat4 boneTransform; if (boneWeight[0] == 0.0) { boneTransform = mat4(1.0); } else { boneTransform = mat4(0.0); for (uint i = 0; i < MAX_BONES_PER_VERTEX; i++) { boneTransform += bones[boneID[i]] * boneWeight[i]; } } gl_Position = mvp * boneTransform * vec4(pos, 1.0); fragPos = (model * boneTransform * vec4(pos, 1.0)).xyz; fragNormal = normalize((transInvModel * boneTransform * vec4(normal, 0.0)).xyz); fragTexturePos = texturePos; } Heres the code that multiplies that matricies. I'm not really sure about it. I think the problem is here. I've brocken it up into 3 stages. The first stage interpolates the translation, rotation and scaling keys of the animation channel (aiNodeAnim) of each bone node (aiNode). An animation (aiAnimation) doesn't necisarily have a channel for each bone node (aiNode), so "dummy" channels fill in the gaps (I could use a std::unordered_map but most of the time there won't be any "dummy" channels). The arrays can be indexed by their channel ID (aiString name). std::vector<glm::mat4> getBoneNodeTransforms(const BoneNodes &boneNodes, const Animation &anim) { std::vector<glm::mat4> boneNodeTransforms(boneNodes.size()); for (ChannelID c = 0; c < boneNodes.size(); c++) { const Channel &channel = anim.channels[c]; if (channel.dummy) { //transform is the mTransformation member of aiNode boneNodeTransforms[c] = boneNodes[c].transform; } else { //getKeyTransform does the interpolation and constructs the matrix //I've tested it and it works as expected boneNodeTransforms[c] = getKeyTransform(channel); } } return boneNodeTransforms; } I'm not completly sure I'm multiplying the translation, rotation and scaling matricies in the right order so heres the function that does that. It's called by getKeyTransform. I'm pretty sure its multiplying rotation then scaling then translation but is that the right order? Should it be scaling, rotation, translation? glm::mat4 makeMat(const glm::vec3 &translation, const glm::quat &rotation, const glm::vec3 &scaling) { //rotation scaling translation return glm::translate( glm::scale( glm::mat4_cast(rotation), scaling ), translation ); } The second stage traverses down the tree of bone nodes (aiNode) and multiplies each node's transformation by that of it's parent. This is the code I'm least certain about. transforms is the return value from getBoneNodeTransforms. I've seen that most people traverse up that tree. Isn't that less efficient because you're multiplying the same matrices more than once? void relativeTransforms(std::vector<glm::mat4> &transforms, const BoneNodes &boneNodes, ChannelID parent) { const BoneNode &parentNode = boneNodes[parent]; for (size_t n = 0; n < parentNode.children.size(); n++) { transforms[parentNode.children[n]] = transforms[parent] * transforms[parentNode.children[n]]; relativeTransforms(transforms, boneNodes, parentNode.children[n]); } } The third stage multiplies each transformation by the offset matrix. I'm not entirly sure what the offset matrix is. There are more bones (aiBone) than there are bone nodes (aiNode) so each bone holds the channel ID so it can find its corresponding bone node. void finalTransform(const std::vector<glm::mat4> &transforms, const Bones &bones) { std::vector<glm::mat4> boneTransforms(bones.size()); for (size_t b = 0; b < bones.size(); b++) { const Bone &bone = bones[b]; boneTransforms[b] = transforms[bone.channel] * bone.offset; } return boneTransforms; } This code calls the above 3 functions and the final vector of matrices get sent to the vertex shader. std::vector<glm::mat4> boneNodeTransforms = getBoneNodeTransforms(boneNodes, anim); relativeTransforms(boneNodeTransforms, boneNodes); return finalTransform(boneNodeTransforms, mesh->getBones()); Another place the problem might be is in this function which converts an aiMatrix4x4 to a glm::mat4 glm::mat4 castMat4(const aiMatrix4x4 &aiMat) { //transposed return { aiMat.a1, aiMat.b1, aiMat.c1, aiMat.d1, aiMat.a2, aiMat.b2, aiMat.c2, aiMat.d2, aiMat.a3, aiMat.b3, aiMat.c3, aiMat.d3, aiMat.a4, aiMat.b4, aiMat.c4, aiMat.d4 }; } Could the problem be somewhere else? Maybe in the mesh loader? Thank you to anyone who read through the whole post and thank you to anyone who can offer some help.