2018-11-23 10:00:49 qq_42292831 阅读数 4129
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4646 人正在学习 去看看 张刚

Scripts:

1> Camera 视角跟随(offset)

2> WSAD (方向键)控制角色移动

3> Click to shoot 单击发射子弹

4> Animation_Loop 动画循环播放

************************************************************************************************************************************

 

一:效果实现

 

 

二:Scripts

1> Camera 视角跟随(offset)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraFollowTarget : MonoBehaviour {

    public Transform Succubus;
    public Vector3 offset;
	// Use this for initialization
	void Start () {
        offset = transform.position - Succubus.position;
	}
	
	// Update is called once per frame
	void Update () {
        transform.position = offset + Succubus.position;
	}
}

 解析:

在Start()函数内部给offset初始化偏移量坐标,相机的坐标-人物的坐标;

然后在Update()更新函数中不断对相机的位置坐标进行更新(人物移动后的坐标+偏移量),

人物的移动可以另外附加脚本进行操作,这里会获取即时的人物坐标来对相机的位置进行赋值。

额外解法:

可以直接将相机物件拖到人物物件下即可(将其作为人物物件的子物件)

 

2> WSAD (方向键)控制角色移动

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BirdMovement : MonoBehaviour {

    public float speed_wsad = 20;
    public float speed_mouse = 20;

    // Use this for initialization
    void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        float d = Input.GetAxis("Mouse ScrollWheel");
        d = d * speed_mouse;
        this.transform.Translate(new Vector3(h, v, d) * Time.deltaTime * speed_wsad);    
    }
}

解析:

这里的WSAD和键盘的上下左右有一致的效果,这里不用去监测WSAD按键的按下,

可以通过另外一种方式来进行移动操作 Input.GetAxis("Horizontal");

 

3> Click to shoot 单击发射子弹

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BirdMovement : MonoBehaviour {

    public float speed = 20;
    public GameObject bullet;

    // Use this for initialization
    void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
        if (Input.GetMouseButtonDown(0))
        {
            //GameObject b = GameObject.Instantiate(this.gameObject, transform.position, transform.rotation);    //暴力分裂效果  transform.position

            GameObject b = GameObject.Instantiate(bullet, new Vector3(transform.position.x, transform.position.y + 2,transform.position.z), transform.rotation);
            Rigidbody rgd = b.GetComponent<Rigidbody>();
            rgd.velocity = this.transform.forward * speed;
        }   
    }
}

解析:

获取子弹bullet对象,在鼠标左键按下的时候实例化该对象,并为对象赋予forward方向初速度; 

 

4> Animation_Loop 动画循环播放

(选中动画 -> Wrap Mode -> Loop)

 

 

 

 

2016-08-17 09:38:53 vipzjh 阅读数 5104
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4646 人正在学习 去看看 张刚

用处:一般当场景出现两个及两个以上,或者会出现重复的物体的时候,用实例化比较方便
目标:鼠标点击后,在鼠标点击的位置出现一个小球
涉及到:预制件,Instantiate(预制件,newVector(?,?,?),Quaternion.identity);
思路:先在Hierarchy建立一个cube,然后拖入工程建成预制件,删除这个cube,然后建立一个空的GameObject,建立一个新的Script。好了要实现代码部分了。

