Jump to content

sjg

Members
  • Posts

    16
  • Joined

  • Last visited

Everything posted by sjg

  1. I had a similar thing where I wanted to display Cyrillic characters, and in the end I rolled my own bitmap font and used the DrawImage function to get them to the screen. Granted, it wasn't cheap (in that there was a bit of an FPS hit), but it did what it said on the tin.
  2. Thought I'd share this as someone might find the topic interesting or even useful. My project includes a random terrain/flora generator which creates the game area on the fly from a bunch of functions. However, I'm inexperienced with mathematics and don't know how to calculate the distance from say, the bottom of an entity to whatever brush is below it, so I did things the way they would happen in the real world: with gravity. I simply spawned a bunch of ents & props in the air, and let them land. Then, I added a hook to each entity so that when they hit the ground for the first time, it marks the time. After a certain period since marking, the collision hook is removed, the entity's mass is set to 0, it's rotated upright and to a random Y rotation, shadow mode to static and the collision type set to Collision::Scene. A brush is then created at the bottom of the model, is given an appropriate shape, and then its material is set to one with a 16x16 texture of alpha-transparency, giving the illusion that the scene prop has a solid body, but without calculating any gravity. Or something like that. It was a few days ago and I didn't document exactly WHY I had to use a brush with an invisible texture but it made sense at the time. I must have tried it with a pivot + shape and had no luck for whatever reason. Anyway here's a video of the terrain generation in action, over and over again. Usually I hide the loading and falling behind an opaque splash screen, but I also put together a simple fade in/out system. Much like the splash screen it's mostly there to distract the eye; the duration is easily changed but I haven't altered it recently so it's still pretty obvious. So, what MacGyver-y "hacky" tricks do you pull? I'm always fascinated by others' creativity when it comes to solving problems. Edit: Just realised I posted this in General Discussion and not Off-Topic. My mistake!
  3. Solved the last post's question with the help of the forums. Moved on to terrain generation. As I'm going for an angular, cartoony feel, I decided a reasonable way to generate my terrain (for now) would be to do it procedurally with a ton of brushes and models (for flora) placed at random at runtime. I'm using the default assets at the moment as I've been procrastinating in making my own (apart from the font and the chickenman model), so all the terrain is grass01. Note the sneaky fade in. I realised that I had no way of finding the heights of the blocks readily, so I bunged a bunch of trees and bushes in the air and let gravity find the heights for me. The fade in disguises not only things falling, but the trees needed to be repositioned on the Y-axis as the roots were showing, so the fade in is long enough to disguise that as well.
  4. Yeah, I checked it more or less as such, but the thing I hadn't taken into account was that if they're standing back to back it's also -1. That's why I had to also chech which side of the player was closest to the other entity. As I mentioned, I'm not much chop when it comes to mathematics, I tend to MacGyver my way through that area. That's been slowly changing since I got into programming; I come from a musical background. Here's what I tested for after I worked out which entity was closest to the player. I don't usually comment my code but there is a shoutout. if (closest != nullptr) { double testIfFacing = facingDirection.Dot(closest->getFacingDirection()); // 1 same, -1 opposite... cheers once again, josh offset = body->getChestPivotLeft()->GetPosition(true) - closest->getBody()->getMainPivot()->GetPosition(); distance = std::sqrt(std::pow(offset.x, 2) + std::pow(offset.y, 2) + std::pow(offset.z, 2)); offset = body->getChestPivotRight()->GetPosition(true) - closest->getBody()->getMainPivot()->GetPosition(); double distance2 = std::sqrt(std::pow(offset.x, 2) + std::pow(offset.y, 2) + std::pow(offset.z, 2)); bool distanceTest = Leadwerks::Math::Min(distance, distance2) < closest->getDistanceFromPlayer(); if (testIfFacing <= -0.6 && distanceTest) { // tweak this setConTarget(closest); } } edit::WHOA, just caught a massive bug. Glad I pasted that in a public forum. Fixed. Whew.
  5. I did it! Not only that, but also in the most immature way possible. First I thought trigonometry could help me... somehow. I'm horrible at maths, so I abandoned that idea. Then I remembered there was more than one way to skin a cat. I went back to the old idea of bolting a pivot onto the front of an entity, but this time I used two empty ones, slightly offset on -x and +x, and I did a check to see which was closest to the target entity: the left pivot, the right pivot, or the main pivot; this told me in a very cheap and nasty way if the target entity was in front or behind the player (or whatever entity for that matter). Couple that with the priceless "facing directions dot product" tip, and I now have something that can be used every game loop frame.
  6. Whew! So far I've done what Josh recommended and I'm also reading up on how to use Pick()... still trying to get my head around it, as I've never really used anything like it before. Josh's suggestion works well, but I'm missing something in my implementation of it because it returns a lot of (not false) positives (such as in the case of two entities standing back to back - they're close and facing opposite directions, after all). It's probably simple to narrow it down, it's just not apparent to me right at this second. Thank you for the swift suggestions! You'll make a man of me yet.
  7. I'm working on finding a better way to find out if two entities are (a) close to each other and (b) facing each other. Initially I thought it was a good idea to bolt a trigger onto them, offset on the local Z-axis and have each entity "carry" one around in front of them but I've now noticed that the physics timestep doesn't line up with the UPS, so if the framerate goes above 60 or so, my game loop doesn't detect a collision during some of those frames. It's probably an overly expensive way of calculating it as well. Ideally I'd like to have some simple detection happening that ticks those first two boxes above, but which I can put in my game loop so it's called once each App::Loop frame, rather than with a collision hook which is only called every physics update. I'm reasonably new to programming (a year or so) and haven't done much in the way of game stuff before, so there are a lot of concepts I'm ignorant about, but is raycasting something I should be reading up on to help me with this or am I barking up the wrong tree?
  8. As an update on last night's post (or yesterday's, depending where you are), I've worked out a rudimentary system to detect if entities are within speaking distance (and in the correct direction) of each other. I cheated a bit and did it all manually in the above video; there was no checking to see if anyone was in the right place when the in-game conversation was triggered. You can see today's work in action here: So, my overly complicated solution was to create a custom wrapper for a pivot (which has a shape set to be a trigger), adding a hook to the collision checker. We'll call this "ConTrig", because that's what I called it, plus it differentiates it. Now, each of my "Conversationalist" entities has a main "character" pivot with a shape attached which is used for general physics/movement/etc, but I added this "ConTrig" to each Conversationalist. The "ConTrig"'s pivot entity not only has a box shape attached to it, but the pivot is set to be a child of the main pivot of the Conversationalist. The box shape is offset from the main pivot locally on the Z axis, so it's in front of the main pivot + model. Now, every frame, the collision callback tells me if a "ConTrig" trigger was triggered, and if so... it doesn't just check who the character is. Through 7 layers of black magic, it is reported right back to the Conversationalist that its trigger was triggered. So, in a very roundabout way, whatever entity I create can say to me "I have somebody right front of me", if that happens to be the case, because they have a trigger bolted onto them with a hotline to God. There's probably a much simpler way to do it. If anyone knows, I'm very keen to find out so I can streamline things.
  9. Three cheers for educational software From the description: Working on this idea (which will eventually have recordings of the phases), with the aim of exposing learners of English to an easy-to-understand introduction to the ins and outs of daily conversation. Currently has no sound, the graphics are very bare, and there is only one conversation. Very much a work in progress but I hope to complete it.
  10. That's not a bad idea The only reason I did them individually was so I could easily add/remove them as I went along.
  11. Alright, so first I created a bunch of hand-drawn textures, which were 256x256 PNGs with a transparent background. I made one for each letter I want to use. I then put them in a subdir of my project and opened the Leadwerks Editor, which automatically converted them to tex. I then had to edit each one to use DXT5 so I could get the alpha channel working properly. Then I created a singleton "GlyphManager" class, which has a std::map<std::wstring, Leadwerks::Texture*> (to hold the textures and reference them) and a std::vector<std::wstring> (the buffer of text to display). Then I wrote a "start" function which loads all the glyphs into the map individually, like so: glyphs[L"A"] = Leadwerks::Texture::Load(path + subdir + "a.tex"); glyphs[L"B"] = Leadwerks::Texture::Load(path + subdir + "b.tex"); The L before the double quotes tells the compiler that it's a wide (multibyte) char. This means I could also load in non-ASCII characters, such as: glyphs[L"Г"] = Leadwerks::Texture::Load(path + subdir + "g.tex"); glyphs[L"Д"] = Leadwerks::Texture::Load(path + subdir + "d.tex"); (Leadwerks Editor doesn't recognise non-ASCII characters in filenames so I divided the images into subdirectories such as "eng-cap" and "rus-cap" Right, so the textures are in place, so what do we do with them? void GlyphManager::displayText(Leadwerks::Context* context) { float startx = 1; float starty = 1; float xoffset = startx; float yoffset = starty; float size = context->window->GetWidth() / 40; context->SetBlendMode(Leadwerks::Blend::Alpha); for (auto str : textToDisplay) { for (auto ch : str) { std::wstring tempWStr; tempWStr.push_back(ch); if (glyphs[tempWStr]) { context->DrawImage(glyphs[tempWStr], xoffset * size, yoffset * size, size, size); } ++xoffset; } xoffset = startx; ++yoffset; } textToDisplay.clear(); } glyphs is my std::map<std::wstring, Leadwerks::Texture*>, and textToDisplay is my std::vector<std::wstring>. It iterates over each line in the vector, and in each line, it gets each char and puts the appropriate letter to the screen in the appropriate place. I did it quickly and nastily; you'll see I iterate over a wstring getting a wchar each time, but then I have to put the single wchar into a wstring and work with that because I wasn't sure how to get the wchar to work as the key in my hashmap. I'm sure there's a better way of doing it. Anyway, that's the gist of it all. So, as it's a singleton method I can call it from anywhere I've included the header. I've been calling it in an update function for my game state every frame, because as you'll notice it clears the buffer at the end of that function. So the result of calling this code every frame: GlyphManager::getInstance()->addTextToDisplay(L" "); GlyphManager::getInstance()->addTextToDisplay(L" "); GlyphManager::getInstance()->addTextToDisplay(L" "); GlyphManager::getInstance()->addTextToDisplay(L"TESTING BITMAP FONT..."); GlyphManager::getInstance()->addTextToDisplay(L" "); GlyphManager::getInstance()->addTextToDisplay(L"THE QUICK BROWN FOX"); GlyphManager::getInstance()->addTextToDisplay(L"JUMPS OVER THE LAZY DOG"); GlyphManager::getInstance()->addTextToDisplay(L" "); GlyphManager::getInstance()->addTextToDisplay(L"РАЗЪЯРЕННЫЙ ЧТЕЦ ЭГОИСТИЧНО БЬЁТ"); GlyphManager::getInstance()->addTextToDisplay(L"ПЯТЬЮ ЖЕРДЯМИ ШУСТРОГО ФЕХТОВАЛЬЩИКА"); is this:
  12. Once again, sorted it out right after posting. I could probably write a book on doing that already. Ended up writing a thing that takes wchars and displays textures. Can talk about this more if anyone's curious.
  13. I'm hoping to get some non-ASCII characters to the screen, but DrawText doesn't like std::wstring. Is there a way around this already, or should I nut out a way to use bitmapped characters?
  14. Never mind, I worked out it was due to something else entirely that I had written. I feel like an idiot now
  15. Hey there, I recently got Leadwerks and I've been trying to nut it out by, well, doing things. Currently having a whale of a time, but as I'm unfamiliar with it, I'm having a problem. The situation is I have a class which I have created and when I instantiate it, it seems to create two instances of it at once. I won't bore you with the actual code, but my process is: 1. Class "Player" has (a) a pivot entity, (b) a Model::Box, and © a physics shape. (a) is parent of (b), (b) has © as its shape. Physics attributes are applied to the pivot entity. 2. Class "MainState" contains a "Player*", which comes into being via a static Player::create() method which, naturally, returns a "Player*" 3. After being called, the object is visible in the world, but when I call SetInput (or even AddForce) on the Pivot entity of my Player, two objects are visible. Both fly off in opposing directions when force is applied. Aside from me not really understanding how to correctly structure such a class in the Leadwerks ecosystem, I'm a bit baffled as to why this is happening. All I know is I'm creating two similar objects in the same physical space and when I move one, they bonk together and the other goes haywire too. The question is: why is it so? What should I do to my class in order to avoid that duplication? Sorry if this turns out to be (ironically) a duplicate of another post, but I couldn't find anyone else anywhere having the same thing happen.
×
×
  • Create New...