Go语言2D游戏开发入门004:零基础打造射击游戏《太空大战》3

上篇文章我们实现了玩家发射子弹的功能,本篇文章将实现《太空大战》v1.2.0版本:实现子弹击毁敌机的功能。

初探碰撞检测原理

要想实现子弹击毁敌机的功能,我们需要先了解碰撞检测的原理。为了简化碰撞检测的难度,我们将使用游戏对象的矩形边界来进行碰撞检测。

上图中,橙色矩形表示玩家发射的子弹,红色矩形表示敌机。要想判断子弹是否击中敌机,我们只需要判断子弹的矩形边界是否与敌机的矩形边界相交即可。如果相交,则认为子弹击中了敌机。

为了便于理解,我们先讨论一下子弹与敌机不相交的情况,排除这些情况后,剩下的情况就是子弹与敌机相交的情况。

首先来看 X 轴的情况,当子弹的 x 坐标 + 子弹的宽度 < 敌机的 x 坐标和当子弹的 x 坐标 > 敌机的 x 坐标 + 敌机的宽度时,子弹与敌机不相交。

go 复制代码
x1+w1 < x2 ||  x1 > x2 + w2

接着来看 Y 轴的情况,当子弹的 y 坐标 + 子弹的高度 < 敌机的 y 坐标和当子弹的 y 坐标 > 敌机的 y 坐标 + 敌机的宽度时,子弹与敌机不相交。

go 复制代码
y1+h1 < y2 || y1 > y2+h2

排除这四种情况后,剩下的情况就是子弹与敌机相交的情况。我们将该碰撞检测过程封装成一个函数,如下所示:

go 复制代码
func CheckRectCollision(x1, y1, w1, h1, x2, y2, w2, h2 float64) bool {
	return !(x1+w1 < x2 ||  x1 > x2 + w2 || y1+h1 < y2 || y1 > y2+h2)
}

本文的代码在上篇文章的代码基础上进行修改。

实现子弹击毁敌机的功能

接下来我们实现子弹击毁敌机,并且实现得分的功能。

首先在 Game 结构体中添加一个字段表示得分,如下所示:

go 复制代码
// Game 结构体表示游戏
type Game struct {
	...
	score    int
	...
}

然后在 NewGame 函数中初始化得分,如下所示:

go 复制代码
// NewGame 初始化游戏
func NewGame() *Game {
	rd = rand.New(rand.NewSource(time.Now().UnixNano()))
	return &Game{
		player: Player{
			x: screenWidth/2 - playerWidth/2,
			y: screenHeight - playerHeight,
		},
		score:    0,
		gameOver: false,
	}
}

将碰撞检测函数添加到 main.go 文件中,如下所示:

go 复制代码
func CheckRectCollision(x1, y1, w1, h1, x2, y2, w2, h2 float64) bool {
	return !(x1+w1 < x2 ||  x1 > x2 + w2 || y1+h1 < y2 || y1 > y2+h2)
}

接着在 Update 方法中,检测子弹与敌机的碰撞,如下所示:

go 复制代码
// Update 更新游戏状态
func (g *Game) Update() error {
	...
    // 检测子弹与敌人的碰撞
	for i, bullet := range g.bullets {
		if !g.bullets[i].active {
			continue
		}
		enemies := make([]Enemy, 0, len(g.enemies))
		for _, enemy := range g.enemies {
			if CheckRectCollision(bullet.x, bullet.y, bulletWidth, bulletHeight,
				enemy.x, enemy.y, enemyWidth, enemyHeight) {
				g.bullets[i].active = false
				g.score++
			} else {
				enemies = append(enemies, enemy)
			}
		}
		g.enemies = enemies
	}
    ...
}

上述代码中,我们使用了 for range 语句遍历 g.bullets 数组,并使用 CheckRectCollision 函数检测子弹与敌机的碰撞。如果碰撞,则将子弹的 active 字段设置为 false,表示子弹被销毁,并且将得分加1,否则将敌机添加到 enemies 数组中(没被添加的敌机相当于被击毁了)。

最后在 Draw 方法中,绘制得分,如下所示:

go 复制代码
// Draw 绘制游戏画面
func (g *Game) Draw(screen *ebiten.Image) {
	...
    // 绘制分数
	ebitenutil.DebugPrint(screen, 
        fmt.Sprintf("Score: %d", g.score))
    ...
}

最后使用如下命令运行游戏,如下所示:

powershell 复制代码
leicw@CodeAI世界:code003$ go run main.go

游戏启动后,效果如下所示:

到这里,我们完成了子弹击毁敌机并且简单实现了得分功能。下篇文章我们将实现敌机发射子弹攻击玩家的功能,敬请期待!

如果遇到问题,欢迎在评论区留言。如果您觉得本文对您有帮助,期待您的分享点赞

推荐阅读

  1. 十分钟带你入门Go语言(Golang)开发
  2. 如何修改powershell命令提示符PS1,打造Linux风格的命令提示符
  3. 互联网、因特网和万维网傻傻分不清,一文带你彻底理解计算机中的各种网络
相关推荐
该用户已不存在4 小时前
Golang 上传文件到 MinIO?别瞎折腾了,这 5 个库拿去用
前端·后端·go
Dobby_055 小时前
【Go】C++转Go:数据结构练习(一)排序算法
数据结构·golang
百锦再5 小时前
Go与Python在AI大模型开发中的深度对比分析
java·开发语言·人工智能·python·学习·golang·maven
钟离墨笺7 小时前
Go语言-->Goroutine 详细解释
开发语言·后端·golang
Yeats_Liao8 小时前
Go Web 编程快速入门 11 - WebSocket实时通信:实时消息推送和双向通信
前端·后端·websocket·golang
华仔啊10 小时前
Go 语言未来会取代 Java 吗?别争了,先看完这篇再说
java·后端·go
草明10 小时前
当 Go 的 channel 被 close 后读写操作会怎么样?
开发语言·后端·golang
Tony Bai1 天前
【Go 网络编程全解】14 QUIC 与 HTTP/3:探索下一代互联网协议
开发语言·网络·后端·http·golang
芝麻粒儿1 天前
天龙八部TLBB系列 - 客户端技术整体性分析
游戏开发·天龙八部·网单·引擎脚本