As was foretold, we've added advertisements to the forums! If you have questions, or if you encounter any bugs, please visit this thread: https://forums.penny-arcade.com/discussion/240191/forum-advertisement-faq-and-reports-thread/
Options

[Game Dev] I don't have a publisher. What I do have are a very particular set of skills.

1666769717292

Posts

  • Options
    KupiKupi Registered User regular
    Kupi's Weekly Friday Game Dev Status Report

    Last week I identified a performance optimization problem that I've been overlooking for a long time: the "Draw" phase wasn't even being measured, and, it turns out, was over half the average run-time per frame.

    What I've decided is that the ECS paradigm, at least in the dogmatic form I've implemented it so far, is not well-suited to data that doesn't change much. The core of ECS is that you'll take a stream of Entities of a particular "archetype" (combination of Components) and pipe it through a System that will somehow transform the values in those Components. The thing is, if you have, say, a collision volume or a sprite that doesn't change often (such as one associated with a platform tile), that means that you'll pick it up and do something with it every frame. Now, my collision detection system is heavily parallelized and has safeties in place to avoid re-processing collision volumes that haven't changed between frames, but even the act of determining that the entity hasn't changed takes some processing. That's a lot of wasted clock cycles!

    So, I'm changing to a new approach for systems like collision detection and sprite rendering where there's a lot of temporal coherence to the data, and certain instances explicitly ought not be part of the entity query. For those systems, there will be a "Controller" object (the reference to which is stored in a singleton Component) that stores class instances of some kind of registered object containing the actual data. You can register an instance with a Controller and get an identifier back that lets you get the registered instance back, which is then stored in a more traditional Component. (This will eventually be used to multiplex collision volumes through a single Component.) Then, different Components can register controlled object instances to the same controller, resulting in different behavior when only one of them is picked up by a particular System. For instance, sprite Components can be divided into StaticSprites that register a sprite-culling bounding box to the Sprite Controller on creation and DynamicSprites that do likewise but then also get picked up by a query in the drawing system that updates their bounding box info each frame. Updating just the 100 sprites that are known to move and never touching the other 10,000 that aren't sounds like it's going to be a performance win to me. But you never know. I've been wrong in the past.

    I've been working on converting the drawing system to use this new arrangement first because 1) it's the big performance blocker right now and 2) sprite drawing is a hell of a lot simpler than collision detection. I'm very nearly done with unit-testing my changes, but not quite close enough to finish them up tonight and get some hard numbers on how it affects the performance. So, we'll see what comes of it next week!

    My favorite musical instrument is the air-raid siren.
  • Options
    ElvenshaeElvenshae Registered User regular
    edited May 2020
    Ugh. Feeling really frustrated tonight.

    I've got a brand-new obj_forced_movement controller that basically gets created whenever a PC knocks a badguy around. It initializes the potential squares the badguy can get moved into (like, you hit him and can knock him 2 squares back*) and changes the obj_cursor in "forced movement mode," which works a lot like normal movement mode in that it looks for right-clicks on valid move_nodes, etc. Meanwhile, the obj_forced_movement controller changes itself to "move the badguy" mode, which basically sits there and doesn't do anything until it gets a right-click-on-a-valid-move_node notice from the cursor. This is all, as near as I can tell, working just fine up until this point (though there is one issue with some UI elements not being displayed when the cursor picks up the obj_forced_movement that are there to handle future cases where you can move multiple targets; but, since I'm not really using them right now, I'm okay with leaving it for later).

    Anyway, once the obj_forced_movement controller knows where you're sending the badguy (because it gets the message), it takes the starting and ending node positions, generates a path, and sends the badguy along the path. For a 1-distance forced move, there should be two points on the path: where you start, and where you end. For some reason, all of my forced-movement attempts have resulted in the badguy moving an extra square in a seemingly-random direction. E.g.:
    . . F . The Fighter smacks the target with his push attack, which has a push range of 1
    . T . .
    . . . .
    
    X X F . The X nodes are marked as viable move_nodes (this is accurate)
    X T X .
    X X X .
    
    . . F . The bottom-left move_node is selected via right-click
    . T . .
    X . . .
    
    . . F . The target moves a step along the path - this is great! This is where it should stop!
    . . . .
    T . . .
    
    . . F . ... but then it moves up a square after its movement for reasons I cannot comprehend.
    T . . .
    . . . .
    

    Like, here's an example, complete with debug "parent" arrows:

    u476g3ixy666.png

    You can pathfind from parent to parent, until you get to the place without a parent (the node you started in). So, that's all good.

    But when I click on the top-right option ... (visible: the cursor announcing it's in Forced Movement mode and the green "move line" showing the path the goblinesque target is going to take):

    z0vbco50hlj7.png

    ... it actually moves two squares: up-right, up, to a square that, when I called the pathfinding function, had no parents and therefore shouldn't have been pathable:

    azuvungyj5p5.png


    * Currently, for debugging purposes, I've commented out the portion of the controller code that marks or unmarks otherwise valid move_nodes based on whether you're knocking someone away, pulling them towards you Scorpion-style, etc., but it worked more-or-less properly.

    Elvenshae on
  • Options
    ElvenshaeElvenshae Registered User regular
    edited May 2020
    Dream debugging may have worked. I may, in fact, be an idiot. :D. Will know for certain when I get to sit down later today.

    Elvenshae on
  • Options
    ElvenshaeElvenshae Registered User regular
    edited June 2020
    Ayup. "Idiot." I woke up, thinking, "Yeah, you looked at the generic creature end-of-path code, but not the more specialized AI-controlled-creature end-of-path code; they're very similar but just a bit different. I bet they think it's their turn."

    I forgot that, until this code change, the only thing that could make a badguy move was the obj_ai_controller. So any time it moved a badguy, it set their endPath variable (which I need to rename to conform to my programming standard vs. the tutorial's) to either "idle" if it didn't have any actions left (so that the AI or the game could grab the next character) or "find a target" if it did (which would check if there were any PCs within reach and attack one or pick someone to move towards).

    Well, the forced movement code didn't affect the enemy's action count, and didn't set a new endPath, so when an enemy got pushed around ...
    . . F . The Fighter smacks the target with his push attack, which has a push range of 1
    . T . .
    . . . .
    
    X X F . The X nodes are marked as viable move_nodes (this is accurate)
    X T X .
    X X X .
    
    . . F . The bottom-left move_node is selected via right-click
    . T . .
    X . . .
    
    . . F . The target moves a step along the path - this is great! This \is\ where it (the forced movement) stops!
    . . . . ... but the enemy thinks, "I just completed a path, and I have all my actions left. I'm going to pick a new target!"
    T . . . There's no one in reach, so I'm going to pick a random target to move towards.
    
    . . F . ... and so it does.
    T . . .
    . . . .
    

    ... or ...

    azuvungyj5p5.png

    "Thanks for pushing me away, Fighter! I'm going to go eat the Cleric now!"

    That also explains why it was weirdly inconsistent. If the Fighter pushed an enemy that had already moved and attacked, then it just moved and stopped and looked kinda normal (and then shit got strange on the next turn). But if the Fighter pushed a badguy who hadn't gone yet that round (because the Fighter shot first!), then it would "bounce."

    That's all cleaned up, now I can uncomment the push around / Scorpion code, and ... Shit. This is the most complicated thing I think I've ever programmed.

    State machines are fuckin' wizardry.

    Now to do some code cleanup; enable the pusher to follow-up the pushee, sometimes; add some more debug functions; maybe a displayed turn order (eventually moving into allowing delayed turns) ... And the next big feature? Pits. At which point, I'll be basically back to where I was in my very, very first prototype of this, but with way more features and way more extensible code that's a helluvalot more readable.

    And then I can turn to the "have a way to win or lose" and have a Real Game (TM).

    ED: ... but now I can't get the follow-up animation to occur ("I push you with my attack, and step into your spot"). I can move the data around, but the on-screen sprites do not do the path animation. Blech.

    ED2: HAHAHAHAH! See, when your "Generate a path for a creature" code that you wrote requires that you pass it the creature doing the walking and their end-point, and you've updated the code autocomplete helptext to show that it's looking for an actor_id, and everywhere else you've used it you've successfully passed the creature's ID ...

    ... and then in your follow-up-forced-movement-code you instead pass it the movement_path of the attacker, you really only have yourself to blame. :D

    Elvenshae on
  • Options
    KupiKupi Registered User regular
    Kupi's Weekly Friday Game Dev Status Report

    Last week I just barely didn't have my new sprite controller system implemented. Well, as it often goes with code, "just barely" is actually "rather significantly", so it took most of the weekend to get all the corner cases debugged. However, I was finally able to get it all working and take some measurements. It looks like my new system underperforms the old one when there are a large number of moving objects in play relative to the number of total objects, but significantly outperforms the old one for the case where there are a large number of non-moving objects and comparatively few moving objects. And I also discovered that when the Update() function is hopelessly behind, the new approach's performance becomes catastrophic.

    So what is the new approach? It's a variation on Sweep And Prune, the venerated broad-phase algorithm that I think I've lectured y'all on at least three times by now. So let's go for a fourth!

    Sweep And Prune is a method for quickly finding overlap pairs in a set of axis-aligned bounding boxes on as many axes as you want-- if you want to cull collision volumes in seven-dimensional spaces, go right ahead! Anyway, for each box, you create a handle to its minimum and maximum extent on each axis, and add it to a list. Then, you sort that list by position. There are multiple ways to translate the resulting sorted list into collision pairs. For instance, you can scan through the list and maintain the set of currently active volumes. When you see a new min-handle, you create an overlap for each volume already in the open set, then add the new volume to the open set. When you see a max-handle, you remove the volume it belongs to from the set. Then you do the same for the remaining axes, and your final overlap set is the set of all overlaps that exist on every axis. However, the preferred way of managing overlaps for video games is to retain a record of which bounding boxes are overlapping, and update it when a volume changes position. The reason for this is that while volumes might be moving around a lot in the game, the amount that movement disrupts the ordering is very small-- on most frames, most volumes won't change position at all, and if they do, it's only by one or two positions. The cost of updating the list is the cost of verifying that it's still properly-ordered-- and if the majority of your elements in the list are non-moving, then you don't even have to examine those once you add them to the list.

    I use essentially the same scheme for my sprites, except that instead of tracking overlaps between all objects, I track the overlap between the camera and the sprites. That is to say, the only time I change my record of whether a sprite should be drawn is when its bounding box handles cross over those of the camera.

    Like I said, the new scheme slightly underperforms the old one when there are a large number of moving objects in play. That makes snese-- more moving objects means more shuffling the handle lists around. Unlike the old system, the new one's performance scales in the number of moving sprites, whereas the old one scales in the number of sprites overall, so for realistic cases (lots of non-moving sprites, only a few moving ones) the new system outperforms the old one. However, it took me a while to figure out why the new system's performance absolutely tanked when Update() fell behind the total allowed frame time. Recall that Monogame always calls Update(), then calls Draw() only if it thinks it has time left over on the frame, unless it's already skipped a large number of Draw() calls. Well, when Draw() is being called very few times relative to Update(), the sprites move very far away from their last known position. That means the list gets even further out of order and Draw() spends even more time re-establishing the sort. An acceptable loss, I think-- after all, this new method only seriously loses performance in a situation that I should never be allowing to happen anyway (Update() never fitting in the allotted frame-time).

    My next goal is to similarly revise my collision detection system the way I did with my sprite-drawing system, in order to allow non-moving, non-updating volumes to be ignored by the majority of processing steps. It also turns out that I may actually have harpooned my white whale: I came up with a scheme that'll allow me to parallelize collision event resolution. If it all pans out, I'll bore you with the details next week. :lol:

    My favorite musical instrument is the air-raid siren.
  • Options
    SurfpossumSurfpossum A nonentity trying to preserve the anonymity he so richly deserves.Registered User regular
    edited June 2020
    holy wow i'm gettin' real mad.

    I started poking at a project again recently, and some update completely broke the WebGL build I was using. It used to work fine, and still works fine running locally, but now on a server it fails when trying to load (specifically, I get "Failed to load resource: net::ERR_CONTENT_DECODING_FAILED" for each of the three Unity files (.data.unityweb, .wasm.code.unityweb, and .wasm.framework.unityweb extensions)). Googling suggests that it's because Unity is now using all kinds of file extensions that the server isn't recognizing, but I've added the .htaccess and web.config files described here, and have tried uploading a build without any compression, but nothing seems to have any effect.

    Does anybody know what the heck?


    edit: asdfjgasgjf apparently I didn't clear my cache before trying the uncompressed build. That seems to have fixed it.

    Surfpossum on
  • Options
    ElvenshaeElvenshae Registered User regular
    I have pits!

    You can fall into them and die!

    Now I’m adding a “falling into a pit” death animation.

    The results are, currently, hilarious. I’ll try and capture a video to share.

  • Options
    CornucopiistCornucopiist Registered User regular
    Surfpossum wrote: »
    edit: asdfjgasgjf apparently I didn't clear my cache before trying the uncompressed build. That seems to have fixed it.

    Always be cache-clearin'

  • Options
    ElvenshaeElvenshae Registered User regular
    You'd think that avidemux would have a very simple plug-in to just put a damn black bar over a portion of the video.

  • Options
    CornucopiistCornucopiist Registered User regular
    FNS update! I finally kicked the habit of fiddling with my RPG moonshot, and ported the tile swapping code to FNS. I also added new (old standard) shaders to get on demand color with a texture applied, and made rectangular buildings for easier collision meshes.
    There's still an issue with the tile swapper though (as it polls the old tile unit, using it for moving objects makes them appear further and further away from the player). But that's fixable! And the code will be faster, too.

    k2exg3lg2e6j.jpg

  • Options
    SurfpossumSurfpossum A nonentity trying to preserve the anonymity he so richly deserves.Registered User regular
    On the very slight chance that someone someday runs into this same problem:

    I was trying to use superscripts and using Unicode characters was working swell up until I ran the game outside of Unity, at which point they would mysteriously stop working past 4.

    After literally hours of messing with the text box boundaries, cutting and pasting characters instead of using the unicode, angry googling, etc. it turns out lots of fonts will have superscript characters for 2, 3, and 4 (even tho 4 is in a different block) but nothing else. Luckily Google's free font database has an incredibly handy thing that lets you easily check how fonts will display something.

    Downloaded a font that has all the superscript characters and voila, everything works again.

  • Options
    LD50LD50 Registered User regular
    Elvenshae wrote: »
    LD50 wrote: »
    Elvenshae wrote: »
    LD50 wrote: »
    That seems like a good next step. It's also worth looking at the ai script and how it's controlling itself (does it actually check player_turn; does it act properly on that check, etc)

    Good call.

    The enemy AI script itself doesn't deal with the player's turn; the little watcher script does. That outputs debug text each time it's invoked - at the end of the player attack functionality and the end of the player movement functionality. Each of those cases seems to work well - e.g., the player presses "m" to move, the debug text indicates that the player is trying to move, the movement UI happens, debug text gets spit out each time the player tries to move to a spot (invalid move target gives an error message; valid move target says you've picked your move spot and lists it out in the log), the "actually move" stuff happens, there's some cleanup, then the watcher script is invoked.

    The watcher script says either "It's still the player's turn" if you've moved but not attacked or attacked but not moved and then exits. If you've done both, it does the turn switch and then starts invoking enemy AI.

    I would take a close look at that watcher script then.

    AHAHAHAHAHAH!

    I commented out all of the AI stuff, and it worked flawlessly. Player moves, player attacks, watcher script says "Your turn is done," watcher script says "It's the badguys' turn," watcher script says, "Badguys are done, it's your turn now," player turn variables are reset, player can take another turn, and loop, loop, loop.

    So, that worked.

    Buuuuut ... when turned the AI back on, I noticed that when it moved the enemy sprite, I moved them to the wrong spot in the room (row * tile_width + (tile_width / 2) instead of - (tile_width / 2), etc.). I'm not sure why that would cause everything to absolutely freak out (given the lack of collisions I have defined in the code at the moment), but it absolutely does.

    Whew!
    Surfpossum wrote: »
    On the very slight chance that someone someday runs into this same problem:

    I was trying to use superscripts and using Unicode characters was working swell up until I ran the game outside of Unity, at which point they would mysteriously stop working past 4.

    After literally hours of messing with the text box boundaries, cutting and pasting characters instead of using the unicode, angry googling, etc. it turns out lots of fonts will have superscript characters for 2, 3, and 4 (even tho 4 is in a different block) but nothing else. Luckily Google's free font database has an incredibly handy thing that lets you easily check how fonts will display something.

    Downloaded a font that has all the superscript characters and voila, everything works again.

    That is infuriating and I don't know if I would have ever been able to catch that myself.

  • Options
    HandkorHandkor Registered User regular
    I probably shouldn't have made this but somehow all this static was not disorienting or nauseating in VR. You're just very blind at the beginning but can see movement since the Temporal AA is blurring the noise using motion blur. Before I added light to reveal some of the world the game was impossible to screenshot. All still screenshots were just static but while playing you could clearly see objects that are in motion. With VR adding depth you can make out the shape too.

    https://www.youtube.com/watch?v=OLhkreKxqVQ

    The static was applied in post processing and applied by projecting a sphere around the player's position. The whole game is rendering to black and any light is used to pierce out of the static.

    I'm really happy with this though since I've been able to throw in a bunch of ideas that I wanted to try. The main one which was travelling on an airship in a cave while mostly blind except for flares and light on the ship. I had even though of making it an audio only game at one point since UE4 has really nice binaural support with simulated material obstruction and attenuation which work really well with VR head tracking.

    If anybody is crazy enough to try it out https://itch.io/jam/2020-unreal-spring-jam/rate/666951

    You can basically play with 3 levels of obscurity:
    Normal: When you grab the torch it shines light revealing the world and also creates an aura darkening the static around the player.
    Hard: Grab the torch to activate the aura but then drop the torch and only play in static
    Very hard: Don't grab the torch and play only by motion and environment lights.

    You can always you the flare gun when stuck.

  • Options
    KupiKupi Registered User regular
    Kupi's Weekly Friday Status Report

    This week I started in on converting my collision detection system to the new paradigm that allows for different volumes to be static or dynamic. Thus far, I've moved over everything except the core collision event generation function, so, y'know, it does everything except the one thing it's supposed to. ¯\_(ツ)_/¯

    Last time I mentioned that I'd figured out how to parallelize event resolution, and that I'd bore you with the details if it all worked out. Well, I don't know if it's worked out yet, but I'm going to bore you with the details anyway.

    ... or, at least, I was. Two things have conspired to prevent this from happening: 1) work took an extra two hours today and I am still floating somewhere just beneath "about to go ballistic", and 2) after typing out 913 words' worth of explanation, I stopped, looked at something I asserted with bold confidence, looked back at my visual aid that I'd drawn up to demonstrate the point, and realized that one of the premises my new system operates on was fatally flawed. Consequently, I have nothing to present at this time.

    My favorite musical instrument is the air-raid siren.
  • Options
    PeewiPeewi Registered User regular
    edited June 2020
    I made a tiny game


    I guess it's not really clear that you're moving when the game border isn't visible.

    I don't have any particular game design goals and I'm mostly doing this as a programming project.

    The window is resizeable and the game scales to match.

    My immediate next goal is to add an options menu (the button on the menu doesn't do anything yet) with key binding.

    I guess then I'll have to add some sounds so I can have a volume slider.

    Peewi on
  • Options
    DisruptedCapitalistDisruptedCapitalist I swear! Registered User regular
    What programming language are you using?

    "Simple, real stupidity beats artificial intelligence every time." -Mustrum Ridcully in Terry Pratchett's Hogfather p. 142 (HarperPrism 1996)
  • Options
    PeewiPeewi Registered User regular
    I'm using C# with Monogame.

  • Options
    LD50LD50 Registered User regular
    Kupi wrote: »
    Kupi's Weekly Friday Status Report

    This week I started in on converting my collision detection system to the new paradigm that allows for different volumes to be static or dynamic. Thus far, I've moved over everything except the core collision event generation function, so, y'know, it does everything except the one thing it's supposed to. ¯\_(ツ)_/¯

    Last time I mentioned that I'd figured out how to parallelize event resolution, and that I'd bore you with the details if it all worked out. Well, I don't know if it's worked out yet, but I'm going to bore you with the details anyway.

    ... or, at least, I was. Two things have conspired to prevent this from happening: 1) work took an extra two hours today and I am still floating somewhere just beneath "about to go ballistic", and 2) after typing out 913 words' worth of explanation, I stopped, looked at something I asserted with bold confidence, looked back at my visual aid that I'd drawn up to demonstrate the point, and realized that one of the premises my new system operates on was fatally flawed. Consequently, I have nothing to present at this time.

    Rubber duck programming at it's best.

  • Options
    KrathoonKrathoon Registered User regular
    Anyone use Godot? It seems to be getting some traction.

  • Options
    AkimboEGAkimboEG Mr. Fancypants Wears very fine pants indeedRegistered User regular
    Krathoon wrote: »
    Anyone use Godot? It seems to be getting some traction.

    I've been playing around with it for a few months now. I don't have any real experience with Unity or Unreal to compare, but overall I'm impressed with Godot, and even more so with the project management and clear communication from the team.

    Give me a kiss to build a dream on; And my imagination will thrive upon that kiss; Sweetheart, I ask no more than this; A kiss to build a dream on
  • Options
    templewulftemplewulf The Team Chump USARegistered User regular
    edited June 2020
    Krathoon wrote: »
    Anyone use Godot? It seems to be getting some traction.

    I've been on it for a few weeks, my previous experience is mostly in Unity.

    Godot really sticks to the OOP approach, as opposed to the component composition approach, so it was a little weird. That said, I've really been enjoying their approach to signals (event sub/pub), and they have Unity cleanly beaten in the KinematicBody2D. It has built in methods for move_and_slide() as well as is_on_floor()! These would have saved me so much time in Unity.

    It seems like more advanced stuff that I was accustomed to with Unity (like writing custom inspectors) is a little less accessible in Godot but still possible. Their dev cycle seems to be much slower with open source, and the tutorial material is a little thinner, but it covers all the major bases.

    Did you have any particular questions?

    templewulf on
    Twitch.tv/FiercePunchStudios | PSN | Steam | Discord | SFV CFN: templewulf
  • Options
    IzzimachIzzimach Fighter/Mage/Chef Registered User regular
    I made a cool mistake with my postprocessing. I added rim lighting using the depth buffer, however it doesn't take actual lighting into account. So even if stuff is invisible or unlit in the background you can still see ghostly outlines. I watched a video about the game A Short Hike and the author mentions that he found a similar effect by accident as well.

    In this picture you can outlines of the mountains even though they are not visible. It happens when underground as well. Looks cool enough that I'll keep it after a bit of tweaks.

    w6vlsss34lq0.png

  • Options
    KrathoonKrathoon Registered User regular
    templewulf wrote: »
    Krathoon wrote: »
    Anyone use Godot? It seems to be getting some traction.

    I've been on it for a few weeks, my previous experience is mostly in Unity.

    Godot really sticks to the OOP approach, as opposed to the component composition approach, so it was a little weird. That said, I've really been enjoying their approach to signals (event sub/pub), and they have Unity cleanly beaten in the KinematicBody2D. It has built in methods for move_and_slide() as well as is_on_floor()! These would have saved me so much time in Unity.

    It seems like more advanced stuff that I was accustomed to with Unity (like writing custom inspectors) is a little less accessible in Godot but still possible. Their dev cycle seems to be much slower with open source, and the tutorial material is a little thinner, but it covers all the major bases.

    Did you have any particular questions?

    I don't really have any questions. I was just deciding if I should invest some time in learning it. It seems like a nice and free alternative.

  • Options
    LilnoobsLilnoobs Alpha Queue Registered User regular
    I've went ahead and submitted my ARPG Stat and Item system to the Unity store today, hit that little button. Now we wait.

    And in the meantime, I can fill out more of the documentation...

    I'm a bit burned on the project, so time to rest a bit. Maybe I'll even play some games.

  • Options
    PeewiPeewi Registered User regular
    I have successfully implemented an options menu for resolution and screen mode (fullscreen, windowed, borderless window).

    Well, almost. The list of resolutions don't fit on-screen and I haven't made a scrolling list yet.

  • Options
    PeewiPeewi Registered User regular
    I have basic keybinding now


    While making this I learned that Monogame doesn't handle non-US keyboard layouts very well. The keys on my Danish keyboard that don't exist on American keyboards, like Æ, Ø and Å aren't registered at all. And for some reason right alt is registered as left control.

    It does have a text input event, which can accurately get a typed character according to keyboard layout, but it is not suited for game input.

    I also need to do a bit of extra work if I want to include mouse buttons in my keybindings (and I do) because keyboard and mouse input are handled differently from each other.

  • Options
    HandkorHandkor Registered User regular
    I wanted to do this last year but missed the dates so for this year's LOWREZJAM I want to make a VR game limited to 64x64 pixels. You'll probably lose depth perception but the head tracking alone should be fun.

  • Options
    CornucopiistCornucopiist Registered User regular
    So, Google removed my free app from the Play Store because "We detected that your app collects personal and sensitive information from children, but this was not disclosed in your Play Console."
    The only thing they could be talking about was the AdMob inclusion of a banner ad. The ad's been there for maybe three years now?
    Last month that banner ad made me 1.66$.
    If the banner ad had stayed up another month, it might have just pushed the total take past 70$ which is when they pay out.

    I don't think that that's a f*cking coincidence you guys.

    So I'm going to withdraw the Family stamp from the app and republish. Yes, I know that torpedoes my visibility to kids. But that app is going to stay up for a decade if that's what it takes to get that 70$.


  • Options
    Alistair HuttonAlistair Hutton Dr EdinburghRegistered User regular
    I've decided I'm going to get into Twine.

    I have a thoughtful and infrequently updated blog about games http://whatithinkaboutwhenithinkaboutgames.wordpress.com/

    I made a game, it has penguins in it. It's pay what you like on Gumroad.

    Currently Ebaying Nothing at all but I might do in the future.
  • Options
    KupiKupi Registered User regular
    Kupi's Weekly Friday Status Report

    I spent the week performing a highly focused investigation into the design of AAA open-world RPG systems, by which I mean to say I pretty much played Xenoblade Chronicles: Definitive Edition every waking moment of the day not already dedicated to social or biological necessities. Consequently, I have no real game development work to report. As is customary, my punishment (and yours) is to type up an extensive documentation of what I would have been working on; in this case, I'll proceed with my description of my revised collision resolution system as though I hadn't hit a design snag that I still haven't overcome.

    My collision detection system uses high-precision shape-casts to determine what happens to moving volumes on a sub-frame level. Because I'm not necessarily looking for realistic physics, just precise ones, interaction between volumes doesn't use mass, density, realistic momentum transfer, or whatever else you'd get out of a proper physics system. Instead, volumes have a "push priority", which is just an integer value that indicates which other volumes it preempts. If two blocking volumes collide, the one with higher push priority continues on its merry way and the one with lower push priority changes direction at whatever point in the frame that collision occurred. More precisely, the following three things occur:

    1) The pushed volume's velocity is projected onto the normal to the surface it collided with.
    2) The pushed volume gains the velocity of the pushing volume for the rest of the frame.
    3) The pushed volume gains a "promoted" push priority equal to that of the pushing volume for the rest of the frame. In concrete terms, if Wall pushes Kupi, and Wall pushes Block, and Kupi pushes Block, if a Wall pushes a Block, that Block can now push Kupi because Block has been promoted to the priority of Wall. And, as always (until it isn't), Baba is You.

    In the event of a tie, both volumes are treated as pushed by the other.

    Static volumes have a push priority of infinity; they always win any blocking interaction with any other volume.

    Here are some visual aids: in this one, the circle is moving and the square is a static volume. The light gray line represents its "intended" velocity; the dark gray line and circles represent its actual trajectory during the frame.

    epdgz56glyxt.png

    In this one, the square is also moving to the left. The circle impacts mid-frame and its velocity becomes the sum of the projection onto the surface normal and the remaining velocity of the square, causing it to end the frame off in the upper-left. It lands in a bit of a strange location, but at least you can see how its movement through the second half of the frame would effectively travel along the surface of the square.

    tvt7x4v768ed.png

    Now, the catch is that when a volume changes direction, it might 1) no longer collide with other volumes that it was projected to, or 2) newly collide with volumes that it hadn't been projected to collide with. Updating the state of the broad-phase structures (the ones that operating on axis-aligned bounding boxes) and evaluating whether any new collisions should be checked for (and removing the ones that are no longer relevant) is what I refer to as "collision resolution".

    Which is why my old system generates collision events in two phases, a highly-parallelized first sweep and then a linearized collision resolution phase. The first phase generates the initial layer of all possible collision events within the phase, notwithstanding updates. Then the system puts all of the generated events in an queue ordered by the time within the frame at which they occur (plus some tie-breakers), and resolves the events one-by-one. Unfortunately, since it's impossible to predict whether any given event will even exist after the event before it resolved, I could never come up with a good way to parallelize collision resolution. UNTIL NOW!!!

    A brief diverge: the system I'm about to present has its genesis in my re-work of the sprite system to better scale in the face of static sprites. In that system, I had to determine which sprites were or were not overlapping the camera at any given time. Since sprites can be rotated, scaled, and offset from the base position of the entity, as can the camera itself, that could involve some complicated calculations-- and complicated calculations were exactly what I was trying to avoid. Instead, I created a square hitbox for each sprite where each side's length was the sum of the width and height of the original sprite. Why that sum? Because of a bit of basic geometry called the Triangle Inequality Theorem. To wit: the length of any given side of a triangle is strictly less than the sum of the length of the other two sides. Sums are almost infinitessimally small to perform and summing the width and height creates a value that's always larger than it needs to be. The longest distance on a given sprite is the hypotenuse from the center of the sprite to one of the corners; if the sprite is rotated correctly, that distance will align with one of the axes. So if the sprite's culling box is larger than that value on both axes, we guarantee that we never cull a sprite that ought to be on the camera. In short: we don't have to be precise, we just have to accommodate the worst-case scenario.

    That's the core of my new approach: to calculate the worst-case scenario for movement of volumes in specific regions, and then process those regions in parallel where they provably can never produce an overlap. I'm calling those regions "collision resolution domains". There's a new step before the collision resolution phase where the system creates the collision resolution domains and then merges the ones it finds that overlap. Merging two collision resolution domains causes the merged domain to expand (because a volume may be pushed outside of its original covered area), which may cause it to overlap and merge with further domains. In a really bad case, that could eventually create a domain that encompasses every moving volume, which is even worse than the current setup because we did all the preprocessing for nothing. However, the majority of volumes in the 2D space won't interact in that way-- allowing collision resolution to be mostly parallel after the pre-computation phase.

    Right now what I'm working on is how to calculate the boundaries of each collision domain. The trick is coming up with a good data structure to do it wit and finding the right rules to govern when and how they merge. This is what I have so far:
    - The system will not proactively create a domain for any static volume. Splitting volumes into "static" and "dynamic" was supposed to let us avoid doing any more processing with static volumes than necessary.
    - Every dynamic volume gets its own domain shaped like the axis-aligned bounding box of the single volume, expanded by its known velocity.
    - For every collision detected in the initial collision test sweep, the domains of the volumes involved should be merged. The merged domain should be tested for overlap with other extant domains. (A Sweep-And-Prune structure can help make this operation swift.)

    The trick is making sure that when a domain expands, the amount it expands by 1) provably covers any area that the volumes within it might move into, but 2) doesn't expand by so much that irrelevant domains get merged together, especially such that they chain-react and pull every volume in existence into the same domain (or worse, overflow the storage involved).

    Incidentally, Incenjuar mentioning their work on an RPG engine prompted my game-dev brain to revisit the choices I made for my Phantasy Star knock-off's battle engine, leading to some investigation of how different damage and attack accuracy functions behave when the character stats involved vary in particular ways. However, I'm already up to a small novel for this week, so if I don't make any more progress on the collision engine next week (and there's still a lot of Xenoblade left...), I'll write that up at that time.

    See you next week!

    My favorite musical instrument is the air-raid siren.
  • Options
    CornucopiistCornucopiist Registered User regular
    So update on the Admob wars:
    Recap: Google decided that my app ChooChoo was no longer adhering to the terms set for child-friendly apps because their Admob adverts send back and store information. They removed ChooChoo from the play store, coincidentally just before they would have needed to pay out my lifetime accrued ad money of 70 million dollars! Just kidding, it's 70 bucks.

    I retaliated by defining ChooChoo as not for children, which it clearly is but there you go.
    They came back saying it clearly is for children, so that's not going to fly.
    Last night they doubled down by no longer serving their Admob banners...

    I'm going to leave it at that. I did my best when I started Admob by restricting the ads (and my revenue) to topics suitable for children by my standards, which are stricter than theirs. I'm not going to starve for lack of that 70 euros (which represents thousands of hours of gameplay, by the by) but I was peaved that they stooped to such a low trick. Now, the play store is dead to me.

    By the by, it's impossible to find the relevant disclosures in a search engine, but a whistleblower unveiled a widespread program within Youtube to do the same to small content creators.

  • Options
    PeewiPeewi Registered User regular
    I have extended my keybinds to include mouse buttons and added very basic graphics and sounds to my game. Sounds can be set to pause and resume playing when pausing and resuming the game.

    (this video has sound, but you probably have to enable it manually)


    I had downloaded a pack of sound effects and I guess Windows really doesn't like ogg files. A folder with 100 files totaling less than a megabyte caused Explorer to hang and crash and both VLC and Microsoft's Groove Music seemed unable to just play all of them in one go.

  • Options
    ElvenshaeElvenshae Registered User regular
    Well, that blows chunks, @Cornucopiist .

  • Options
    GSMGSM Registered User regular
    So, Google removed my free app from the Play Store because "We detected that your app collects personal and sensitive information from children, but this was not disclosed in your Play Console."
    The only thing they could be talking about was the AdMob inclusion of a banner ad. The ad's been there for maybe three years now?
    Last month that banner ad made me 1.66$.
    If the banner ad had stayed up another month, it might have just pushed the total take past 70$ which is when they pay out.

    I don't think that that's a f*cking coincidence you guys.

    So I'm going to withdraw the Family stamp from the app and republish. Yes, I know that torpedoes my visibility to kids. But that app is going to stay up for a decade if that's what it takes to get that 70$.


    That would be a pretty incredible scam if they regularly reported apps using their ad service for their own bad data collection practices when they near the payout threshold.

    We'll get back there someday.
  • Options
    nervenerve Registered User regular
    I made some progress on the UI for the RPG that I am making. I plan to add a character portrait next to the HP bar but it is empty right now. I'm pretty satisfied with the overall look but may change the style of the window headers. Would anyone be willing to give some feedback?
    zbcohcnvw8cq.png

  • Options
    PeewiPeewi Registered User regular
    nerve wrote: »
    I made some progress on the UI for the RPG that I am making. I plan to add a character portrait next to the HP bar but it is empty right now. I'm pretty satisfied with the overall look but may change the style of the window headers. Would anyone be willing to give some feedback?
    zbcohcnvw8cq.png

    I have no idea what the sideways eject button does.

    I think using a fancy font for the window titles and item names could look nice.

  • Options
    nervenerve Registered User regular
    If you are referring to the arrow buttons then those are meant to be 'back' buttons. I was actually considering removing those and the 'X' close buttons in favor of just using key bindings or something. Thanks for the feedback!

  • Options
    PeewiPeewi Registered User regular
    Yeah, I meant the triangle with a line next to the X on the quest log. I'd put the back button on the left. It seems to be the convention for software with back buttons, like web browsers.

    I'd keep the close buttons. My expectation from similar UIs is that the keyboard key that opened a window will also close it and that escape will close all open windows, but games like that often also have close buttons on each window.

  • Options
    SurfpossumSurfpossum A nonentity trying to preserve the anonymity he so richly deserves.Registered User regular
    My "game" is playable, for certain definitions of playable! The goal is to reduce the target polynomial by factoring etc.

    You drag the tiles down at the bottom around; drag 'em through an operator (the four rectangles in the upper half) and onto the target to perform the operation on the target (the yellow rectangle up top) using the dragged tile. You can drag tiles through operators and then other tiles to "combo" stuff. You can also drop stuff into the bays (green rectangles in the middle) to store it. Trash stuff by dragging it into the trash can (red square in the lower right).

    85l080e2ar6w.png

    http://surfpossum.com/applets/dragAndDrop/index.html
    (might be better on mobile)
    http://surfpossum.com/applets/dragAndDrop/index2.html
    (might be better on desktop)

    Plans for the near future:
    - add energy and scoring (gain score for reducing targets, use energy for operations/trashing)
    - find out how the heck to get things to display nicely on any given resolution
    - allow trashing of target/generate new ones
    - more intelligent target generation, with difficulty options etc.
    - a menu??

  • Options
    PeewiPeewi Registered User regular
    That's neat and I messed around with it for a little bit.

    I had assumed the goal is to reduce it to 0, but I guess that's not allowed?
    I think the system of dragging through additional tiles to combine them is a little confusing and it took me a little while to understand. Maybe some sort of visualization would help.
    I tried dropping additional expressions on the green spaces and I didn't understand why it only worked with the first one. It was not clear to me that I had to drag to the tile in the middle of the green space. This becomes even less intuitive when you have an expression that extends beyond the borders of the tile.
    If you make a very long expression in the yellow area the text becomes tiny and difficult to read. If you make a very long expression elsewhere it extends beyond the screen.

    Subtraction appears to work in two different ways. Example: If I drag x to - and then to y in the yellow area, it gives "-x + y". If I drag x to - and then to a y tile it gives "x + -y".

Sign In or Register to comment.