Unity3D之局域网CS对战(第六天笔记)

今天终于把全部的视频看完了,里面的代码也有基本理解了,也都全部敲了一遍,今天主要是游戏的结束逻辑我结束的界面设计.对我来说这个是挺简单的.

另外今天也把昨天的问题给解决了,昨天主要是人物的动画无法同步到其他客户端.最后发现是NetworkView这个组件只能同步单个组件或属性,

如果要同步多个属性只能再添加一个NetworkView组件然后把需要同步的属性赋值到Observed属性中,比如说你需要同步角色的位置信息那么你需要添加一个NetworkView然后再把角色的位置属性赋值到Observed属性,但是这个只能看到的是人物在移动并看不到动画在播放,因为人物的动画并没有同步到其他客户端,你需要再添加一个NetworkView组件然后把动画属性赋值到Observed.

但是如果属性多了的话这中方法就不适用了,那么还可以适用RPC进行同步如:

networkView.RPC(“PlayState”, RPCMode.All, “soldierFalling”);

把需要执行的动画都放到RPC上进行远程过程的调用.这样就可以把播放的动画同步到其他客户端了.

如果使用networkView组件那么直接执行: 如 animation.Play(animName);就可以了

 

今天调试了好久才发现这个问题.

 

 

Unity3D之局域网CS对战(第五天笔记)

今天主要学习了角色在局域网中的控制,怎样把角色同步到其他客户端然后各自控制自己的角色互不影响.使用RPC调用角色控制.

需要注意的是:

1. // go.GetComponent<Player>().SetOwnerPlayer(Network.player);//这个代码只设置了当前创建者中的战士的ownerPlayer属性在其他客户端这个属性是空的;

2. go.networkView.RPC(“SetOwnerPlayer”, RPCMode.AllBuffered, Network.player);//远程调用;使用这个远程调用

在 SetOwnerPlayer方法上面必须声明是[RPC];否则会出错.如下:

[RPC]//使用注解表示这个方法是一个远程调用;
public void SetOwnerPlayer(NetworkPlayer player)
{
this.ownerPlayer = player;
if (Network.player!=this.ownerPlayer)
{
LoseControl();

Debug.Log(“失去控制”);
}
}

3.需要同步的数据都需要使用RPC远程调用实现.

4.在需要获取同步角色中自身组件的函数中一定要把函数放在RPC远程调用函数中执行才有用这样执行的才是调用自身的那个.

如:需要在每个角色中获取

motor=this.GetComponent<CharacterMotor>();

则需要把motor=this.GetComponent<CharacterMotor>();放在 SetOwnerPlayer函数里面调用才行.

 

今天最终的效果还是没有调试出来,不知道是我的原因还是版本的原因,反正客户端和服务器端的动画还无法同步出来死亡伤害也无法实现,

只能明天再调试一下了.

Unity3D之局域网CS对战(第四天笔记)

今天又看了几集视频然后对着做了一遍,今天算是写的第二次笔记了,因为昨天没写所以只能一天写2篇了.

今天主要是场景的加载然后是对游戏角色的实例化局域网服务器和客户端的创建,还有游戏开始UI的设计.

需要注意的是以下几点.

1.在网络中需要用 Network.Instantiate(soldierPrefab, pos1.position, Quaternion.identity, group);实例化角色或物体.

2.创建UI的Alpha值可直接鼠标右键单击然后现在Tween进行添加然后对透明度进行调节.

3. OnConnectedToServer() 当客户端连接服务器成功的时候执行它.

4. Network.player//获取本地NetworkPlayer实例。  int group = int.Parse(player + “”);可以转换成组号.

5.GUITexture的图片需要再物体下添加相机组件然后在Game视图下才能看见.(编辑模式的时候),之前也因为这个调试了好久才发现没有在Game视图下看在Sence视图下是看不到的所以无法编辑.一直以为没有创建成功.

 

Unity3D之局域网CS对战(第三天笔记)

