Jump to content
  • Advertisement

Leaderboard

The search index is currently processing. Leaderboard results may not be complete.

Popular Content

Showing content with the highest reputation on 08/19/19 in all areas

  1. 2 points
    Afaik OpenGL can swap data in an out between system and video memory. What's the maximum texture size your graphics card supports ? Does it support compression ? Is there a chance that that you can split the texture into tiles ?
  2. 2 points
    Same! Just started my journey and got both of them to learn right away. Sometimes it gets confusing, but I'm sure you'll be able to make it through!
  3. 1 point
    The August 2019 Challenge on GameDev.net has been announced and it is about recreating DOOM with current technology. I missed the original DOOM craze in the 1990s although I had developed some computer games in the decade before that. So I first had to look at the Wikipedia entry on DOOM to see what it was all about. What a coincidence that the story, created in 1993, begins in 2019! Mars is supposed to be colonised by now with experiments being done on teleportation between Mars and its two tiny moons, Phobos and Deimos. One interpretation of the plot is that the teleportation machines are subverted so that they spew out horrible creatures from some unknown origin - hell? The creatures are determined to attack us and they must therefore be exterminated, which forms the action of the game. As I have not seen the original DOOM I am not qualified to respond directly to GameDev.net's challenge but it set me thinking tangentially. What about a prequel to DOOM, where the teleporters are being tested before being installed on Mars and its moons? Let us imagine that the testing was not thorough enough, leaving vulnerabilities to be exploited by hackers. Pre-DOOM is thus about the laboratory in which 3 teleporters are to be tested before being set up in their intended locations. The player will try each machine out and complete a test report. If all seems satisfactory we then have to consider what could still be wrong. Perhaps there is something outside the testing lab? My little game is written in JavaScript with an HTML5 front page. It is entirely client-based. It uses the HTML5 2D graphics context but no other libraries or frameworks. I have adapted it from another HTML5 game of mine, The Forest, an explanation of which can be found here. Pages after that describe the history (from 1982) and programming details. Pre-DOOM uses my own photographs for some of the graphics, just like The Forest. The game is basically complete and available completely free here: https://www.grelf.net/predoom There are just a few untidinesses to be addressed. www.grelf.net August 2019
  4. 1 point
    It can be difficult to determine balance from numbers/stats alone. Balance is often determined in balance playtesting. If there are just the two of you and you have different opinion as to balance, a session with impartial playtesters should help sway one or both of you. There are two Extra Credits videos you both should watch on YouTube: "Playtesting - How to Get Good Feedback on Your Game" and "Understanding Your Player: Play Sessions - How Will People Play Your Game?" A paper prototype can be a useful way to go if A-B testing with your software is impractical.
  5. 1 point
    I'm Chris Eck, and I'm the tools developer at HBS for the Battletech project. I've recently been given permission to write up articles about some of the things I work on which I hope to post on a semi regular basis. Feel free to ask questions about these posts or give me suggestions for future topics. However please note, I am unable to answer any questions about new/unconfirmed features. I've been tackling Unity 2018 upgrade issues as they come my way, and I've been chugging along with my data driven enumeration refactors. I've done four or five now so I'm starting to gain a deeper understanding of the process. I find all references to the hard coded enum and identify where any code decisions are being made. Then I create data fields to drive that logic instead. After I have all those bits defined, I create the table/columns in the database and then populate it. Creating the C# classes and functions that interface with the database is not quite copy/paste grunt work. There needs to be a class with the fields, and functions to select, insert, and update those rows in the database. But the fields for the different enumerations are all different. The work isn't difficult, but it's time consuming and a bit fiddly. When I started writing this final set I told myself, "Self... Writing this code is boring and repetitive... There has to be a better way..." Enter Code Generation I had several completed examples so I the kinks already worked out. I used all the AmmoCategory classes and functions and just copied them into a text file. I then replaced anything that had AmmoCategory specific items with some keys that I could find and replace. I ended up with a template file that looked like this: public class %ClassName% { %FieldList%} #region %TableName% public static List<%ClassName%> SelectAll%PluralTableName%(this MetadataDatabase mdd) { string query = "SELECT %TableAlias%.* FROM %TableName% as %TableAlias%"; List<%ClassName%> %LowerTableName%List = mdd.Query<%ClassName%>(query).ToList(); return %LowerTableName%List; } public static %ClassName% Select%TableName%ByID(this MetadataDatabase mdd, int %LowerTableName%ID) { %ClassName% %LowerTableName%Row = mdd.Query<%ClassName%>( "SELECT * FROM %TableName% WHERE %TableName%ID=@%TableName%ID", new { %TableName%ID = %LowerTableName%ID }) .FirstOrDefault(); return %LowerTableName%Row; } public static %ClassName% Insert%TableName%Value(this MetadataDatabase mdd, %TableName%Value %LowerTableName%) { mdd.Execute("INSERT INTO %TableName%" + " (%InsertFieldList%)" + " values(%InsertValueList%)", new { %InsertAnonymousTypeList% }); %ClassName% %LowerTableName%Row = Select%TableName%ByID(mdd, %LowerTableName%.ID); return %LowerTableName%Row; } public static %ClassName% Update%TableName%Value(this MetadataDatabase mdd, %TableName%Value %LowerTableName%) { mdd.Execute("UPDATE %TableName% SET" + " %UpdateFieldList%" + " WHERE %UpdateWhereFieldList%", new { %InsertAnonymousTypeList% }); %ClassName% %LowerTableName%Row = Select%TableName%ByID(mdd, %LowerTableName%.ID); return %LowerTableName%Row; } public static %ClassName% InsertOrUpdate%TableName%Value(this MetadataDatabase mdd, %TableName%Value %LowerTableName%) { InsertOrUpdateEnumValue(mdd, %LowerTableName%); %ClassName% %LowerTableName%Row = Select%TableName%ByID(mdd, %LowerTableName%.ID); if (%LowerTableName%Row == null) { %LowerTableName%Row = Insert%TableName%Value(mdd, %LowerTableName%); } else { %LowerTableName%Row = Update%TableName%Value(mdd, %LowerTableName%); } return %LowerTableName%Row; } #endregion // %TableName% Then I defined my WeaponCategory table in the database (that's the new one I was working on). The table has the various column names and their data types defined and Sqlite has a PRAGMA command that can pull that information for you. Once I have that data, I can start with my substitution. Here's what the code generating function looks like /// <summary> /// Given a table name, pull that table's info from the database and generate code for /// the DTO, Select, Insert, and Update functions. /// </summary> /// <param name="tableName">The name of the table to generate code for</param> /// <param name="pluralTableName">The pluralized name. I didn't feel like writing code to figure out when to drop the y and ad ies. :P</param> /// <returns>The generated code for the DTO, Select, Insert, and Update functions.</returns> public static string GenerateCode(string tableName, string pluralTableName) { MetadataDatabase mdd = MetadataDatabase.Instance; string lowerTableName = char.ToLower(tableName[0]) + tableName.Substring(1); string className = string.Format("{0}_MDD", tableName); string lowerClassName = string.Format("{0}_MDD", lowerTableName); List<SqliteTableInfo> columnInfoList = mdd.GetTableInfo(tableName); string tableAlias = ""; for (int i = 0; i < tableName.Length; ++i) { char c = tableName[i]; if (char.IsUpper(c)) tableAlias += char.ToLower(c); } // Load up our template file. string generatedCode = File.ReadAllText("SqliteCodeGen\\CodeGenTemplate.txt"); StringBuilder fieldList = new StringBuilder(); StringBuilder insertFieldList = new StringBuilder(); StringBuilder insertValueList = new StringBuilder(); StringBuilder insertAnonymousTypeList = new StringBuilder(); StringBuilder updateFieldList = new StringBuilder(); StringBuilder updateWhereFieldList = new StringBuilder(); // Loop through each of our column names and build the data that we need for (int i = 0; i < columnInfoList.Count; i++) { SqliteTableInfo columnInfo = columnInfoList[i]; fieldList.AppendLine(BuildFieldLine(columnInfo.name, columnInfo.type)); insertFieldList.Append(BuildInsertField(columnInfo)); insertValueList.Append(BuildInsertValue(columnInfo)); insertAnonymousTypeList.Append(BuildInsertAnonymousType(columnInfo, lowerTableName)); if (columnInfo.pk > 0) updateWhereFieldList.Append(BuildUpdateWhereField(columnInfo)); else updateFieldList.Append(BuildUpdateField(columnInfo)); } // Remove the extra ", " from each of these lists. insertFieldList.Remove(insertFieldList.Length - 2, 2); insertValueList.Remove(insertValueList.Length - 2, 2); insertAnonymousTypeList.Remove(insertAnonymousTypeList.Length - 2, 2); updateFieldList.Remove(updateFieldList.Length - 2, 2); // Remove the extra "AND " from this list updateWhereFieldList.Remove(updateWhereFieldList.Length - 4, 4); generatedCode = generatedCode.Replace("%TableName%", tableName); generatedCode = generatedCode.Replace("%PluralTableName%", pluralTableName); generatedCode = generatedCode.Replace("%TableAlias%", tableAlias); generatedCode = generatedCode.Replace("%LowerTableName%", lowerTableName); generatedCode = generatedCode.Replace("%ClassName%", className); generatedCode = generatedCode.Replace("%LowerClassName%", lowerClassName); generatedCode = generatedCode.Replace("%FieldList%", fieldList.ToString()); generatedCode = generatedCode.Replace("%InsertFieldList%", insertFieldList.ToString()); generatedCode = generatedCode.Replace("%InsertValueList%", insertValueList.ToString()); generatedCode = generatedCode.Replace("%InsertAnonymousTypeList%", insertAnonymousTypeList.ToString()); generatedCode = generatedCode.Replace("%UpdateFieldList%", updateFieldList.ToString()); generatedCode = generatedCode.Replace("%UpdateWhereFieldList%", updateWhereFieldList.ToString()); // If you want to write out a file instead of use the copy/paste window, uncomment this line. //File.WriteAllText(string.Format("SqliteCodeGen\\{0}.cs", tableName), generatedCode); return generatedCode; } public static string BuildFieldLine(string fieldName, string fieldTypeText) { string fieldType = "string"; // INTEGER can mean a few different things in SQLITE if (fieldTypeText == "INTEGER") { // We're identifying bools by convention. See if this starts with one of the common bool words. if (IsBool(fieldName)) fieldType = "bool"; else if (fieldName.EndsWith("ID")) fieldType = "long"; else fieldType = "int"; } else if (fieldTypeText == "REAL") fieldType = "float"; else if (fieldTypeText == "TEXT") fieldType = "string"; else Debug.LogError(string.Format("Unsupported Field Type [{0}] - defaulting to string", fieldType)); string fieldLine = string.Format("\tpublic {0} {1} {{ get; private set;}}", fieldType, fieldName); return fieldLine; } private static bool IsBool(string fieldName) { if (IsBoolWord(fieldName, "Can")) return true; if (IsBoolWord(fieldName, "Force")) return true; if (IsBoolWord(fieldName, "Has")) return true; if (IsBoolWord(fieldName, "Is")) return true; if (IsBoolWord(fieldName, "Include")) return true; if (IsBoolWord(fieldName, "Should")) return true; if (IsBoolWord(fieldName, "Use")) return true; if (IsBoolWord(fieldName, "Uses")) return true; return false; } public static bool IsBoolWord(string fieldName, string boolWord) { if (fieldName.StartsWith(boolWord) && fieldName.Length > boolWord.Length && char.IsUpper(fieldName[boolWord.Length])) return true; else return false; } private static string BuildInsertField(SqliteTableInfo columnInfo) { return string.Format("{0}, ", columnInfo.name); } private static string BuildInsertValue(SqliteTableInfo columnInfo) { return string.Format("@{0}, ", columnInfo.name); } private static string BuildInsertAnonymousType(SqliteTableInfo columnInfo, string lowerTableName) { string annonymousType = string.Format("{0}={1}.{0}, ", columnInfo.name, lowerTableName); return annonymousType; } private static string BuildUpdateWhereField(SqliteTableInfo columnInfo) { return string.Format("{0}=@{0} AND ", columnInfo.name); } private static string BuildUpdateField(SqliteTableInfo columnInfo) { return string.Format("{0}=@{0}, ", columnInfo.name); } Since Sqlite only has a few data types INTEGER, REAL, TEXT, BLOB - it doesn't have types for bool. In the database, we use integer based fields for those. On the c# side though, I want to use bools. I identify which fields are bools by naming convention. If it starts with something like "Is" or "Has" and the next letter is capital, then I call it a bool. It may not be perfect, but it's easily fixed if I misidentify a field. Running it against this table CREATE TABLE "WeaponCategory" ( "WeaponCategoryID" INTEGER NOT NULL UNIQUE, "IsBallistic" INTEGER NOT NULL, "IsMissile" INTEGER NOT NULL, "IsEnergy" INTEGER NOT NULL, "IsSupport" INTEGER NOT NULL, "IsMelee" INTEGER NOT NULL, "CanUseInMelee" INTEGER NOT NULL, "IsAffectedByEvasive" INTEGER NOT NULL, "ForceLightHitReact" INTEGER NOT NULL, "DamageReductionMultiplierStat" TEXT NOT NULL, "ToBeHitStat" TEXT NOT NULL, "DesignMaskString" TEXT NOT NULL, "TurretDamageMultiplier" REAL NOT NULL, "VehicleDamageMultiplier" REAL NOT NULL, "MinHorizontalAngle" REAL NOT NULL, "MaxHorizontalAngle" REAL NOT NULL, "MinVerticalAngle" REAL NOT NULL, "MaxVerticalAngle" REAL NOT NULL, "UIColorRef" TEXT NOT NULL, "FallbackUIColor" TEXT, "Icon" TEXT NOT NULL, "HardpointPrefabText" TEXT NOT NULL, "UseHardpointPrefabTextAsSuffix" INTEGER NOT NULL, PRIMARY KEY("WeaponCategoryID") ); yields the following code. #region WeaponCategory public static List<WeaponCategory_MDD> SelectAllWeaponCategories(this MetadataDatabase mdd) { string query = "SELECT wc.* FROM WeaponCategory as wc"; List<WeaponCategory_MDD> weaponCategoryList = mdd.Query<WeaponCategory_MDD>(query).ToList(); return weaponCategoryList; } public static WeaponCategory_MDD SelectWeaponCategoryByID(this MetadataDatabase mdd, int weaponCategoryID) { WeaponCategory_MDD weaponCategoryRow = mdd.Query<WeaponCategory_MDD>( "SELECT * FROM WeaponCategory WHERE WeaponCategoryID=@WeaponCategoryID", new { WeaponCategoryID = weaponCategoryID }) .FirstOrDefault(); return weaponCategoryRow; } public static WeaponCategory_MDD InsertWeaponCategoryValue(this MetadataDatabase mdd, WeaponCategoryValue weaponCategory) { mdd.Execute("INSERT INTO WeaponCategory" + " (WeaponCategoryID, IsBallistic, IsMissile, IsEnergy, IsSupport, IsMelee, CanUseInMelee, IsAffectedByEvasive, ForceLightHitReact, DamageReductionMultiplierStat, ToBeHitStat, DesignMaskString, TurretDamageMultiplier, VehicleDamageMultiplier, MinHorizontalAngle, MaxHorizontalAngle, MinVerticalAngle, MaxVerticalAngle, UIColorRef, FallbackUIColor, Icon, HardpointPrefabText, UseHardpointPrefabTextAsSuffix)" + " values(@WeaponCategoryID, @IsBallistic, @IsMissile, @IsEnergy, @IsSupport, @IsMelee, @CanUseInMelee, @IsAffectedByEvasive, @ForceLightHitReact, @DamageReductionMultiplierStat, @ToBeHitStat, @DesignMaskString, @TurretDamageMultiplier, @VehicleDamageMultiplier, @MinHorizontalAngle, @MaxHorizontalAngle, @MinVerticalAngle, @MaxVerticalAngle, @UIColorRef, @FallbackUIColor, @Icon, @HardpointPrefabText, @UseHardpointPrefabTextAsSuffix)", new { WeaponCategoryID = weaponCategory.WeaponCategoryID, IsBallistic = weaponCategory.IsBallistic, IsMissile = weaponCategory.IsMissile, IsEnergy = weaponCategory.IsEnergy, IsSupport = weaponCategory.IsSupport, IsMelee = weaponCategory.IsMelee, CanUseInMelee = weaponCategory.CanUseInMelee, IsAffectedByEvasive = weaponCategory.IsAffectedByEvasive, ForceLightHitReact = weaponCategory.ForceLightHitReact, DamageReductionMultiplierStat = weaponCategory.DamageReductionMultiplierStat, ToBeHitStat = weaponCategory.ToBeHitStat, DesignMaskString = weaponCategory.DesignMaskString, TurretDamageMultiplier = weaponCategory.TurretDamageMultiplier, VehicleDamageMultiplier = weaponCategory.VehicleDamageMultiplier, MinHorizontalAngle = weaponCategory.MinHorizontalAngle, MaxHorizontalAngle = weaponCategory.MaxHorizontalAngle, MinVerticalAngle = weaponCategory.MinVerticalAngle, MaxVerticalAngle = weaponCategory.MaxVerticalAngle, UIColorRef = weaponCategory.UIColorRef, FallbackUIColor = weaponCategory.FallbackUIColor, Icon = weaponCategory.Icon, HardpointPrefabText = weaponCategory.HardpointPrefabText, UseHardpointPrefabTextAsSuffix = weaponCategory.UseHardpointPrefabTextAsSuffix, }); WeaponCategory_MDD weaponCategoryRow = SelectWeaponCategoryByID(mdd, weaponCategory.ID); return weaponCategoryRow; } public static WeaponCategory_MDD UpdateWeaponCategoryValue(this MetadataDatabase mdd, WeaponCategoryValue weaponCategory) { mdd.Execute("UPDATE WeaponCategory SET" + " IsBallistic=@IsBallistic, IsMissile=@IsMissile, IsEnergy=@IsEnergy, IsSupport=@IsSupport, IsMelee=@IsMelee, CanUseInMelee=@CanUseInMelee, IsAffectedByEvasive=@IsAffectedByEvasive, ForceLightHitReact=@ForceLightHitReact, DamageReductionMultiplierStat=@DamageReductionMultiplierStat, ToBeHitStat=@ToBeHitStat, DesignMaskString=@DesignMaskString, TurretDamageMultiplier=@TurretDamageMultiplier, VehicleDamageMultiplier=@VehicleDamageMultiplier, MinHorizontalAngle=@MinHorizontalAngle, MaxHorizontalAngle=@MaxHorizontalAngle, MinVerticalAngle=@MinVerticalAngle, MaxVerticalAngle=@MaxVerticalAngle, UIColorRef=@UIColorRef, FallbackUIColor=@FallbackUIColor, Icon=@Icon, HardpointPrefabText=@HardpointPrefabText, UseHardpointPrefabTextAsSuffix=@UseHardpointPrefabTextAsSuffix" + " WHERE WeaponCategoryID=@WeaponCategoryID ", new { WeaponCategoryID = weaponCategory.WeaponCategoryID, IsBallistic = weaponCategory.IsBallistic, IsMissile = weaponCategory.IsMissile, IsEnergy = weaponCategory.IsEnergy, IsSupport = weaponCategory.IsSupport, IsMelee = weaponCategory.IsMelee, CanUseInMelee = weaponCategory.CanUseInMelee, IsAffectedByEvasive = weaponCategory.IsAffectedByEvasive, ForceLightHitReact = weaponCategory.ForceLightHitReact, DamageReductionMultiplierStat = weaponCategory.DamageReductionMultiplierStat, ToBeHitStat = weaponCategory.ToBeHitStat, DesignMaskString = weaponCategory.DesignMaskString, TurretDamageMultiplier = weaponCategory.TurretDamageMultiplier, VehicleDamageMultiplier = weaponCategory.VehicleDamageMultiplier, MinHorizontalAngle = weaponCategory.MinHorizontalAngle, MaxHorizontalAngle = weaponCategory.MaxHorizontalAngle, MinVerticalAngle = weaponCategory.MinVerticalAngle, MaxVerticalAngle = weaponCategory.MaxVerticalAngle, UIColorRef = weaponCategory.UIColorRef, FallbackUIColor = weaponCategory.FallbackUIColor, Icon = weaponCategory.Icon, HardpointPrefabText = weaponCategory.HardpointPrefabText, UseHardpointPrefabTextAsSuffix = weaponCategory.UseHardpointPrefabTextAsSuffix, }); WeaponCategory_MDD weaponCategoryRow = SelectWeaponCategoryByID(mdd, weaponCategory.ID); return weaponCategoryRow; } public static WeaponCategory_MDD InsertOrUpdateWeaponCategoryValue(this MetadataDatabase mdd, WeaponCategoryValue weaponCategory) { InsertOrUpdateEnumValue(mdd, weaponCategory); WeaponCategory_MDD weaponCategoryRow = SelectWeaponCategoryByID(mdd, weaponCategory.ID); if (weaponCategoryRow == null) { weaponCategoryRow = InsertWeaponCategoryValue(mdd, weaponCategory); } else { weaponCategoryRow = UpdateWeaponCategoryValue(mdd, weaponCategory); } return weaponCategoryRow; } #endregion // WeaponCategory That's quite a bit of boilerplate code. And not only is generating the code way faster than I could do it by hand, I can count on it being bug free. Or if there is ever a bug in it, I can fix it in my code generation and rerun it against my table entities to fix the same problem everywhere. I had been putting this off for a while. Any time I was making a new table for the database, time pressures were always high. It was faster to do the one-off table by hand than to do the code-gen system (in the immediate short term). Now that I finally have some breathing room I was able to put this system in place. It didn't take very long and it will probably pay for the time investment after I do one more of these enumerations. Personal Project Update - Car Wars A friend of mine invited me to participate in his company's game jam. They all use Unreal so I've been putting my free time into running through Unreal tutorials. I don't want to be a boat anchor on his team. >.< So Car Wars is going to be postponed probably a couple of weeks while I participate in that. Tips From your Uncle Eck Keep an eye out for code generation opportunities. If you're writing the same type of code over and over and Generics aren't quite the right fit, consider writing some code generation. It probably doesn't take as long as you might think and you'll save yourself time in the long run. Links Twitter Post: https://twitter.com/Eck314/status/1162755432592683008
  6. 1 point
    Clearly you're using the wrong language 😛 From https://docs.python.org/3/reference/expressions.html?highlight=comparison#comparisons
  7. 1 point
    That piece is from 2003, updated in 2010. While it sounds like reasonable advice to me, I'm curious about to what degree it still applies today? It feels like a lot has changed in the games industry: Crowdfunding, Unity & UE4, Steam Direct, ...
  8. 1 point
    Short answer: Forget it. Long answer: Finding an investor is genuily hard, they usually invest in teams with experience, i.e. people who have worked in a leading position on one or multiple successful games in the past. You may have luck if you have a small project that requires $100k or less but since you are looking for an investment of I guess more than $1 million you have a higher chance of winning the lottery than finding an investor. You will need a prototype anyway. You can then try to get money via crowdfunding and investors will probably contact you if your campaign is successful. But getting there is already hard and you will need money, probably in excess of $20k, just for the marketing and PR for your crowdfunding campaign. But realistically you won't get more than maybe $200k with that approach since it is your first game. I know of a team who got something between $100k and $200k and those people did kind of lie (claimed to have experience and a large team when in reality the people with the experience were freelancers and the actual team without freelancers was just 2 people - the CEO and the CEO's little brother who was hired as a programmer despite him having little experience).
  9. 1 point
    You've answered your own question. You don't get what you don't pay for.
  10. 1 point
    This is good advice and probably you just got it wrong. Example: You tell the programmer you want huge worlds with details at all scales, using engine X because some guy on a forum says it's great. But the programmer knows from experience engine X can't do that well, and he proposes to write a custom engine from scratch, or to use another engine Y because it worked well in a similar project before. In this case the programmer is in the better position to make the decision, because you don't know anything about programming or engine limitations yourself. To find out if the programmers are good or not in the interview i suggest you let them show the projects they worked on. Probability is high at least one guy worked on procedural planets or terrain etc. before and you like it. That's surely better than rejecting somebody just because he likes Java, or for other technical reasons you don't fully understand yourself. If you would not have worked on 3D models for the game already, i would ask if 2D would be an option. Could make things a lot easier. Pixel art sprites are easier to get done than acceptable 3D character animation for example. Might be still worth a thought. 3D Models could be used than in the next, larger project.
  • Advertisement
  • Advertisement
  • Popular Contributors

  • Member Statistics

    • Total Members
      259817
    • Most Online
      6110

    Newest Member
    Shilluk
    Joined
  • 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!