public class newPre : MonoBehaviour {
public Transform Cubepre;//注意,要把cube的预制件拖入 这个变量Cubepre中
    void Start() {

       for (int y =1; y < 3; y++)
       {
          for (int x =0; x < 3; x++)
          {
            Instantiate(Cubepre, new Vector3(x, y, 0),Quaternion.identity);
         }//里面的参数就是1,是预制件,2是坐标,3是默认的
            //上面的代码的作用是,这些位置产生小球//下面要在update,实现鼠标点击出现小球
       }
    }

3D的好像鼠标定位有点复杂,所以//下面要在update,实现鼠标点击出现小球 这个功能在之前的2D下实现

if(Input.GetMouseButtonDown(0))
      {
     //       Camera.main.ScreenToWorldPoint(Input.mousePosition);//这个是鼠标坐标
Instantiate(Cubepre,Camera.main.ScreenToWorldPoint(Input.mousePosition),Quaternion.identity);
      }

这样就很简单的实现了。

2017-12-29 19:56:14 qq_29413829 阅读数 27627
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4646 人正在学习 去看看 张刚

Instantiate函数是unity3d中进行实例化的函数,也就是对一个对象进行复制操作的函数,这个函数共有五个重载(overloaded)函数,对这五个函数的理解不清楚的话产生的效果也不相同,现在对这五个函数做一定的理解。

先附上unity3d API 中对这个函数的描述:
Instantiate函数
Instantiate函数实例化是将original对象的所有子物体和子组件完全复制,成为一个新的对象。这个新的对象拥有与源对象完全一样的东西,包括坐标值等。
original:用来做复制操作的对像物体,源对象
position:实例化的对象的位置坐标
rotation:实例化的对象的旋转坐标(旋转四元数)
parent:实例化对象的父对象,就是给这个实例化对象找的爹,在完成实例化函数处理后,实例化对象将在父对象下,是父对象的子对象
instantiateWorldSpace(老的叫WorldSpaceStays):这个值为TRUE,表示实例化对象相对于世界坐标系的位置(是位置,不是坐标值,比如实例化前在Canvas左上角,实例化后还在左上角)不变,相对于父对象的坐标值变了。为false,表示实例化对象相对于父对象的坐标值不变,但在世界坐标系中的位置变了。

这里写图片描述
这两个函数的区别是instantiateWorldSpace等于true/false的区别。
第一个函数相当于instantiateWorldSpace等于false。效果:实例化对象将放在父对象下,完全保存了源对象的属性,其位置坐标值是相对于父对象的,值不变,在世界坐标系下位置发生变化。
第二个函数相当于instantiateWorldSpace等于TRUE。效果:实例化对象将放在父对象下,完全保存了源对象的属性,其位置坐标值是相对于父对象的,值改变,在世界坐标系下位置不发生变化。

第一个函数:
这里写图片描述

这里写图片描述

这里写图片描述
0是源对象,text1~text9是实例化对象(text1的值为20;text2=40;text3=60;…text9=180;这边让他们显示都叠在一起了),左边的坐标值没有变化,效果图上的位置变了。
第二个函数:
这里写图片描述
这里写图片描述
左边的坐标值有变化,效果图上的位置不变。可以看到,实例化出来的位置不一样。

这里写图片描述
这两个函数的position和rotation是指定实例化对象出现的位置。

ps:所有物体的transform都是相对于父对象来说的。至于为什么能够直接操作该物体相对于世界坐标系的状态是因为:transform通过遍历自己的父对象计算之后得到的结果。

2015-06-20 20:56:11 neilol 阅读数 1926
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4646 人正在学习 去看看 张刚
Intro to Unity
This instructable is aimed at super beginners!

You will need to install Unity 4.x (Free or Pro).
http://unity3d.com/unity/download

Start up Unity and create a New Project. Don't worry about importing things yet!

Step 1: This is UNITY!

Picture of This is UNITY!
Learn about the different Unity Windows are here:
http://unity3d.com/unity/workflow/integrated-editor

Let's set our layout to the Default layout.
Go to the Menu Bar and click on Window > Layouts > Default

