Search code examples
2dgdscriptgodot4

How to Loop Map with Godot Engine


The text may be incorrect as it is translated by Deepl Translations.

I am currently making a 2D game with the Godot engine, and the map is 1280x1280px, and I would like to make a map with just this one image.

The main problem is that when I get to the edge of the map, I want the map to appear on the other side, but the position is a little off or buggy.

I'm not getting any errors or anything. Is there some other way or another way to write the code?

Here is a video of the current operation → https://youtu.be/H1LKOYwO0hE

Source code

`extends Node2D

const SPEED:int = 200
const DEFAULT_ANIMATION:String ="run_down"


# 子ノードを取得
@onready var player = $anim
@onready var camera = $Camera2D

var now_anime: String
var velocity: Vector2

#カメラ制限座標
var left_limit = -1344
var right_limit = 1344
var up_limit = -958
var down_limit = 958

#フラグ管理
var limit_flag = {
    "x": false,
    "y": false
}


func _ready():
    # 実行アニメーション名を初期化
    now_anime = DEFAULT_ANIMATION

func _process(delta):
    velocity = Vector2()
    
    # キー押下状況に応じてアニメーションと移動幅を更新
    if Input.is_action_pressed("ui_up"):
        now_anime = "run_up"
        velocity.y = -SPEED
    elif Input.is_action_pressed("ui_right"):
        now_anime = "run_right"
        velocity.x = SPEED
    elif Input.is_action_pressed("ui_down"):
        now_anime = "run_down"
        velocity.y = SPEED
    elif Input.is_action_pressed("ui_left"):
        now_anime = "run_left"
        velocity.x = -SPEED
        
    if Input.is_action_pressed("ui_up") && Input.is_action_pressed("ui_right"):
        now_anime = "run_right"
        velocity.x = SPEED / 2
        velocity.y = -SPEED / 2
    elif Input.is_action_pressed("ui_right") && Input.is_action_pressed("ui_down"):
        now_anime = "run_right"
        velocity.x = SPEED / 2
        velocity.y = SPEED / 2
    elif Input.is_action_pressed("ui_down") && Input.is_action_pressed("ui_left"):
        now_anime = "run_left"
        velocity.x = -SPEED / 2
        velocity.y = SPEED / 2
    elif Input.is_action_pressed("ui_left") && Input.is_action_pressed("ui_up"):
        now_anime = "run_left"
        velocity.x = -SPEED / 2
        velocity.y = -SPEED / 2

    # 更新したアニメーションに切り替え
    player.set_animation(now_anime)
    
    # 移動実施
    player.position += velocity * delta
    
    if right_limit < player.position.x || player.position.x < left_limit:
        limit_flag["x"] = true
    if down_limit < player.position.y || player.position.y < up_limit:
        limit_flag["y"] = true
    
    print(player.position)  
    print(limit_flag)
    print(" ")
    limitMethod()
        

func limitMethod():
    if limit_flag["x"] == false && limit_flag["y"] == false:
        camera.global_position = player.position            
    if limit_flag["x"] && limit_flag["y"]:
        limit_flag["x"] = false
        limit_flag["y"] = false
    if limit_flag["x"]:
        limit_flag["x"] = false
        player.position.x = player.position.x * -1
    if limit_flag["y"]:
        limit_flag["y"] = false
        player.position.y = player.position.y * -1`

I have used transform to skip to the specified coordinates, but if I use transform to skip to the specified coordinates while moving, the position is shifted.

The only thing I tried was to use transform to fly the character to the specified coordinates.


Solution

  • I will work with a single axis, with the intention to make this easier to understand.

    Let us start with a line representing the image, and I'll mark the center to represent the origin:

    Reference line with origin

    And you have defined some limits. So let us add those:

    Reference line with origin and limits

    The limits happen to be at the same distance to the origin. Which I believe is intentional. However, there is nothing preventing them from being different.

    You also have the player position, and it might go beyond the limits, for example:

    Reference line with origin, limits, and player position beyond the right limit

    Currently, you are flipping the position of the player around the origin, like this:

    player.position.x = player.position.x * -1
    

    Which results in placing the player beyond the limit of the opposite side:

    Reference line with origin, limits, and player position beyond the left limit

    I believe that is not what you want.


    What I believe you want - and I might have misunderstood the problem - is to take the distance that the player went beyond the limit...

    Reference line with origin, limits, and player position beyond the right limit, with distance indicated

    Which would be:

    var distance := player.position.x - exceeded_limit
    

    And then change the position of the player to be that same distance but from the opposite limit:

    Reference line with origin, limits, and player position between the limits, with distance indicated from the left limit

    Which would be:

    player.position.x = opposite_limit + distance
    

    Replacing the distance we have:

    player.position.x = opposite_limit + (player.position.x - exceeded_limit)
    

    Rearrange:

    player.position.x = player.position.x + opposite_limit - exceeded_limit
    

    Which is the same as:

    player.position.x += opposite_limit - exceeded_limit
    

    In other words, you take away the exceeded limit and add the opposite limit.


    In the illustration I have place the player beyond the right limit. However, if it were beyond the left limit to begin with, it would be like this:

    var distance := exceeded_limit - player.position.x
    player.position.x = opposite_limit - distance
    

    Replacing:

    player.position.x = opposite_limit - (exceeded_limit - player.position.x)
    

    Which is the same as:

    player.position.x = opposite_limit - exceeded_limit + player.position.x
    

    Rearranging:

    player.position.x = player.position.x + opposite_limit - exceeded_limit
    

    Which is the same as:

    player.position.x += opposite_limit - exceeded_limit
    

    And, as you can see, it works outs to the same formula.


    Finally, of course, I have only illustrated the horizontal axis, but the same logic applies for the vertical axis.

    I hope this makes sense, and that you can use it to rewrite limitMethod from scratch to get the result you want.