zoukankan      html  css  js  c++  java
  • [译]Godot系列教程六

    Pong

    Godot自带的Demo中有大量更复杂的示例,但这款叫“Pong”的游戏可以对2D游戏的基本特性做一个介绍。

    静态资源

    本文所用到的一些资源文件:http://files.cnblogs.com/files/x3d/pong_assets.zip

    场景设置

    考虑到兼容旧设备,该游戏的分辨率设置为 640x400像素,相关操作在项目设置中进行。默认背景色为黑色:

    在场景面板中创建一个Node2D节点作为项目的根节点。Node2D是2D引擎里的基础类型。然后,添加一些“精灵”(Sprite)节点并为之都设置相应的纹理。最终的场景布局应该类似下图(注意:球在中间!):

    场景树则应类似下图:

    将该场景保存为"pong.scn"文件,并将之设置为项目主场景。

    输入动作设置

    视频游戏有很多种输入方法,键盘、游戏柄、鼠标、触屏(多点触摸)等。但是对于“pong”这个游戏来说,仅需实现在空格内上下移动的事件响应即可。要实现所有可能的输入方法还是很麻烦的,对应更大的编码量。而且现在的多数游戏还允许玩家对控制器进行自定义设置,这对于开发来说更麻烦。针对这种情况,Godot创建了一种机制 - 输入动作(Input Action)。一旦定义了一种输入动作,意味着对应的输入方法被添加了。

    再次打开“项目属性”对话框,切换到“Input Map”选项卡。添加4个动作:left_move_up, left_move_down, right_move_up, right_move_down,并为它们指定按键。为左手边玩家设置A/Z键,右手边玩家设置向上/向下光标键,这样的设置在多数场景下都能正常工作。

    脚本

    为场景面板中的根节点创建脚本,打开它。该脚本继承自Node2D:

    
        extends Node2D
    
        func _ready():
            pass
    

    _ready()函数是最先被调用的函数(其实更早被执行的是_enter_tree(),只是这里还未涉及到这个概念)。构造函数中,完成了两件事情:首先是启用处理流程,然后是保存一些有用的值:屏幕尺寸、pad:

    
    
        extends Node2D
    
        # 成员变量
        var screen_size
        var pad_size
        var direction = Vector2(1.0, 0.0)
    
        func _ready():
            screen_size = get_viewport_rect().size
            pad_size = get_node("left").get_texture().get_size()
            set_process(true)
    

    接着,添加一些在游戏处理过程中需要用到的变量:

    
    # 成员变量
    var screen_size
    var pad_size
    var direction = Vector2(1.0, 0.0)
    
    # 常量,球初始移动速度(单位:像素/秒)
    const INITIAL_BALL_SPEED = 80
    # 球的实时速度(单位:像素/秒)
    var ball_speed = INITIAL_BALL_SPEED
    # pad的移动速度
    const PAD_SPEED = 150
    
    func _ready():
        screen_size = get_viewport_rect().size
        pad_size = get_node("left").get_texture().get_size()
        set_process(true)
    

    最后,编写处理函数:

    
        func _process(delta):
    

    获取一些要用到的值进行计算。先是球的位置,再是每个pad的矩形区域(Rect2)。Sprite对象默认会对它们的纹理进行居中处理,所以必须要进行调整,pad_size / 2

    
            var ball_pos = get_node("ball").get_pos()
            var left_rect = Rect2( get_node("left").get_pos() - pad_size/2, pad_size )
            var right_rect = Rect2( get_node("right").get_pos() - pad_size/2, pad_size )
    

    获取球的位置后,整合就比较简单:

    
            ball_pos += direction * ball_speed * delta
    

    既然球有了新的位置,应该对之进行各种情况的测试。首先,针对底部和顶部边界:

    
            if ( (ball_pos.y < 0 and direction.y < 0) or (ball_pos.y > screen_size.y and direction.y > 0)):
                direction.y = -direction.y
    

    如果其中一个pad被接触到,改变方向并少量加速。

    
            if ( (left_rect.has_point(ball_pos) and direction.x < 0) or (right_rect.has_point(ball_pos) and direction.x > 0)):
                direction.x = -direction.x
                ball_speed *= 1.1
                direction.y = randf() * 2.0 - 1
                direction = direction.normalized()
    

    球如果跑出屏幕,游戏结束。游戏重新开始:

    
            if (ball_pos.x < 0 or ball_pos.x > screen_size.x):
                ball_pos = screen_size * 0.5  # ball goes to screen center
                ball_speed = 80
                direction = Vector2(-1, 0)
    

    一旦球处理好了,节点根据新的位置更新:

    
            get_node("ball").set_pos(ball_pos)
    

    要实现仅在玩家有相应输入时,更新对应pad。Input类在这里就非常有用了:

    
            #move left pad  
            var left_pos = get_node("left").get_pos()
    
            if (left_pos.y > 0 and Input.is_action_pressed("left_move_up")):
                left_pos.y += -PAD_SPEED * delta
            if (left_pos.y < screen_size.y and Input.is_action_pressed("left_move_down")):
                left_pos.y += PAD_SPEED * delta
    
            get_node("left").set_pos(left_pos)
    
            #move right pad 
            var right_pos = get_node("right").get_pos()
    
            if (right_pos.y > 0 and Input.is_action_pressed("right_move_up")):
                right_pos.y += -PAD_SPEED * delta
            if (right_pos.y < screen_size.y and Input.is_action_pressed("right_move_down")):
                right_pos.y += PAD_SPEED * delta
    
            get_node("right").set_pos(right_pos)
    

    好了!这么几行代码就写出了一个简单的“Pong”游戏。

  • 相关阅读:
    ftp卡死问题
    Windows 10 安装FileZilla Server
    The last packet successfully received from the server was 39,900 milliseconds ago问题解决
    java.sql.SQLException: Could not retrieve transaction read-only status from server 问题解决
    三主机配置 keepalived VIP高可用
    subprocess.Popen在win10下会有异常
    python 使用内置方法读取注册表
    过年有感
    java.security.InvalidKeyException: Illegal key size 解决办法
    Android Studio 检查Top Activity
  • 原文地址:https://www.cnblogs.com/x3d/p/simple_2d_game.html
Copyright © 2011-2022 走看看