  1. Menu Bar
  2. Object Manipulation Tools (Gizmo): Use this to pan the view and move, rotate, and resize objects.
  3. Pivot Setting: This changes the location of the Gizmo to either be at the object's pivot point or the object's center.
  4. Coordinate Settings: Use this to change whether to move an object in the global coordinate system or its local coordinate system (based on the object's rotation).
  5. In-Editor Game Manipulation Tools: Use these to start/stop, pause, and step the game.
  6. Layers: Change what layers are visible in your scene in case you want to work only on one set of objects.
  7. Layout Menu: Change your current window layout.
  8. Hierarchy Window: Game objects in here are part of the current scene. Manipulate them here.
  9. Scene / Game / Animator viewer:  This is where you view your game. Navigate this by using right click with WASD or the mouse to pan/zoom/tilt.
  10. Gizmo: This is a Gizmo. Use this to move, rotate, and resize objects based on the selected tool.
  11. Inspector Window: This is where you change settings for a selected object.
  12. Project Window: This is where all the assets for the project are stored.
  13. Console Window: Errors, warnings, and print messages will all appear here. Use this to debug.
  14. Message Bar: Whenever you have an error, warning, or message, it will show up down here. Go to the console to fix all your bugs.

Step 2: Importing Packages

Picture of Importing Packages
We're going to start by importing some of Unity's Standard Assets.

In the Menu Bar, look under the Assets tab to Import some packages.

Assets > Import Package > Terrain Assets
Assets > Import Package > Character Controller

Step 3: Terrain

Picture of Terrain

Let's add some mountains!


In the Menu Bar go to GameObject  > Create Other > Terrain

Select the terrain object by clicking on it in the Scene or in the object list in the Hierarchy window.

Click the Raise/Lower Terrain button in the inspector panel.


Left click and drag anywhere on the terrain in the Scene to raise the elevation.
Hold down shift to lower.
Experiment with different brush shapes and sizes.

untextured terrain


Adding Textures


Now select the Paint texture tool in the Inspector.
Click the Edit Textures button under the Textures heading and select Add Texture.

Paint Texture Tool


In the window that appears click select Select in the box labelled Texture.
Double click Grass (Hill) in the window that appears.
Click Add at the bottom of the Add Terrain texture Window.

Add Terrain Texture Dialog

Add a few more textures using the same method.

Texture Painting


With the terrain and Paint Texture tool still selected select a texture other than grass.
Now, just as with the height modification, click and drag in the viewport to change the texture of the terrain.

textured terrain


Move your Main Camera


Find your camera by double clicking the Main Camera object in the list of objects on the left side of the screen under Hierarchy.

Enable the movement tool by clicking on the 4-directional arrow in the upper left.

Movement Tool

You can move objects by dragging the arrows of the tool.
Move your Main Camera object so that the Camera Preview shows something interesting.

Step 4: Lights

Picture of Lights

Game Object > Create Other > Directional Light

Try changing the Intensity of the light or play around with the direction and location.

Light Property WindowRotating the Light

Let's see what the player is looking at!

Now you can see things!

Step 5: Player

Picture of Player
Locate the First Person Player Controller asset in the Project window.
Assets > Standard Assets > Character Controllers > First Person Controller

Project Tab Showing First Person Player Controller Selected

Add a player to the scene by dragging and dropping it into the Hierarchy window. 

Rename it to Player by changing the name in the Inspector Window.
Note: if you do not press enter/return after renaming it, the name will not change.
 
Try positioning the Player on top of the terrain.

Make sure the Player isn't intersecting terrain, otherwise you'll fall through.

Delete Main Camera by right clicking on it's name in the Hierarchy and pressing Delete.

Press play. You should be able to walk around now :)

Step 6: Scene Objects

Picture of Scene Objects

Let's get a nice building for free!


https://www.assetstore.unity3d.com/#/content/6298

Package Import Dialog


Open in Unity. Download! Create account or log in as needed.
Import all the assets.

Assets > Import Package > Skyboxes
Check only the files relating to DawnDusk

Skybox Import

Edit > Render Settings > Skybox Material

RenderSettings Dialof Skybox

Drag and drop the  prefabs of the models into your scene.

Step 7: Lock/Hide Cursor

Picture of Lock/Hide Cursor
Create Scripts Folder

Make a new Javascript Script called "Menu."

We'll start by adding the most basic Menu element for a first person shooter: locking and hiding the mouse when in game.
// True if the menu is open and mouse is unlocked
var MenuOpen : boolean = false;

function Start () {
    UpdateCursorLock();
}

function Update() {
    // Check whether the menu button was released
    if (Input.GetButtonUp("MenuOpen")) {
        MenuOpen = !MenuOpen;
        UpdateCursorLock();
    }
}

// Called each time the Gui needs to be drawn
function OnGUI () {
    if (!MenuOpen) {
        // Draw the crosshair
        
        
// Center the text inside the label
        var centeredStyle = GUI.skin.GetStyle("Label");
        centeredStyle.alignment = TextAnchor.MiddleCenter;
        // Draw the label at the center of the screen
        GUI.Label (Rect (Screen.width/2-50, Screen.height/2-25, 100, 50), "+", centeredStyle);
    }
}

function UpdateCursorLock() {
    Screen.lockCursor = !MenuOpen;
    Screen.showCursor = MenuOpen;
}

To get the Menu on the scene, let's create an Empty Game Object (GameObject > Create Empty).

Let's call this "Menu."

Drag the script on to the Menu object.

We'll add more functionality to this later.

Let's add a Menu Open / Close button


Edit > Project Settings > Input.
Open the "Axes."
Under the Size in the Input Manager, edit the size to be 21.
Rename one of the new Inputs to be called "Menu Open" and inside it, set the "Positive Button" to be "escape"

Step 8: Guns and Bullets

Picture of Guns and Bullets

Gun


Let's try out this gun:
https://www.assetstore.unity3d.com/#/content/10332

Drag in DartGun Prefab from Compressed Gas Pistol > Prefab > DartGun to the scene.

A prefab is like a Class but in 'object' form. It's the copy with good defaults that you can use for all your different levels.

Put DartGun in Player > Main Camera

Player Hierarchy

Position/Rotate DartGun (Player > Main Camera > DartGun) according to the values below:

Gun Prefab Properties

Position/Rotate inner DartGun (Player > Main Camera > DartGun > DartGun) according to the values below:

Gun Model Properties


Let's create and shoot some bullets!


Create Sphere by going to GameObject > Create Other > Sphere

Rename the object to Bullet

Add a new RigidBody to the Bullet object.
Click Add Component > Physics > RigidBody

Uncheck Use Gravity
Set Collision Detection to Continuous

Set the scale of the sphere's transform to 0.2, 0.2, 0.2

Bullet Transform

Let's create a new javascript Script called "Bullet."
// The speed the bullet moves
var Speed : float = .4;

// The number of seconds before the bullet is automatically destroyed
var SecondsUntilDestroy : float = 10;

private var startTime : float;

function Start () {
    startTime = Time.time;
}

function FixedUpdate () {
    // Move forward
    this.gameObject.transform.position += Speed * this.gameObject.transform.forward;
    
    
// If the Bullet has existed as long as SecondsUntilDestroy, destroy it
    if (Time.time - startTime >= SecondsUntilDestroy) {
        Destroy(this.gameObject);
    }
}
    
function OnCollisionEnter(collision : Collision) {
    
    
// Remove the Bullet from the world
    Destroy(this.gameObject);
}



Drag and drop the Bullet script from the Project Window (Assets > Scripts) to the Bullet Object in the Hierarchy Window.
Finally, let's make the Bullet into a prefab and delete it from the scene.
Create a prefab of the bullet by dragging the Bullet object into the Project window to the Assets > Prefabs in the Hierarchy Window.

Let's create a new javascript Script called "Gun." 
// This is the bullet prefab the will be instantiated when the player clicks
// It must be set to an object in the editor

var Bullet : GameObject;

// Fire a bullet
function Fire () {
    // Create a new bullet pointing in the same direction as the gun
    var newBullet : GameObject = Instantiate(Bullet, transform.position, transform.rotation);
}

function Update () {
    // Fire if the left mouse button is clicked
    if (Input.GetButtonDown("Fire1")) {
        Fire();
    }
}


Drag and drop the Gun script from the Project Window (Assets > Scripts) to the Gun Object in the Hierarchy Window.

Drag and drop the Bullet Prefab into the Gun script where it says "None (Game Object)."

Remember to always apply changes to the prefab by going to the scene object > inspector window > prefab > apply.

Let's make sure the Player doesn't get shot!


Layers > Edit Layers

Layers Drop Down


Create Bullet Layer
Create Player Layer

Layer Editor

Select the Bullet object and set its layer to Bullet.

Bullet Layer

Select the Player and set to Player layer.
Say yes to changing the children.

Edit > Project Settings > Physics

Uncheck Bullet/Player and Bullet/Bullet

Physics Layers


Step 9: AI

Picture of AI
You will need to download the following Zombie:
http://www.mixamo.com/editor/new/86

Press yes to viewing the animation.
Click Download
Click Sign Up
Create Account
Click Download again
Click Checkout
Select FBX for Unity for Download Format
Click Download

Create Models Folder in the Projects window > Assets

Drag and Drop the Zombie into the Models Folder

If a warning window pops up when importing the model click Fix Now.

GameObject > Create Empty
Rename the GameObject to Zombie
Drag the Zombie model onto the Zombie Object

Zombie Model in Zombie Object

Put a Character Controller on the Zombie Object
In the inspector set the Center Y  to 1
Add a Capsule Collider component
Add Component > Physics > Capsule Collider
** Make sure to copy the exact values over.

Capsule ColliderCharacter Controller Settings


Create a new script named Zombie in your scripts folder.
var VisionDistance : float = 200;
var MovementSpeed : float = 2;
var Health : int = 2;

function FixedUpdate () {
    // Get the Player object
    var player : GameObject = GameObject.Find("Player");
    var characterController : CharacterController = GetComponent(CharacterController);
    
    
// Get the position of the Zombie's eyes
    var eyePosition : Vector3 = transform.position;
    eyePosition.y += characterController.height;
    
    
// Get the difference between the player and the Zombie positions
    // This creates a direction vector pointing in the direction of the Player.
    var lookDirection = player.transform.position - eyePosition;
    lookDirection = lookDirection.normalized;
    
    
// Only look for the player or objects that are part of the scenery (terrain, buildings, etc.)
    var layerMask : int = 1 << LayerMask.NameToLayer("Player") | 1 << LayerMask.NameToLayer("Default");
    
    
// The direction the Zombie will move, defaults to standing still
    var movementDirection : Vector3 = Vector3.zero;
    
    
// hitInfo will contain information about what the Zombie can see.
    var hitInfo : RaycastHit;
    if (Physics.Raycast(eyePosition, lookDirection, hitInfo, VisionDistance, layerMask)) {
        // If the Zombie can see the Player move toward them.
        if (hitInfo.collider.gameObject == player) {
            movementDirection = lookDirection;
            movementDirection.y = 0;
            movementDirection = movementDirection.normalized;
        }
    }
    
    
// Face and move in the chosen direction
    if (movementDirection != Vector3.zero) {
        transform.rotation = Quaternion.LookRotation(movementDirection, Vector3.up);
    }
    characterController.SimpleMove(movementDirection * MovementSpeed);
}
Put script on the Zombie.

Create Zombie Layer (Layers > Edit Layers)

Put Zombie into Zombie Layer so that the Zombie can 'see through' other zombies.

Drag and drop the Zombie into the Assets > Prefabs folder to create a prefab of it.

Step 10: Animation

Picture of Animation
Locate the Zombie@walking_3 asset in the Models folder.
The same way you made a script, this time, make an Animator Controller

Project Window > Right Click > Create > Animator Controller

Name it Zombie Animator.Now double click on the Zombie Animator.

Now in the Project Window, locate the Zombie@walking_3 asset again.

Open up the asset by clicking the arrow next to it.

Zombie Animator

Now drag and drop the walking_3 animation into the Animator Window.

Connect the Any State to the walking_3 state by right clicking on Any State > Make Transition and then click on walking_3.

First, let's make sure that the walking 3 loops correctly by editing the Transition arrow (click on the Transition arrow).

transition

Make sure the walking animation doesn't over lap and the arrows on the timeline are next to each other.

Next, let's make sure the animation isn't super duper slow by editing the walking_3 animation inside the Animator window.
Set the speed to around 3.4.
 

Now in your scene, go to the Zombie and drag the animator controller on to the animator object.
Uncheck Apply Root Motion and set the culling mode to Always Animate.

Finally, go to Prefab > Apply and apply the settings to the prefab. Make sure that the Zombie prefab now also has an animator controller!

Test it out in the scene!

Step 11: Spawning Zombies

Picture of Spawning Zombies
Let's make a Spawner!

Create a new empty GameObject.
Name the object Spawner.
Create a new script named Spawner and add the following code to it:
// The object to be spawned
var SpawnObject : GameObject;

// in seconds
var SpawnStartDelay : float = 0;
var SpawnRate: float = 5.0;

function Start()
{
    InvokeRepeating("Spawn", SpawnStartDelay, SpawnRate);
}

// Spawn the SpawnObject
function Spawn()
{
    Instantiate(SpawnObject, transform.position, transform.rotation);
}


Add the script to the Spawner.
With the Spawner selected drag and drop the Zombie prefab into the Spawn Object property of the Spawner script.

Spawner Porperties

You may notice that this script is very similar to the Gun script.

Make this into a prefab.

Place some in your map!

Step 12: Stats and End Condition

Picture of Stats and End Condition
Let's give the player some health, the zombies some health and attack power, and the gun some attack power.

Add a new script called Player in the scripts folder.
The following code will allow the Player to be damaged, and restart the game when the player is killed.
// The number of times the Player can be damaged before the game restarts
var Health : int = 10;

// Minimum number of seconds between the player getting hurt
var DamageInvulnerabilityDelay : float = 2;

// Keeps track of the last time the Player was damaged
private var invulnerabilityStartTime : float;

function Start () {
    // Set initial value so the Player is temporarily invulnerable at spawn
    invulnerabilityStartTime = Time.time;
}

// Attempt to damage the player by the specified number of hit points
function Hurt(damage : int) {
    // If we have waited at least as long as DamageInvulnerabilityDelay
    if (Time.time - invulnerabilityStartTime >= DamageInvulnerabilityDelay) {
        // Damage the Player
        Health -= damage;
        
        
// Reset the invulnerability timer
        invulnerabilityStartTime = Time.time;
    }
    
    
// If the Player has no health left
    if (Health <= 0) {
        // Reload the level
        Application.LoadLevel(Application.loadedLevelName);
    }
}


If the zombie collides with the player, hurt the player.

Add the following function to the Zombie script.
// When the Zombie collides with something
function OnTriggerStay(other : Collider) {
    // Get the Player that the Zombie collided with, if any
    var player = other.gameObject.GetComponent(Player);
    
    
// If it collided with something other than a Player player will be null
    if (player != null) {
        // Subtract one from the Player's health
        player.Hurt(1);
    }
}


If the bullet hits a zombie, hurt the zombie.
Replace the OnCollisionEnter function in the Bullet script with the following

function OnCollisionEnter(collision : Collision) {
    // Get the Zombie that the Bullet collided with, if any
    var zombie = collision.transform.gameObject.GetComponent(Zombie);
    
    
// If it collided with something other than a Zombie zombie will be null
    if (zombie != null) {
        // Subtract one from the Zombie's health
        zombie.Health--;
        
        
// If the zombie is out of health remove them from the game
        if (zombie.Health <= 0) {
            Destroy(collision.transform.gameObject);
        }
    }
    
    
// Remove the Bullet from the world
    Destroy(this.gameObject);
}









Step 13: HUD and Menu system

Picture of HUD and Menu system
Now let's improve our Menu script!

Let's add Resume, Restart, and Quit buttons as well as something telling us how much health is left.

Add both of these functions to the Menu script:
function DrawHUD() {
    
    
// Get the health from the player
    var player = GameObject.Find("Player");
    var health = player.GetComponent(Player).Health;

    // Position
    var left = 10;
    var top = 10;
    var width = 100;
    var height = 25;
    
    
// Make a background box
    GUI.Box (Rect (left, top, width, height), "Health: " + health);
    
    
DrawCrosshair();
}

// Draw the menu
function DrawMenu() {
    var centerX = Screen.width/2;
    var centerY = Screen.height/2;
    
    
// location of the menu
    var menuLeft = centerX - 50;
    var menuTop = centerY - 50;
    var menuWidth = 100;
    var menuHeight = 100;
    
    
var buttonX = menuLeft + 10;
    var buttonWidth = 80;
    var buttonHeight = 20;
    var buttonDist = 25; // distance between each button
    
    
// Make a background box
    GUI.Box (Rect (menuLeft, menuTop,menuWidth,menuHeight), "Menu");
    
    
// Start / Resume
    if (GUI.Button (Rect (buttonX,menuTop + 1 * buttonDist,buttonWidth,buttonHeight), "Resume")) {
        MenuOpen = false;
        UpdateCursorLock();
    }
    
    
// Restart
    if (GUI.Button (Rect (buttonX,menuTop + 2 * buttonDist,buttonWidth,buttonHeight), "Restart")) {
        Application.LoadLevel(Application.loadedLevel);
    }
    
    
// Quit (Only works in the Build. Does not work in the eidtor!)
    if (GUI.Button (Rect (buttonX,menuTop + 3 * buttonDist,buttonWidth,buttonHeight), "Quit")) {
        Application.Quit();
    }
}


Now replace the OnGUI function with:

// Called each time the Gui needs to be drawn
function OnGUI () {
    if (!MenuOpen) {
        DrawHUD();
    } else {
        DrawMenu();
    }
    DrawCrosshair();
}


Enjoy visual feedback!

Step 14: Play Around and Have Fun

Picture of Play Around and Have Fun
Make some more interesting Terrain.

Make some arms and fingers for the gun. Rotate them backwards on shoot to emulate recoil!

You could try, for instance, making the Zombie run to the player and then do gangnam style by downloading some animations:
http://www.mixamo.com/motions?page=1&order=relevance&free=1&limit=48
转自:http://www.instructables.com/id/Intro-to-Unity/
2018-03-23 20:07:47 MadBam_boo 阅读数 633
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4646 人正在学习 去看看 张刚

Unity3d实战之Unity3d网络游戏实战篇(13):登录&注册面板

学习书籍《Unity3d网络游戏实战》 罗培羽著 机械工业出版社
本文是作者在学习过程中遇到的认为值得记录的点,因此引用的代码等资源基本出资罗培羽老师的书籍,如有侵权请联系,必删。

