学习unity后再用OpenGL去做坦克大战

基于OpenGL重做坦克大战,结合Unity学到的游戏设计思路。包括关卡设定、玩家和敌人运动、子弹发射与碰撞检测。利用Unity的组件思想简化代码,优化包括子弹管理、纹理打包和空间划分。
摘要由CSDN通过智能技术生成

i.说明:

其实这个游戏做了很多遍了,第一次是用EasyX,第二次是学完GitHub上的learnOpenGL,第三次是在unity上,看了B站上unity的教程在unity上做了之后给我的感触很大,以前真是有什么来什么,现在看了游戏的教程才略懂循序渐进,现在是第四次,还是用opengl,做的就比较合理、简明了。
做这个游戏算是对learnOpenGL教程的一个复习吧,并且融合了学习unity后的一些巧妙的思想。unity提供给我们游戏的框架,也就是把那些可复用的核心代码封装到无数类中供我们使用,我们自己从底层做也是这样。所以有关渲染的内容,如着色器、纹理的配置、使用均封装在单独的类和方法中,只需要调用几个方法就能轻松的使用。有关渲染的类可以看通过消砖块的游戏对OpenGL(glfw)、图形学、游戏编程的一个小的总结这篇文章中的具体解释。本文主要记录游戏功能实现的细节以及从unity中学到的一些思想。

素材及源码:素材
链接:https://pan.baidu.com/s/1GpWYE7zEhBZnxE_5qOV_Ow
提取码:lbfn

ii.游戏相关的主要功能实现:

1.游戏关卡(地图)的设定、加载:

所谓游戏关卡,在unity中就是不同的场景,对自己做就是渲染不同的精灵。
这里用了两种方式: 从文件中加载和随机生成。(用1、2、3、4.。。。代表对应元素)

(1)从文件中读取需要自己去想怎么设置各种元素个数,方便控制:
void GameLevel::Load(const char *file, unsigned int levelWidth, unsigned int levelHeight)
{
   
    // clear old data
    this->Bricks.clear();
    // load from file
    unsigned int tileCode;
    GameLevel level;
    std::string line;
    std::ifstream fstream(file);
    std::vector<std::vector<unsigned int>> tileData;
    if (fstream)
    {
   
        while (std::getline(fstream, line)) // read each line from level file
        {
   
            std::istringstream sstream(line);
            std::vector<unsigned int> row;
            while (sstream >> tileCode) // read each word seperated by spaces
                row.push_back(tileCode);
            tileData.push_back(row);
        }
        if (tileData.size() > 0)
            this->init(tileData, levelWidth, levelHeight);
    }
}
(2)随机生成可以节省我们自己去想地图的时间,这也是我从unity做坦克大战时的做法:也很合理
void GameLevel::Load(unsigned int levelWidth, unsigned int levelHeight)
{
   
    // clear old data
    this->Bricks.clear();
	int tileData[12][16];//16*12大小的地图
	srand((unsigned)time(NULL));
	unsigned int type,tmp;
	//最外围不能有元素,故0和15不会出现
	//先是不涉及基地的前9层
	for(int i=1;i<9;i++){
   
		for(int j=1;j<15;j++){
   
			tmp=rand()%16;//16种可能(0-15)控制不同元素出现的概率
			if(tmp==13) type=1;//13为砖墙(1)
			else if(tmp==14) type=3;//14为水(3)
			else if(tmp==15) type=4;//15为草(4)
			else if(tmp>=6&&tmp<=12) type=0;//6-12没东西(5)
			else type=2;//0-5为土墙(2)
			tileData[i][j]=type;
		}
	}
	//基地的9-11层:中间为基地,基地周围一圈土墙
	for(int i=9;i<11;i++){
   
		for(int j=1;j<15;j++){
   
			if(i==9&&j>=6&&j<10){
   //基地上方土墙
				type=2;
			}else{
   
				tmp=rand()%16;//(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15;0-4代表土墙,5-12为地面,13,14,15为砖墙、水、草)
				if(tmp==13) type=1;
				else if(tmp==14) type=3;
				else if(tmp==15) type=4;
				else if(tmp>=5&&tmp<=12) type=0;
				else type=2;
			}
			tileData[i][j]=type;
		}
	}
	//基地左右两侧的土墙
	tileData[10][9]=2;
	tileData[10][6]=2;
	tileData[11][9]=2;
	tileData[11][6]=2;
	this->init(tileData, levelWidth, levelHeight);
}