本来这篇笔记是应该在昨天写的但是因为昨天调试程序调试了很久没有成功,太晚了就没在写笔记了,改到现在进行补回.

昨天主要学习的是:

1.子弹射击的闪光效果(也就是枪火的效果),主要在Uuity3D中创建一个Quad然后给这个Quad指定一张贴图,把贴图背景设置为透明.

2.子弹射击的弹痕效果,方法和创建闪光效果类似但是另外需要添加法线贴图,需要2张图片.

3.子弹朝向问题,子弹的朝向是人物视野的中央而不是枪口的前方,然后再视野中央添加一个准星.

 

需要注意的问题:

1.之前一直调试都未成功后来才发现是在子弹的自带的碰撞器没有删除,本来在子弹中就已经用了射线碰撞器然后本身又有一个碰撞器 就导致物体一直处于碰撞状态.

2.然后就是给脚本的公共变量赋值时应该赋的是frefab而不是已经存在的物体,不然当物体消失是 变量的值也消失了.

3.Physics.Raycast(oriPos, direction, out hitinfo, length);此函数检测物体投射射线的碰撞,其中hitinfo是获取碰撞的信息.

//hitinfo.normal;//可以得到碰撞点的垂线向量 也就是碰撞面的法线.

//hitinfo.point是碰撞点.

Unity3D之局域网CS对战(第二天笔记)

今天学习了第一人称视野的控制和添加动画,原来实际上的动画就是控制骨骼的运动.所以当你挂载物体时如果要在动画中体现出来那么你就要挂载到相应的骨骼位置下,这样动画动起来你挂载的物体才能跟着动.比如说摄像机想要跟随头部的运动那么你就要挂载到相应的头部骨骼下才行.

学习中有以下几个重点:

1.

animation.Play(animName);//立即停止当前动画播放animName动画;
animation.CrossFade(animName, 0.2f);//有0.2秒的缓冲时间然后渐变为animName动画;

2.

LateUpdate是在所有Update函数调用后被调用。这可用于调整脚本执行顺序。例如:当物体在Update里移动时,跟随物体的相机可以在LateUpdate里实现。

之前看视频的时候发现视频里面siki老师讲的他是可以在当mouseLook脚本里面控制骨骼的旋转的,我自己放到我的项目里面发现确不行后面一节视频才讲到原来就是LateUpadate和Update先后调用问题,因为模型的动画是在每一帧都会调用的就相当于Update而对骨骼的旋转如果再放在Update里面就得不到相应的改变,只能放在LateUpate里面当动画执行后再去执行鼠标对模型骨骼的旋转.

3.

float h=Input.GetAxis(“Horizontal”);//获取键盘的左右方向输入;
float v=Input.GetAxis(“Vertical”);//获取键盘的上下方向输入;

 

 

Unity3D之局域网CS对战(第一天笔记)

今天准备开始学习一下Unity3D网络游戏的开发了,刚好在泰克在线上看到了这个CS的局域网对战项目,正好符合我的口味,准备一天看个一章应该没问题关键是总共才3章估计3天也就看完了也跟着做完了哈哈.

今天主要了解了以下几点:

1.Unity3D的网络组件—-network,它实际上是一个类

Network类是网络实现的核心并提供核心函数。

2.利用 Network.InitializeServer进行初始化一个服务器,它需要3个参数,最大连接数,端口号,是否NAT地址转换.

3.给需要同步的物体加上 network view组件,此组件用来在局域网之内去同步一个游戏物体的组件,但是它会把创建他的作为它的主人,同步到其他客户端,它自己本身不会被其他客户端同步.

4.客户端连接使用Network.Connect(ip, listenPort);其中IP则是IP地址,而listenPort则是服务器端创建的端口号.

5.第一称里面的Mouse Look.cs脚本是鼠标控制角色的视角的脚本,而其他的脚本是控制角色的移动的.

6.Input.GetAxis(“Mouse X”)可以获取鼠标或键盘的输入然后对角色进行控制,

