原文: Libgdx游戏开发(5)——碰撞反弹的简单实践-Stars-One的杂货小窝

本篇简单以一个小球运动,一步步实现碰撞反弹的效果

本文代码示例以kotlin为主,且需要有一定的Libgdx入门基础

注:下面动态图片看着有些卡顿,是录制的问题,实际上运行时很流畅的

水平滚动

简单起见,我们通过ShapeRenderer绘制一个圆形,作为我们的小球,并让其从开始位置向右水平移动

import com.badlogic.gdx.ApplicationAdapter
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.glutils.ShapeRenderer class CircleBallTest : ApplicationAdapter() {
lateinit var shape: ShapeRenderer override fun create() {
shape = ShapeRenderer()
} var x = 50f
var y = 50f override fun render() {
//每次渲染绘制前,清除屏幕
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) x += 5 //设置填充模式,圆形默认即为白色
shape.begin(ShapeRenderer.ShapeType.Filled);
//圆形半径为50,起点位置位于(50,50)
shape.circle(x, y, 50f)
shape.end()
} //这里忽略了相关资源释放代码逻辑...
}

启动游戏代码(方便阅读,下文中此代码不会再贴出!):

package com.arthurlumertz.taplixic;

import com.badlogic.gdx.backends.lwjgl3.*;

public class DesktopLauncher {

	public static void main (String[] arg) {
Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
config.setWindowedMode(960, 540);
config.setForegroundFPS(60);
new Lwjgl3Application(new CircleBallTest(), config);
}
}

效果如下:

水平滚动并反弹

上述已经实现了一个小球滚动,但发现滚动到边缘就不见了,我们加个效果,碰到右边缘就反弹

package com.arthurlumertz.taplixic

import com.badlogic.gdx.ApplicationAdapter
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.glutils.ShapeRenderer class CircleBallTest : ApplicationAdapter() {
lateinit var shape: ShapeRenderer override fun create() {
shape = ShapeRenderer()
} var x = 50f
var y = 50f var isRight = true override fun render() {
//每次渲染绘制前,清除屏幕
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) if (isRight) {
x += 5
} else {
x-=5
} //设置填充模式,圆形默认即为白色
shape.begin(ShapeRenderer.ShapeType.Filled);
//圆形半径为50,起点位置位于(50,50)
shape.circle(x, y, 50f)
shape.end() //右边缘检测 圆心的x坐标加上半径大于或等于当前游戏屏幕宽度
if (x + 50 >= Gdx.graphics.width) {
isRight=false
} //左边缘检测 圆心的x坐标减去半径小于或等于0(起点)
if (x - 50 <=0) {
isRight=true
}
} //这里忽略了相关资源释放代码逻辑...
}

效果如下(录制效果的时候没加左边缘检测):

这里实际可以直接将对应的+5-5统一转为一个速度加量,方向需要反转的时候乘以-1即可

同时,我们上述小球相关代码封装为一个Ball类来进行使用,优化后的代码如下:

//定义一个ball类实现相关操作
class Ball{
var size = 50f var x = 50f
var y = 50f var speedX = 5f fun gundon() {
x += speedX
} fun draw(shape: ShapeRenderer) {
shape.begin(ShapeRenderer.ShapeType.Filled)
shape.circle(x, y, size)
shape.end()
} //检测边缘反弹
fun checkFz() {
//到达右边缘,加量变反
if (x + size >= Gdx.graphics.width) {
speedX = speedX * -1
} //到达左边缘,加量变反
if (x - size <= 0) {
speedX = speedX * -1
}
}
}

游戏代码:

class CircleBallTest : ApplicationAdapter() {
lateinit var shape: ShapeRenderer val ball by lazy { Ball() } override fun create() {
shape = ShapeRenderer()
} override fun render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) ball.draw(shape) ball.gundon() ball.checkFz()
} //这里忽略了相关资源释放代码逻辑...
}

这里代码我是将绘制,坐标和边缘碰撞检测分别封装对应的方法

  • draw() 绘制
  • gundon()修改坐标的方法
  • checkFz()则是进行碰撞检测的方法

这里为什么要将绘制和修改坐标抽成2个方法,是因为我研究游戏暂停的时候发现的,这里先卖个关子,之后会讲到(算是自己无意摸索出来的小技巧)

四面滚动反弹

上述我们只是在水平方向移动,现在想要小球斜方向发出,之后四周反弹,应该如何实现呢?

想要斜方向发出,我们还需要在上面实现的基础上加个y坐标加量,同时修改x,y坐标,就能让小球斜着运动了(数学中的线性方程,或者可以看做是给了小球上方向和右方向的力)

当然,如果你修改对应的增加量数值,可以实现不同斜率方向

这里我固定x和y的加量相同,即45度方向运动

四周反弹其实可以拆分为左右和上下方向,碰到左和右就反转x的增量,碰到上和下就反转y的增量


