Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

Community Reputation

13163 Excellent


About JTippetts

  • Rank

Personal Information

  • Role
    3D Artist
  • Interests


  • Github

Recent Profile Visitors

63151 profile views
  1. JTippetts

    collision sprite

    phil's been putting this particular dead horse out there to get beaten for 14 years now, so apparently we don't grow tired of it. That poor horse just keeps getting beaten unrecognizable. For anyone who may be new to this guy's schtick, just go ahead and check his posting history. Then be aware that for some reason a lot of that posting history is no longer there. There've been a few forum migrations since the horse was first killed. I was unable to access anything from before 2012 (page 39 in his profile history) directly from his profile. Google can help ya, though! For instance, a quick search turns up hex grids from 2005, where he opens with his usual statement-as-a-question, expecting people to do the all the work, and follows it up with a blatant failure to listen. It's a pattern you might find eerily familiar. A bit of advice to people currently in this loop of madness, and to those who might be tempted to dive right in thinking that they just happen to have the magic that'll make phil listen and learn: It's a waste of time. If this comment of his from 2013 is to be believed, he has a BS in computer science, so if 4 years of university and a subsequent decade of posting on gd.net have failed to teach him anything, then I highly doubt anyone can. You would probably have better outcome by finding an ACTUAL dead horse to beat.
  2. JTippetts

    Resources for learning Programmer Art?

    The book Texturing and Modeling: A Procedural Approach was super helpful for me. That being said, on Amazon it's listed for $101 USD for the hardcover edition, which is way more than I paid for it many years ago. A lot of the information in that book can be found online, as it deals greatly with things like fractal noise.
  3. A little googling turned up this implementation of 3D simplex noise (other dimensions plus several other noise types also included in that github) complete with analytical derivatives in GLSL.
  4. JTippetts


    It's like getting a crap sandwich instead of the tasty hot pastrami on rye you wanted, then being told you're wrong (and an entitled jerk) to be unhappy about it. It's stuff in between two slices of bread, isn't it? What's there to be unhappy about?
  5. JTippetts

    Showing Orthogonal Screenshots

    Perspective Similar scene in orthographic With a top-downish view, the difference is subtle but present; the closer you get to fully top-down, the less the difference becomes, because most of the scene elements are then roughly the same distance away. Where the difference really becomes stark is switching to full side-on views: Side perspective Side orthographic You can see that in the side shot, the elements recede into the background in perspective, but in orthographic even trees that are far away appear exactly the same size onscreen as trees that are nearer the camera. In a true 3D game like this, with a movable camera, the effect when in motion is quite disorienting, and even nauseating, so I'd recommend avoiding orthographic if you have a free camera. Locked into a top-down view, however, ortho is usually fine.
  6. JTippetts


    That's good, because that is exactly what it is. If I had a cookie, I'd give it to you. As I said in my OP, I just can't get all that worked up about it because I've already walked away, but the reason for the ongoing anger in the community was 100% about the message they sent by taking this announcement and giving it prime featuring at Blizzcon. (Final announcement, first panel discussion.) That message is "see this? This is what we're gonna focus on. It's not what you came here for, it's not why you've been buying our games, it's not what you want, but we honest to God don't give a shit because there's boatloads of lootbox cash to be made so all y'all can just piss off." They have every right to do so, and if such a business plan fits their overall company vision then like has been said repeatedly, they'd be fools or worse not to. Had they kept that thing low-key, though, instead of putting it center stage at Blizzcon, it'd probably have just flown under the radar. But putting it where they did in the way that they did made for some pretty funny memeable moments and just a lot of warm and happy memories.
  7. JTippetts


    Climb down off your smug high horse, ffs. A gamer doesn't suddenly put on their cold robot suit just because they also become a developer. Not very many of those billions were at Blizzcon, though. The folks that WERE at Blizzcon certainly weren't looking for this kind of drek. There is such a thing as messaging, and it's pretty important in this day and age. Making the announcement of this thing at Blizzcon, in lieu of any actual real news of D4, sent a pretty clear and strong message, spelled out in two raised middle fingers. LOL. Just... no. C'mon, man. Many of those gacha games are just Diablo clones, made by people who have a hell of a lot more experience making Diablo clones than Blizzard has experience actually making Diablo. Quite a few Chinese players have commented in the wake of this cluster#*@! about how reskinning lootbox games is a large part of Netease's schtick. People who have played the Diablo thing have done side by side comparisons with Netease's existing fare, and the evidence of a reskin is there. Reskin their game, drop some Blizzard polish on it, start selling lootboxes and soul gem packs.
  8. JTippetts


    So your position is that, simply because a company has stumbled upon a new way of gathering to themselves a bazillion dollars by fleecing whales and selling lootboxes to people with poor impulse control, the former fans of the company's previous work are supposed to just be super duper happy about it and not express any of their sadness or anger for a bygone age? Just shut up and take it? Seems an odd position to take, but eh.
  9. JTippetts


    I have a hard time getting worked up about the Diablo:Immortal announcement, because I never really got over the bitter disappointment that was Diablo 3. Of course they're turning the Diablo franchise into reskinned generic mobile pay to win trash. It was obvious what path they were on with it after Diablo 3. I'm just a little surprised at how quickly they got there; I figured they would have squeezed out and pinched off at least one more awful installment before deciding to throw up the middle fingers to their legacy fans like that. Kudos to them for at least having the balls to announce it in possibly the worst venue they could have: in front of hundreds of fans devoted enough to shell out for a Blizzcon pass. Watching that guy's face fall off as the boos started stirred within me feelings that can only be described by unpronouncable German words.
  10. JTippetts

    See those saws (and despair)

    The sawblades meet with my son's approval, and he can be a pretty picky critic sometimes. Kid knows his sawblades pretty well.
  11. JTippetts

    OOP is dead, long live OOP

    I'd upvote this even more if I could. Thanks, Hodgman, you're a beautiful person for going above and beyond like this.
  12. JTippetts

    Drunks Standing Around Punching Each Other

    This is how it has been until this journal post. I think I just let myself be head-faked too badly by the auras. I ran into the case where GC was able to walk through a shaman's damaging aura without taking a hit, and it felt too weird so I busily set about over-complicating things, as is my normal reaction to weird stuff.
  13. JTippetts

    Combat Stats

    I am currently working on combat stats. I've worked on them before, but never really fleshed out a system I've been satisfied with. For the most part, I've gotten by with half-assed, or at best three-fourths-assed systems that always kinda change as my requirements change, but with no clear structure or rules. All of that half-assed code and system is gone now. In its place is basically a spreadsheet. In fact, it would make sense to define the data files underpinning it all as an actual spreadsheet. There are problems with that, though; namely that I'm terrible at spreadsheets, since I've never really used them. Sure, I have LibreOffice Calc on my laptop, and sure I've even fired it up once or twice. But I find the spreadsheet format to be clunky, and I really don't want to write a bunch of code to pull fields and expressions out of an XML document. So, I'm writing my data files by hand. It's actually not bad so far, though I can see the need to write a tool for it in the future. So, stats. As a jumping off point, I want to implement a system similar to Path of Exile. My goal is to support player-side stats with a similar level of depth/and complexity, and to also support monster-side stats with the ability to scale enemies based on player level. In order to support rapid iteration and testing of concepts, the stats need to be mostly defined in data. Some underlying concepts (damage types, damage scaling, etc...) are hard-coded, but the stat relations are defined in JSON files that are specified as attributes of the CombatStats component that all combat-enabled units possess. If you are not familiar with Path of Exile, their system is a 3-stat based (Strength, Intellect, Dexterity) system, with 4 types of damage mitigation: armor (to mitigate physical), evasion (to dodge stuff), energy shield (to absorb damage) and resistances (for elemental damage types and chaos damage). Dexterity contributes to Evasion, Intellect contributes to Energy Shield, and Strength contributes to Life (which is stupid, imo; it should contribute to Armor instead, for the sake of balance). Body Armor, Boots and Gloves all have score requirements for Str, Dex and Int; there are high-strength armors that provide high Armor rating, high-int armors for Energy shield, etc... So in order to equip certain things, you need sufficient quantities of the relevant stat(s). Classes are also aligned with the three base stats, with one character class per stat, and one character class for each hybrid (ie, Templar is a Strength/Int hybrid class). Resistances stand outside of the 3-stat system, with each resistance being increased by mods on gear or from the passive talent tree. They are a percentage-based mitigation, with each having a maximum cap (starts at 75%) that can be raised through talents or equipment. Aside from the 3 stats, there are other ways to build a character. Simple passives such as +%increased Spell Damage, or +%increased Melee damage, and other simple number increases are available. More importantly, there are Keystone talents available on the talent tree, and special mods available on certain unique items, that provide more complicated stat alterations than simple number increases/decreases. For example, the Avatar of Fire keystone dictates that 50% of all physical, lightning or damage the player deals is converted to Fire damage, and the character deals nothing but Fire damage. This has a huge effect on how the rest of the character can build. In conjunction with an item that provides 50% of physical damage is converted to Fire, it means you can build a straight melee brawler who can deal massive physical damage, but have all of that damage convert to Fire with a possibility for Fire damage to ignite targets, causing a DoT Burn effect. So, in light of the fact that I would like to build something similar, I've come up with a fairly simple system. I have implemented a StatSet structure, which owns an unordered_map of stats. The stats are keyed by a string hash, so that they can be requested either by name or by the hash of the name. Requesting by name is useful for debugging/testing, and requesting by the hash is marginally more performant. A Stat is implemented simply as a linked list of mods. In earlier versions, I implemented Stat as a value plus a list of mods, where each mod was either a flat addition to the stat, or a multiplier. The final value of the stat, then, was calculated as (Base + (SumOfFlatMods)) * (1.0 + SumOfMultMods) In this setup, you can have mods that add a flat amount (say, +10) to a given stat, or you can have mods that increase a given stat by some percentage. Specifying a Mult mod as 0.5, for example, is tantamount to increasing the stat value by 50%. In the current iteration, I have done away with the Base value, since it's basically just a Flat mod in disguise. Now, a Stat is simply a list of mods that either apply a flat additive value or a multiplier. These mods can either be simple numeric values, or they can be derived from other stats. I have also added a mod type of Scale, which can be set to scale the final result of a mod by a value. This Scale value is normally 1, so that it has no effect, but if a mod of type Scale with a value of 0 is applied, then it can set the stat to 0. This facilitates stats such as the previously mentioned Avatar of Fire, by applying a mod of 50% to the ConvertPhysicalToFire (and other conversion stats), and by supplying a mod of 0 to the Scale field of the other damage types, as an example. Thus, a Stat's value is finally calculated as ((SumOfFlatMods) * (1.0+SumOfMultMods))*ScaleMod. (Scale mods are not calculated as sums, but rather as a direct replacement. You can specify multiple Scale mods, but only the last one encountered will apply.) Also allowed are mods that can fix the value of a stat to some specified maximum or minimum. By this means, I can cap a stat (for example, a resistance capped at 75%) and use another stat to specify the cap value (resistance max). I can also cap the bottom end of a stat, for example by clamping a resistance to a -1.0 value, meaning that you can't go any lower, and it's not possible to do more than double damage against a target due to negative resistance. This basement cap can, of course, be modified, opening up the potential for builds that are very powerful against negative-resistance enemies. These various relations are specifiable in a JSON file. In fact, I can load multiple JSON files into a StatSet. This allows me to break off common functionality into one file, and load class-specific files per-unit. The syntax of my data files is still a little bit clunky, but here is an example: { "MajorStatPerLevel": [{"Type": "Flat", "Value":5}], "MinorStatPerLevel": [{"Type": "Flat", "Value":2}], "Bravado": [{"Type": "Flat", "Value": 5}, {"Type": "StatFlat", "ModType": "CalcLinear", "Stat": "Level", "Scale": "MajorStatPerLevel"}], "Arrogance": [{"Type": "Flat", "Value": 3}, {"Type": "StatFlat", "ModType": "CalcLinear", "Stat": "Level", "Scale": "MinorStatPerLevel"}], "Cunning": [{"Type": "Flat", "Value": 3}, {"Type": "StatFlat", "ModType": "CalcLinear", "Stat": "Level", "Scale": "MinorStatPerLevel"}], } In this example, I define two 'utility' stats, MajorStatPerLevel and MinorStatPerLevel, as flat values (5 and 2). Then I define 3 core stats (Bravado, Arrogance and Cunning, which are goblin-ish reskins of the more familiar Strength, Int and Dex). These core stats are defined using 2 mods apiece: a flat base mod, and a mod that applies a flat amount calculated as Level multiplied by a scaling factor. (The Level of a combatant is just another stat; in this way, by changing the Level stat, I 'automatically' get level-based scaling.) This snippet would scale Bravado higher than Arrogance and Cunning, and so would be appropriate for a Bravado-centric character class. A different file could be loaded for Arrogance or Cunning-based classes. (I could, of course, provide stats for hybrids, but I think 3 classes is quite enough for a solo developer to try to tackle.) This setup means that with each 1 increase in experience Level, the unit gains 5 Bravado and 2 of Arrogance and Cunning, on top of a base of 5, 3 and 3. To get the current value of Bravado, I can simply call StatSet::GetStat(name)::Get(), and the scaling occurs depending on the value of Level. To implement something along the lines of the Avatar of Fire keystone, I might do something like this: { "AvatarOfFire": [{"Type": "Flat", "Value": 0}, {"Type": "Max", "Value": 1.0}], "AvatarOfFireConversionScale": [{"Type": "Flat", "Value": 0.5}], "ConvertCrushToBurn": [{"Type": "StatFlat", "ModType": "CalcLinear", "Stat": "AvatarOfFire", "Scale": "AvatarOfFireConversionScale"}], "CrushDamageFinal": [{"Type": "StatScale", "ModType": "CalcOneMinusStat", "Stat": "AvatarOfFire"}], } In this case, Avatar of Fire acts as a simple flag. If 0, no real effect is applied. The CrushToBurn conversion is ignored in damage calculations since it's equal to 0. A damage value of type Crush will be processed, amplified using the CrushDamage stat (not shown here, but all damage types have one which is used to boost damage based on things such as +%increased Crush damage), and then scaled by the value of CrushDamageFinal, which is calculated as (1-AvatarOfFire)). Since AoF is 0, this amounts to a simple multiply by 1 operation. However, simply by adding a Flat mod valued at 1 to the AvatorOfFire stat, the behavior of the other stats changes. Now, the ConvertCrushToBurn stat is non-zero, with a value of 50%, so in the damage calculation after CrushDamage is applied, then 50% of the intermediate value is converted to a damage record of type Burn. Any remaining damage of type Crush, then, is scaled by CrushDamageFinal which is now equal to 0 (ie, 1-AoF), meaning that any Crush damage remaining becomes effectively 0. By supplying a similar set of mods for the other damage types, I have effectively modeled the behavior of PoE's Avatar of Fire passive talent. StatSets can be merged. For example, I can have the base StatSet for a character, then each piece of equipment can have its own mini StatSet that contains mods for just the stats it's interested in modifying. For example, a sword could have a mod for the JabDamage stat that increases Jab damage by 15%. When an attack is made using that sword, the combat system would copy the character's base stat set, then merge the swords stat set into it to get the final working set. This allows me to have equipment that can modify any of the stats, including flag-type stats such as Avatar of Fire. Thus, I could do things like "Equipping this armor grants Avatar of Fire". Removing the armor removes that particular set of stats from the merge. The system still has some jankiness. It's pretty clunky writing JSON files (my poor " key), plus the syntax of the various mods leaves quite a bit to be desired. Also, for the moment, the ability to merge StatSets applies only to simple numeric mods (can't use equipment to apply mods that rely on other stats, for example.) I don't see this being a problem at the moment, but it could be in the future. Still, for the relative simplicity of the underlying structure, it's given me quite a lot of flexibility in structuring the stat systems. I've got level-scaling of monsters, monsters that scale differently based on their JSON spec files, monsters with randomized mods, etc... It's pretty cool how it's all coming together. (Forgive the potato-quality of the stat sheet in the accompanying screen shot. This crap is way too much in flux right now for me to waste time building a custom UI widget yet.)
  14. JTippetts

    Drunks Standing Around Punching Each Other

    In practice, in my own personal playtesting plus some informal testing by a couple others, it feels weird to have it structured the way I describe. The number one source of weirdness seems to be the fact of DoTs ticking while other units are acting. This includes ground effects. In fact, it's almost infuriating to be having all this damage occur while the player can't do anything about it, and it makes having DoT damage sort of pointless. The whole point of a DoT is to provide damage but still give the target of the damage options and time in order to mitigate it. But I'm finding that the vast majority of DoT damage occurs during periods when the unit is not in control, making it impossible to mitigate except in advance. I'm considering reverting DoTs and ground effects to only ticking when the unit acts, but have auras tick/apply whenever a unit is in range (whether the unit is acting or the aura owner is acting.) This feels better, even if it's technically inconsistent. As long as it's understood up front that's the rule, maybe I can get away with it. If that feels weird, my fallback will be to have the auras apply only when the owner is acting, and just handwave away the inconsistencies.
  15. JTippetts

    My brief tour through 3d engines

    There is a Blender exporter for Urho3D at https://github.com/reattiva/Urho3D-Blender if you want to give that engine a second look. I pretty much use Urho3D exclusively these days, and find there is not much I can't do with it.
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!