C# 多态相关的文章

一 C# 多态的实现

封装、继承、多态,面向对象的三大特性,前两项理解相对容易,但要理解多态,特别是深入的了解,对于初学者而言可能就会有一定困难了。我一直认为学习OO的最好方法就是结合实践,封装、继承在实际工作中的应用随处可见,但多态呢?也许未必,可能不经意间用到也不会把它跟“多态”这个词对应起来。在此抛砖引玉,大家讨论,个人能力有限,不足之处还请指正。
之前看到过类似的问题:如果面试时主考官要求你用一句话来描述多态,尽可能的精炼,你会怎么回答?当然答案有很多,每个人的理解和表达不尽相同,但我比较趋向这样描述:通过继承实现的不同对象调用相同的方法,表现出不同的行为,称之为多态。

例1:

代码 

public class Animal{public virtual void Eat(){Console.WriteLine("Animal eat");}}public class Cat : Animal{public override void Eat(){Console.WriteLine("Cat eat");}}public class Dog : Animal{public override void Eat(){Console.WriteLine("Dog eat");}}class Tester{static void Main(string[] args){Animal[] animals = new Animal[3];animals[0] = new Animal();animals[1] = new Cat();animals[2] = new Dog();for (int i = 0; i < 3; i++){animals[i].Eat();}}}

输出如下:

Animal eat...

Cat eat...

Dog eat...

在上面的例子中,通过继承,使得Animal对象数组中的不同的对象,在调用Eat()方法时,表现出了不同的行为。

多态的实现看起来很简单,要完全理解及灵活的运用c#的多态机制,也不是一件容易的事,有很多需要注意的地方。

1. new的用法

先看下面的例子。

例2

代码 

public class Animal{public virtual void Eat(){Console.WriteLine("Animal eat");}}public class Cat : Animal{public new void Eat(){Console.WriteLine("Cat eat");}}class Tester{static void Main(string[] args){Animal a = new Animal();a.Eat();Animal ac = new Cat();ac.Eat();Cat c = new Cat();c.Eat();}}

运行结果为:

Animal eat...

Animal eat...

Cat eat...

可以看出,当派生类Cat的Eat()方法使用new修饰时,Cat的对象转换为Animal对象后,调用的是Animal类中的Eat()方法。其实可以理解为,使用new关键字后,使得Cat中的Eat()方法和Animal中的Eat()方法成为毫不相关的两个方法,只是它们的名字碰巧相同而已。所以, Animal类中的Eat()方法不管用还是不用virtual修饰,也不管访问权限如何,或者是没有,都不会对Cat的Eat()方法产生什么影响(只是因为使用了new关键字,如果Cat类没用从Animal类继承Eat()方法,编译器会输出警告)。

我想这是设计者有意这么设计的,因为有时候我们就是要达到这种效果。严格的说,不能说通过使用new来实现多态,只能说在某些特定的时候碰巧实现了多态的效果。

2.override实现多态

真正的多态使用override来实现的。回过去看前面的例1,在基类Animal中将方法Eat()用virtual标记为虚拟方法,再在派生类Cat和Dog中用override对Eat()修饰,进行重写,很简单就实现了多态。需要注意的是,要对一个类中一个方法用override修饰,该类必须从父类中继承了一个对应的用virtual修饰的虚拟方法,否则编译器将报错。

好像讲得差不多了,还有一个问题,不知道你想没有。就是多层继承中又是怎样实现多态的。比如类A是基类,有一个虚拟方法method()(virtual修饰),类B继承自类A,并对method()进行重写(override修饰),现在类C又继承自类B,是不是可以继续对method()进行重写,并实现多态呢?看下面的例子。

例3:

代码 

public class Animal{public virtual void Eat(){Console.WriteLine("Animal eat");}}public class Dog : Animal{public override void Eat(){Console.WriteLine("Dog eat");}}public class WolfDog : Dog{public override void Eat(){Console.WriteLine("WolfDog eat");}}class Tester{static void Main(string[] args){Animal[] animals = new Animal[3];animals[0] = new Animal();animals[1] = new Dog();animals[2] = new WolfDog();for (int i = 0; i < 3; i++){animals[i].Eat();}}
}

 运行结果为:

Animal eat...

