Pulstar's Forum Posts

  • I start with planning key gameplay mechanics and technical features and their scope. Next I do a prototype for the technically riskiest concepts (basically things I never tried doing before). If it works, it goes further ahead, if not the concept is shelved, the scope is changed or otherwise the project evolves.

    Next when I start going into specific systems I look into their interdependency first and prioritize the ones on which others are dependent. For example, I could not implement combat mechanics before inventory mechanics worked. So I worked on a rudimentary inventory system first, design it so that it can easily be expanded if I miss something without scrapping the whole thing. That happened a lot to me in the past.

    For art I am a big fan of programmers art. For two reasons, one is that art is a timesink and time is the biggest constraint in a solo hobbyist project, it is best not to commit too much of it if you are not certain that. The other is that I am more of a technical/designer person than an artist, in the end once the technical part is done I will most likely hire a proper artist to redo most of the art. Making decent looking GUI is probably the best I can do.

  • I made an example showing how to filter/search for recipes by ingredient(s) used:

    https://www.dropbox.com/s/eo2ym6av6bqnm ... .capx?dl=1

    It should also show the XPath query used for filtering only the recipes containing the given selected components. There's also some extra attributes that could also be used in the searching but I was too lazy to do any GUI for them or implement the functionality.

    It also shows the quantity of the recipe output and the quantity of the component inputs. XML code is below (its also in the capx)

    Recipes:

    <?xml version="1.0"?>
    <recipes>
    <recipe name="Hammer" qty="1" lvl="3" type="weapon">
    	<component qty="2">Wood</component>
    	<component qty="1">Iron Bar</component>
    </recipe>
    <recipe name="Healing Salve" qty="3" lvl="1" type="consumable">
    	<component qty="2">Leaf</component>
    	<component qty="1">Wood</component>
    	<component qty="1">Medicinal Herb</component>
    </recipe>
    <recipe name="Staff of Bashing" qty="1" lvl="1" type="weapon">
    	<component qty="3">Wood</component>
    </recipe>
    <recipe name="Leaf Skirt" qty="1" lvl="2" type="armor">
    	<component qty="10">Leaf</component>
    	<component qty="2">Leather</component>
    </recipe>
    <recipe name="Short Sword" qty="1" lvl="5" type="weapon">
    	<component qty="7">Iron Bar</component>
    	<component qty="2">Leather</component>
    </recipe>
    </recipes>[/code:3atbg7v1]
    
    Items:
    
    [code:3atbg7v1]<?xml version="1.0"?>
    
    <items>
    <item type="armor" sprite="0" MaxStack="1">Leaf Skirt</item>
    <item type="weapon" sprite="0" MaxStack="1">Staff of Bashing</item>
    <item type="weapon" sprite="1" MaxStack="1">Hammer</item>
    <item type="weapon" sprite="2" MaxStack="1">Short Sword</item>
    <item type="component" sprite="0" MaxStack="99">Leaf</item>
    <item type="component" sprite="1" MaxStack="99">Iron Bar</item>
    <item type="component" sprite="2" MaxStack="99">Wood</item>
    <item type="component" sprite="3" MaxStack="99">Leather</item>
    <item type="component" sprite="4" MaxStack="99">Medicinal Herb</item>
    <item type="consumable" sprite="0" MaxStack="99">Healing Salve</item>
    
    </items>[/code:3atbg7v1]
  • So am I right on organizing them? If a Hammer has ingredients of wood and iron then I would have three separate XML files.

    One for wood, one for iron and one with craftable items (hammer, basket, hat)?

    If user searches hammer then it will show wood and iron.

    If user searches wood then hammer will show up.

    If user searches wood and iron then I can compare and still bring up hammer since it is in both?

    If I search leaf and wood then hammer would not show up because hammer isn't under leaf.

    I assume I would compare the the leaf and wood XML and remove the ones that don't match.

    I am not sure how to do that. Would I somehow use an array to compare?

    Would this be the best way?

    As I wrote in my post above, have ALL recipes in one XML file. Have them as parent nodes of their <ingredient> nodes. Then all you would need is an XPath query saying return all recipe nodes where the ingredient child is wood OR iron. If you had an XPath query searching for recipes using wood OR leaf, the hammer would show up on the list. No need to eliminate anything yourself, Xpath would return only nodes containing either of the ingredients. That would be it.

    Well, the issue would be constructing an XPath query string dynamically based on inputs to the "search list recipes with specified properties" function. That requires some planning on what you want the player to able to search for.

  • Also need to know how to hide a few from search for restrictions.

    Such as level or if recipe isn't unlocked yet.

    An example Capx would be great, but an explanation would work as well.

    I am thinking I will need a XML/JSON for the craft that has the recipe and a XML/JSON for each ingredient that has the names of the crafts the ingredient is in.

    Would I do Category the same? How would I show the recipe list in alphabetical order?

    While XML has a higher learning curve and is more of a pain to modify (I wrote an excel macro just to convert tables into the desired XML text output), it would be faster and easier to implement all the other functionality you want for this with XML. The reason for that is XPath queries. For JSON I think you would need to setup custom logic to get query-like functionality which you need for the recipe system features you desire (hiding unavailable recipes). Depending on what you need and how you organize the data, it can be more of a hassle but maybe that's just my ignorant opinion. I always used XML for these kinds of game databases (mostly for items, but not only).

    If you are already familiar with XML and XPath queries I would suggest XML as it will result in less stuff to debug within C2. Issue with it is human-readability, preparing the file itself and getting the XPath queries right.

    If I would be doing a system such as yours (actually I will need to do one, but probably after I get the skill trees fully working and combat turn logic working). I would do it as below:

    1) All recipes are stored within one XML file database. Every recipe is a single <recipe> element. The <recipe> element should have an attribute called "Output" and "OutputQuanity", these would define the item created and the quantity of the item created. You can also have additional attributes such as "Type", "ClassNeeded", "LevelNeeded" so that you can narrow down and filter the recipe list via XPath easily.

    Under each <recipe> element you would have <ingredient> child element. These <ingredient> elements should have an attribute called "QuantityNeeded". That would define how much of the ingredient would be needed to create one output batch of items.

    2) Now the hard part. What is an ingredient and how to check for it? There are two approaches here I can think of. The easy one is "each ingredient is a unique item", think WoW crafting. Then you just need to check the relevant inventory object (probably an array) with the player's items for the item named as the ingredient. If you are getting crafting materials directly from the natural source or resource nodes (mining copper veins, chopping trees for wood etc.). In this case the ingredients themselves would be listed with all the other items in an item XML object.

    The hard approach is what Fallout 4 did (yes, that game actually managed to not take the easy route with some RPG-ish mechanics, shocking I know), have ingredients not exist only as items, but as properties of other items. Say a telephone is made out of some copper and plastic. So basically allow breaking down junk items into components. This system is more realistic and depending on the theme of the game (in Fallout 4's case, a post-apocalyptic world of jury-rigging and salvage prospecting) may fit better. In this case your item system would need to be amended with data on what and how can be broken down into what. Also you would might want to add some logic to allow automatic breaking down of junk items when crafting a specific recipe, but that would also require additional logic to identify what can be broken down.

    3) Regardless of a picked approach at the end you need to show the available recipes via the games GUI, as a list. You will need an array. What I would do is fill this array using an xml object and the "for each node" condition, after entering an xpath query. So on a list refresh the array would have its width set to 0, next the query would be entered (you can build this dynamically out of function parameters with some text string appending) and the array would be filled by entering a new array X element for each node of the XML file returned by the XPath query. The main issue here really is setting up the XPath queries correctly. XPath is quite powerful but it is easy to make a mistake and get a broken query that does nothing, especially when building the XPath query dynamically based on function paremeters.

    4) Finally once the use selects one of the listed recipes (or for all visible recipes), you will need to use the XPath to the particular recipe (or for each recipe), get its components and check if they are in the required quantity in the player's inventory.

  • There are a couple of ways. But I think the best one would be to have just one generic message object(s). I imagine you would want a speech bubble or box or something and on top of it a spritefont or regular text object that from this point on I will simply call a label. Alternatively if you use sprite fonts and have one with outlines (to make it more readable against differently coloured backgrounds) you would need the label alone (typical floating text like in lucas arts adventure games of old).

    Now these objects (label and message box) should be invisible at layout start. What you would do is move these to the desired position (above the sign or player, I recommend using an image point for this) on collision, changing the text to the desired message and then making both objects visible.

    The message itself should be stored in each sign object as text variable. That way when the collision event with the sign happens, it would pick the right text (so long as the player does not overlap or collide with multiple signs simultaneously).

    All you would need to do now is to create an event as below:

    Conditions:

    On Player collision with Sign

    Actions:

    Move Label to sign image point (1)

    Set Label text to Sign.text

    Set Label visible

    Of course now you also need a way to make the message invisible either when the player stops colliding with it or after a given time (possibly both). For the former a simple inverted "player overlaps sign" event would be enough, as it would trigger when the player is not overlapping the sign. For the latter a timer and/or fade behaviour can be used (but then you need to remember to set opactity to 100% in addition to making the Label object visible when moving the sign).

  • you need to use sprites not the tilemap

    I am sorry but that is not correct:

    https://www.dropbox.com/s/bfwr6zs8mmzaf ... .capx?dl=1

    Shoot at a cactus. Press the button to generate a new map when out of cacti to shoot. The collision polygon is a bit too small on them so it mail fail occasionally, that can be changed in the tilemap tools in the C2 editor.

    That is one way to do it with just one tilemap, although for best performance I recommend using two tilemaps. One without collisions for most of the grapics and the other with collision for just the destroyable tiles. This is because only empty tiles do not have collision masks (it is not possible to disable collisions for specific tiles), therefore like in the example I linked to above, the "on collision" event will trigger every tick. If you would disable the second condition of the on collision event in my example which checks what tile the projectile collided with, the bullet would erase the tile on which the player is standing.

    I use something similar for LOS with walls, walls are a separate tilemap from the surface and have collisions plus solid behaviour.

    At the end of the day, working with an easier game engine made me waste more time. I came to realize that having a better notion of coding and also using better tools was the solution.

    That's my humble two cents

    This is my conclusion as well. Once I am done with my current project, apart from maybe a quick prototype, I am not investing more time into using Construct. I learned a lot, definitely got my money's worth out of the purchase (not in actual money but you get the idea). It was not a complete waste of time definitely, but it was a detour so to speak. What Jayjay and the others wrote is not very encouraging if one has ambitions beyond the web for a construct-based project.

    We will see where C3 heads off to, but my general feeling is it only has a future as an educational product.

  • Make a local variable in the consumption event, call it roll. Set it to random(0,100) in the ammo consumption event in the first sub-event.

    Have the chance of no ammo consumption as a variable of the player object, let's say it is called chance_of_no_ammo_consumption.

    In the ammo consumption event, add a subevent after the one where you set roll, compare variable roll great or equal to player.chance_of_no_ammo_consumption.

    As an action if that condition is met, add ammo consumption. If the roll is higher than the chance of ammo consumption, ammo will be consumed. If you roll a value lower than the ammo consumption chance, nothing will happen (so no ammo consumed).

  • For this explanation I assume the array is named array and the parameter through which you pass it is parameter 0.

    How do I pass an array as a parameter ?

    Enter the parameter you want as "array.uid" (without quotes) when calling the function. Of course make sure that only the specific array you want is picked in the sub-event from which you call the function.

    Then in the "on function" event just use an array pick by UID condition as the second condition, enter "function.param(0)" as the UID by which you want to pick. Alternatively if you use your own variable you use to identify arrays, you can just pass that and pick an instance that has the right value.

    How do I pass an array as a return value ?

    Just use array.UID again, similar to above.

    How do I have a local array in an event ?

    You can't set an array as local to an event, this is one of the drawbacks of construct 2. There are some workarounds though. One I use is that I have a global dummy array. In the every event/function/whatever/ it is used it first gets cleared, resized. Then I use it as I wish. So far this has not came back to bite me, but knowing how unpredictable loops sometimes are in construct (the "for"/"for each" loops seem to run iterations in parallel rather than sequentially) I only use it in while and repeat loops only or events without loops.

    Another is to create the array in the event to use it and destroy it in the end. But this one is not as simple as you might think, because in the tick/frame in which an object is created it cannot be picked events apart from the pick by UID event. A workaround for this is to have a function that creates and object and returns its UID.

    The an alternative for one dimensional arrays is to use a local string variable and build a coma "," or semicolon ";" or pipe "|" string where each value is an array element. Then use the tokenat and tokencount expressions to retrieve the element. That is truly local but it has its own limitations.

    Same for dictionaries and XML trees...

    They also cannot be set to local. I would suggest trying to do something similar as I wrote for arrays.

    And how do I count occurrences of an element in an array ?

    I assume you meant occurrences of a particular element value (how many time the array contains "foo" for example). This one is simple. Just use a "for each element" array condition. Then add a subevent to the event containing the "for each element" checking the value at "array.CurX" if it matches the desired value. In that subevent add 1 to a local variable tracking occurrences.

  • It is not a limitation. I believe you are using it incorrectly.

    The reason the counter does not change on kill all is that the event only triggers if a sprite with "countme" set to true exists. Pickedcount for an Object will never return 0 if you do it in any kind of event that picks instances of that object meeting a condition, because events with conditions trigger only after at least one instance meeting the conditions is found (assuming there is no condition set by you to tell it "if picked count>X", then you would need x+1). Also the event changing the counter is before the event destroying the enemies. What happens is:

    Tick 1

    1) counter is changed to reflect current number (5)

    2) button was pressed, destroyed all (after counter last updated)

    Tick 2

    1) no enemies exist and thus the condition for updating the counter is not met. This is why you see the initial number as the set text action does not execute at all.

    The proper way to do this would be as in the attached capx, use a subevent in a event block with no conditions, check if any marked with "countme" enemies exist in one subevent, else in the other subevent set counter to 0 (as they don't exist).

    https://www.dropbox.com/s/pdj2npl3h0tu1 ... .capx?dl=1

  • Instead of "on collision" use the "is overlapping another object" condition, right click on the condition and select invert. Invert works like a "NOT" statement IIRC.

    Basically that will trigger only if the instance is not colliding with whatever sprite you want it to not collide with.

  • I do not have much time as I have a business trip tomorrow morning, but I glanced at your capx and I can tell you I had the same problem. And mine was a bit bigger because I have a 64 by 64 tile building floor with ~40 randomly generated rooms with different shapes.

    What I did was the following, please note I forgotten some details and I feel an immense sense of dread whenever I need to look into my map generation logic (at 350 event blocks it is a bit big and unpleasant to look at, also it takes 40-50 seconds to generate a level on my LG spirit LTE/4G droid phone (Desktop PC with NW.js takes 3-4 seconds for the same). I know the solution is not fool proof but the margin of not accessible rooms I get is acceptable (maybe 1 in a 100 if not less). Still it should give you some ideas.

    One thing I did is that in my array that stores all map data in z-indexes (from 0 to 17 I think, stuff like fog of war, walls, bitwise for walls etc.). One of the things stores was room ID.

    1) Generate rooms/walls first. I used prefabs for this but it doesn't matter so long as you have an array which tells you which tile belongs to which room. I have a separate array used for rooms which uses the y-axis to store data such as, what is the parent room, is the room connected to the starting room (elevator in my case). So every time I placed a new room, it would also get pushed as an X element to the array.

    2) For each room I checked the whole map array for all tiles belonging to that room that were walls (but not corner walls). Every time a tile like that was found, it was added to yet another array. This array stored the x coordinate at y=1 and the y coordinate of the tile at y=2. So what was at y=0 you ask? A random number from 0 to 100. Why? Because after I finished checking the whole map for that particular room and had all its wall, I would sort the array. Since it sorts by values at (x,0) I would have wall arrays in a random order.

    3) I would go through the now randomly sorted wall tiles for the room and start checking the following. Does it neighbour a different room? If yes, is that room already a child or parent of this room (a parent here is a room that is "closer" to the start, a child is a room "closer" to the end, but not by actual distance but by the number of rooms needed to cross)? If yes, we skip to the next tile in the array, if not we can create a door at that tile. The room to which we just connected is now set as the parent of the current room. If the parent happens to be connected to the start, we also mark the current room as connected in the room array.

    4) We did 2 and 3 for each room. So next we check the room array if all rooms are connected to the start. When we find a room that is not connected, we do 2 and 3 for it again. The logic should again create a door to a room that was previously not directly connected with the current one. We do that for every room that is not connected until all rooms are connected or there are no more connections that can be created for the unconnected rooms(I do this via a while loop).

    Actually I stretched the truth a bit, I looked at my project and I never bothered marking rooms as being out of possibilities to connect. I just hard-capped the while loop that goes through each room>generates a door>creates the connection tree/map, to run two times an apparently it was enough to not get unconnected rooms >_>. I do not know why, but there's probably some mathematical theory or theorem that explains this. I kind of like it because the room connections are quite random, sometimes there are dead end rooms, there are rooms with 2 doors, some have 3 and in more rare cases 4.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Is the tilemap a side-scrolling map or a top-down one? I assume the former from your image. (edit: I saw your second post after posting this one, obviously sidescrolling)

    Here's a capx example:

    https://www.dropbox.com/s/nhwqq14d716xy ... .capx?dl=1

    Basically for bridges or straight slopes you only need to use the a or m (slope) parameter of a linear function. You go from the lower x to the upper x and add a to Y with every loop iteration.

    For filling terrain of a random height you need to nest a loop that will fill terrain from the bottom to it top (or vice versa) within the loop going from the lower x to the upper x. Every time you go to the new x you pick a random Y that will be your top.

    With some tinkering you can also clamp the random Y's so that the height difference between x and x+1 is of a given maximum. Basically something like Y=Y+floor(random(0,3)*choose(-1,1). That will generate the height at the next X position at most 2 tiles lower or higher than the previous x position. The terrain would be more even yet still jagged at places.

  • Wait, are you using actual pixel sized sprites or a tilemap with pixel sized tiles? Did you test how fast the collisions work with it? It sounds like it would run rather slow.

    At any rate I have bad news, there is an upper limit on how much total array size the engine can handle. I once reached it when experimenting with inifinite world generation.

    The workaround in nwjs I found was to offload avery part of the array that is not used by the visible area into as a json string to custom text files files using nwjs file saving to disk function. I would load them back into a smaller visible area array when needed. That however required setting up a filenaming system so the game knew what to load at what coordinates.

  • CJacobsSA

    Try the below demo I just made. Everything should be commented (besides the very obvious on flash stop make warning text invisible event).

    Basically this is an inventory system working kind of like in minecraft where you have a max stack size per slot. Although unlike in minecraft here the stack size is the same for all objects, set by the global variable MaxStackSize. In minecraft tools, buckets etc. have a stack size of 1 vs 64 for most if not all blocks IIRC.

    I ended up using a while loop as it is the most flexible and efficient IMO for doing such searches through an array. Note that the demo is fairly rudimentary, and it will not for instance, prioritize putting a block into a not yet full slot with the same type over putting it in an empty slot (if one has a lower index). As there is no way in the demo to remove an item from a slot, this case will never happen.

    https://www.dropbox.com/s/3k9v2fdlqhn3b ... .capx?dl=1