 建立好网络模块后,我们可以开始对UI进行编程,实现可视化的登录注册面板。在第二节-代码资源分离的界面系统中,实现了Panel基类,之后的所有面板都会基于该基类并根据需求进行实现。本节给出登录、注册的实例。

 1、登录面板
 根据自己的喜好构建一个登录界面,这里给出一个测试样例:
 这里写图片描述
 注意,其中的Panel和Tips是Canvas下的空物体,用于对各种Panel进行分组,他们拥有的是Rect Transform组件而不是Transform组件。
 LoginPanel本身是Panel类型,以Text为后缀的是Text类型,以Input为后缀的是IntputField类型,以Btn为后缀的是Button类型。记得将LoginPanel拖拽到Resources文件夹中,因为PanelMgr的OpenPanel方法将从Resources文件夹中寻到对应的Panel并实例化。

 根据LoginPanel所示,我们在登录时需要输入用户名、密码、点击登录或者注册。这四个物体使我们所关注的。
 创建C# Script,命名为LoginPanel,声明四个变量:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;   // don't forget it.

public class LoginPanel : PanelBase {
    /*
     * Add a logout listener.
     */
    private InputField idInput;  // InputField of user name 
    private InputField pwInput;  // InputField of password
    private Button loginBtn;     // Button of login
    private Button regBtn;       // Button of register
}

