3d游戏设计 Homework10

6 篇文章 0 订阅
4 篇文章 0 订阅

3d游戏设计 Homework10


这里写图片描述

总结

这次的作业是使用Unet完成一个p2p的联网游戏。主要难点不在于代码上,而在于搞清楚Unet的p2p简单原理,知道代码运行在哪里,执行在哪里,下面就来捋下知识点。

首先要明白服务端和客户端的概念,其中一台主机作为服务端,但同时他也是客户端(因为他也要玩游戏),明白什么是运行在本地的,什么是运行在服务端上的,通过if(!isLocalPlayer)orif(!isServer)进行运行。但是有的时候客户端产生的行为效果想让其他客户端知道,这个时候就需要将客户端运行的代码交给服务端执行,就需要使用到c#特性【command】,命令服务端执行。由于一些具有本地权限的网络对象,服务端想对客户端的网络对象进行修改的时候,修改之后会被本地权限覆盖,因此就需要用特性【clientRPC】标识在服务端运行的代码,要在客户端执行,下面上代码。

代码修改自unity官方的network tutorial,这次代码的质量不是太高(耦合度太高),也没有使用设计风格。

PlayerMove

PlayerMove完成了摄像头跟踪,船舶移动,蓄力攻击。要提到的是,蓄力攻击的加速度是在客户端运行的,要放到服务端执行,其中accelation是在本地进行执行的,但是服务端的accelation一直为0,所以我们还需要在完成CmdPrepareAccelation()在服务端进行蓄力,这里应该创建一个clientAccelation,但是我没有这样做,这样就会出现其他客户端玩家会帮助服务端玩家蓄力,也是我留的一个小坑,房主就会像开挂一样蓄力超快。

using UnityEngine;
using UnityEngine.Networking;

public class PlayerMove : NetworkBehaviour
{
    [Header("Movement Variables")]
    [SerializeField] float turnSpeed = 45.0f;
    [SerializeField] float movementSpeed = 5.0f;
    [Header("Camera Position Variables")]
    [SerializeField] float cameraDistance = 5f;
    [SerializeField] float cameraHeight = 2f;


    public GameObject bulletPrefab;
    public Rigidbody localRigidBody;
    private Transform mainCamera;
    private Vector3 cameraOffset;
    private float accelation;

    public override void OnStartLocalPlayer()
    {
        GetComponent<MeshRenderer>().material.color = Color.blue;
    }

    private void Start()
    {
        if (!isLocalPlayer)
        {
            return;
        }

        localRigidBody = this.GetComponent<Rigidbody>();

        Debug.Log(transform.position);

        cameraOffset = new Vector3(0f, cameraHeight, -cameraDistance);

        mainCamera = Camera.main.transform;

        MoveCamera();
    }

    private void FixedUpdate()
    {
        if (!isLocalPlayer)
            return;

        /*var turnAmount = Input.GetAxis("Horizontal") * 0.1f;
        var moveAmount = Input.GetAxis("Vertical") * 0.1f;
        transform.Translate(x, 0, z);*/

        var turnAmount = Input.GetAxis("Horizontal") * 0.1f;
        var moveAmount = Input.GetAxis("Vertical") * 0.1f;

        Vector3 deltaTranslation = transform.position + transform.forward * movementSpeed * moveAmount * Time.deltaTime;
        localRigidBody.MovePosition(deltaTranslation);

        Quaternion deltaRotation = Quaternion.Euler(turnSpeed * new Vector3(0, turnAmount, 0) * Time.deltaTime);
        localRigidBody.MoveRotation(deltaRotation * localRigidBody.rotation);

        if (Input.GetKey(KeyCode.Space))
        {
            accelation += Time.deltaTime * 2;
            CmdPrepareAccelation();
        }

        if (Input.GetKeyDown(KeyCode.Space))
        {
            accelation = 0;
            CmdZeroAccelation();
        }

        if (Input.GetKeyUp(KeyCode.Space))
        {
            CmdFire();
        }
        MoveCamera();
    }

    [Command]
    private void CmdPrepareAccelation()
    {
        accelation += Time.deltaTime * 2;
    }

