Help with math expressions

  • I am developing a strategy board war game. When I click a troop sprite and then click on the map, it should set the animation frame depending on the distance to travel. For instance, if I click 3 tiles away, it should show an arrow which length covers 3 tiles. If clicked on a neighbour tile, just 1 tile size arrow. In the arrow sprite, first frame shows 1 tile arrow, second frame, 2 tiles arrow. And so on.

    The events for that are quite simple. The issue is I want to keep things proportional, so into the parameters dialog for the frame to show up, I want to calculate the distance in tiles between the target tile and the one the troop is onto.

    To achieve that, I use Pithagoras theorem. Both sides of the triangle are Touch.X-Troop.X and Touch.Y-Troop.Y.

    So, distance = hypotenuse, thus:

    (√ ( (Touch.X - Troop.X)² + (Touch.Y - Troop.Y)²))/"tile size"

    The formula above is not accurate enough, for it calculates from where I touch, not the center of the tile, where the troop will land. Yet not by mistake. Just for sake of simplicity. It would be Tilemap.TileToPositionX(Tilemap.PositionToTileX(Touch.X)) instead of just Touch.X. Troop needn't recalculating, because it will always be at the center of the tile, due to the previous movement having already calculated that.

    So, the entire formula looks like this:

    (√ ( Tilemap.TileToPositionX(Tilemap.PositionToTileX(Touch.X)) - Jugador.X)² + (Tilemap.TileToPositionX(Tilemap.PositionToTileX(Touch.X)) - Jugador.Y)²))/64

    That should be into the parameter box for the value of the frame to be called. That way, 1 tile away calls 1st frame, which is 1 tile arrow,...

    But I am having a hard time writing down the expression, for I have no experience on programming. The trouble is not finding the right expressions, but the right syntax. Maybe I am missing some symbol or adding some other that shouldn't be there.

  • There are hundreds of useful expressions in C2, you can easily find them in that semi-transparent window that appears when you are editing event parameters:

    For example, instead of that huge formula, you can simply use distance() expression.

    Also, having different animation frames for each distance is not a very good solution. Here is a demo I made with a variable arrow size:

    dropbox.com/s/kbmvya5np2jzq68/ArrowOnTilemap.capx

  • Ok, that way I didn't know could be done. Impressive! Really simpler than my take.

    Just two doubts:

    -you set arrowline position manually (10,4). I suppose it's given as example. I figure out it would be troopX, troopY. Also the arrow being onto a lower layer, in order to avoid eclipsing the troop sprite on the screen.

    -isn't it possible to make it without the local variables? I mean- skeeping the system action and begining with the arrowline. The trigger would be On Touch/click on Tilemap.

    -arrow set position to (Troop.X, Troop.Y)

    -arrow set angle toward (Tilemap.SnapX(Mouse.X), (Tilemap.SnapY(Mouse.Y))

    -arrow set width to distance (Self.X, Self.Y, (Tilemap.SnapX(Mouse.X), (Tilemap.SnapY(Mouse.Y))

    Is that possible? Or it might not allow the tilemap.snap expression inside distance?

    It's just because I prefer to stick to fewer actions/objects/variables. I think (correct me if I'm wrong, I actually have no such knowledge) having to update and retrieve variables could lower performance because of loading/saving data into memory, compared to a seemingly big but simple formula, which CPU calculates lightning fast. And actions go one by one, so even though hardly noticeable, it will always be slower because every action has to wait for the previous one to be fulfilled before starting their own.

    Anyway, trully grateful for the help! That was just what I was looking for. I didn't know about distance parameters... that eases the thing a whole bunch. Also the Snap expression for the tilemap is awsome. I was walking on circles with positiontotile<>tiletoposition hahaha.

  • dop2000

    Now I have it already simplified. It will be played on mobile and I want the arrow to show up just when touching and then freeze, so changed the every tick condition with On tap on tilemap. Removed variables and everything seems to work fine. Thanks so much!!!

    1drv.ms/u/s!AojCIgmN1VlPiWjfQMhXp4MCGcdS

  • With local variables the code is easier to read, and easier to modify if needed. Performance-wise there should be no difference, unless you are doing these calculations millions times per second. (which is not the case)

  • Ok, there's no slow down with variables. I am working with approximately 20 or 30 instances of the same sprite, yet, as you say, just calculating when a 'chess' moves. They'd rather have instance variables for each one? I am no used at all with playing with instances and their behaviour. Every piece of help is most welcome

  • Instance variable are for permanently storing some values for each instance. Say, if you have Enemy sprite, you might want to add "health" instance variable to it.

    In this event I added a temporary variable, just to make the code simpler. I don't need to keep this variable after the event. So a simple local variable is sufficient.

  • But I have several sprites which behave the same, except for their atributes (health, range, power,...) and their position. I am struggling to be able to move one instance only, but they always move alltogether

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • I thought you were still talking about that arrow. If you have several sprite instances and only need to move one, you need to pick it before moving. You can set an instance variable isMoving=true to that instance, or pick it by UID or use some other condition.

  • dop2000

    Sorry I didn't explain the whole situation in the first time.

    I have, let's say 20 troop instances. When I touch on a troop instance, it changes with some effect (shadow, color, light,... doesn't matter) and 'activates just it' so that if I then touch on a tile, an arrow shows up from that troop towards the tile which I touched.

    There is a small option to change the target for a troop. You may have touched a tile by mistake, or decide to move another troop instead. When I touch a tile for the first time, it starts blinking and when I double tap, flash disables and arrow gets locked. Then, that troop instance becomes inavailable for chosing until next turn.

    But the instance doesn't move yet. Then, I touch another troop instance, again onto the tilemap, and then the arrow. And so on until no troops left for choosing. Then you say to 'skip turn' (in any way, I didn't decided it yet, whether a button, double tap or else) and every instance moves along their own arrow to their target tile. And also the movement of each troop should be 'erasing' the arrow, but no worties with that, because it's the same thing you teached me before with every tick setting arrowline width according to distance.

    I have done everything right when working with just one instance. But at the moment I create the rest, it's complete chaos.

    I am figuring out some ways to make just one instance moves, like placing an instance variable which can be 'state': active | inactive (this actually came from you on another post, talking about ternary operators). When I touch the troop instance, it sets every other instance to inactive (in case you choose one and then decide to move another one), then sets the variable active for that instance and then compare which instances are active for the arrow event to happen. At double tapping, it locks the arrow and sets inactive again the instance.

    But I don't know how to call the movement of each troop instance for their own arrow. I am trying to understand how to call a specific instance of an object, to ve able to reference it to the troop. I mean, something like- move to the arrow instance that was created afeter touching you, or the arrow touching the line that touches you, or something of the like. I don't know either if it' possible to relate the arrow instance created at touching the tile after the troop with that very troop instance touched before. Something along the lines of containers maybe...? Pin behaviour with variable attaching point?

    Maybe a position variable for each could solve that?

    I am running out of time and really busy these days, so I hardly can access my PC at night, just taking every bit of spare time to learn C3 with the smartphone. I'll link to my C3P later

  • Container is a good idea. Add arrow to the same container with troop sprite. When you pick a troop instance, its own arrow will be picked automatically. When arrow is not needed, make it invisible.

    If you make an event like "Arrow set position to troop", each arrow will set position to its own instance of troop, because they are in the same container, and you don't even need "for each" loop here.

    Add a bunch of instance variables to troop - for example targetX, targerY, hasRoute etc.

    If I understand correctly, only one troop can be active at a time, so instead of the instance variable isActive, it may be easier to use a global variable activeTroopUID. When a troop is tapped, set activeTroopUID=troop.UID, and then you will be able to pick this troop by its UID in any other event.

    On confirmed destination tile set targetX, targerY to tile x/y.

    On 'Skip turn' you can start moving every troop to its own target tile (targetX and targerY). I suggest MoveTo behavior, but you can use something else.

  • dop2000

    That's awsome! You understood exactly as it is. That was my intention. And you even optimised it in just a few codes. I'm spending these days trying to apply this brand new approach to my project.

    Eternaly grateful mate!!!

  • dop2000

    I am failing to apply this to my project. At the moment I have more than one instance, I managed to make each one sets up their own arrow to their own target. Yet they both eventually move to the same position- left upper corner. Not referencing each one their own target instance variable Troop.TargetX, Troop.TargetY (though I also tried MovedTo their arrow object due to container, or so I intended, and the outcome was even worse, they didn't moved at all).

    I have messed with sub-events, trying to understand the difference between system 'pick instance by evaluate' and sprite 'pick by unique UID' conditions. I have chosen the system pick condition because of a so-believed repeated object incompatibility when making sub-events that I'll further explain below.

    Another issue comes when I try to make a sub-event from the same object of the parent condition. I'll explain:

    I want to touch a troop instance. And then, only if I touch onto a tile (and only if I touch on a tile after having touched/activated a troop instance), arrow shows up.

    If I don't touch onto any tile and instead I tap any other instance, it should just change global variable active troop to that instance, thus becoming available for targeting a tile with the arrow showing up)

    Would I have touched a tile and the arrow showed up, I could already tap on another troop, so that previous arrow sets invisible and the one from the new-tapped troop sets visible (not at that very moment, but when I later touch on a tile). Well, that arrow never disappears...

    The point is that if I have a 'On Tile tapped' condition, at the moment I try to make a sub-event (for locking just the selected tile) with 'on tilemap double tappef', it just isn't there as an available condition. It only allows to check if it's in touch at the moment, which simply can't meet my purpose. I suspect I am not getting the point of how events order work (yeah... I have read the manual).

    So I have to move the On double tap condition to a new event below, and then can't lock the instance I am working with at that time. It's hardly possible to accurately reach with the finger the point where the arrow is, specially since is blinking and seems not to be touchable when not visible. I tried making it a simple double tap onto the screen, but at the first tap, it recognizes it as a tap trigger and sets the arrow to the point where I touch. How can I work around this? Is it possible to double tap without C3 taking into account the first tap? Is it due to having another tap condition? I'm a bit lost on this, for would bet if I where able to make the double tap a sub-event of the tap event, it would wolve the problem. No reason behind, indeed. Just a hunch.

    I don't know whether may be necessary to include some sort of loop, like 'for' or 'for each'. Or I might be arranging events and sub'events in the wrong way. Or not understanding picking instances at all. I tried also to add an else condition to set invisible every arrow which is not locked yet, but didn't succeed either. Or backing off to the instance variable active|inactive and comparing values.

    Moreover, I have set the set arrow visible/invisible action when I tap a tile. But it shows up when I tap the troop. Maybe because of the container.

    I am a complete mess rith now. Have rewriten once and once again the event sheet shifting between conditions, actions and variables and still being unable to join everything altogether.

    1drv.ms/u/s!AojCIgmN1VlPiWjfQMhXp4MCGcdS

  • Hi santiagoestrade

    You have many errors there I didn't spend much Time to find all of them but I give you the most importants

    The First is Picking:

    The System Pick Nth Instance is different than Pick by UID

    System Pick Nth Instance = here You give IID of the objects

    Pick By UID: Here is where you give the UIDs

    If you don't know exactly or you get stuck, make some Debugs Txt to help you Debugging

    Here is one example so you understand what is UID and IID

    https://www.dropbox.com/s/a0ql8mcmxgle5c9/Picking%20UID%20Vs%20IID.capx?dl=0

    Activate and deactivate Events 5 & 6 to swap between them to see the difference

    Second Thing Triggers:

    Events that have The Green Arrow are "Triggers" this means that they run just once not very thick so the event 6 it will not do what you trying to do, you have to do it under some event that is true while the Player is Moving so Triggers are not suitable for this. Plus the triggers is most suitable to make them on the Top Events unless its really necessary

    You see you did the opposite event 2 the top event is true everythick an you put the triggers under it so the top event is Picking constantly, you should change it and put it on subevent of a trigger like on tap tilemap so it will pick the object only when is necessary not every thick

    This all for today :)

    I made a demo for you, but I couldn't read the whole explanation because I didn't have Time so it may not be exactly what you trying to do but it will help you and also I didn't look for 100% bugs free so you may stumble on some

    I hope it helps

    Link Capx: https:// dropbox.com/s/dtqzxlni8zj3knz/Chees%20Example.capx

    Strange doesn't let me post Links to the Capx so I split it

  • tarek2

    Ok I'll try to understand every piece of advise you gave me.

    The thing about picking I knew was a flaw of mine. But I am not using nTH (which I suppose it's the one that takes the IID, referenced just for their sprite, so being into a container and created at the same time as their parent object, should always have the same IID, if I understood what you meant), but pick by evaluate variable, so I check the global variable Active troop. I tried with the sprite pick by UID by for whatever reason it always picked both instances or none. Now it is picking the right one.

    I tried even with your capx, replacing the picking nTH to 'pick by evaluate' and works with UID as it does with IID + 'pick by nTH'. Tried also with system compare variable and also picks the right one. The point is I think not to understand correctly the benefits of picking by IID instead of UID. Talking about containers- according to what I have read, on a sprite created, each other attached sprite in his container is also created. So they are always created in the same order. So they should have the same IID. Don't they? In my case, first troop has IID 0 and his arrow IID 0 (first instance of his object) too. As second troop is created, it gets assigned IID 1 and his arrow is created also with IID 1 (second instance of his object). That way is simpler to relate them. Did I understand correctly?

    Right now, with system compare by evaluate picking condition each troop is moving towards its own arrow. I added a boolean instance variable TargetLocked which sets up at double tapping tilemap/arrow, thus confirming target. Then, when skipping turn, an AND condition picking instances with TargetLocked true.

    Indenting all the arrow and target as a sub-event I did as well and everything seems fine with that. The point is that at tapping the troop instance, arrow shows up, when it should have been set invisible. That is an event-order issue I suppose. Will work on that.

    My main problem now is When I tap a different instance, the arrow of the previous ibstance I had activated before, still keeps visible.

    I see what you mean with the every tick on the arrow line. As you say, I am no as used to event arranging. So my guess is condition should be 'Troop is moving'.

    Even the thing about not being able to double tap!!! I know what you mean. By indenting the event, I ensure each double tap 'belongs' only to their picked troop instance. But the point is that if I have Touch.Tap as a condition on the parent event, it is no longer showing up to be selected as a condition for the sub-event.

    C3 simply doesn't allow to say:

    -parent condition: tap on instance

    - sub-event condition: double tap on arrow/tilemap

    I am not sure if I understand correctly what you are explaining about triggers. Could it mean that 'double tap on tilemap/arrow' can't be conditioned as a sub-event of 'tap on troop' because they are both triggers, so runtime would expect to happen at the same time? That would explain why the first touch of the 'double tap on tilemap/arrow always triggers the 'tap on troop event'. So... if changing the sub-event condition to 'is touching tilemap/arrow' wouldn't make it succed either, as I have experienced.

    Maybe the link for my capx didn't updated when I was working on it last night.

    Here is again:

    1drv.ms/u/s!AojCIgmN1VlPiWjfQMhXp4MCGcdS

    Thanks again for taking the time to help. I know it's a basic issue, but coming from a non IT background, reading the forum, tutorials on scirra and the manual don't happen to clear my mind. And any pointing in the right direction is most appreciated. I'll play around with your capx to see if I can understand.

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)