Dog eat...

WolfDog eat... 

在上面的例子中类Dog继承自类Animal,对方法Eat()进行了重写,类WolfDog又继承自Dog,再一次对Eat()方法进行了重写,并很好地实现了多态。不管继承了多少层,都可以在子类中对父类中已经重写的方法继续进行重写,即如果父类方法用override修饰,如果子类继承了该方法,也可以用override修饰,多层继承中的多态就是这样实现的。要想终止这种重写,只需重写方法时用sealed关键字进行修饰即可。

3. abstract-override实现多态

先在我们在来讨论一下用abstract修饰的抽象方法。抽象方法只是对方法进行了定义,而没有实现,如果一个类包含了抽象方法,那么该类也必须用abstract声明为抽象类,一个抽象类是不能被实例化的。对于类中的抽象方法,可以再其派生类中用override进行重写,如果不重写,其派生类也要被声明为抽象类。看下面的例子。

例4:

代码 

public abstract class Animal{public abstract void Eat();}public class Cat : Animal{public override void Eat(){Console.WriteLine("Cat eat");}}public class Dog : Animal{public override void Eat(){Console.WriteLine("Dog eat");}}public class WolfDog : Dog{public override void Eat(){Console.WriteLine("Wolfdog eat");}}class Tester{static void Main(string[] args){Animal[] animals = new Animal[3];animals[0] = new Cat();animals[1] = new Dog();animals[2] = new WolfDog();for (int i = 0; i < animals.Length; i++){animals[i].Eat();}}}

运行结果为:

Cat eat...

Dog eat...

Wolfdog eat...

从上面可以看出,通过使用abstract-override可以和virtual-override一样地实现多态,包括多层继承也是一样的。不同之处在于,包含虚拟方法的类可以被实例化,而包含抽象方法的类不能被实例化。

 

二 浅谈C#多态的法力

前言:我们都知道面向对象的三大特性:封装,继承,多态。封装和继承对于初学者而言比较好理解,但要理解多态,尤其是深入理解,初学者往往存在有很多困惑,为什么这样就可以?有时候感觉很不可思议,由此,面向对象的魅力体现了出来,那就是多态,多态用的好,可以提高程序的扩展性。常用的设计模式,比如简单工厂设计模式,核心就是多态。

其实多态就是:允许将子类类型的指针赋值给父类类型的指针。也就是同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。如果这边不理解可以先放一放,先看下面的事例,看完之后再来理解这句话,就很容易懂了。
理解多态之前首先要对面向对象的里氏替换原则和开放封闭原则有所了解。

里氏替换原则(Liskov Substitution Principle):派生类(子类)对象能够替换其基类(超类)对象被使用。通俗一点的理解就是“子类是父类”,举个例子,“男人是人,人不一定是男人”,当需要一个父类类型的对象的时候可以给一个子类类型的对象;当需要一个子类类型对象的时候给一个父类类型对象是不可以的!

开放封闭原则(Open Closed Principle):封装变化、降低耦合,软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。因此,开放封闭原则主要体现在两个方面:对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。

对这两个原则有一定了解之后就能更好的理解多态。

首先,我们先来看下怎样用虚方法实现多态

我们都知道,喜鹊(Magpie)、老鹰(Eagle)、企鹅(Penguin)都是属于鸟类,我们可以根据这三者的共有特性提取出鸟类(Bird)做为父类,喜鹊喜欢吃虫子,老鹰喜欢吃肉,企鹅喜欢吃鱼。

创建基类Bird如下,添加一个虚方法Eat():

    /// <summary>/// 鸟类:父类/// </summary>public class Bird{/// <summary>/// 吃:虚方法/// </summary>public virtual void Eat(){Console.WriteLine("我是一只小小鸟,我喜欢吃虫子~");}}

创建子类Magpie如下,继承父类Bird,重写父类Bird中的虚方法Eat():

    /// <summary>/// 喜鹊:子类/// </summary>public  class Magpie:Bird{/// <summary>/// 重写父类中Eat方法/// </summary>public override void Eat(){Console.WriteLine("我是一只喜鹊,我喜欢吃虫子~");}}

