R0J0hound's Forum Posts

  • construct.net/en/forum/construct-2/how-do-i-18/8-direction-behavior-slide-95148

    I think that was the topic. Later posts have a more refined solution.

  • Good to know, I still use c2 though.

    I apologize I didn’t look at the section to see the question was for c3.

    Does the textheight expression take into account new lines and wrapping? If so you could divide it by the height for a single word to get the number of lines.

    If it acts like that js function then I guess you could use the same algorithm above, just set the text before using the textWidth expression.

    And actually for c2 you could do something similar. Create a bunch of dummy text objects with the same font, set each to a word from the text, wait till the next frame, and use the measurements with the algorithm. Then you wouldn’t need to use js at all.

  • I didn’t test it, but yeah seems it doesn’t take parameters in construct. It’s just measuring whatever you set the text to.

    The js function is what’s needed though. I’ll maybe put to and to together another day.

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • The wrapping is done in constructs runtime, but I guess you can run through the wrapping logic yourself. The only tool we need is to be able get the width of any text with a given font. The text object has textWidth but last I checked it takes a tick to update in construct which isn’t ideal.

    Here’s a algorithm to find the number of lines with word wrap. I’ll be a bit lazy and just use a single line of text like in your op.

    Global number x=0
    Global number y=0
    Global number w=0
    Global text line=“four score...”
    
    Start of layout
    Repeat tokencount(line, “ “) times
    — set w to text.textWidth(tokenat(line, loopindex, “ “))
    — compare x+w+1 < text.width
    — — add w+1 to x
    — else
    — — add 1 to y
    — — set x to w

    Basically at least. At the end of it y will be the number of lines. It requires resetting x and y if it’s used again.

    Anyways since the textWidth expression is delayed a tick and you’re after how to do it with js here’s an idea.

    This is the function you’re after:

    developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/measureText

    Basically you’d create a canvas object, get a 2d context, set the font of the context and use that above function with the same algorithm as above.

    Admittedly I was a bit sloppy since it’s Adding 1 for a space in front of some lines. But it should give a general idea to refine later to match what construct is doing.

  • One way would be to loop between the previous and current positions and check for overlaps there.

    If you’d like an algorithm, this should work, or at least some variation of this would be acceptable.

    Global number x0=0
    Global number y0=0
    Global number x1=0
    Global number y1=0
    Global number steps=0
    
    Sprite: is dragging
    Or
    Sprite: on drop
    — Set x1 to sprite.x
    — set y1 to sprite.y
    — set steps to max(abs(x1-x0),abs(y1-y0))
    — repeat steps+1 times
    — — sprite: set x to lerp(x0,x1,loopindex/steps)
    — — sprite: set y to lerp(y0,y1,loopindex/steps)
    — — sprite: overlaps sprite2
    — — — stop loop
    — — — sprite: set x to lerp(x0,x1,(loopindex-1)/steps)
    — — — sprite: set y to lerp(y0,y1,(loopindex-1)/steps)
    
    Sprite: on drag start
    Or
    Sprite: is dragging
    — set x0 to sprite.x
    — set y0 to sprite.y
  • The tilemap plugin combines tiles together into larger collision rectangles. That probably explains why the collision checks go up when the ground gets more irregular. The tilemap can’t combine as many tiles

  • If it's in a group or a sub-event it will say local instead of global. Making it static will make it behave like a global.

  • I do it all the time in C2. It should work fine unless something changed in C3. I can’t find any info of such a change.

    I don’t agree with the lack of safety though. Things are run in order and the global will only change when you tell it to.

  • Picking is pretty consistent but the issue you are having has to do with when newly created objects are pickable.

    Elsewhere on the forum it’s discussed as newly created objects are pickable as normal on the next “top level event.”

    So you probably have an event setup similar to this:

    start of layout
    — repeat 3 times
    — — create sprite
    — for each sprite
    — — rotate sprite 45 degrees

    Function calls can be thought of as their events being run in place without anything picked. Here I just used a rotate action to illustrate.

    Anyways the effect of the above is only the already existing sprites get rotated, not the newly created ones.

    One fix could be to do this:

    start of layout
    — repeat 3 times
    — — create sprite
    
    Start of layout
    — for each sprite
    — — rotate sprite 45 degrees

    Which will rotate all the sprites.

    The short version of what’s going on is newly created objects are not pickable till another top level event (an event that isn’t a sub-event). That is other than the new object being picked in that event.

    Long version:

    construct.net/en/forum/construct-2/closed-bugs-22/picking-objects-not-work-129083

    Hope some of that helps.

  • Ah ok. Well here is a different way to do it. since it's only six different teams you can combine the pair in one number, and instead of generating it with code (which you still could do), you could just populate the array with this: It will be a 5x3 array.

    Three pairs per week for five weeks.

    12 13 14 15 16
    34 25 35 24 23
    56 46 26 36 45

    you can swap rows/columns and pairs in the same column.

    For all 15 weeks. just the above duplicated three times. A 3x15 array.

    12 13 14 15 16 12 13 14 15 16 12 13 14 15 16
    34 25 35 24 23 34 25 35 24 23 34 25 35 24 23
    56 46 26 36 45 56 46 26 36 45 56 46 26 36 45

    You can still swap stuff around but you can cause the same match to occur on consecutive weeks.

    To check you can do this:

    global number x=0
    global number y=0
    
    for "x" from 0 to 15-2
    for "y" from 0 to 3-1
    -- set x to loopindex("x")
    -- set y to loopindex("y")
    -- if array.at(x,y)=array.at(x+1,y)
    -- or array.at(x,y)=array.at(x+1,(y+1)%3)
    -- or array.at(x,y)=array.at(x+1,(y+2)%3)
    -- -- ... there is the same match on consecutive weeks.
    

    Probably the algo at that point would be:

    1. load intial array values.

    2. swap stuff around

    3. check if there are any repeat matches from one week to the next.

    4. if there are repeats go back to 2 and try again.

    5. otherwise you have a good layout.

    That could succeed first try or never succeed.

    You probably can do something smarter by knowing that there are ony five different weeks of pairs.

    Then it simplifies to a string a sting of numbers

    123451234512345

    Then just scramble those around, and then fill the weeks in the array form that. Then all that would be left is to swap items around in each column.

    I mean the algo would be the same, just simpler to do.

  • Worst case you could brute force check each pair and shift things around. Probably a tripple nested loop or something like that.

    Instead would it be enough to just randomize the first row and use an offset pattern for the others?

    //// comment: fill the first col with 1-6. You'd do you random numbering here.
    for "x" from 0 to 5
    -- array: set at (loopindex("x"), 0) to loopindex("x")
    
    for "y" from 1 to 4
    for "x" from 0 to 5
    -- array: set at (loopindex("x"), loopindex("y")) to array.at((loopindex("x")+loopindex("y"))%6, 0)

    Then that spits out an array like this (6x6 actually):

    123456
    234561
    345612
    456123
    561234
    612345

    And from a cursory glance you should be able to just shuffle rows and columns around and there will still be no duplicate matches. So here are some events to swap random rows and columns 100 times:

    global number i0=0
    global number i1=0
    global number temp=0
    global text axis= "x or y"
    
    repeat 100 times
    -- set axis to choose("x","y")
    -- set i0 to int(random(6))
    -- set i1 to int(random(6))
    -- repeat 6 times
    -- -- axis equals "x" 
    -- -- -- set temp to array.at(loopindex, i0)
    -- -- -- array: set at(loopindex, i0) to array.at(loopindex, i1)
    -- -- -- array: set at(loopindex, i1) to temp
    -- -- axis equals "y"
    -- -- -- set temp to array.at(i0, loopindex)
    -- -- -- array: set at(i0, loopindex) to array.at(i1, loopindex)
    -- -- -- array: set at(i1, loopindex) to temp
  • Oldx and oldy would be variables you'd use to store the old position of the tilemap. They could be global variables or instance variables of the tilemap. You just have to define them.

    Other than that, yeah those are the actions to position the tilemap onscreen. Except the order you do those actions is important. You need set the position of the tilemap first before pasting. Then you'd need to move the tilemap back afterwards to it's original position. Thinking about it i did forget a step, the paster object needs to be moved too.

    So here's variety of the above working in the same way as your events. Instead of storing the old position it stores the position difference, and moves stuff back and forth by that.

    global number dx = 0
    global number dy = 0
    
    every tick:
    -- paster: clear to rgba(0,0,0,0)
    -- paster: set position to (player.x, player.y)
    
    //comment// actions to paste tilemap
    every tick
    -- set dx to palyer.x-scrollx
    -- set dy to player.y-scrolly
    -- tilemap: set position to (self.x-dx, self.y-dy)
    -- paster: set position to (self.x-dx, self.y-dy)
    -- paster: paste tilemap
    -- tilemap: set position to (self.x+dx, self.y+dy)
    -- paster: set position to (self.x+dx, self.y+dy)
    
    every tick
    -- paster: set position to (120,120)
  • The tilemap object will only draw tiles onscreen. So the workaround is to move the tilemap, paste it then move it back.

    So maybe something like:

    Start of layout

    — set oldX to tilemap.x

    — set oldy to tilemap.y

    Every tick

    — tilemap: set x to self.x-player.x+scrollx

    — tilemap: set y to self.y-player.y+scrolly

    — parser: paste tilemap

    — tilemap: set position to (oldx, old.y)

  • If no instances of an object are picked then all it’s expressions default to 0.

    What should happen is in event 48 the just created instance is picked. Then in 49 all the instances should be pickable like normal. But looks like none of the token instances are picked in 49, hence getting the zero.

    Looks like a bug. If the event were not in a group then 49 would have all the token instances picked. Groups shouldn’t affect that.

    At one point events in groups were considered sub-events. There was then a change so they would all be top level events so new object picking would work. If that’s no longer the case it appears to be a bug.

    EDIT:

    Got around to testing this. Can't reproduce. The token.count or things not being able to be picked.

  • There isn't a loop. Here's a specific example. It passes the filtered sprites via an instance boolean. The function is called once.

    every tick:
    --- sprite: set picked to false
    
    sprite: x>100
    sprite: x<200
    --- sprite: set picked to true
    --- function call "foo" ()
    
    on function "foo"
    sprite: is picked
    --- sprite: rotate 100*dt degrees clockwise

    The uid and loop way to do the same thing. The function is called once per instance. Any if you want to pass a newly created instance you're pretty much forced to use this way.

    sprite: x>100
    sprite: x<200
    for each sprite
    --- function call "foo" (sprite.uid)
    
    on function "foo"
    sprite: pick by uid function.param(0)
    --- sprite: rotate 100*dt degrees clockwise

    With such a simple example it's irrelevant which way to use. I can see the value of being able to pass what's been picked, but that's pretty much a valid way to do it. Functions only pass values for the foreseeable future from what I can tell.