    [Command]
    private void CmdZeroAccelation()
    {
        accelation = 0;
    }

    private void MoveCamera()
    {
        mainCamera.position = transform.position;
        mainCamera.rotation = transform.rotation;
        mainCamera.Translate(cameraOffset);
        mainCamera.LookAt(transform);
    }

    [Command]
    void CmdFire()
    {
        // This [Command] code is run on the server!

        // create the bullet object locally
        Transform emitTransform = transform.GetChild(1);
        var bullet = (GameObject)Instantiate(
             bulletPrefab,
             emitTransform.position,
             Quaternion.identity);
        Debug.Log(accelation);
        bullet.GetComponent<Rigidbody>().velocity = transform.forward * 5 * accelation;

        // spawn the bullet on the clients
        NetworkServer.Spawn(bullet);

        // when the bullet is destroyed on the server it will automaticaly be destroyed on clients
        Destroy(bullet, 4.0f);
    }

    private void OnGUI()
    {
        if (!isLocalPlayer) return;
        GUIStyle gUIStyle = new GUIStyle();
        gUIStyle.fontSize = 14;
        gUIStyle.normal.textColor = Color.cyan;
        GUI.Label(new Rect(Screen.width / 2 - 130, Screen.height / 2 + 140, 200, 100), "[w.a.s.d]:move " +
            "the boat.\n[space]:attack, and you can accumulate attacking distance by holding [space].\n" +
            "if your health bar disappear, you will move to another place to play again.", gUIStyle);
    }
}

HealthBar

将本地的血量显示成血条。

using UnityEngine;
using System.Collections;

public class HealthBar : MonoBehaviour
{
    GUIStyle healthStyle;
    GUIStyle backStyle;
    Combat combat;

    void Awake()
    {
        combat = GetComponent<Combat>();
    }

    void OnGUI()
    {
        InitStyles();

        // Draw a Health Bar

        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);

        // draw health bar background
        GUI.color = Color.grey;
        GUI.backgroundColor = Color.grey;
        GUI.Box(new Rect(pos.x - 26, Screen.height - pos.y + 20, Combat.maxHealth / 2, 7), ".", backStyle);

        // draw health bar amount
        GUI.color = Color.green;
        GUI.backgroundColor = Color.green;
        GUI.Box(new Rect(pos.x - 25, Screen.height - pos.y + 21, combat.health / 2, 5), ".", healthStyle);
    }

    void InitStyles()
    {
        if (healthStyle == null)
        {
            healthStyle = new GUIStyle(GUI.skin.box);
            healthStyle.normal.background = MakeTex(2, 2, new Color(0f, 1f, 0f, 1.0f));
        }

        if (backStyle == null)
        {
            backStyle = new GUIStyle(GUI.skin.box);
            backStyle.normal.background = MakeTex(2, 2, new Color(0f, 0f, 0f, 1.0f));
        }
    }

    Texture2D MakeTex(int width, int height, Color col)
    {
        Color[] pix = new Color[width * height];
        for (int i = 0; i < pix.Length; ++i)
        {
            pix[i] = col;
        }
        Texture2D result = new Texture2D(width, height);
        result.SetPixels(pix);
        result.Apply();
        return result;
    }
}

Combat

Combat完成了血量减少,和血量低于0是移动到原地。

using UnityEngine;
using UnityEngine.Networking;

public class Combat : NetworkBehaviour
{
    public const int maxHealth = 100;

    [SyncVar]
    public int health = maxHealth;

    public void TakeDamage(int amount)
    {
        if (!isServer)
            return;

        health -= amount;
        if (health <= 0)
        {
            health = maxHealth;

            // called on the server, will be invoked on the clients
            RpcRespawn();
        }
    }

    [ClientRpc]
    void RpcRespawn()
    {
        if (isLocalPlayer)
        {
            // move back to zero location
            transform.position = new Vector3(0,1,0);
        }
    }
}

Bullet

完成了碰撞检测,碰撞时减少血量。

using UnityEngine;

