Yann's Forum Posts

  • newt you do need to pick via UID if you want to know what is the particular object type of the family member you picked (yes it's usefull sometimes)

    However, I agree with you on the fact that if he wants to decrease the hp of any object in the family, the hp should be a family variable, not an instance variable.

  • Is the game played through the mobile web browser, or in a native wrapper like phonegap?

    A black screen could be caused by the wrapper failing, or maybe by a memory failure (too big assets?)

    What could be done to rule out a logic bug would be to just make a simple C2 app (like something that displays a countdown), If it displays correctly, it means your logic is the problem. Else, it means it's either C2 or your eventual wrapper, or memory.

    You could also test with a simple capx with no event (so no logic bug) but with a lot of images. To check if it could be a memory issue.

    In any case, not having access to a console will limit your research.

  • It's hard to understand the reason of the comportment you describe.

    Thus, I'm not really sure I understand.

    But I read this as:

    if shooter has in range enemy1 and 2 enemy 2, it should first target enemy 1 if enemy 2 isn't on the back of the shooter (?), else, the closest enemy2... Still feel kind of weird.

  • Guizmus yes, typecasting

  • // se the movement parameters
    Global number xA = 10
    Global number yA = 20
    Global number xB = 100
    Global number yB = 120
    Global number speed = 100
    
    // some variables used in runtime
    Global number dist = 0
    Global number t = 0
    
    System: trigger once
         -> System: set dist to distance(xA,yA,xB,yB)
    
    System: t<1
          -> System: set t to min(1, dt*speed/distance)
          -> Sprite: set X to lerp(xA,xB,t)
          -> Sprite: set Y to lerp(yA,yB,t)[/code:3hpqub3m]
         
    With that you have a clean, precise and constant motion from A to B
    note that lerp isn't some magic function.
    lerp(a,b,t)  = a + (b-a) * t
    no more, no less. You give it 3 values, it gives you one.
  • Construct2's typecasting

    + Player: on collide with familyObject
    + SpecificObject: UID = familyObject.UID
             -> SpecificObject: substract 1 from hp[/code:1zsh9bm6]
  • Would indeed be a simpler approach than my bloated unreliable example =)

  • Changing the value of a global variables is way more complex than what you think.

    Global variables in construct2 aren't javascript variables, they are objects with, amongst other things, "name", "data", "initial" properties.

    They are indeed in the all_global_vars array of the c2runtime.

    But the big problem is that when you export your project, a lot of that stuff gets minified.

    Nonetheless, it seems there's enough to write something that can parse the runtime and find the objects which "look like" global variables and then narrow down the search on the name.

    Here is what you can put in the Browser Execute javascript:

    function getGlobalObject(name) {
        var runtime = document.getElementById('c2canvas').c2runtime;
        for (var p in runtime) {
            if(Object.prototype.hasOwnProperty.call(runtime,p)) {
                var prop = runtime[p];
                if(prop === undefined) continue;
                if(prop === null) continue;
                if(typeof prop !== 'object') continue;
                if(prop.length === undefined) continue;
    
                for(var i = 0; i < prop.length; i++) {
                    if(prop[i].parent !== undefined && 
                       prop[i].data !== undefined   && 
                       prop[i].sheet !== undefined  && 
                       prop[i].name !== undefined) {
                        // probably the global var array
                        if(prop[i].name === name) {
                            // that one!
                            return prop[i];
                        }
                    } else {
                        // no need to loop if not global var array
                        break;
                    }
                }
            }
        }
        return null;
    }
    
    function setGlobalVar(name,value) {
        var g = getGlobalObject(name);
        if(g === null) return;
        g.data = value;
    }
    
    function getGlobalVar(name) {
        var g = getGlobalObject(name);
        if(g === null) return 0;
        return g.data;
    }
    
    setGlobalVar('myGlobal',4); // here is where you set your global
    [/code:1ve38njy]
    This code gets the runtime from the canvas (assuming it has the id "c2canvas")
    Then go through all the properties looking for arrays (which are objects with a length property)
    And then loop through all the element of the array to find objects with parent, data, sheet and name properties.
    Those properties are hopefully not minified (at least for now) and it seems enough to narrow down the search
    Then just checking for the name property gives you the proper global variable object you can get/set.
    
    As a word of advice, don't do that everytick... I don't think it's super efficient. Also... You should probably make a plugin for that kind of stuff. Since the plugin code gets minified the same way, you get something more reliable.
  • Yup, this is definitely a bug. Changing the speed of the first animation to 0 shouldn't affect the behavior of other animations.

    And looking into the plugin, the bug seems kind of obvious.

    In instanceProto.onCreate:

    		if ( !(this.type.animations.length === 1 && this.type.animations[0].frames.length === 1)   && 
                 this.type.animations[0].speed !== 0)
    		{
    			this.runtime.tickMe(this);
    			this.isTicking = true;
    		}
    [/code:fkgvvy1u]
    Which, to me, is easier to understand removing the NOT at the beginning which gives you:
    [code:fkgvvy1u]
    		if (  (this.type.animations.length !== 1 || this.type.animations[0].frames.length !== 1)   && 
                 this.type.animations[0].speed !== 0)
    		{
    			this.runtime.tickMe(this);
    			this.isTicking = true;
    		}
    [/code:fkgvvy1u]
    Which translates to: tick the sprite only if [it has a more than one animations OR if the first animation has more than one frame] AND if the first animation has a speed different of 0.
    So, if the first animation has a speed of 0, the sprite will not be ticked until you change animation or set the speed in event.
    
    For a fix, I would propose that (moving the check after setting this.cur_animation):
    [code:fkgvvy1u]
            this.cur_animation = this.getAnimationByName(this.properties[1]) || this.type.animations[0];
            this.cur_frame = this.properties[2];
    
            if (this.cur_animation.frames.length > 1 && this.cur_animation.speed !== 0)
            {
                this.runtime.tickMe(this);
                this.isTicking = true;
            }
    [/code:fkgvvy1u]
    We get the information about current animation, and then according to its length and speed, we tick the sprite or not (:
    
    (not sure I understand why in current code there's a check to know if the number of animation is greater than 1... In Acts.prototype.SetAnim, the ticking is set back on as soon as you set any animation anyway... which is kind of weird, there should be a check for speed and frame count as well)
  • Problem Description

    The container isn't checked when using the Set position to object action.

    The problem is expected because in acts.SetPosToObject in commonace.js, no container is ever checked.

    Also the problem needs a specific situation to really be noticeable.

    Because in most cases the SOL filtering and the auto pairing (by IID) kind of mask the issue.

    Here is my fix proposition:

    			acts.SetPosToObject = function (obj, imgpt)
    			{
                    var inst;
    				
                    if(this.is_contained && obj.is_contained) {
                        for(var i = 0; i < this.siblings.length; i++){
                            var sibling = this.siblings[i];
                            if (sibling.type === obj) {
                                inst = sibling;
                                break;
                            }
                        }
                    } else {
                        inst = obj.getPairedInstance(this);
                    }
    
    				if (!inst)
    					return;
    [/code:2banhj7z]
    
    [url=https://app.box.com/s/e4bei0aoj8neqkbxabp3]setPositionToObject%26container.capx[/url]
        
    [b]Description of Capx[/b]
    When you click on the bluegray square its boolean "clicked" is set to true
    If "clicked" is true for any bluegray square, the associated orange square should be positionned to the corresponding bluegray square
    
    [b]Steps to Reproduce Bug[/b]
    [ul]
        [li] click on the bluegray squares in any order[/li][/ul]
        
    [b]Observed Result[/b]
    Various unexpected positionning
        
    [b]Expected Result[/b]
    Each orange square should go to its corresponding bluegray square because of the container pairing
        
    [b]Affected Browsers[/b]
    [ul]
        [li] Chrome: (YES)
        [/li][li] FireFox: (YES)
        [/li][li] Internet Explorer: (YES)[/li][/ul]
        
    [b]Operating System and Service Pack[/b]
    Win7  SP1
        
    [b]Construct 2 Version ID[/b]
    r163
  • I think combining On touch end + is Touching object does exactly that.

  • PixelRebirth

    Actually you could still implement your idea.

    For example you could have an autoload property in edittime you could set to yes or no

    You can get this property on create, if it's true you load the plugin and the trigger will be... triggered (as I did it)

    If it's false the user can still call the load action (as you did) and there you would provide a callback that will call the trigger (instead of an empty function)

    However, doing that you give the possibility to the user to load the API more than once... And I'm not sure that in the end it would be a good design choice (not sure what would happen either)

    So yeah, in the end I would stick with auto loading it. (Yeah I'm thinking while typing)

  • Hmmm, seems like an intersting topic, so allow me to barge in (:

    PixelRebirth

    To me the way you use the GameAPI.loadAPI() is wrong, the aim of this function is to provide a "trigger" for when the API is loaded

    So you should probably create an OnLoaded trigger instead of having a function that just call the loading.

    It's like saying "Send this AJAX request and.... blah"

    The way you should be able to do that is:

         instanceProto.onCreate = function(){
              this.API = null;
              this.gamePaused = false;
              GameAPI["loadAPI"](function(API) {
                  ?this.API = API;
                  ?this.runtime.trigger(cr.plugins_.pix_spilgames.prototype.cnds.OnLoadAPI, this);
              });
         };

    with the corresponding condition just returning true

         Cnds.prototype.OnLoadAPI = function () {
              return true;
         };
            // and because we can:
         Cnds.prototype.isAPILoaded = function () {
              return this.API != null;
         };

    This way the C2 user can start doing things here.

    The same way, you should probably provide triggers for OnGamePaused, OnGameResumed

         Acts.prototype.RequestAd = function ()
         {
              // alert the message
              //GameAPI.GameBreak.request(fnPause, fnResume);
              GameAPI["GameBreak"]["request"](
                  ?function() {
                        // pause
                        this.gamePaused = true;
                        this.runtime.trigger(cr.plugins_.pix_spilgames.prototype.cnds.OnGamePaused, this);     
                  ?},
                  ?function() {
                        // resume
                        this.gamePaused = false;
                        this.runtime.trigger(cr.plugins_.pix_spilgames.prototype.cnds.OnGameResumed, this);     
                  ?}
              );
         };

    With the corresponding

         Cnds.prototype.OnGamePaused = function () {
              return true;
         };
         Cnds.prototype.OnGameResumed = function () {
              return true;
         };
            // why not
         Cnds.prototype.isPaused = function () {
              return this.gamePaused ;
         };

    With all that you shouldn't need to put anything in typeProto.onCreate

    And please, note that it's on the top of my head and that I dunno too much about how spilgames works, but It should work :D

  • You do not have permission to view this post

  • You do not have permission to view this post