2.玩家运动:

显然按上下左右玩家不仅要向对应方向移动,还要朝向那个方向,这里还是从unity中得到的灵感,我们有两种方式控制:旋转物体或者改变物体的纹理(上下左右四幅)。如果是我们自己实现这一切的话,显然改变物体的纹理更为容易,旋转还要考虑当前朝向,不可取。此外还有不

		// 移动坦克
		if (this->Keys[GLFW_KEY_A])
        {
   
			PlayerTank->Sprite=ResourceManager::GetTexture("p1tankL");
			PlayerTank->Velocity=glm::vec2(-TANK_VELOCITY,0);
			PlayerTank->Move(dt,this->Width,this->Height);
			PlayerTank->dir=L;
        }
		if (this->Keys[GLFW_KEY_D])
        {
   
			PlayerTank->Sprite=ResourceManager::GetTexture("p1tankR");
			PlayerTank->Velocity=glm::vec2(TANK_VELOCITY,0);
			PlayerTank->Move(dt,this->Width,this->Height);
			PlayerTank->dir=R;
        }
		if (this->Keys[GLFW_KEY_W])
        {
   
			PlayerTank->Sprite=ResourceManager::GetTexture("p1tankU");
			PlayerTank->Velocity=glm
好的,我可以为您提供基本的代码结构和思路。 首先,您需要在Unity3D中创建一个新的场景,并将坦克、地形和其他游戏对象添加到场景中。 接下来,您需要创建一个脚本来控制坦克的行为。在这个脚本中,您可以添加以下功能: 1. 坦克的移动控制:通过WASD或者方向键来控制坦克的前进、后退、左转、右转等方向。 2. 坦克的炮弹发射:通过鼠标点击或者空格键来控制坦克发射炮弹。 3. 坦克的碰撞检测:判断坦克是否与地形或其他游戏对象发生碰撞,如果发生碰撞,则需要执行相应的处理逻辑,比如扣除生命值等。 4. 坦克的生命值控制:通过变量来控制坦克的生命值,当坦克的生命值减为0时,坦克将被摧毁。 5. 坦克的得分计算:通过变量来控制坦克的得分,当坦克击败其他敌方坦克时,将获得相应的得分。 然后,您需要创建敌方坦克,并为敌方坦克添加类似于玩家控制的脚本,控制它们的行为。 最后,您需要添加一些额外的游戏逻辑,比如游戏的开始、暂停、结束等功能,以及一些音效、粒子特效等来增加游戏的趣味性。 下面是一个简单的C#代码示例: ```csharp using UnityEngine; public class TankController : MonoBehaviour { public float moveSpeed = 5f; public float rotateSpeed = 5f; public GameObject bulletPrefab; public Transform firePoint; public float bulletSpeed = 10f; public int maxHealth = 100; public int currentHealth; public int score = 0; private Rigidbody rb; void Start() { currentHealth = maxHealth; rb = GetComponent<Rigidbody>(); } void Update() { float h = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical"); transform.Translate(Vector3.forward * v * moveSpeed * Time.deltaTime); transform.Rotate(Vector3.up * h * rotateSpeed * Time.deltaTime); if (Input.GetButtonDown("Fire1")) { Fire(); } } void Fire() { GameObject bullet = Instantiate(bulletPrefab, firePoint.position, firePoint.rotation); Rigidbody bulletRb = bullet.GetComponent<Rigidbody>(); bulletRb.velocity = transform.forward * bulletSpeed; } void OnCollisionEnter(Collision collision) { if (collision.gameObject.tag == "Terrain") { // do something when colliding with terrain } if (collision.gameObject.tag == "Enemy") { // do something when colliding with enemy } } void TakeDamage(int damage) { currentHealth -= damage; if (currentHealth <= 0) { Die(); } } void Die() { // do something when tank dies } } ``` 这只是一个简单的示例代码,您可以根据自己的需求进行修改和扩展。希望对您有所帮助!
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值