如.Input.GetAxis(“Mouse X”)就是获取鼠标左右方向的移动,而 Input.GetAxis(“Horizontal”);是获取键盘左右方向的移动.

c#标准的事件定义与使用

上一篇博文中我写了一篇关于我对事件的理解和使用而那个是为了更好理解事件和认识他,但是一般的使用和.NET库中的事件使用的是标准的事件定义.

标准的 事件定义如下:

public delegate void Mydelegate(object sender,MyEventArgs e);

public event Mydelegate myevent;

委托类型的第一个参数表示的是当前事件发出者的实例对象.

其中第二个参数的类型MyEventArgs是一个继承自EventArgs的类;它主要是事件发出者用来向事件的订阅者传递数据用的.而EventArgs是.NET里面自带的类.

如下是我写的一个完整的 标准事件使用的例子:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication3
{

class PubEventArgs : EventArgs//事件数据类
{
private readonly string m_magazineName;
private readonly DateTime m_pubDate;
public PubEventArgs(string mangazineName,DateTime pubDate)
{
m_magazineName = mangazineName;
m_pubDate = pubDate;

}
public string magazineName
{
get { return m_magazineName; }

}
public DateTime pubDate
{
get
{
return m_pubDate;
}

}

}
class Publisher//出版社类;
{
public delegate void PubComputerEventHandler(object sender, PubEventArgs e);//定义出版电脑杂志委托类型;
public delegate void PubLifeEventHandler(object sender, PubEventArgs e);//定义出版生活杂志委托类型;
public event PubComputerEventHandler pubComputer;//出版电脑杂志事件;
public event PubLifeEventHandler pubLife;//出版生活杂志事件;

protected virtual void OnPubComputer(PubEventArgs e)//虚方法用来调用触发事件传递事件数据;
{
PubComputerEventHandler handler = pubComputer;
if (handler != null)
handler(this, e);

}
protected virtual void OnPubLife(PubEventArgs e)//虚方法用来调用触发事件传递事件数据;
{
PubLifeEventHandler handler = pubLife;
if (handler != null)
handler(this, e);

}
public void issueComputer(string name, DateTime date)//触发事件方法;
{
Console.WriteLine("发行" + name);
OnPubComputer(new PubEventArgs(name, date));
}
public void issueLife(string name, DateTime date)//触发事件方法;
{
Console.WriteLine("发行" + name);
OnPubLife(new PubEventArgs(name, date));
}

}
class Subscriber//订阅者类;
{

private string name;
public Subscriber(string objname)
{
this.name = objname;
}
public void Receiver(object sender,PubEventArgs e)//订阅者处理方法;
{
Console.WriteLine(this.name+"已订阅" + e.magazineName+" "+e.pubDate);
}

}

class Program
{
static void Main(string[] args)
{
Subscriber sub1 = new Subscriber("fgreen");//订阅者1;
Subscriber sub2 = new Subscriber("ty");//订阅者2;

Publisher pub = new Publisher();//出版社对象;
pub.pubComputer += new Publisher.PubComputerEventHandler(sub1.Receiver);//订阅者1 订阅电脑杂志;
pub.pubLife += new Publisher.PubLifeEventHandler(sub1.Receiver);//订阅者1 订阅生活杂志;

pub.pubLife += new Publisher.PubLifeEventHandler(sub2.Receiver);//订阅者2 订阅生活杂志
//订阅者2并没有订阅电脑杂志;

pub.issueComputer("电脑杂志", Convert.ToDateTime("2015-5-13"));//出版社发行电脑杂志;
pub.issueLife("生活杂志", Convert.ToDateTime("2015-5-13"));//出版社发行生活杂志;
Console.ReadLine();

}
}
}

我对c#事件的理解

在C#里面 事件就是类在发生它关注的事情时用来提供通知的一种方式,

所有的事件都依托于委托因为声明一个事件必须为其声明委托类型,它是由委托来进行激活的.

如声明一个事件