创建一个子类Eagle如下,继承父类Bird,重写父类Bird中的虚方法Eat():

    /// <summary>/// 老鹰:子类/// </summary>public  class Eagle:Bird{/// <summary>/// 重写父类中Eat方法/// </summary>public override void Eat(){Console.WriteLine("我是一只老鹰,我喜欢吃肉~");}}

创建一个子类Penguin如下,继承父类Bird,重写父类Bird中的虚方法Eat():

    /// <summary>/// 企鹅:子类/// </summary>public  class Penguin:Bird{/// <summary>/// 重写父类中Eat方法/// </summary>public override void Eat(){Console.WriteLine("我是一只小企鹅,我喜欢吃鱼~");}}

到此,一个基类,三个子类已经创建完毕,接下来我们在主函数中来看下多态是怎样体现的。

    static void Main(string[] args){//创建一个Bird基类数组,添加基类Bird对象,Magpie对象,Eagle对象,Penguin对象Bird[] birds = { new Bird(),new Magpie(),new Eagle(),new Penguin()};//遍历一下birds数组foreach (Bird bird in birds){bird.Eat();}Console.ReadKey();}

运行结果:

由此可见,子类Magpie,Eagle,Penguin对象可以赋值给父类对象,也就是说父类类型指针可以指向子类类型对象,这里体现了里氏替换原则。

父类对象调用自己的Eat()方法,实际上显示的是父类类型指针指向的子类类型对象重写父类Eat后的方法。这就是多态。

多态的作用到底是什么呢?
其实多态的作用就是把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
以上程序也体现了开放封闭原则,如果后面的同事需要扩展我这个程序,还想再添加一个猫头鹰(Owl),很容易,只需要添加一个Owl类文件,继承Bird,重写Eat()方法,添加给父类对象就可以了。至此,该程序的扩展性得到了提升,而又不需要查看源代码是如何实现的就可以扩展新功能。这就是多态带来的好处。

我们再来看下利用抽象如何来实现多态

还是刚才的例子,我们发现Bird这个父类,我们根本不需要使用它创建的对象,它存在的意义就是供子类来继承。所以我们可以用抽象类来优化它。
我们把Bird父类改成抽象类,Eat()方法改成抽象方法。代码如下:

    /// <summary>/// 鸟类:基类/// </summary>public abstract class Bird{/// <summary>/// 吃:抽象方法/// </summary>public abstract void Eat();}

抽象类Bird内添加一个Eat()抽象方法,没有方法体。也不能实例化。
其他类Magpie,Eagle,Penguin代码不变,子类也是用override关键字来重写父类中抽象方法。
Main主函数中Bird就不能创建对象了,代码稍微修改如下:

        static void Main(string[] args){//创建一个Bird基类数组,添加 Magpie对象,Eagle对象,Penguin对象Bird[] birds = { new Magpie(),new Eagle(),new Penguin()};//遍历一下birds数组foreach (Bird bird in birds){bird.Eat();}Console.ReadKey();}

执行结果:

由此可见,我们选择使用虚方法实现多态还是抽象类抽象方法实现多态,取决于我们是否需要使用基类实例化的对象.

比如说 现在有一个Employee类作为基类,ProjectManager类继承自Employee,这个时候我们就需要使用虚方法来实现多态了,因为我们要使用Employee创建的对象,这些对象就是普通员工对象。
再比如说 现在有一个Person类作为基类,Student,Teacher 类继承Person,我们需要使用的是Student和Teacher创建的对象,根本不需要使用Person创建的对象,
所以在这里Person完全可以写成抽象类。

总而言之,是使用虚方法,或者抽象类抽象方法实现多态,视情况而定,什么情况?以上我说的两点~

接下来~~~~

我要问一个问题,喜鹊和老鹰都可以飞,这个飞的能力,我怎么来实现呢?

XXX答:“在父类Bird中添加一个Fly方法不就好了~~”

我再问:“好的,照你说的,企鹅继承父类Bird,但是不能企鹅不能飞啊,这样在父类Bird中添加Fly方法是不是不合适呢?”

XXX答:“那就在能飞的鸟类中分别添加Fly方法不就可以了吗?”

对,这样是可以,功能完全可以实现,可是这样违背了面向对象开放封闭原则,下次我要再扩展一个鸟类比如猫头鹰(Owl),我还要去源代码中看下Fly是怎么实现的,然后在Owl中再次添加Fly方法,相同的功能,重复的代码,这样是不合理的,程序也不便于扩展;

其次,如果我还要添加一个飞机类(Plane),我继承Bird父类,合适吗?

很显然,不合适!所以我们需要一种规则,那就是接口了,喜鹊,老鹰,飞机,我都实现这个接口,那就可以飞了,而企鹅我不实现这个接口,它就不能飞~~

好,接下来介绍一下接口如何实现多态~

添加一个接口IFlyable,代码如下:

    /// <summary>/// 飞 接口/// </summary>public interface IFlyable{void Fly();}

喜鹊Magpie实现IFlyable接口,代码如下:

    /// <summary>/// 喜鹊:子类,实现IFlyable接口/// </summary>public  class Magpie:Bird,IFlyable{/// <summary>/// 重写父类Bird中Eat方法/// </summary>public override void Eat(){Console.WriteLine("我是一只喜鹊,我喜欢吃虫子~");}/// <summary>/// 实现 IFlyable接口方法/// </summary>public void Fly(){Console.WriteLine("我是一只喜鹊,我可以飞哦~~");}}

老鹰Eagle实现IFlyable接口,代码如下:

    /// <summary>/// 老鹰:子类实现飞接口/// </summary>public  class Eagle:Bird,IFlyable{/// <summary>/// 重写父类Bird中Eat方法/// </summary>public override void Eat(){Console.WriteLine("我是一只老鹰,我喜欢吃肉~");}/// <summary>/// 实现 IFlyable接口方法/// </summary>public void Fly(){Console.WriteLine("我是一只老鹰,我可以飞哦~~");}}

在Main主函数中,创建一个IFlyable接口数组,代码实现如下:

    static void Main(string[] args){//创建一个IFlyable接口数组,添加 Magpie对象,Eagle对象IFlyable[] flys = { new Magpie(),new Eagle()};//遍历一下flys数组foreach (IFlyable fly in flys){fly.Fly();}Console.ReadKey();}

执行结果:


由于企鹅Penguin没有实现IFlyable接口,所以企鹅不能对象不能赋值给IFlyable接口对象,所以企鹅,不能飞~

好了,刚才我提到了飞机也能飞,继承Bird不合适的问题,现在有了接口,这个问题也可以解决了。如下,我添加一个飞机Plane类,实现IFlyable接口,代码如下:

    /// <summary>/// 飞机类,实现IFlyable接口/// </summary>public  class Plane:IFlyable{/// <summary>/// 实现接口方法/// </summary>public void Fly(){Console.WriteLine("我是一架飞机,我也能飞~~");}}

在Main主函数中,接口IFlyable数组,添加Plane对象:

    class Program{static void Main(string[] args){//创建一个IFlyable接口数组,添加 Magpie对象,Eagle对象,Plane对象IFlyable[] flys = { new Magpie(),new Eagle(),new Plane()};//遍历一下flys数组foreach (IFlyable fly in flys){fly.Fly();}Console.ReadKey();}}

执行结果:

由此,可以看出用接口实现多态程序的扩展性得到了大大提升,以后不管是再扩展一个蝴蝶(Butterfly),还是鸟人(Birder)创建一个类,实现这个接口,在主函数中添加该对象就可以了。
也不需要查看源代码是如何实现的,体现了开放封闭原则!

接口充分体现了多态的魅力~~

 

以上通过一些小的事例,给大家介绍了面向对象中三种实现多态的方式,或许有人会问,在项目中怎么使用多态呢?多态的魅力在项目中如何体现?
那么接下来我做一个面向对象的简单计算器,来Show一下多态在项目中使用吧!

加减乘除运算,我们可以根据共性提取出一个计算类,里面包含两个属性 Number1和Number2,还有一个抽象方法Compute();代码如下:

    /// <summary>/// 计算父类/// </summary>public abstract class Calculate{public int Number1{get;set;}public int Number2{get;set;}public abstract int Compute();}

接下来,我们添加一个加法器,继承计算Calculate父类:

    /// <summary>/// 加法器/// </summary>public class Addition : Calculate{/// <summary>/// 实现父类计算方法/// </summary>/// <returns>加法计算结果</returns>public override int Compute(){return Number1 + Number2;}}

再添加一个减法器,继承计算Calculate父类:

    /// <summary>/// 减法器/// </summary>public class Subtraction : Calculate{/// <summary>/// 实现父类计算方法/// </summary>/// <returns>减法计算结果</returns>public override int Compute(){return Number1 - Number2;}}

在主窗体FormMain中,编写计算事件btn_Compute_Click,代码如下:

    private void btn_Compute_Click(object sender, EventArgs e){//获取两个参数int number1 = Convert.ToInt32(this.txt_Number1.Text.Trim());int number2 = Convert.ToInt32(this.txt_Number2.Text.Trim());//获取运算符string operation = cbb_Operator.Text.Trim();//通过运算符,返回父类类型Calculate calculate = GetCalculateResult(operation);calculate.Number1 = number1;calculate.Number2 = number2;//利用多态,返回运算结果string result = calculate.Compute().ToString();this.lab_Result.Text = result;}/// <summary>/// 通过运算符,返回父类类型/// </summary>/// <param name="operation"></param>/// <returns></returns>private Calculate GetCalculateResult(string operation){Calculate calculate = null;switch (operation){case "+":calculate = new Addition();break;case "-":calculate = new Subtraction();break;}return calculate;}

在该事件中主要调用GetCalculateResult方法,通过运算符,创建一个对应的加减乘除计算器子类,然后赋值给父类,其实这就是设计模式中的简单工厂设计模式,我给你一个运算符你给我生产一个对应的加减乘除计算器子类,返回给我。。其实大多数的设计模式的核心就是多态,掌握好多态,设计模式看起来也很轻松。

现阶段工作已经完成,但是过了一段时间,又添加新的需求了,我还要扩展一个乘法了,那好,很简单只要创建一个乘法计算器继承Calculate父类即可,看代码:

    /// <summary>/// 乘法计算器/// </summary>public  class Multiplication:Calculate{public override int Compute(){return Number1*Number2;}}

然后在GetCalculateResult函数中添加一个case 就好了:

    switch (operation){case "+":calculate = new Addition();break;case "-":calculate = new Subtraction();break;case "*":calculate = new Multiplication();break;}

执行结果:

好了,就这么方便,一个新的功能就扩展完毕了,我根本不需要查看源代码是如何实现的,这就是多态的好处!

多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。

多态性可以是静态的或动态的。在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。

 

三 抽象和接口

什么时候用接口什么时候用抽象?

抽象:是对相同属性和方法的提炼而得

接口:是对相同行为不同实现方法的提炼

如:  每种支付方式 支付之前都需要校验一下支付金额是不是真确的,不能小于等于0 。因为校验方式,校验代码都是一样的,所以我们可以定义一个 抽象类给抽象出来.

public abstract class AbstractPayWay implements PayWay{private Double money;private boolean verify(){return  money != null && money > 0; }/*** 这里实现了  PayWay 中的  pay 接口 方法 所以 AbstractPayWay 的子类 无需 实现该 方法,* 只需要 实现 doPay() 方法,并且 如果  doPay()方法被成功调用则说明肯定 校验成功了。*/@Overridepublic boolean pay(){boolean verify = this.verify();if(!verify){System.out.println("支付金额验证错误!");return false;}return this.doPay();}public abstract boolean doPay();
}

所以  WeixinPayWay  ZhifubaoPayWay 支付的具体实现类可以改改为 

/*** 继承  AbstractPayWay 所以无需 写公共的校验逻辑,直接写支付业务逻辑* @author cyy*/
public class WeixinPayWay extends AbstractPayWay{@Overridepublic boolean doPay() {System.out.println("这里无需校验支付金额,直接调用支付方法就行");System.out.println("微信支付成功");return false;}}public class ZhifubaoPayWay extends AbstractPayWay{@Overridepublic boolean doPay() {System.out.println("这里无需校验支付金额,直接调用支付方法就行");System.out.println("支付宝支付成功");return false;}}

 

 

 

参考:

https://www.cnblogs.com/wl-blog/p/10361894.html

https://blog.csdn.net/wab719591157/article/details/73741919

https://blog.csdn.net/u012135077/article/details/48286837

https://blog.csdn.net/u013538542/article/details/45365019

 

 

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246218.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ 虚函数和虚表

几篇写的不错的文章&#xff0c;本文是整合了这几篇文章&#xff0c;感谢这些大佬 https://www.jianshu.com/p/00dc0d939119 https://www.cnblogs.com/hushpa/p/5707475.html https://www.jianshu.com/p/91227e99dfd7 多态: 多态是面相对象语言一个重要的特性,多态即让同一…

Unity 2017 Game Optimization 读书笔记(2)Scripting Strategies Part 2

1. Share calculation output 和上一个Tip很像&#xff0c;可以缓存计算结果或者各种信息&#xff0c;避免多次重复的计算&#xff0c;例如在场景里查找一个物体&#xff0c;从文件读取数据&#xff0c;解析Json等等。 容易忽略的点是常常在基类了实现了某个方法&#xff0c;在…

Unity 2017 Game Optimization 读书笔记(3)Scripting Strategies Part 3

1.Avoid retrieving string properties from GameObjects 通常来讲&#xff0c;从C#的object中获取string 属性没有额外的内存开销&#xff0c;但是从Unity中的Gameobject获取string属性不一样&#xff0c;这会产生上一篇讲到的 Native-Managed Bridge&#xff08;Native内存和…

Unity 2017 Game Optimization 读书笔记(4)Scripting Strategies Part 4

1.Avoid Find() and SendMessage() at runtime SendMessage() 方法和 GameObject.Find() 相关的一系列方法都是开销非常大的。SendMessage()函数调用的耗时大约是一个普通函数调用的2000倍&#xff0c;GameObject.Find() 则和场景的复杂度相关&#xff0c;场景越复杂&#xff0…

Unity HDRP中的光照烘焙测试(Mixed Lighing )和间接光

部分内容摘抄自&#xff1a;https://www.cnblogs.com/murongxiaopifu/p/8553367.html 直接光和间接光 大家都知道在Unity中&#xff0c;我们可以在场景中布置方向光、点光、聚光等类型的光源。但如果只有这些光&#xff0c;则场景内只会受到直接光的影响&#xff0c;而所谓的…

聊聊Unity项目管理的那些事:Git-flow和Unity

感谢原作者https://www.cnblogs.com/murongxiaopifu/p/6086849.html 0x00 前言 目前所在的团队实行敏捷开发已经有了一段时间了。敏捷开发中重要的一个话题便是如何对项目进行恰当的版本管理。项目从最初使用svn到之后的Git One Track策略再到现在的GitFlow策略&#xff0c;中…

聊聊网络游戏同步那点事

写的非常好的一篇博文&#xff0c;转载自https://www.cnblogs.com/murongxiaopifu/p/6376234.html 0x00 前言 16年年底的时候我从当时的公司离职&#xff0c;来到了目前任职的一家更专注于游戏开发的公司。接手的是一个platform游戏项目&#xff0c;基本情况是之前的团队完成…

Unity 2017 Game Optimization 读书笔记 Dynamic Graphics(1)

The Rendering Pipeline 渲染表现差有可能取决于CPU端&#xff08;CPU Bound&#xff09;也有可能取决于GPU(GPU Bound).调查CPU-bound的问题相对简单&#xff0c;因为CPU端的工作就是从硬盘或者内存中加载数据并且调用图形APU指令。想找到GPU-bound的原因会困难很多&#xff…

Unity 2017 Game Optimization 读书笔记 Dynamic Graphics(2)

Lighting and Shadowing 现代的游戏中&#xff0c;基本没有物体能在一步就完成渲染&#xff0c;这是因为有光照和阴影的关系。光照和阴影的渲染在Fragment Shader中需要额外的pass。 首先要设置场景中的Shadow Casters和Shadow Receivers&#xff0c;Shadow Casters投射阴影&…

Unity 2017 Game Optimization 读书笔记 The Benefits of Batching

batching&#xff08;合批&#xff09; 和大量的描述一个3D物体的数据有关系&#xff0c;比如meshes&#xff0c;verices&#xff0c;edges&#xff0c;UV coordinates 以及其他不同类型的数据。在Unity中谈论batching&#xff0c;指的是用于合批mesh数据的两个东西&#xff1a…

Unity 2017 Game Optimization 读书笔记 Dynamic Graphics (3)

Rendering performance enhancements Enable/Disable GPU Skinning 开启GPU Skinning可以减轻CPU或GPU中Front End部分中某一个的负担&#xff0c;但是会加重另一个的负担。Skinning是mesh中的顶点根据动画中骨骼的当前位置进行计算&#xff0c;从而让角色摆出正确的姿势。 …

Unity手游开发札记——布料系统原理浅析和在Unity手游中的应用

原文&#xff1a;https://zhuanlan.zhihu.com/p/28644618 0. 前言 项目技术测试结束之后&#xff0c;各种美术效果提升的需求逐渐成为后续开发的重点&#xff0c;角色效果部分的提升目标之一便是在角色选择/展示界面为玩家提供更高的品质感&#xff0c;于是可以提供动态效果的…

行为树(Behavior Tree)实践(1)– 基本概念

原文&#xff1a;http://www.aisharing.com/archives/90 行为树&#xff08;Behavior Tree&#xff09;实践&#xff08;1&#xff09;– 基本概念 自从开博以来&#xff0c;每天都会关心一下博客的访问情况&#xff0c;看到一些朋友的订阅或者访问&#xff0c;不胜欣喜&…

Unity 2017 Game Optimization 读书笔记 Dynamic Graphics (5) Shader优化

Shader optimization Fill Rate和 Memory Bandwidth开销最大的地方就是Fragment Shader。开销多大取决于Fragment Shader的复杂程度&#xff1a;多少纹理需要采样&#xff0c;多少数学计算函数需要使用等等。GPU的并行特性意味着在线程中如果任何地方存在瓶颈&#xff0c;都会…

Unity 2017 Game Optimization 读书笔记 Dynamic Graphics (6)

1. Use less texture data 这条优化技巧非常直接&#xff0c;减少texture的数据量&#xff0c;减少分辨率或者降低位数&#xff0c;虽然可能会降低渲染质量。但是通常使用16-bit textures并不会明显的感觉到渲染效果下降。 MipMap技术可以有效减少VRAM和Texture Cache之间来回…

LeetCode 面试题57 - II(剑指offer) 和为s的连续正数序列

今天毕业五年了&#xff0c;一直忙于工作和享受&#xff0c;自从当年找完工作后就一直没有再刷过题&#xff0c;作为搬砖的码农&#xff0c;觉得还是应该养成长期刷题的习惯坚持下去。之前坚持了每天被一会单词&#xff0c;如今雅思一本也快看完了&#xff0c;从今天开始准备在…

反走样技术相关文章

https://zhuanlan.zhihu.com/p/28800047 https://zhuanlan.zhihu.com/p/57503957 https://zhuanlan.zhihu.com/p/33444125 https://zhuanlan.zhihu.com/p/33444429 走样的原因及其分类 说到走样&#xff0c;首先要说的就是采样。这也算是很多图形学专著中提到反走样相关技…

求n的阶乘的算法框图_单片机常用的14个C语言算法

问&#xff1a;怎么每天看到这种文章&#xff1f;答&#xff1a;只需搜索公众号"51单片机学习网"免费关注算法(Algorithm)&#xff1a;计算机解题的基本思想方法和步骤。算法的描述&#xff1a;是对要解决一个问题或要完成一项任务所采取的方法和步骤的描述&#xff…

LeetCode 286. 墙与门 多源BFS和DFS

思路1&#xff1a; DFS&#xff0c;对于每个门进行一次DFS搜索&#xff0c;记录每个位置对每个门的距离&#xff0c;当有更小距离的门时更新这个数值 public void WallsAndGates(int[][] rooms) {for (int i 0; i < rooms.GetLength(0); i){for (int j 0; j < rooms[i]…

贝塞尔曲线

文章参考于&#xff1a;https://www.jianshu.com/p/0c9b4b681724 https://gameinstitute.qq.com/community/detail/129188 贝赛尔曲线的前世今生&#xff1a; 贝塞尔曲线&#xff0c;这个命名规则一眼看上去大概是一个叫贝塞尔的数学家发明的。但&#xff0c;贝塞尔曲线依据…