[Noob] Why aren't my blocks staying within same distance?

neverkneverk Posts: 5Member

I try to make a blocks that move at the same time, but for some reason their spacing is changing.

What am I doing wrong?

Global variables
`extends Node

    var dir = 1
    var play = true
    var speed = 400`

Here is my Block code:
`extends KinematicBody2D

    func _ready():
        set_fixed_process(true)

    func _fixed_process(delta):
        var motion = Vector2()

        if(globals.play):
            motion += Vector2(globals.dir,0)

        if(get_global_pos().x <= 0):
            globals.dir = 1
        elif(get_global_pos().x >= 720):
            globals.dir = -1

        motion = motion.normalized()*globals.speed*delta
        move(motion)`

This is the start situation:

The space between the blocks doesn't stay constant.

Answers

  • woopdeedoowoopdeedoo Posts: 109Member
    edited January 2017

    A bit hard to tell, but if I understand correctly, it seems that code is in each of the blocks but there's one global direction vector for them all, and my guess is that since you're changing the direction when the leading block hits the edge, at that point some of the other blocks haven't had the chance to move yet, so they turn around before they should.

    (you can probably see it if you reduce their speed drastically)

    EDIT: it seems they also gain distance from the start (before hitting any edge of the screen for the first time). If that's the case, that's probably because the block in front of them hasn't moved yet. The move function from the KinematicBody only moves an object up to the point of collision, so if the 3rd block wants to move, but for some reason the 4th block hasn't moved yet, the 3rd block ends up standing still for this frame. If this is the case, you may want to have them move in order (from front to back), and probably invert that order depending on which direction they're moving.

    Or deactivate collisions between them (out of the top of my head I can't say exactly how to do that -- I haven't been dealing with many KinematicBodies myself yet -- but it's probably something to do with collision layers), or move the remainder if the collision was with another block and after it moves. The move() function returns the movement that was left at the point of collision, you can store it in a variable.
    Ex:

    var remainder = move(motion)
    # somehow test if block in front has moved, and if so:
    move(remainder)
    

    This may be tricky to implement though, it might be way easier to just move them in order.

  • AvencherusAvencherus Posts: 49Member

    To me it seems odd to use a global velocity, but I would venture that your problem is that you're recalculating the direction change after it's applied to the motion of the one that presumably is going to hit the edges. So the contacting block has it's motion continuing in the old direction for one frame, all the others will then use the changed direction. This error accumulates.

    So move the motion += Vector2(globals.dir,0) below the boundary test.

  • neverkneverk Posts: 5Member

    Thanks for the suggestions guys, but i couldn't get it working.

    @woopdeedoo
    I removed the kinematic body from the Node, so no collision.should be happening. Probably helped a little bit..

    @Avencherus
    I tried to move the motion in different positions, but it's always almost the same.

        func _fixed_process(delta):
            var motion = Vector2()  
    
            motion += Vector2(globals.dir,0)    
            motion = motion.normalized()*globals.speed*delta
            move(motion)
    
            if(get_global_pos().x <= 0):
                globals.dir = 1
    
            if(get_global_pos().x >= 720):
                globals.dir = -1
    
  • neverkneverk Posts: 5Member

    @woopdeedoo actually your answer is probably correct, but I just can't fixit...

  • razvanc-rrazvanc-r Posts: 84Member
    edited January 2017

    here see if this helps you:

    extends KinematicBody2D
    #
    const XLIM = {'min': 0, 'max': 720} # store limits here instead of hard coding in `if`
    onready var y = self.get_pos().y # I assume here that y will be fixed and will not change
    var dir = Vector2(1, 0) # have it vector from start
    var speed = 1000
    #
    func _ready():
        set_fixed_process(true)
    #
    func _fixed_process(dt):
        var dx = self.dir * self.speed * dt # dt, dx because I'm a physicist... habbits
        move(dx) # first do the move action
        var pos = self.get_pos()
        if pos.x <= XLIM['min'] or pos.x >= XLIM['max']:
            self.dir.x *= -1 # reverse direction, it's more generic, it happens when either condition is met
            # THIS IS THE MAGIC PART:
            pos.x = clamp(pos.x, XLIM['min'], XLIM['max']) # <- try commenting this out and see what happens :)
            self.set_pos(pos) # now force the node to be at this exact position
            # END OF MAGIC :P
    

    PS. I forgot to mention, the problem is rounding errors, yeah, that's what you get for trying to represent infinite precision real numbers with limited resources :) AKA PC. So the above script is just attached as in the picture to all those kinmatic body nodes

  • woopdeedoowoopdeedoo Posts: 109Member

    @neverk said:
    woopdeedoo actually your answer is probably correct, but I just can't fixit...

    Can you tell us what exactly you're trying to achieve? It might be easier for everyone to have some perspective on how to fix it if we can see what exactly is broken, otherwise we might be pointing you in the wrong direction.

    I mean, you could be trying to make some sort of moving platform for a platformer, or a spring-like effect like you see in @razvanc-r's post, or a million other things, and how to fix it kind of depends on what you're doing. :smile:

    If you're following a tutorial or something, it might be helpful to post a link to it.

  • razvanc-rrazvanc-r Posts: 84Member

    @woopdeedoo, that's not a spring effect, those are nodes that move at constant speed which is exactly what he wants

  • neverkneverk Posts: 5Member

    Actually I want them to move as one big block. I'm trying to port my game from construct to Godot.
    https://www.scirra.com/arcade/puzzle-games/stkr-4006

  • razvanc-rrazvanc-r Posts: 84Member
    Answer ✓

    Oh I misunderstood, in that case it's even simpler, well somewhat, you'll have to calculate the x dimension of your element (depending on how many blocks you'll add to it). Here, explore this example I attached. It's basically the same as before but instead of any kinematic body mumbo jumbo everything is under a Node2D. You'll probably want your Sprites under some Area2D or under some RigidBody2D or something in case you want them to register collisions.

  • woopdeedoowoopdeedoo Posts: 109Member

    @razvanc-r, seemed like a spring-ish effect, but nevermind.

    @neverk, in that case, @razvanc-r is probably right. Although, I'm guessing you could disregard physics bodies altogether. It seems from the nature of that game you probably want your sprites to move by fixed amounts (like in Tetris), and you can just re-position them (set_pos()) as Node2Ds every frame, so I don't see a need for physics (unless you want them to behave differently while falling).

  • razvanc-rrazvanc-r Posts: 84Member

    @woopdeedoo don't get fulled by the gif, it looks like a spring because of the frame rate, it definitely isn't a spring, just check the code, it's there :)

  • neverkneverk Posts: 5Member

    @razvanc-r Great! Thank you very much. This is really helpful!

Sign In or Register to comment.