 然后,按照需求重载父类PanelBase的Init()方法和OnShowing()方法:

#region Operation-Cycle
public override void Init (params object[] args)
{
    base.Init (args);
    skinPath = "LoginPanel";
    layer = PanelMgr.PanelLayer.Panel;
}

public override void OnShowing ()
{
    base.OnShowing ();
    Transform skinTrans = skin.transform;
    idInput = skinTrans.Find ("idInput").GetComponent<InputField> ();
    pwInput = skinTrans.Find ("pwInput").GetComponent<InputField> ();
    loginBtn = skinTrans.Find ("loginBtn").GetComponent<Button> ();
    regBtn = skinTrans.Find ("regBtn").GetComponent<Button> ();

    loginBtn.onClick.AddListener (OnLoginButtonClick);
    regBtn.onClick.AddListener (OnRegisterButtonClick);
}
#endregion

 在Init()方法中,将skinPath设置为LoginPanel,这样调用PanelMgr.OpenPanel方法才能在Resource文件夹中找到对应的Panel。
 在OnShowing()方法中,首先,获取到LoginPanel的实例的Transform组件,然后使用Transform.Find(string name).GetComponent<>()来获取需要用到的组件。并给Button添加点击事件。

 当用户点击Login按钮时,Client需要检测用户输入的用户名和密码是否为空,如果为空则输出对应的提示信息(Tips组的Panel,实现方法与LoginPanel的方法相似,读者可尝试自行实现);否则,将用户名和密码打包成消息发送给服务端,并等待服务端的处理结果,根据处理结果决定用户是进入游戏大厅还是输出提示信息。
 当用户点击Register按钮时,跳转到RegisterPanel,关闭LoginPanel。

#region OnButtonClickEvent
void OnLoginButtonClick()
{
    if (idInput.text == "" || pwInput.text == "") {
        //Debug.Log ("[LoginPanel.OnLoginButtonClick] Id and pw can't stay empty.");
        PanelMgr.instance.OpenPanel<TipPanel>("","Id and pw can't stay empty.");
        return;
    }

    if (NetMgr.servConn.status != Connection.Status.Connected) {
        NetMgr.servConn.proto = new ProtocolBytes ();
        if (!NetMgr.servConn.Connect ("127.0.0.1", 1234)) {
            PanelMgr.instance.OpenPanel<TipPanel> ("", "Connect server fail.");
        }
    }

    ProtocolBytes protocol = new ProtocolBytes ();
    protocol.AddString ("Login");
    protocol.AddString (idInput.text);
    protocol.AddString (pwInput.text);
    Debug.Log ("[LoginPanel.OnLoginButtonClick] Send protocol: Login " + idInput.text + "[id] " + pwInput.text + "[pw]");
    NetMgr.servConn.Send (protocol, OnLoginBack);
}

void OnRegisterButtonClick()
{
    PanelMgr.instance.OpenPanel<RegisterPanel> ("");
    Close ();
}
#endregion

