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:


  1. extends Node2D
  2. func _ready():
  3. pass

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

  1. extends Node2D
  2. # 成员变量
  3. var screen_size
  4. var pad_size
  5. var direction = Vector2(1.0, 0.0)
  6. func _ready():
  7. screen_size = get_viewport_rect().size
  8. pad_size = get_node("left").get_texture().get_size()
  9. set_process(true)

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


  1. # 成员变量
  2. var screen_size
  3. var pad_size
  4. var direction = Vector2(1.0, 0.0)
  5. # 常量,球初始移动速度(单位:像素/秒)
  6. const INITIAL_BALL_SPEED = 80
  7. # 球的实时速度(单位:像素/秒)
  8. var ball_speed = INITIAL_BALL_SPEED
  9. # pad的移动速度
  10. const PAD_SPEED = 150
  11. func _ready():
  12. screen_size = get_viewport_rect().size
  13. pad_size = get_node("left").get_texture().get_size()
  14. set_process(true)

最后,编写处理函数:


  1. func _process(delta):

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


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

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


  1. ball_pos += direction * ball_speed * delta

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


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

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


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

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


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

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


  1. get_node("ball").set_pos(ball_pos)

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


  1. #move left pad
  2. var left_pos = get_node("left").get_pos()
  3. if (left_pos.y > 0 and Input.is_action_pressed("left_move_up")):
  4. left_pos.y += -PAD_SPEED * delta
  5. if (left_pos.y < screen_size.y and Input.is_action_pressed("left_move_down")):
  6. left_pos.y += PAD_SPEED * delta
  7. get_node("left").set_pos(left_pos)
  8. #move right pad
  9. var right_pos = get_node("right").get_pos()
  10. if (right_pos.y > 0 and Input.is_action_pressed("right_move_up")):
  11. right_pos.y += -PAD_SPEED * delta
  12. if (right_pos.y < screen_size.y and Input.is_action_pressed("right_move_down")):
  13. right_pos.y += PAD_SPEED * delta
  14. get_node("right").set_pos(right_pos)

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

[译]Godot系列教程六 - 简单的二维游戏的更多相关文章

  1. [译]Godot系列教程三 - 场景实例化(续)

    场景实例化(续) 要点 场景实例化带来很多便利的用法,总体来说有: 将场景细分,更便于管理 相对于某些引擎中的Prefab组件更灵活,并且在许多方面更强大 是一种设计更复杂的游戏流程甚至UI的方式 这 ...

  2. [译]Godot系列教程一 - 场景与节点

    场景(Scene)与节点(Node) 简介 先设想有那么一瞬间你自己不再是一名游戏开发者了,而是一名大厨! 你的装备换成了一套大厨的制服.不要考虑制作游戏的事情,你现在的职责是为你的顾客创建新的可口的 ...

  3. [译]Godot系列教程二 - 场景实例化(Instancing)

    场景实例化(Instancing) 原理阐述 创建一个场景并将节点扔到里面对于小项目是适用的,但随着项目不断发展,用到越来越多的节点,整个项目很快就会演化成难以管理的状态. 为了解决这个问题,Godo ...

  4. [译]Godot系列教程五 - 制作Godot编辑器插件

    制作插件 下文仅针对2.1版本. 关于插件 插件是为编辑器扩展出更多有用工具的重要方式.它可以完全用GDScript和标准场景开发,甚至都不需重新加载编辑器就可生效.不像模块,你无需创建C++代码.也 ...

  5. [译]Godot系列教程四 - 编写脚本

    编写脚本(Scripting) 简介 关于无需编程即可创建视频游戏的那些工具的谈论有很多.不用学习编程知识对很多独立开发者来说就是一个梦想.这种需求 - 游戏开发者.甚至在很多公司内部,希望对游戏流程 ...

  6. CRL快速开发框架系列教程六(分布式缓存解决方案)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  7. C#微信公众号开发系列教程六(被动回复与上传下载多媒体文件)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

  8. [转]Android Studio系列教程六--Gradle多渠道打包

    转自:http://www.stormzhang.com/devtools/2015/01/15/android-studio-tutorial6/ Android Studio系列教程六--Grad ...

  9. Android Studio系列教程六--Gradle多渠道打包

    Android Studio系列教程六--Gradle多渠道打包 2015 年 01 月 15 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://stormzh ...

随机推荐

  1. nginx last 和break redirect 和 permanent

    一.last & break (1)last 和 break 当出现在location 之外时,两者的作用是一致的没有任何差异. 注意一点就是,他们会跳过所有的在他们之后的rewrite 模块 ...

  2. 第2章 Python基础-字符编码&数据类型 字典 练习题

    1.写代码,有如下字典,按照要求实现每一个功能,dic = {'k1':'v1','k2':'v2','k3':[11,22,33]} 请循环输出所有的 key dic = {'k1':'v1','k ...

  3. 如何在 Mac 上通过 Boot Camp 安装 Windows?

    如何在 Mac 上通过 Boot Camp 安装 Windows? The following contents are chosen from the apple website, thanks f ...

  4. MySql(十七):MySql架构设计——高可用设计之思路及方案

    前言: 数据库系统是一个应用系统的核心部分,要想系统整体可用性得到保证,数据库系统就不能出现任何问题.对于一个企业级的系统来说,数据库系统的可用性尤为重要.数据库系统一旦出现问题无法提供服务,所有系统 ...

  5. MySql(十二):MySql架构设计——可扩展设计的基本原则

    一.前言 科技在发展,硬件设备的发展渐渐无法满足应用系统对处理能力的要求.不过,我们还是可以通过改造系统的架构体系,提升系统的扩展能力,通过组合多个低处理能力的硬件设备来达到一个高处理能力的系统,也就 ...

  6. shell 知识点

        Q:1 Shell脚本是什么.它是必需的吗? 答:一个Shell脚本是一个文本文件,包含一个或多个命令.作为系统管理员,我们经常需要使用多个命令来完成一项任务,我们可以添加这些所有命令在一个文 ...

  7. 深入理解Linux内核-系统调用

    系统调用:用户态进程向内核发出的,实现用户态进程调用硬件设备的函数或者中断:优点:使编程更容易,将用户从学习硬件设备的低级编程特性中解放:提高系统到安全性,内核在满足请求之前可以做正确性检查:提高可移 ...

  8. 基于 vue 全家桶的 spa 项目脚手架

    项目简介 Github: https://github.com/hanan198501/vue-spa-template 我们基于 vue-cli 脚手架生成项目模板做了一些改造,加入了 vue-ro ...

  9. 菜鸟学SSH(十六)——Struts2内部是如何工作的

    前面说完了Spring.Hibernate,很自然今天轮到struts了.struts的核心原理就是通过拦截器来处理客户端的请求,经过拦截器一系列的处理后,再交给Action.下面先看看struts官 ...

  10. how to build jdk 9 source code

    http://hg.openjdk.java.net/build-infra/jdk9/raw-file/tip/README-builds.html#vs2013 http://royvanrijn ...