Yann's Forum Posts

  • When you're developping a game, you enter the world of tricks and faking.

    It's just not a straightforward process.

    The only time I worked on a game with full, non modular assets, was on a friends point&click game.

    But we still used a trick: we made video sequences that looped and we layered a HUD on top. Changing a view was merely just reaching another point on the video and looping through a range (like from the 30th second to the 45th).

    The year before I learnt the lesson. Another friend was making the same kind of point&click but with Sprite animations. The project (it was multimedia fusion 2 but it's not relevant here) went up to 1.5Go and took like 10 minutes to open.

    And at least 1 minute or 2 to preview it. The Ram used, I think, went up to 800Mo.

    All that because there were a lot of 1024x768 sprite animation.

    If you're curious about the calculation it's rather simple. A pixel has 4 channels R,G,B,A and each Chanel takes 1byte (8bit, 256 levels).

    So a 1024 x 768 image will take 1024*768*4 bytes which is exactly 3Mo.

    This friend of mine had like 4 camera view with looping animation(to create some kind of mood...) and when I say animations, it was 3D animated render and composited on after effect. So making tonnes of frames was pretty cheap. And there were between 50 and 150 frames. On top of that, there were some state changes, which means, an entirely new animation loop each time.

    So the project probably had up to 250/300 images.... Here are your 800Mo of Ram. (And of project size since, I think multimedia fusion 2 store images as raw bitmaps).

    Now, for a better example that kind of speak for itself, you have Rayman Origins.

    <img src="https://dl.dropboxusercontent.com/u/23551572/misc/rayman-repetition.jpg" border="0" />

    And I'm probably missing tonnes of things.

    I wouldn't be surprised if some part of the land in the background were used for the foreground (or the other way arround)

    But anyway, you can see that this image is build by duplicating the same assets. They are resized/mirrored but also the hue,saturation and lightness are tweaked as well as some blurring effect to fake out of focus objects.

    What I suspect as well, since it's made with the ubiart framework. is that the curly plants might be distorted sprites to create a bit more variety. And also, you can see those plant on other levels but with a more purple hue.

    And that's only what I discovered. They are definitely more tricks that allowed them to lower the memory footprint and so increase the amount of graphics in the image.

    A good 2D game artist has to think of modularity. It's not easy, it's even, often, painfull for the artist. But that's the price of real time rendering (:

  • septeven

    J't'en prie (:

  • septeven

    I think you can create the datalist node outside of the jQuery(document).ready() call

    That's just when you append it to the canvasdiv node that you have to be sure it's been loaded.

    You also just need to wait to set the Attribute of the element.

    In short your behinstProto.onCreate can look like that:

         behinstProto.onCreate = function()
         {
              /** Load properties **/
              this.myProperty = this.properties[0];
    
              var self = this;
              this.wordsArray = [];
    
              this.datalist = document.createElement("datalist");
              this.datalist.id = "datalist" + this.inst.uid;
    
              /** on cr�er une array contenant la liste des mots **/
              self.wordsArray  = self.properties[0].split(",");
              var wordsArrayLength = self.wordsArray.length;
    
              for (var i = 0; i < wordsArrayLength; i++)
              {
                   var word = document.createElement("option");
                   word.value = self.wordsArray[i];
                   jQuery(word).appendTo(self.datalist);
              }
    
              jQuery(document).ready( function() {
                        /** on r�cup�re la textbox concern�e **/
                        var textbox = self.inst.elem;
                        textbox.setAttribute("list", "datalist"+self.inst.uid);
                        /** on ajoute l'�l�ment datalist au projet **/
                        jQuery(self.datalist).appendTo(self.runtime.canvasdiv ? self.runtime.canvasdiv : "body");
    
                   }
              );
    
         };
    
  • Link to .capx file (required!):

    destroyInstanceSound.capx

    Steps to reproduce:

    You can drag&drop the red sprite to hear the effect of the 4 positionned sound

    When you click on a blue sprite, it is destroyed and the sound they "emit" should stop.

    Observed result:

    Only if you destroy the instance with the highest IID will you stop all sounds.

    Else the positionned sound are still playing their sound on position.

    Expected result:

    When I destroy a sprite, the associated positionned sound should be destroyed

    I looked into the audio plugin.

    The cause of this, is that when getAudioBuffer is called it will return the same AudioBuffer for the 4 sounds.

    So in getAudioInstance, this AudioBuffer will see it's playTagWhenReady property overwritten by a new tag each time until the last enemy instance.

    I couldn't quite find why the C2AudioInstances's tag does the same but they do (probably in request.onload in C2AudioBuffer's constructor).

    Then, when the stop action is executed the 3 first tags won't be recognized.

    So none of the positionned sound will stop.

    Browsers affected:

    Chrome: yes

    Firefox: probably

    Internet Explorer: probably

    Operating system & service pack:

    Windows server 2008 r2 SP1

    Construct 2 version:

    r124

    Blood Type:

    O+

    Joke level:

    -InfiniteYann2013-04-09 20:51:19

  • I'm not sure if it will be usefull, but I made

    Subscribe to Construct videos now

    some days ago.

    If you can get any XML formated document, you should be able to parse it however you need to with the plugin.

  • jbmoyer

    I made it myself, and yes it should be exactly right to the second.

    Here it's exactly 15h43 and the image says "in one day and 16 minutes" which is perfect :D

    If you had a false estimation it might be because of me. I made a mistake in the php and it was off by +1h after the daylight change.

    So yeah now it's correct (:

  • Yeah new vid \o/

    In this one I'm exploring the XML plugin. How you can access a given nodes, how to loop through them, check for attributes, etc.

    Have fun, and don't by shy with feedbacks :D

    Subscribe to Construct videos now
  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • Nope won't work.

    You have to see the event like a filter or as I like to visualize it, a colander

    Fighter Is overlapping Fighter will eliminate all Fighter objects that aren't overlapping at least one Fighter object other than itself.

    Then Pick Fighter instance 0 will elimitate all other objects.

    So Pick Fighter instance 1 afterward will just invalidate the event since it will return false (you don't have the instance 1 anymore in your colander).

    So in short... you can't really use them like that in your situation.

    However you can use the IID shortcut

    You can do

    Sprite(0).team != Sprite(1).team

    So one way to achieve what you want to do is:

    + Fighter: Is overlapping Fighter:
        // First we build a list of IID
        -> Array: Set size to (0,1,1)
    
        + System: Foreach Fighter
            -> Array: push back Fighter.IID on X axis
    
        // Then we need to pick all to be able to use the IID instead of the picked indexes
        + System: Pick all Fighter
        + System: Repeat Array.width times
            Local number A = 0  // IID of the first term of the comparaison
            -> System: Set A to Array.At(loopindex)
    
            + System: Repeat Array.width times
                Local number B = 0  // IID of the second term of the comparaison
                -> System: Set B to Array.At(loopindex)
    
                + System: A != B
                + System: Fighter(A).team != Fighter(B).team
                + System: distance(Fighter(A).X,Fighter(A).Y,Fighter(B).X,Fighter(B).Y) < Fighter.Width * sqrt(2)
                + System: Pick Fighter instance A
                    -> Fighter: set State to "attack"
                    -> System: Stop loop // here since we found a match we stop the inner most loop

    Note that there's one little problem with this implementation:

    I'm grouping all the Fighters that overlap with other fighters by building a list of IID in an array.

    Then I make a team comparaison between all of them.

    Which is wrong! Since you only want to check Fighters that overlaps each others. If you have two groups of fighter in two different area that overlap each other you would want to treat them separately.

    To kind of adress this issue, I'm using a distance comparaison (in the last subevent)

    But it's a bit imprecise. What you would want in fact, to be able to run the overlap check for each possible pair.

    One way to do that is to use Family. You check for each Fighter if it overlaps a family containing the fighters. This way you can easily evaluate each pair.

    Another way to do that is to handle collisions by yourself. An easy collision check algo is a circle collision. You just have to check if the distance between the object is lower than the sum of the radius of each object in the comparaison pair.

    And still another way is to use two different object (let's call them col1 and col2) but with the same collision. You pair them together in the same container so they follow each other and you check overlap between col1 and col2 of each object. This way you can more easily isolate treat each overlap pair separately.

    That's equivalent of using family in the principles

    Anyway that's the gist of it (:

  • works for me

    I was too lazy to reproduce exactly what I wrote before.

    I used string parsing instead of dictionary look up but the principal is the same.

    Instead of a dictionnary.Get('elf_4')

    I do a list = dictionnary.Get('elf') and then tokenat(list,4,newline)

    same idea

    Which made me write a little function to keep things clear.

    basicNameGenerator.capx

  • Joannesalfa

    name = dictionary[race&"_"&floor(random(6))]&dictionary[race&"_"&floor(random(6))]&choose("",dictionary[race&"_"&floor(random(6))])

    doesn't work?

  • I would build a dictionary of phonemes like:

    dictionary['elf_0'] = 'aeg'
    dictionary['elf_1'] = 'am'
    dictionary['elf_2'] = 'ama'
    dictionary['elf_3'] = 'dir'
    dictionary['elf_4'] = 'nor'
    dictionary['elf_5'] = 'ri?'
    ...
    dictionary['dwarf_0'] = 'dah'
    dictionary['dwarf_1'] = 'lon'
    dictionary['dwarf_2'] = 'mor'
    dictionary['dwarf_3'] = 'ren'
    dictionary['dwarf_4'] = 'tero'
    dictionary['dwarf_5'] = 'war'
    ...
    dictionary['human_0'] = 'rob'
    dictionary['human_1'] = 'ali'
    dictionary['human_2'] = 'dove'
    dictionary['human_3'] = 'fha'
    dictionary['human_4'] = 'vyre'
    dictionary['human_5'] = 'quo'
    ...

    etc

    and then generating a name by picking 2 or 3 phonem at random like

    name = dictionary[race&"_"&floor(random(6))]&dictionary[race&"_"&floor(random(6))]&choose("",dictionary[race&"_"&floor(random(6))])

    Of course you could complexify a bit by having phoneme reserved to be only at the start or end of a name, other that could be in both.

    Should also keep track of how much phoneme you have per category. (for the range of the randomness)

  • reminds me of what I wrote a year and a half ago

    http://www.scirra.com/forum/big-report-ideas-problems-after-the-c2-contest_topic45653.html (in 2/ syntax coloration)

  • Ashley

    Yeah I know about the next top level thingy, but that makes a capx look a bit harder to read when you do that:

    on left click
      -> create object
    on left click
      -> function call "checkThings"
    
    on right click on object
      -> destroy object
    on right click on object // should that trigger by the way?
      -> function call "checkThings"

    instead of:

    on left click
      -> create object
      -> next tick
      -> function call "checkThings"
    
    on right click on object
      -> destroy object
      -> next tick
      -> function call "checkThings"

    (plus you probably would have to repeat some picking condition/calculation to end up with the same context in more complex situations)

    And the idea behind creating an alias to wait 0 seconds, is that it looks less wrong ('cause if I understand, you actually wait more or less dt seconds)

  • Hey there,

    I just had this simple idea.

    It's ver well know, now that when we have a newly created or destroyed object, we need to wait for the next tick to access them.

    For instance when we use functions a lot even when the function is called in the created block, the newly created object won't be visible.

    My usual work around is to put a wait 0 seconds

    But it's not really intuitive. And at some point, nothing insure that this behavior will be kept in future versions (since it's more like a hack). Maybe in the future, the implementation of wait will be changed and wait 0 seconds will trigger instantly... who knows?... and why should we care about internal implementation? (:

    So maybe an action dedicated for just that situation, like a "Wait next tick" OR "trigger next tick" action would be better (although "triger next tick" looks more like a condition)

    What do you think Ashley ? (:

  • Global constant number TRUE  = 1
    Global constant number FALSE = 0
    + Function: On function "isCovered" :
       Local number result = 0
       -> System: set result to TRUE
       + System: for "y" from 0 to rectangle.Width
          + System: for "x" from 0 to rectangle.Height
             Local number covered = 0
             Local number px = 0
             Local number py = 0
             -> System: set px to rectangle.X - rectangle.width/2  + loopindex("x")
             -> System: set py to rectangle.Y - rectangle.height/2 + loopindex("y")
             + System: Foreach circle
             + System: distance(circle.X,circle.Y,px,py) <= circle.width/2
                -> System: covered = TRUE
                -> System: stop loop  // stop the foreach
             + System: covered = FALSE
                -> System: set result to FALSE
                -> System: stop loop  // stop the "x" loop
                -> System: stop loop  // stop the "y" loop
       -> Function: set return value to result[/code:a9ngkl9o]
    
    Untested. But the idea is to sample each pixel of your rectangle and see if there's a circle for which the distance from the center of the circle to this point is lower than its radius.
    I make several assumption here:
      - you only have one rectangle shape in your layout
      - your circle.width is exactly equal to your circle's diameter (I use width/2 for the radius)
      - the origin of your rectangle and circle is in the middle
    
    Be carefull the amount of computation will be proportionnal to rectangle.width*rectangle.height*circle.Count  at worst case, which is if the rectangle is completely covered since all the loop are stopped as soon as an out of circle point is found.
    
    If you happen to use some kind of grid snapping, you can probably lower the amount of computation since you shouldn't have to check every single point of the rectangle (but not sure)
    
    In any case you shouldn't run this function every tick, but probably only when you drop a circle.
    
    Also using any kind of C2's built-in overlap check isn't really reliable since a circle's collision polygon is usually an octogon and also, checking for radius is probably faster than using polygon based collision detection.
    
    Edit:
    here's a working implementation:
    [url=https://app.box.com/s/vbkvbkmkt2yjq5kd37w9]rectCoveredByCircle.capx[/url]
    as you can see it can get quickly slow.Yann2013-03-26 08:36:17