 在Register的点击事件中,我们先对用户输入进行判空处理,然后对用户的网络连接进行检测,之后再打包用户输入的用户名和密码,发送给服务端并等待处理结果。在事件结尾我们使用了NetMgr.servConn.Send (protocol, OnLoginBack);,(详情传送门走起)当接收到服务端返回的处理结果后,Client将调用OnLoginBack方法,根据结果执行不同的逻辑。

#region OnBackEvent
void OnLoginBack(ProtocolBase protoBase)
{
    ProtocolBytes protocolRec = (ProtocolBytes)protoBase;
    int start = 0;
    string protoName = protocolRec.GetString (start, ref start);
    int result = protocolRec.GetInt (start, ref start);
    if (result == 0) {
        //Debug.Log ("[LoginPanel.OnLoginBack] Login success. ");
        PanelMgr.instance.OpenPanel<TipPanel>("","Login success. ");
        PanelMgr.instance.OpenPanel<LobbyPanel> ("");
        Close ();
    }else{
        //Debug.Log ("[LoginPanel.OnLoginBack] Login fail. ");
        PanelMgr.instance.OpenPanel<TipPanel>("","Login fail. Please check your username and password.");
    }
}
#endregion

 如果用户密码正确,进入大厅,否则弹出错误提示。

 2、注册面板
 测试样例:
 这里写图片描述
 需要用到的UI跟LoginPanel相差不大,只是多了一个确认密码的UI而已。其他部分改改Text、改改位置即可。
 在RegisterPanel中,增加了一个Repaet UI,用于用户密码的二次确认。其他部分跟LoginPanel类似,因此,RegisterPanel脚本跟LoginPanel脚本不同的地方就在于对用户的输入的密码增加一个二次确认的判断,其余部分相差不大,读者可自行体会:
 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class RegisterPanel : PanelBase {

    private InputField idInput;
    private InputField pwInput;
    private InputField rpInput;
    private Button regBtn;
    private Button closeBtn;

    #region Operation-Cycle
    public override void Init (params object[] args)
    {
        base.Init (args);
        skinPath = "RegisterPanel";
        layer = PanelMgr.PanelLayer.Panel;
    }

    public override void OnShowing ()
    {
        base.OnShowing ();
        Transform skinTrans = skin.transform;
        idInput = skinTrans.Find ("idInput").GetComponent<InputField> ();
        pwInput = skinTrans.Find ("pwInput").GetComponent<InputField> ();
        rpwInput = skinTrans.Find ("rpInput").GetComponent<InputField> ();
        regBtn = skinTrans.Find ("regBtn").GetComponent<Button> ();
        closeBtn = skinTrans.Find ("closeBtn").GetComponent<Button> ();

        regBtn.onClick.AddListener (OnRegisterButtonClick);
        closeBtn.onClick.AddListener (OnCloseButtonClick);
    }
    #endregion

    #region OnButtonClickEvent
    void OnRegisterButtonClick()
    {
        // check empty input.
        if (idInput.text == "" || pwInput.text == "" || rpInput.text == "") {
            //Debug.Log ("[RegisterPanel.OnRegisterButtonClick] Id and pw and check pw can't stay empty.");
            PanelMgr.instance.OpenPanel<TipPanel>("","Id and pw and check pw can't stay empty.");
            return;
        }

        // check if the password correct.
        if (pwInput.text != rpInput.text) {
            //Debug.Log ("[RegisterPanel.OnRegisterButtonClick] Two password are different.");
            PanelMgr.instance.OpenPanel<TipPanel>("","Two password are different.");
            return;
        }

        // check the connection status
        if (NetMgr.servConn.status != Connection.Status.Connected) {
            NetMgr.servConn.clientProtocol= new ProtocolBytes ();
            if (!NetMgr.servConn.Connect ("127.0.0.1", 1234)) {
                PanelMgr.instance.OpenPanel<TipPanel> ("", "Connect server fail.");
            }
        }

        // send message
        ProtocolBytes protocol = new ProtocolBytes ();
        protocol.AddString ("Register");
        protocol.AddString (idInput.text);
        protocol.AddString (pwInput.text);
        Debug.Log ("[LoginPanel.OnRegisterButtonClick] Send protocol: Register " + idInput.text + "[id] " + pwInput.text + "[pw]");
        NetMgr.servConn.Send (protocol, OnRegisterBack);     // wait for result.
    }

    void OnCloseButtonClick()
    {
        PanelMgr.instance.OpenPanel<LoginPanel> ("");
        Close ();
    }
    #endregion

    #region OnBackEvent
    void OnRegisterBack(ProtocolBase protoBase)
    {
        ProtocolBytes protocol = (ProtocolBytes)protoBase;
        int start = 0;
        string protoName = protocol.GetString (start, ref start);
        int result = protocol.GetInt (start, ref start);
        //  if ok, open login panel, else print out tips panel.
        if (result == 0) {
            //Debug.Log ("[RegisterPanel.OnRegisterBack] Register success.");
            PanelMgr.instance.OpenPanel<TipPanel>("","Register success.");
            PanelMgr.instance.OpenPanel<LoginPanel> ("");
            Close ();
        } else {
            //Debug.Log ("[RegisterPanel.OnRegisterBack] Register fail.");
            PanelMgr.instance.OpenPanel<TipPanel>("","Register fail. Please use another id.");
        }
    }
    #endregion
}

 本节只举了LoginPanel和RegisterPanel两个例子,其他的面板实现方式都是类似的,如果有认真读懂这两个脚本的话,自己设计其他面板是没有太大的问题的。如果想要UI好看点,可以研究一下Unity3d的Aniimation。
 官方教程传送门-Unity3d Animation Tutorial

如果想要在打开面板前后加入动画或者其他逻辑,可以重载OnShowing和OnShowed方法;
如果想要在关闭面板前后加入动画或者其他逻辑,可以重载OnClosing和OnClosed方法。

 以上。

没有更多推荐了,返回首页