public class Bullet : MonoBehaviour
{
    void OnCollisionEnter(Collision collision)
    {
        var hit = collision.gameObject;
        var hitPlayer = hit.GetComponent<PlayerMove>();
        if (hitPlayer != null)
        {
            // Subscribe and Publish model may be good here!
            Debug.Log("test");
            var combat = hit.GetComponent<Combat>();
            combat.TakeDamage(30);

            //Destroy(gameObject);
        }
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
传说中的龙书是也。。。 最好最新的DirectX游戏开发入门书籍 英文版+中文版+源代码 打包 非常适合初学者 内容提要 -------------------------------------------------------------------------------- 本书主要介绍如何使用DirectX 9.0开发交互式3D图形程序,重点是游戏开发。全书首先介绍了必要的数学工具,然后讲解了相关的3D概念。其他主题几乎涵盖了Direct3D中的所有基本运算,例如图元的绘制、光照、纹理、Alpha融合、模板,以及如何使用Direct3D实现游戏中所需的技术。介绍顶定点着色器和像素着色器的章节(包含了效果框架和新的高级着色语言的内容)对这些关键运算进行了较为集中的讨论。 本书内容深入浅出,内容广泛,可供从事3D游戏程序设计、可视化系统设计或其他图形应用程序开发的开发人员和大中专院校学生参考,也极适合各种游戏开发培训机构作为Direct3D编程的培训教程。 目录 -------------------------------------------------------------------------------- 第Ⅰ部分 基础知识 必备的数学知识\t 3D空间中的向量\t 矩阵\t\t 基本变换\t 平面(选读)\t 射线(选读)\t 小结\t\t 第Ⅱ部分 Direct3D基础 第1章 初始化Direct3D 1.1 Direct3D概述\t 1.2 COM(组件对象模型)\t 1.3 预备知识\t 1.4 Direct3D的初始化\t 1.5 例程:Direct3D的初始化 1.6 小结\t 第2章 绘制流水线\t 2.1 模型表示\t 2.2 虚拟摄像机 2.3 绘制流水线 2.4 小结\t 第3章 Direct3D中的绘制\t 3.1 顶点缓存与索引缓存 3.2 绘制状态\t 3.3 绘制的准备工作\t 3.4 使用顶点缓存和索引缓存进行绘制\t 3.5 D3DX几何体 3.6 例程:三角形、立方体、茶壶、D3DXCreate* 3.7 小结\t 第4章 颜色\t 4.1 颜色表示 4.2 顶点颜色 4.3 着色\t 4.4 例程:具有颜色的三角形\t 4.5 小结\t 第5章 光照\t 5.1 光照的组成\t 5.2 材质\t 5.3 顶点法线\t 5.4 光源\t 5.5 例程:光照 5.6 一些附加例程\t 5.7 小结\t 第6章 纹理映射 6.1 纹理坐标\t 6.2 创建并启用纹理\t 6.3 纹理过滤器 6.4 多级渐进纹理 6.5 寻址模式 6.6 例程:纹理四边形 6.7 小结\t 第7章 融合技术\t 7.1 融合方程\t 7.2 融合因子 7.3 透明度 7.4 用DirectX Texture Tool创建Alpha通道\t 7.5 例程:透明效果\t 7.6 小结\t 第8章 模板\t 8.1 模板缓存的使用\t 8.2 例程:镜面效果\t 8.3 例程:Planer Shadows\t 8.4 小结\t 第Ⅲ部分 Direct3D的应用 第9章 字体\t 第10章 网格(一)\t 第11章 网格(二)\t 第12章 设计一个灵活的Camera类 第13章 地形绘制基础\t 第14章 粒子系统\t 第15章 拾取\t 第Ⅳ部分 着色器和效果 第16章 高级着色语言(HLSL)入门\t 第17章 顶点着色器入门\t 第18章 像素着色器入门\t 第19章 效果框架\t 附录 Windows编程入门\t 参考文献 作者介绍 -------------------------------------------------------------------------------- Prank Luna是Hero lnteractive的程序员,从事交互式3D图形编程已有八年多。他最早接触DirectX可以追溯到DirectX5发布之时,目前居住在加州的洛杉矶市。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值