import com.badlogic.gdx.ApplicationAdapter
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.glutils.ShapeRenderer class CircleBallTest : ApplicationAdapter() {
lateinit var shape: ShapeRenderer val ball by lazy { Ball() } override fun create() {
shape = ShapeRenderer()
} override fun render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) ball.draw(shape) ball.checkFz()
}
} class Ball{
var size = 50f var x = 50f
var y = 50f var speedX = 5f
//y坐标增量
var speedY = 5f fun gundon() {
x += speedX
//进行添加
y += speedY
} fun draw(shape: ShapeRenderer) { shape.begin(ShapeRenderer.ShapeType.Filled)
shape.circle(x, y, size)
shape.end()
} //检测边缘反弹
fun checkFz() {
//这里为了方便理解,我每个条件都拆出来了 //到达右边缘,x变反
if (x + size >= Gdx.graphics.width) {
speedX = speedX * -1
} //到达下边缘,y变反
if (y - size <= 0) {
speedY = speedY * -1
} //到达上边缘,y变反
if (y + size >= Gdx.graphics.height) {
speedY = speedY * -1
} //到达左边缘,x变反
if (x - size <= 0) {
speedX = speedX * -1
}
}
}

效果如下:

加个板子进行弹球

在上面的基础上,我们添加一个板子用来接球

  1. 使用ShapeRenderer对象绘制实心矩形作为板子
  2. 考虑板子和球的碰撞
  3. 方向键左右可控制板子移动
  4. 碰到下边缘,球消失

shape.rect()方法用来绘制一个矩形,在x,y坐标绘制一个定义的宽高矩形,(x,y)坐标即为此矩形的左上角

圆心的y坐标 - 半径 >= 矩形的y坐标,圆心x坐标-半径小于矩形的x坐标,圆心x坐标+半径大于或等于矩形的x坐标+矩形宽度,即视为两者碰撞

下面代码和Ball一样,封装了一个MyBan类,实现板子的绘制和控制移动

import com.badlogic.gdx.ApplicationAdapter
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.glutils.ShapeRenderer class CircleBallTest : ApplicationAdapter() {
lateinit var shape: ShapeRenderer val ball by lazy { Ball() }
val line by lazy { MyBan() } override fun create() {
shape = ShapeRenderer()
} override fun render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) line.draw(shape)
line.control() ball.draw(shape)
ball.checkFz() //检测碰撞到数横条
ball.checkLineP(line)
}
} class MyBan {
var width = 200f
var height = 10f var x = 0f
var y = height fun draw(shape: ShapeRenderer) {
shape.begin(ShapeRenderer.ShapeType.Filled)
//这里注意: x,y是指矩形的左上角
shape.rect(x, height, width, height)
shape.end()
} fun control() {
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
x -= 200 * Gdx.graphics.deltaTime
} if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
x += 200 * Gdx.graphics.deltaTime
} //这里屏蔽y坐标改变,只给控制左右移动
return if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
y += 200 * Gdx.graphics.deltaTime
} if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
y -= 200 * Gdx.graphics.deltaTime
}
}
} class Ball {
var size = 5f var x = 50f
var y = 50f var speedX = 5f
var speedY = 5f //与板子的碰撞检测
fun checkLineP(myB: MyBan) {
if (y - size <= myB.y) {
speedY = speedY * -1
}
} fun gundon() {
x += speedX
y += speedY
} fun draw(shape: ShapeRenderer) {
shape.begin(ShapeRenderer.ShapeType.Filled)
shape.circle(x, y, size)
shape.end()
} fun checkFz() {
//到达右边缘,x变反
if (x + size >= Gdx.graphics.width) {
speedX = speedX * -1
} //到达下边缘,y变反
//todo 这个是判输条件!
if (y - size <= 0) {
//消失
//speedY = speedY * -1
} //到达上边缘,y变反
if (y + size >= Gdx.graphics.height) {
speedY = speedY * -1
} //到达左边缘,x变反
if (x - size <= 0) {
speedX = speedX * -1
}
}
}

效果如下:

参考

