愤怒的小鸟游戏开发实现
要实现一个《愤怒的小鸟》游戏,有多种技术方案可选,主要基于不同的游戏引擎和编程语言。下面我将详细介绍几种主流实现方式,并提供核心代码示例。
一、技术方案对比
| 方案 | 使用引擎/框架 | 编程语言 | 适合平台 | 开发复杂度 | 物理引擎 |
|---|---|---|---|---|---|
| 方案1 | Unity3D | C# | 跨平台(PC、移动端) | 中等 | Unity内置物理引擎 |
| 方案2 | Cocos2d-x | C++/JavaScript | 跨平台 | 中等 | Box2D |
| 方案3 | HTML5 Canvas | JavaScript | Web浏览器 | 中等 | Box2DWeb/pymunk |
| 方案4 | PyGame + pymunk | Python | PC桌面 | 较低 | pymunk |
二、Unity3D实现方案(推荐)
Unity是最流行的游戏开发引擎之一,内置强大的物理系统,非常适合开发《愤怒的小鸟》这类物理游戏。
1. 项目设置与基础场景
csharp
// CameraController.cs - 相机控制脚本
using UnityEngine;
public class CameraController : MonoBehaviour
{
public Transform target; // 跟随的目标(小鸟)
public float smoothSpeed = 0.125f;
public Vector3 offset = new Vector3(0, 0, -10);
void LateUpdate()
{
if (target != null)
{
Vector3 desiredPosition = target.position + offset;
Vector3 smoothedPosition = Vector3.Lerp(
transform.position,
desiredPosition,
smoothSpeed
);
transform.position = smoothedPosition;
}
}
}
2. 小鸟物理控制
csharp
// BirdController.cs - 小鸟控制脚本
using UnityEngine;
public class BirdController : MonoBehaviour
{
public float maxDragDistance = 2.0f; // 最大拖拽距离
public float launchForce = 10.0f; // 发射力量
public LineRenderer trajectoryLine; // 轨迹线渲染器
private bool isDragging = false;
private Vector3 startPosition;
private Rigidbody2D rb;
private SpringJoint2D springJoint;
void Start()
{
rb = GetComponent<Rigidbody2D>();
springJoint = GetComponent<SpringJoint2D>();
startPosition = transform.position;
}
void OnMouseDown()
{
if (!isDragging)
{
isDragging = true;
rb.isKinematic = true;
}
}
void OnMouseDrag()
{
if (isDragging)
{
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mousePos.z = 0;
// 限制拖拽范围
Vector3 dragDirection = (startPosition - mousePos).normalized;
float dragDistance = Vector3.Distance(mousePos, startPosition);
dragDistance = Mathf.Min(dragDistance, maxDragDistance);
transform.position = startPosition + dragDirection * dragDistance;
// 显示轨迹线
UpdateTrajectory();
}
}
void OnMouseUp()
{
if (isDragging)
{
isDragging = false;
rb.isKinematic = false;
// 计算发射方向
Vector3 launchDirection = (startPosition - transform.position).normalized;
rb.AddForce(launchDirection * launchForce, ForceMode2D.Impulse);
// 禁用弹簧关节
if (springJoint != null)
springJoint.enabled = false;
// 隐藏轨迹线
if (trajectoryLine != null)
trajectoryLine.enabled = false;
}
}
void UpdateTrajectory()
{
// 使用物理模拟预测轨迹
if (trajectoryLine != null)
{
trajectoryLine.enabled = true;
trajectoryLine.positionCount = 20;
Vector3[] positions = new Vector3[20];
Vector3 currentPos = transform.position;
Vector3 velocity = (startPosition - transform.position).normalized * launchForce;
for (int i = 0; i < 20; i++)
{
positions[i] = currentPos;
velocity += Physics2D.gravity * Time.fixedDeltaTime;
currentPos += velocity * Time.fixedDeltaTime;
}
trajectoryLine.SetPositions(positions);
}
}
}
3. 弹弓实现
csharp
// Slingshot.cs - 弹弓控制脚本
using UnityEngine;
public class Slingshot : MonoBehaviour
{
public Transform leftPoint; // 左弹弓点
public Transform rightPoint; // 右弹弓点
public Transform centerPoint; // 中心点(小鸟初始位置)
public GameObject birdPrefab; // 小鸟预制体
private GameObject currentBird;
void Start()
{
SpawnNewBird();
}
void SpawnNewBird()
{
if (birdPrefab != null && centerPoint != null)
{
currentBird = Instantiate(birdPrefab, centerPoint.position, Quaternion.identity);
// 添加弹簧关节连接到弹弓
SpringJoint2D springJoint = currentBird.AddComponent<SpringJoint2D>();
springJoint.connectedAnchor = centerPoint.position;
springJoint.distance = 0.1f;
springJoint.dampingRatio = 1f;
springJoint.frequency = 4f;
}
}
void Update()
{
// 绘制弹弓橡皮筋
if (currentBird != null && isDragging)
{
DrawRubberBand();
}
}
void DrawRubberBand()
{
LineRenderer lineRenderer = GetComponent<LineRenderer>();
if (lineRenderer != null)
{
lineRenderer.positionCount = 3;
lineRenderer.SetPosition(0, leftPoint.position);
lineRenderer.SetPosition(1, currentBird.transform.position);
lineRenderer.SetPosition(2, rightPoint.position);
}
}
}
4. 障碍物与猪的物理属性
csharp
// Obstacle.cs - 障碍物脚本
using UnityEngine;
public class Obstacle : MonoBehaviour
{
public enum MaterialType
{
Wood,
Stone,
Ice,
Glass
}
public MaterialType material = MaterialType.Wood;
public float health = 100f;
void Start()
{
// 根据材质设置物理属性
Rigidbody2D rb = GetComponent<Rigidbody2D>();
Collider2D collider = GetComponent<Collider2D>();
switch (material)
{
case MaterialType.Wood:
rb.mass = 1.0f;
rb.drag = 0.5f;
break;
case MaterialType.Stone:
rb.mass = 2.5f;
rb.drag = 0.8f;
break;
case MaterialType.Ice:
rb.mass = 0.8f;
rb.drag = 0.1f;
break;
case MaterialType.Glass:
rb.mass = 0.5f;
rb.drag = 0.3f;
break;
}
}
void OnCollisionEnter2D(Collision2D collision)
{
// 计算碰撞伤害
float impactForce = collision.relativeVelocity.magnitude;
float damage = impactForce * 10f;
health -= damage;
if (health <= 0)
{
DestroyObstacle();
}
}
void DestroyObstacle()
{
// 播放粒子效果
ParticleSystem breakEffect = GetComponentInChildren<ParticleSystem>();
if (breakEffect != null)
{
breakEffect.Play();
}
// 延迟销毁
Destroy(gameObject, 0.5f);
}
}
// PigController.cs - 猪的控制脚本
using UnityEngine;
public class PigController : MonoBehaviour
{
public float health = 50f;
public GameObject deathEffect;
void OnCollisionEnter2D(Collision2D collision)
{
// 根据碰撞速度计算伤害
float impactForce = collision.relativeVelocity.magnitude;
if (impactForce > 2f)
{
float damage = impactForce * 5f;
TakeDamage(damage);
}
}
void TakeDamage(float damage)
{
health -= damage;
if (health <= 0)
{
Die();
}
}
void Die()
{
// 播放死亡效果
if (deathEffect != null)
{
Instantiate(deathEffect, transform.position, Quaternion.identity);
}
// 增加分数
ScoreManager.Instance.AddScore(1000);
Destroy(gameObject);
}
}
三、HTML5 + JavaScript实现方案
使用HTML5 Canvas和Box2D物理引擎,适合Web平台开发。
html
<!DOCTYPE html>
<html>
<head>
<title>愤怒的小鸟 - HTML5版</title>
<style>
canvas {
border: 1px solid #000;
display: block;
margin: 20px auto;
background: #87CEEB;
}
#gameInfo {
text-align: center;
font-family: Arial, sans-serif;
}
</style>
</head>
<body>
<div id="gameInfo">
<h2>愤怒的小鸟</h2>
<p>分数: <span id="score">0</span> | 剩余小鸟: <span id="birdsLeft">5</span></p>
</div>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<script>
// 游戏主类
class AngryBirdsGame {
constructor() {
this.canvas = document.getElementById('gameCanvas');
this.ctx = this.canvas.getContext('2d');
this.score = 0;
this.birdsLeft = 5;
this.currentBird = null;
this.isDragging = false;
this.startPos = {x: 0, y: 0};
this.endPos = {x: 0, y: 0};
// 游戏对象数组
this.birds = [];
this.pigs = [];
this.obstacles = [];
this.init();
this.gameLoop();
}
init() {
// 创建弹弓
this.createSlingshot();
// 创建障碍物
this.createObstacles();
// 创建猪
this.createPigs();
// 创建小鸟
this.createBird();
// 绑定事件
this.bindEvents();
}
createSlingshot() {
// 绘制弹弓
this.slingshot = {
x: 100,
y: 400,
width: 20,
height: 80
};
}
createBird() {
this.currentBird = {
x: this.slingshot.x,
y: this.slingshot.y,
radius: 15,
color: 'red',
velocity: {x: 0, y: 0},
launched: false
};
}
createObstacles() {
// 创建木箱障碍物
for (let i = 0; i < 3; i++) {
this.obstacles.push({
x: 500 + i * 60,
y: 400,
width: 40,
height: 40,
type: 'wood',
health: 100
});
}
}
createPigs() {
this.pigs.push({
x: 550,
y: 440,
radius: 20,
health: 50,
color: 'green'
});
}
bindEvents() {
this.canvas.addEventListener('mousedown', (e) => {
const rect = this.canvas.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
// 检查是否点击了小鸟
const distance = Math.sqrt(
Math.pow(mouseX - this.currentBird.x, 2) +
Math.pow(mouseY - this.currentBird.y, 2)
);
if (distance < this.currentBird.radius && !this.currentBird.launched) {
this.isDragging = true;
this.startPos = {x: mouseX, y: mouseY};
}
});
this.canvas.addEventListener('mousemove', (e) => {
if (this.isDragging && this.currentBird && !this.currentBird.launched) {
const rect = this.canvas.getBoundingClientRect();
this.endPos = {
x: e.clientX - rect.left,
y: e.clientY - rect.top
};
// 限制拖拽距离
const maxDistance = 100;
const dragX = this.startPos.x - this.endPos.x;
const dragY = this.startPos.y - this.endPos.y;
const distance = Math.sqrt(dragX * dragX + dragY * dragY);
if (distance > maxDistance) {
const angle = Math.atan2(dragY, dragX);
this.endPos.x = this.startPos.x - Math.cos(angle) * maxDistance;
this.endPos.y = this.startPos.y - Math.sin(angle) * maxDistance;
}
this.currentBird.x = this.endPos.x;
this.currentBird.y = this.endPos.y;
}
});
this.canvas.addEventListener('mouseup', () => {
if (this.isDragging && this.currentBird && !this.currentBird.launched) {
this.isDragging = false;
this.launchBird();
}
});
}
launchBird() {
// 计算发射速度和方向
const deltaX = this.startPos.x - this.endPos.x;
const deltaY = this.startPos.y - this.endPos.y;
const power = 0.3; // 力量系数
this.currentBird.velocity = {
x: deltaX * power,
y: deltaY * power
};
this.currentBird.launched = true;
this.birdsLeft--;
document.getElementById('birdsLeft').textContent = this.birdsLeft;
}
updateBird() {
if (this.currentBird && this.currentBird.launched) {
// 应用重力
this.currentBird.velocity.y += 0.5;
// 更新位置
this.currentBird.x += this.currentBird.velocity.x;
this.currentBird.y += this.currentBird.velocity.y;
// 边界检查
if (this.currentBird.x > this.canvas.width ||
this.currentBird.y > this.canvas.height ||
this.currentBird.x < 0) {
this.createBird();
}
// 碰撞检测
this.checkCollisions();
}
}
checkCollisions() {
// 与猪的碰撞
this.pigs.forEach((pig, index) => {
const distance = Math.sqrt(
Math.pow(this.currentBird.x - pig.x, 2) +
Math.pow(this.currentBird.y - pig.y, 2)
);
if (distance < this.currentBird.radius + pig.radius) {
pig.health -= 30;
if (pig.health <= 0) {
this.pigs.splice(index, 1);
this.score += 1000;
document.getElementById('score').textContent = this.score;
}
}
});
// 与障碍物的碰撞
this.obstacles.forEach((obstacle, index) => {
const birdLeft = this.currentBird.x - this.currentBird.radius;
const birdRight = this.currentBird.x + this.currentBird.radius;
const birdTop = this.currentBird.y - this.currentBird.radius;
const birdBottom = this.currentBird.y + this.currentBird.radius;
const obstacleLeft = obstacle.x;
const obstacleRight = obstacle.x + obstacle.width;
const obstacleTop = obstacle.y;
const obstacleBottom = obstacle.y + obstacle.height;
if (birdRight > obstacleLeft &&
birdLeft < obstacleRight &&
birdBottom > obstacleTop &&
birdTop < obstacleBottom) {
obstacle.health -= 50;
if (obstacle.health <= 0) {
this.obstacles.splice(index, 1);
}
}
});
}
draw() {
// 清空画布
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// 绘制背景
this.ctx.fillStyle = '#87CEEB';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
// 绘制地面
this.ctx.fillStyle = '#8B4513';
this.ctx.fillRect(0, 500, this.canvas.width, 100);
// 绘制弹弓
this.ctx.fillStyle = '#8B4513';
this.ctx.fillRect(this.slingshot.x - 10, this.slingshot.y, 20, 80);
this.ctx.fillRect(this.slingshot.x - 40, this.slingshot.y + 60, 80, 20);
// 绘制拖拽线
if (this.isDragging && this.currentBird && !this.currentBird.launched) {
this.ctx.beginPath();
this.ctx.moveTo(this.slingshot.x, this.slingshot.y);
this.ctx.lineTo(this.currentBird.x, this.currentBird.y);
this.ctx.strokeStyle = '#8B4513';
this.ctx.lineWidth = 3;
this.ctx.stroke();
}
// 绘制小鸟
if (this.currentBird) {
this.ctx.beginPath();
this.ctx.arc(
this.currentBird.x,
this.currentBird.y,
this.currentBird.radius,
0,
----
## 参考来源
- [21个测试高频面试题](https://blog.csdn.net/2301_79535618/article/details/146230496)
- [CSDN日报190911:Unity3D开发小游戏;常见的五种神经网络](https://blog.csdn.net/blogdevteam/article/details/100739839)
- [IOS cocos2d学习笔记-扉页](https://blog.csdn.net/banana_416432275/article/details/9717335)
- [Python 愤怒的小鸟代码实现(1):物理引擎pymunk使用](https://blog.csdn.net/marble_xu/article/details/102079236)
- [【Unity3D开发小游戏】《愤怒的小鸟》Unity开发教程](https://blog.csdn.net/q764424567/article/details/100726495)
- [html5游戏开发-愤怒的小鸟-开源讲座(一)-跳入弹出的小鸟](https://blog.csdn.net/lufy_legend/article/details/7765599)