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

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

初探碰撞检测原理

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

在这里插入图片描述

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

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

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

x1+w1 < x2 ||  x1 > x2 + w2

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

y1+h1 < y2 || y1 > y2+h2

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

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 结构体中添加一个字段表示得分,如下所示:

// Game 结构体表示游戏
type Game struct {
	...
	score    int
	...
}

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

// 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 文件中,如下所示:

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 方法中,检测子弹与敌机的碰撞,如下所示:

// 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 方法中,绘制得分,如下所示:

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

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

leicw@CodeAI世界:code003$ go run main.go

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

在这里插入图片描述

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

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

推荐阅读

  1. 十分钟带你入门Go语言(Golang)开发
  2. 如何修改powershell命令提示符PS1,打造Linux风格的命令提示符
  3. 互联网、因特网和万维网傻傻分不清,一文带你彻底理解计算机中的各种网络
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code AI世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值