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. 互联网、因特网和万维网傻傻分不清,一文带你彻底理解计算机中的各种网络
相关推荐
Z.风止4 小时前
Go-learning(1)
开发语言·笔记·后端·golang
小二·5 小时前
Go 语言系统编程与云原生开发实战(第7篇)分布式系统核心能力:配置中心 × 链路追踪 × 熔断降级(生产级落地)
开发语言·云原生·golang
lead520lyq5 小时前
Golang Grpc接口调用实现账号密码认证
开发语言·后端·golang
小二·5 小时前
Go 语言系统编程与云原生开发实战(第6篇)云原生部署实战:Docker 镜像瘦身 × K8s 部署 × Helm 一键发布
docker·云原生·golang
花酒锄作田12 小时前
MCP官方Go SDK尝鲜
golang·mcp
老姚---老姚19 小时前
在windows下编译go语言编写的dll库
开发语言·windows·golang
bing.shao1 天前
Golang 开发者视角:解读《“人工智能 + 制造” 专项行动》的技术落地机遇
人工智能·golang·制造
ONE_PUNCH_Ge1 天前
Go 语言泛型
开发语言·后端·golang
烟花落o1 天前
贪吃蛇及相关知识点讲解
c语言·前端·游戏开发·贪吃蛇·编程学习
啊汉2 天前
古文观芷App搜索方案深度解析:打造极致性能的古文搜索引擎
go·软件随想