public delegate void Mydelegate();//声明事件委托类型 ;

public event Mydelegate Myevent;//声明事件;

 

一般在声明事件的类中要包含触发事件的方法,因为创建事件的类就相当于出版社,而它的一个事件就相当于它具体要出版哪一本书,

而触发事件就是出版社要在什么时候出版这本书.而此书的订阅者则是此事件的事件处理对象,具体的事件处理程序则需要订阅者自己定义;

 

如以下程序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication4
{
public delegate void Mydelegate();

class publish
{
public event Mydelegate myevent;
public void issue()//定义类调用触发事件的方法;
{

if(myevent!=null)
myevent();//触发事件;

}
}

class Order
{
private string productnName;
private int productID;
public Order(string name,int id)
{

this.productnName = name;
this.productID = id;
}
public void Product()
{
Console.WriteLine(“已下单 产品名称:{0},产品ID:{1}”, productnName, productID);

}

}
class Program
{
static void Main(string[] args)
{
publish pub = new publish();//供货商;
Order people1=new Order(“小米2s”,100);//消费者1需要小米2S;
Order people2 = new Order(“苹果5s”, 1000);//消费者2需要苹果5S;
pub.myevent += new Mydelegate(people1.Product);//people1订货;

pub.myevent += new Mydelegate(people2.Product);//people2订货;
pub.issue();//发货;
Console.ReadLine();
}

 

}
}

执行后如下显示.

 

 

上面的程序表达了一个供货商或厂商直接像消费者提供订货渠道,然后由订货者自己订货,只有供货商自己才能发货也就是说事件的定义者自己才能

触发事件,而事件处理程序由事件的订阅者定义.

 

 

 

 

c#里的委托

最近在学习c#但是里面的委托和事件只是一个比较难理解的知识点,我觉得委托就是类似c/c++里面的函数指针,声明一个委托就类似于声明一个委托类型.

而在c#中委托类型是静态的它并不属于某个类对象,他可以定义在类内可以可以定义在类外,在类内部定义时需要用类名进行引用.

定义 委托类型:

如  public delegat void  Mydelegate();这就相当于在c/c++定义了一个公有类型的 无返回值 无参数的 函数指针.

只是在c#中它可以作为一个类型 去定义一个变量,这个变量就是一个函数的引用也就是函数的指针,

如   用创建的委托类型去创建一个委托变量和给委托变量赋值 Mydelegate  test=new Mydelegate(函数名);

给委托变量赋值 实际上就是给这个变量赋一个或开辟一个函数的内存空间,而括号内的函数名就是你所定义的函数,此函数必须和你定义的

委托类型一样,如委托类型是 无返回值,无参数的那么你所定义的函数也必须和此类型相同才能正确初始化委托变量.

如需要使用它则直接像使用函数那样 使用这个委托.

当然你还可以 直接使用匿名方法给委托变量赋值这就相当于在定义数组的时候直接赋初值.

还可以给委托对象添加多个调用方法如;

 

 

Linux下的JDK安装

今天一口气把Linux下的JDK安装完成了,顺便把Linux下的eclipse也装上去了,小花了点时间,但是很值得.

就是环境变量的那里容易出错,查了一下网上的资料发现还是有很多种方法配置环境变量的

其中一种还是比较快的 就是直接在 /etc 文件夹下的profile文件后面直接加上

JAVA_HOME=”这里填上JDK安装目录”//一定要root权限打开profile文件才行,不然保存不了.
PATH=$JAVA_HOME/bin:$PATH
CLASSPATH=.:$JAVA_HOMEb/dt.jar:$JAVA_HOMEb/tools.jar
export JAVA_HOME
export PATH
export CLASSPATH

然后重启系统就行了,这样的权限很大 不管什么用户都可以用.

Linux下的eclipse安装还是很简单的直接下载安装就可以了 和WINDOWS下是差不多的.

刚好下次上实验课要用到这个顺便就试试LINUX下的JAVA编程看看效果,哈哈.