Libgdx游戏开发(5)——碰撞反弹的简单实践的更多相关文章

  1. [libGDX游戏开发教程]使用libGDX进行游戏开发(1)-游戏设计

    声明:<使用Libgdx进行游戏开发>是一个系列,文章的原文是<Learning Libgdx Game Development>,大家请周知.后续的文章连接在这里 使用Lib ...

  2. [libGDX游戏开发教程]使用libGDX进行游戏开发(12)-Action动画

    前文章节列表:  使用libGDX进行游戏开发(11)-高级编程技巧   使用libGDX进行游戏开发(10)-音乐音效不求人,程序员也可以DIY   使用libGDX进行游戏开发(9)-场景过渡   ...

  3. Libgdx游戏开发(2)——接水滴游戏实现

    原文:Libgdx游戏开发(2)--接水滴游戏实现 - Stars-One的杂货小窝 本文使用Kotlin语言开发 通过本文的学习可以初步了解以下基础知识的使用: Basic file access ...

  4. [libgdx游戏开发教程]使用Libgdx进行游戏开发(11)-高级编程技巧 Box2d和Shader

    高级编程技巧只是相对的,其实主要是讲物理模拟和着色器程序的使用. 本章主要讲解利用Box2D并用它来实现萝卜雨,然后是使用单色着色器shader让画面呈现单色状态:http://files.cnblo ...

  5. 精通libGDX游戏开发-RPG实战-开发游戏的基本前提

    说起RPG,大概国人是不会陌生的. 这不得不从中国单机游戏市场说起,由于早期软件市场被盗版杀死,顺带的,单机游戏软件作为软件市场的分支,也没赚什么钱,养不活公司纷纷倒闭,只到RPG游戏<仙剑奇侠 ...

  6. [libgdx游戏开发教程]使用Libgdx进行游戏开发(10)-音乐和音效

    本章音效文件都来自于公共许可: http://files.cnblogs.com/mignet/sounds.zip 在游戏中,播放背景音乐和音效是基本的功能. Libgdx提供了跨平台的声音播放功能 ...

  7. [libgdx游戏开发教程]使用Libgdx进行游戏开发(2)-游戏框架搭建

    让我们抛开理论开始code吧. 入口类CanyonBunnyMain的代码: package com.packtpub.libgdx.canyonbunny; import com.badlogic. ...

  8. PuTsangTo-单撸游戏开发03 碰撞与跳跃瑕疵版

    继续上一部分,游戏的定位是横版平台动作类游戏,所以得有跳跃动作,首先想到的就是物理引擎,不过在2D游戏里,仅为了角色的跳跃而引入物理引擎,目前想来有些不至于,仅使用cocos默认带有的碰撞系统也足够了 ...

  9. 精通libGDX游戏开发-RPG实战-欢迎来到RPG的世界

    欢迎来到RPG的世界 本章我会快速的使用tiled这样的瓷砖地图工具,来带领大家创造所设想的世界. 创建并编辑瓷砖地图 瓷砖地图(tile-based map)是广泛应用于各种游戏类型的地图格式,li ...

  10. [libgdx游戏开发教程]使用Libgdx进行游戏开发(7)-屏幕布局的最佳实践

    管理多个屏幕 我们的菜单屏有2个按钮,一个play一个option.option里就是一些开关的设置,比如音乐音效等.这些设置将会保存到Preferences中. 多屏幕切换是游戏的基本机制,Libg ...

随机推荐

  1. [GPT] Unable to negotiate with xx.xx.xx.xx port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss

      这个错误通常发生在 SSH 客户端无法找到与 SSH服务器 匹配的主机密钥类型时. 这可能是因为SSH服务器配置为使用SSH客户端不支持的主机密钥类型. 要解决此问题,您需要将缺少的主机密钥类型添 ...

  2. 提取jks文件证书和私钥

    提取jks文件证书和私钥 JKS文件由公钥和密钥构成利用Java Keytool 工具生成的文件,它是由公钥和密钥构成的,公钥就是我们平时说的证书(.cer后缀的文件),私钥就是密钥(.key后缀的文 ...

  3. SAP集成技术(二)接口库

    目前还没有一个集中的地方能找到全部SAP接口,它们分散在几个不同的地方. 本文链接:https://www.cnblogs.com/hhelibeb/p/17843509.html 内容部分来自< ...

  4. R3_Elasticsearch Index Setting

    索引的配置项按是否可以更改分为static属性与动态配置,所谓的静态配置即索引创建后不能修改.目录如下:生产环境中某索引结构(7.X后有变化) 索引静态配置 1.分片与压缩 index.number_ ...

  5. kali 安装完不能使用 root 账户登录图形化界面(一直报错)

    kali 安装完不能使用 root 账户登录图形化界面 在普通账户界面,先设置 root 账户密码:sudo passwd root 切换 root 账户登录:su root vim /etc/pam ...

  6. pikachu靶机练习平台-xss

    第一题:反射性xss(get) 输出的字符出现在url中 第二题:反射性xss(post) 登录后输入<script>alert(1)</script> 第三题:存储型xss ...

  7. kali linux 渗透测试 01 kali介绍

    安全问题的根源 分层思想------盲人摸象 只追求功能实现----比较片面 最大的安全威胁是人---- 安全目标 先于攻击者发现和防止漏洞出现 攻击型安全 防护性安全 渗透测试 尝试击破安全防御机制 ...

  8. Atera 用户为最终用户提供对办公计算机的远程访问

    ​一言以蔽之:由 Splashtop 提供支持的 Atera 的客户远程访问功能允许使用 Atera 的 MSP 设置和管理其最终用户对办公计算机的远程访问. 新冠肺炎大流行已加速了全球远程工作的进程 ...

  9. 智能控制 | AIRIOT智慧楼宇管理解决方案

    许多行业客户在智慧楼宇的建设中主要面临运营管理低效,楼宇内部各个系统相互独立,不仅管理操作复杂,而且各系统间的数据无法分享,无法支撑大数据分析.此外,由于楼宇管理系统的低效,50%的建筑能耗是被浪费的 ...

  10. 一文带你读懂Arthas实现原理

    一. 前言 Arthas 相信大家已经不陌生了,肯定用过太多次了,平时说到 Arthas 的时候都知道是基于Java Agent的,那么他具体是怎么实现呢,今天就一起来看看. 首先 Arthas 是在 ...