fisholith's Forum Posts

  • Awesome, glad it helped out.

    Oh, I fixed the images. My "Img" tags were around the web address, not the file address. Derp. :)

  • (edit: just realize that "ran" variable was declared just above the if statement, and added it in.)

    I just found a block of code in the Function object's runtime that seems to log info to the browser's(?) console when the game is in preview mode.

    // Note: executing fast trigger path based on fs.name
    var ran = this.runtime.trigger(cr.plugins_.Function.prototype.cnds.OnFunction, this, fs.name);
    
    // In preview mode, log to the console if nothing was triggered
    if (isInPreview && !ran)
    {
    	log("[Construct 2] Function object: called function '" + name_ + "', but no event was triggered. Is the function call spelt incorrectly or no longer used?", "warn");
    }[/code:3owxtq4i]
    
    What do "isInPreview" and "!ran" represent here? I have a guess, but I haven't come across "isInPreview" in the SDK documentation, though I might have just missed them.
    
    Is this method of logging safe to implement as a third-party plugin developer, or is it a special case thing. 
    Any weird pitfalls to be aware of? 
    
    Just curious. Thanks.
  • (Note: File and image attaching are not working for me at the moment, so I'm using external URLs for when everything comes back on line.)

    Hey justifun,

    Essentially you would be simulating a 3D space.

    I'll outline some terms and ideas first, and then explain how you might put them together to get your character jumping up onto crates and walking on them.

    Three Axes

    Ignoring jumping (Z) to start with, you just have X and Y making up the ground plane.

    X allows you to walk West and East, which is represented as left and right movement on the screen.

    Y allows you to walk North (away from camera) and South (towards camera), which is represented as up and down movement on the screen.

    When you add jumping, you now have a third coordinate to keep track of, Z. We track the character's Z coord with our custom altitude variable.

    Z allows you to ascend and descent over the "ground", and is represented as up and down movement on the screen.

    Since Y and Z are both represented as up and down movement on the screen, in many games a shadow is placed under the character, so that it's easy to tell the difference between walking North and South, and Jumping up and down. When jumping, the character moves up and down, but the shadow stays on the ground at the footprint coords.

    Collision & Z-overlap

    (image link) - Here the player is in mid jump, and their shadow is visible on the block just below.

    If we want the character to be able to stand on a box, then we need to know when the character's XY footprint is overlapping the box's XY footprint.

    We also need to know how "tall" the box is, (its Z-height).

    Once we know we're overlapping a box on the altitude (Z) axis, we can grab the Z-height value of the box, and use that as the current ground height. If that height is higher than the player's Z elevation, then the box is an obstacle to the player, but if it's lower than the player's Z elevation, then the player can pass "over" the box, or walk on it.

    (image link) - Player sitting on a block, overhanging edge. (Player's footprint in green.)

    (image link) - Player falling off the block. Notice that the footprint no longer overlaps the block's footprint.

    (image link) - Player sitting on ground beside block.

    Z-axis physics

    In my first post I explained that you could outsource the jumping mechanics to a platform behavior object. In this new case, where the ground can have more than one height things get trickier. It's still possible to outsource to a platform behavior object, but its tricky enough that it might be better to just build your own simple Z-axis physics.

    Demo capx

    I built a demo capx that shows how some of this stuff could work in practice, though the code is a little hacky in places.

    fi_demo_JumpingInPseudo3D.capx

  • No worries. Hope it works out.

  • Is there a good way to make Conditions and Actions that take an arbitrary number of arguments?

    I notice that the Function object uses

    AddVariadicParams()

    to do this, but when I searched the forums, I only found one post on the topic explaining that it sort of a hack, built specifically for the Function object. Granted the post was from a few years ago so I don't know if AddVariadicParams has changed since then.

    The best work around I've found other than that is to provide a single do-nothing parameter, from which you can call an expression that has the side effect of passing its variable arguments into an array behind the scenes, which can then be used by the Actions or Condition.

    Any thoughts or suggestions welcome.

  • Hey Taximan,

    One possible approach is, instead of having the 8 direction behavior control your character sprite directly, have it control your character's invisible "footprint" (a separate sprite object). Create a new object to act as your character sprite and, every tick, set its coordinates to match the coordinates of your footprint object.

    Altitude variable

    Now you just need one more value to store the player's current altitude above the ground. Normally your altitude will be 0, because you'll be standing flat on the ground. When you jump, this value will increase up to your maximum jump height and then decrease back to 0.

    So far so good, but that altitude number won't move your player by itself.

    Actually jumping

    Earlier I said we'd set the character's coordinates to match the footprint's coordinates. We now need to make a small change...

    We still make the character's X coord match the footprint's X coord, but we set the character's Y coord to equal the footprint's Y coord PLUS the altitude number.

    Now when you move the character should follow the footprint, and when you jump, the character should hop up and down "vertically" over the footprint.

    As an added bonus, you can attach a little shadow image to the footprint object and it will always be directly "under" your character even when jumping.

    Borrowing Jump altitude from the Platform behavior

    Now, if you don't want to build custom code to make the altitude variable "jump" when you press jump, you can borrow the jump behavior from the platform object in a roundabout way.

    We basically create an invisible platform object that can only jump, put it somewhere out of the way, and we use its Y position as the real character's jump altitude.

    Specifically, we create an invisible platform object with it's controls disabled (so the player can't move it), and then we make the game's Jump key trigger the platform object's "Simulate control" action to simulate a Jump, so the player can make it jump, but not move around.

    We'll also need to make an invisible solid object for it to stand on, and we'll position them both so that the platform object's Y coord is 0 when it's resting on the solid ground object.

    Every tick, the player's altitude variable should be set to the platform object's Y coord.

    This method also allows you to optionally use some of the other nice features of the platform object's jump system, like holding jump to go higher.

  • Hey Zarhon,

    One approach that might work...

    If the player object stores it's tile coords internally, in private variables, then we can multiply those coords by 60, to get the pixel location of the tile's corner, and then add 30 to get the pixel location of the tile's center.

    If the tile coords are (0,1), the "multiply 60" step converts it to pixel coords (0, 60), but this will be a tile corner, so the "add 30" step converts it to (30,90), which is a tile center.

    Whenever we change the tile coord, we recalculate the player's pixel location in the above fashion.

    This way we can keep the player's hotspot in the center of the sprite, and snap to tile centers instead of corners.

  • Interesting, and a very good point.

    With respect to "properties", do you mean C2 property panel properties, or JavaScript object properties? In my earlier post I meant JavaScript object properties, but at the time it hadn't occurred to me that it was ambiguous. Sorry about that.

    And, yes, now that I've been looking through more plugins, "onCreate" seems to be the way to go. I haven't tested to see if "pluginProto.Instance" is called on a per-instance-created basis, but I think you're right about "onCreate" being the better option for objects that are intended to allow multiple instances. In any case, "onCreate" will definitely get called each time.

    Thanks again for the information and advice. You're always super helpful rex.

  • One method that can be really handy for diagnosing these kinds of problems is to create a Text object, and then create an event inside the loop to print debuging info into that Text object.

    e.g.

    Insert the following event as a sub-event of the

    "Segments.ImagePointCount = 2", and

    "Segments.ImagePointCount = 3".

    Event:

    * Compare ( loopindex >= 0 )

    * Compare ( loopindex <= 3 )

    // This event will run 4 times, for the loop indexes 0, 1, 2, and 3.

    Actions:

    * Append text ( " Loopindex:" & loopindex )

    * Append text ( " SegUID:" & Segments.UID )

    * Append text ( " platUID:" & PlatformCollision.UID )

    * Append text ( " plat2UID:" & PlatformCollision2.UID ) // Only needed for count = 3

    * Append text ( " Seg.ImgPtX1" & Segments.ImagePointX(1) )

    * Append text ( " Seg.ImgPtY1" & Segments.ImagePointY(1) )

    * Append text ( " Seg.ImgPtX2" & Segments.ImagePointX(2) ) // Only needed for count = 3

    * Append text ( " Seg.ImgPtY2" & Segments.ImagePointY(2) ) // Only needed for count = 3

    * Append text ( " Seg.Col:" & Segments.Collision)

    * Append text ( newline )

    The "newline" at the end will make each loop iteration print out on it's own line.

    Be sure to use "Append text" and NOT "Set text".

    Note that some of the actions in the above event only apply to the case where "Segments.ImagePointCount = 3", and not when it "= 2". For the "= 2" case, you can remove all the actions that are commented "// Only needed for count = 3".

    You'll probably have to stretch out the text object so that it has room to display multiple lines.

    You may also want to set it's font size to something, small like 8 point, and set it's initial text to be blank.

  • Hey kaleu50,

    To my knowledge C2 uses a polygon collision system, rather than calculating per-pixel collisions, meaning you would need a polygon collision object, or several, that match the contents of the canvas.

    It's theoretically possible to create invisible collision objects via events that overlay the drawn-on parts of the canvas, but it's not likely to be very practical outside of some special cases.

    One possible approach might be to use the tile map object, set the tiles to 1x1 pixels, and create a "solid" tile with a square collision polygon. if you can paint 1x1 collision tiles over the same area your canvas brush is painting color, then it might work.

    Granted I've never used the tile map for anything like that so I don't know if there would be performance issues. I expect there would be. Though I think the tile map would still be much better than a ton of 1x1 sprites, which might not even run at all.

    Update:

    Okay I just tried the tile map setup I described, and to my astonishment, it actually runs in realtime without issue. Granted that was with 1 px wide lines. When I blocked in 50% of the 832, 480 screen with a solid mass of 1x1 collision tiles (over 200,000 collidable tiles) the game still ran smoothly. It started to slow down a bit when I got to 75% coverage (over 300,000 tiles). Practically speaking, if you could cull out the center tiles, and only make the edges of objects collidable, then you could probably make a pretty decent per pixel collision system.

    I tried both 8-Direction and Platform behavior with it and it seems to work as you'd expect.

    Also, the 1x1 pixel tiles are only important if you're doing something like simulating a per-pixel collidable terrain for a platformer. If super precise collision detection isn't essential, such as testing for loose overlaps with the mouse pointer, you could make the tiles 4x4 pixels and the whole setup would have 16 times fewer tiles in filled areas.

    (By "16 times fewer" I mean "1/16th the amount of tiles", but both ways of phrasing it sound weird, now that I'm looking at them.)

    In any case, I hope that helps somewhat.

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • No problem, glad I could help

  • No problem.

  • Interesting.

    Thanks for pointing out that they can be declared in onCreate

    I was going to ask about that specifically, as I wasn't sure if there was anything special needed to use it reliably. It sounds like it just works.

    Between Instance and onCreate, is there a particular reason one might be preferable to the other, or is it more just a matter of style or convention?

    I was trying to remember why I did one versus the other, and looking back through the original SDK templates (I mainly work from custom templates) I found the following comment inside the pluginProto.Instance body:

    this.type = type;

    this.runtime = type.runtime;

    // any other properties you need, e.g...

    // this.myValue = 0;

    I think this may be why I've been putting properties there. I'm not sure if it makes a difference.

    That said, the official Dictionary plugin declares properties in onCreate, and the official AJAX plugin declares properties in pluginProto.Instance. So I'm not sure if there's anything important about one vs the other, or if it's just down to preference.

  • When adding properties to my object in the SDK runtime, should I create instance properties in:

    (Edit: By "properties" I mean JavaScript Object properties, not C2 property-panel properties.)

    pluginProto.Instance = function(type) { ... }

    or

    instanceProto.onCreate = function() { ... }

    Currently I'm creating them inside "pluginProto.Instance" as that's what I've seen in other plugins.

    Is there any situation where one is better than the other?