untiy 第二个逗比又无聊的跑酷demo

逗比刘真是菜啊,天天就知道写这种无聊的东西,写了也不一定有人看的。看了也不一定有人喜欢。喜欢也没有什么卵用啊。先分享一波图吧。

大家第一眼看见是个什么?(逗比刘第一眼说 是精子小蝌蚪啊,逗比刘好邪恶啊)

做一个这样的demo可以说基本用不到很多素材,最重要的素材就是那个圆圈,这个圆圈对于一个程序员来说画起来应该蛮简单的吧。前天我们讲到如果绘制一个2D的圆环,今天我们就绘制一个3D的圆环,如果我们把一个2D的圆绕着一个轴旋转一周就可以做出一个3D的圆环了。

那么我们首先的建一个基本的类Pipe用来构建我们的圆环。我们做出一般的情况就是做出一个整环,然后继续延伸到半个乃至固弧度的圆环。首先我们先从圆环开始。我先发一波图看我们最后的节点的信息是怎么分布的。

我们可以从这张图可以看出,整个圆环的点分布我们可以由最上面在yz平面上的一个圆绕着z轴旋转就构成了我们整个圆环,旋转180度就是个半圆,旋转90度就是一个四分之一圆,这样我们可以通过旋转多少度来控制整个圆环的长度。我们需要控制圆环的换的宽度和圆环的半径,位于yz平面的圆控制我们圆环的宽度。位于yz平面的圆中心点和该圆的旋转点的距离就是构成我们圆环的半径。那么我们就可以得出整个3D圆环上的点的规律。给出点在yz平面圆的的角度和yz平面的圆围绕着中心点旋转了多少度就可以计算出了该点。位于yz平面上的那个圆
上的点在y轴分量最大的那个 点就是最高的那个点,从图中我们可以清晰的看到。 现在我们做个假设假如位于yz平面那个圆上的最高的那个点为a1,那么将yz平面绕着z轴旋转90度的时候我们定义其为y1z1平面,那么这时的a1点就变成了在x轴上分量最大了。所以他们所有点在x轴和y轴的分量我们定义为x=r*sin(旋转角度),y=r*cos(旋转角度)。因为位于yz平面圆上不同位置上的点他们绕着z轴构成的半径都不一样的,所以半径r=圆环的半径+圆环的宽度*cos(点在圆上的角度,位于最高点的角度为0,位于最低点角度为180度,角度的递增顺序是逆时针),所以它的z轴分量就应该为z=圆的宽度*sin(点在圆上的角度)。如果理解有点困难的话大家在大脑里面意淫一下可以出来了。

所以理解这个规律之后,我们就需要建立一个基本的类来生成一个3D的圆环了。同时将它的圆环的宽度和圆环的半径暴露到inspect上方便我们控制。同时我们还应该写出我们刚刚分析通过点在圆上的角度和圆绕z轴形成的角度来得到我们的点方法,同时我们还是定义绘制网格的3个数组,还有我们圆上总共有多少个点,及我们可以旋转的角度(这里所说的我们不可能每隔一度就绘制这些点,我们的做法是每隔20度添加一个圆上的点了,或者我们绘制更加稀疏每隔30度添加一个圆的点)。

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

public class Pipe : MonoBehaviour
{
    public float PipeRadius;//圆环的宽度
    public float CurveRadius;//圆环的半径

    public int PipesegmentCount;//定义圆上有顶点的个数
    public int CurvesegmentCount;//定义圆的个数

    private List<Vector3> _verticles;
    private List<int> _indictInts;
    private List<Vector2> _uvList;   

    [SerializeField] private Material _meshMaterial;//定义圆环的材质
    private void Awake()
    {

        _verticles = new List<Vector3>();
        _indictInts = new List<int>();
        _uvList=new List<Vector2>();                  

    }
    private Vector3 GetVector3(float pipeAngle, float curveAngle)//通过点在圆上的角度和圆围绕z轴旋转的度数
    {
        float r = CurveRadius + PipeRadius * Mathf.Cos(pipeAngle);
        float x = r * Mathf.Sin(curveAngle);
        float y = r * Mathf.Cos(curveAngle);
        float z = PipeRadius * Mathf.Sin(pipeAngle);

        return new Vector3(x, y, z);
    }

    public void OnDrawGizmos()
    {
        for (int i = 0; i < _verticles.Count; i++)
        {
            Gizmos.DrawSphere(_verticles[i],0.1f);
        }

    } 

}

建完了基本的类后我们开始添加一个添加点的方法。我们还是一个圆一个圆的添加。然后将他们的绘制顺序和顶点的uv信息同样也给出来。

    private Mesh CreateMesh(int pipecout, int curvecout, float angle)
    {
        Mesh myMesh = new Mesh();
        float pipeoffset = Mathf.PI * 2 / PipesegmentCount;
        float curveoffset = angle * Mathf.Deg2Rad / (CurvesegmentCount - 1);
        CurveAngle = angle;

        for (int i = 0; i < CurvesegmentCount; i++)
        {
            for (int j = 0; j < PipesegmentCount; j++)
            {
                Vector3 temp = GetVector3(pipeoffset * j, curveoffset * i);
                _verticles.Add(temp);
            }
        }
        for (int i = 0; i < CurvesegmentCount; i++)
        {
            for (int j = 0; j < PipesegmentCount; j++)
            {
                _uvList.Add(new Vector2(i % 2, j % 2));
            }
        }
        for (int i = 0; i < CurvesegmentCount - 1; i++)
        {
            for (int j = 0; j < PipesegmentCount; j++)
            {
                _indictInts.Add(i * pipecout + j);
                _indictInts.Add((i + 1) % curvecout * pipecout + j);
                _indictInts.Add((i + 1) % curvecout * pipecout + (j + 1) % pipecout);

                _indictInts.Add(i * pipecout + j);
                _indictInts.Add((i + 1) % curvecout * pipecout + (j + 1) % pipecout);
                _indictInts.Add(i * pipecout + (j + 1) % pipecout);
            }
        }

        myMesh.vertices = _verticles.ToArray();
        myMesh.triangles = _indictInts.ToArray();
        myMesh.uv = _uvList.ToArray();

        return myMesh;
    }

做完这些我们就可以做出一个给定角度的3D圆环了,我们继续给它添加响应的组件。

        _uvList=new List<Vector2>();

       <span style="background-color: rgb(255, 153, 0);"> var mesh = CreateMesh(PipesegmentCount, CurvesegmentCount, 360);
        this.GetComponent<MeshFilter>().mesh = mesh;</span>

做完这些只是第一步。接下里我们要怎么让2段3D圆环无缝的链接起来,如果第一段圆环的长度是90度(我们用角度来定义圆环的长度),那么第二段圆环的那么绕z的角度那么就是上一段圆环的角度的一个负值对应第一段的圆环长度90就是-90度了。那么下一段就是前面2段长度之和的一个负值了,如果我们这样做那岂不是很麻烦么?当我们生成第二段圆环的时候,我们将第二段的父物体设置成第一段,那么它相对于第一段的围绕z的角度就是上一段圆环角度的负值了,当我们生成第三段圆环的时候,我们将该段圆环的父物体设置成第二段圆环,那么它相对于第二段圆环围绕z轴的角度就是第二段圆环的角度的赋值了,一次类推。

从右边的视图中我们就可以清晰的看见游戏物体的父子关系了。如果我们就只是把几段这样的圆环连接起来的话,那我们还做成几段干嘛直接做成一大段就行了啊。那么我们接下来要做的就是把我们的第二段让它旋转围绕着第一段。而不是让所有的圆环都在一个平面上。截一波图看看。

要让第二段和第一段不在一个平面上,所以我们就需要对其旋转了。那么该怎么旋转和平移呢。截一波图分析分析。

首先我们需要让第二段圆环围绕着圆环本地y轴移动圆环的半径的距离(不是圆环的宽度)

图片截的不怎么好,但是步骤依次从左到右从上到下的顺序的看就明白了如何操作的了。好了我们就给出对应的代码,这个方法的作用应该写在我们这个pipe类中。你也可以写到一个pipe管理类中 其实都一样了。

 public void ConnectPipe(Pipe prePipe)
    {
        float relativeRotation = Random.Range(0, PipesegmentCount) * 360f / PipesegmentCount;//首先我们定义它需要旋转多少度

        transform.SetParent(prePipe.transform, false);//第一步确定父子关系,即让他变成上一段的孩子

        transform.localPosition = Vector3.zero;
        transform.localRotation = Quaternion.Euler(0f, 0f, -prePipe.CurveAngle);//然后就是设置它的本地坐标的欧拉角
        transform.Translate(0f, prePipe.CurveRadius, 0f);//开始沿着y轴移动(本地坐标系)
        transform.Rotate(relativeRotation, 0f, 0f);//开始绕着x轴移动了(本地坐标系)
        transform.Translate(0f, -CurveRadius, 0f);//然后移回到响应的点
        transform.SetParent(prePipe.transform.parent);//最后重新设置父亲节点
        transform.localScale = Vector3.one;
    }

接着我们做一个管理圆环的管理类。

public class PipeSystem : MonoBehaviour
{

    [SerializeField] private int _pipecout;

    private List<Pipe> _pipes;
    private int _curindex = 0;

    void Awake ()
    {
        _pipes = new List<Pipe>();
    }  

}

我们一般设置这个pipecount的数量不能太多,我个人觉得4个就比较好了。我们虽然的是地图无限的拼接,但是我们只用4段圆环,当我们玩家跑到第二段圆环的时候,我们不删除第一段圆环而是让第一段圆环接到第四段圆环的后面这样就可以做到不生成额外的圆环,对于障碍物的生成我们采用对象池对其进行一点小小的优化。对于这个管理类他应该提供一些基本的方法,例如我们玩家跑到第二段圆环上去了之后这个时候我们的管理类应该通知我们的第一段环接到第四段圆环上去同时重新生成这一段圆环的障碍物同时返回这一段圆环的引用,同时在awake方法中初始化我们的对象池和圆环的位置及相应的信息。

   <span style="background-color: rgb(255, 153, 0);"> [SerializeField] private GameObject _pipeGameObject;
    [SerializeField] private GameObject _cubeObs;
    [SerializeField] private GameObject _cylinderObs;</span>
      <span style="background-color: rgb(255, 153, 0);">  Pools.ManageRecyclePool(new ObjectPool()
        {
            Prefab = _cubeObs,
            InstancesToPreallocate = 50
        });
        Pools.ManageRecyclePool(new ObjectPool()
        {
            Prefab = _cylinderObs,
            InstancesToPreallocate = 50
        });</span>
        _pipes = new List<Pipe>();
      <span style="background-color: rgb(255, 153, 0);">  for (int i = 0; i < _pipecout; i++)
	{
            GameObject ob = GameObject.Instantiate(_pipeGameObject);
            ob.transform.SetParent(this.transform);
            _pipes.Add(ob.GetComponent<Pipe>());
	    if (i != 0)
	    {
                _pipes[i].ConnectPipe(_pipes[i-1]);
	    }
	 }</span>

接下来添加切换圆环即当我们玩家跑到第二段圆环的时候这时我们当前圆环数组中的索引需要发生变幻的。我们知道做一个横版的跑酷游戏例如那种某大型游戏公司的跑酷游戏一样我们的做法有时并不一定非要让玩家移动,而是让背景移动。所以这个的做法就是让背景移动,可是这是一个由很多不同角度的圆环组成的一个地图,那么有移动地图谈何容易啊。所以我们做法是将所有的圆环设置一个父亲节点对其统一管理。我们在开始的时候我们需要将第一段圆环和我们父亲节点保持相对不动,在update方法中我们让我们的父亲节点它的位于z轴的欧拉角随着时间的流逝不断的增大这样就好比我们在移动我们的第一段的圆环一样。这样玩家就在第一段圆环上移动一样。当我们父亲节点的所发生的总偏移量大于圆环的长度(用角度来模拟)的时候。这是我们父亲节点的总偏移量重置为0,如果我们还是按照原来的方式进行移动的话,那么肯定会出错。这时我们就需要重置我们的父亲节点的位置了,这时我们需要做几步来完成这样一份工作。1
把所有的圆环子节点把他们的父亲节点设置为空,然后把原来圆环的父亲节点位置设置成我们的第二段圆环的位置。然后再把所有的圆环又设置成原来的父亲节点了。具体的代码如下。

    private int _tempindex = 0;
    public Pipe SwitchPipe()
    {
        _tempindex = _curindex;
        _curindex++;
        _curindex = _curindex%_pipecout;
        for (int i = 0; i < _pipecout; i++)
        {
            _pipes[i].transform.parent=null;
        }
        this.transform.localPosition = _pipes[_curindex].transform.position;
        this.transform.localEulerAngles = _pipes[_curindex].transform.eulerAngles;

        for (int i = 0; i < _pipecout; i++)
        {
            _pipes[i].transform.SetParent(this.transform);
        }

        return _pipes[_curindex];

    }

这个方法里面差个障碍物的重置。所以我重新写了一个方法专门用来重置障碍物的。

    public void ResetPipe()
    {
        _pipes[_tempindex].ResetObstacle();
        _pipes[_tempindex].ConnectPipe(_pipes[(_tempindex + _pipecout - 1) % _pipecout]);

    }

接下来就是添加player类,这个类就比较简单,主要就是一个update方法。我就直接贴出代码了。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

public class Player :MonoBehaviour
{
    public PipeSystem PipeSystem;
    public float Velocity;

    private Pipe _currentPipe;

    private float _totalAngle = 0;
    [SerializeField] private float _speed;
    private void Start()
    {
        _currentPipe = PipeSystem.SetupFirstPipe(this.transform);
    }

    private bool _resetPipe = false;
    private void Update()
    {
        float delta = Time.deltaTime * _speed;
        _totalAngle += delta;
        if (_totalAngle >= _currentPipe.CurveAngle)
        {
            delta = _currentPipe.CurveAngle - _totalAngle + delta;
            PipeSystem.transform.localEulerAngles += new Vector3(0, 0, delta);
            _currentPipe = PipeSystem.SwitchPipe();
            _resetPipe = true;
            delta = 0;
            _totalAngle = 0;

        }
        if (_totalAngle > 20 && _resetPipe)
        {
            PipeSystem.ResetPipe();
            _resetPipe = false;
        }
        UpdatePlayerRotation();
        PipeSystem.transform.localEulerAngles += new Vector3(0, 0, delta);
    }
    private void UpdatePlayerRotation()
    {
        if (Input.GetMouseButton(0))
        {
            transform.localRotation *= Quaternion.AngleAxis(2, Vector3.right);
        }
    }
}

添加完了玩家,我们圆环还有一些障碍物还没有生成,所以这里我们就需要添加添加障碍物的方法了。然后我们回到Pipe类中添加如下代码。

    private void CreateObstacleItem()
    {
        float pipeoffset = Mathf.PI * 2 / PipesegmentCount;
        float curveoffset = CurveAngle * Mathf.Deg2Rad / (CurvesegmentCount - 1);

        for (int i = 0; i < CurvesegmentCount-1; i++)
        {
            int b = Random.Range(0, 10);
            if (b % 2 == 0)
            {
                int index = Random.Range(0, PipesegmentCount);
                int type = Random.Range(0,10) % (int)ObscaleEnum.Cylinder;
                GameObject obj = null;
                switch (type)
                {
                    case 1:
                        obj = CreatAwlObstacle(i, index, pipeoffset, curveoffset);
                        break;
                    case 0:
                        obj = CreatePrimitiveTypeObscale(ObscaleEnum.Cube,i, index, pipeoffset, curveoffset);
                        break;
                    case 2:
                        obj = CreatePrimitiveTypeObscale(ObscaleEnum.Cylinder, i, index, pipeoffset, curveoffset);
                        break;
                }
                _obstacleObjects.Add(obj);
            }
        }
    }

然后添加几个创建障碍物的方法,首先添加创建圆锥体障碍物,后面就是添加创建圆柱体和长方体障碍物的方法了。

    private GameObject CreatAwlObstacle(int curvindex, int pipeindex, float pipeoffset, float curveoffset)
    {
        List<Vector3> pointList = new List<Vector3>();

        int index = pipeindex;
        int temp = (index + 1) % PipesegmentCount;

        Vector3 t1 = GetVector3(pipeoffset * index, curveoffset * curvindex);
        Vector3 t2 = GetVector3(pipeoffset * index, curveoffset * (curvindex + 1));
        Vector3 t3 = GetVector3(pipeoffset * temp, curveoffset * (curvindex + 1));
        Vector3 t4 = GetVector3(pipeoffset * temp, curveoffset * curvindex);
        Vector3 mid = (t1 + t3) / 2;

        float raiuds = Vector3.Magnitude(t2 - t1);
        Vector3 dirx = (t2 - t1).normalized;
        Vector3 diry = (t3 - t2).normalized;
        for (int i = 0; i <= 20; i++)
        {
            float rad = i*18*Mathf.Deg2Rad;
            var pos =raiuds* dirx*Mathf.Sin(rad)/2 +raiuds*diry*Mathf.Cos(rad)/2;
            pointList.Add(pos);
        }
        Vector3 normal = Vector3.Cross(dirx, diry).normalized;
        Vector3 t5 = normal * 0.5f;
        pointList.Add(t5);

        var obj = _meshBuilder.CreateAwlMeshObj(pointList);

        obj.transform.SetParent(this.transform,false);
        obj.transform.localPosition = mid + normal * 0.01f;

        pointList.Clear();
        return obj;
    }
    private GameObject CreatePrimitiveTypeObscale(ObscaleEnum type,int curvindex, int pipeindex, float pipeoffset, float curveoffset)
    {

        int index = pipeindex;
        int temp = (index + 1) % PipesegmentCount;

        Vector3 t1 = GetVector3(pipeoffset * index, curveoffset * curvindex);
        Vector3 t2 = GetVector3(pipeoffset * index, curveoffset * (curvindex + 1));
        Vector3 t3 = GetVector3(pipeoffset * temp, curveoffset * (curvindex + 1));
        Vector3 mid = (t1 + t3)/2;
        Vector3 dirVector3 = (t3 - t2).normalized;

        Vector3 normal = Vector3.Cross(t2 - t1, t3 - t2);
        GameObject cube = Pools.Spawn(type==ObscaleEnum.Cube?_cube:_cyl);
        float scaley = Random.Range(0.05f, 1.5f);

        float offset = Random.Range(0, 10)%2 == 0 ? 0 : -0.3f;
        cube.transform.localScale = new Vector3(0.1f, scaley, 0.1f);
        cube.transform.up = normal;
        cube.transform.SetParent(this.transform, false);
        cube.transform.localPosition = mid + normal * scaley * 2 + dirVector3 * offset;

        cube.GetComponent<MeshRenderer>().material = _meshMaterial;

        return cube;
    }

然后我们害的给出网格创建的基本方法了。

public class MeshBuilder
{

    private Material _meshMaterial;
    public void Intilized(Material mat)
    {
        _meshMaterial = mat;
    }

    public GameObject CreateAwlMeshObj(List<Vector3> pointList)
    {
        GameObject ob=new GameObject("Obstacle");
        List<int> indicts=new List<int>();

        Mesh mesh=new Mesh();
        mesh.vertices = pointList.ToArray();
        int temp = pointList.Count - 1;
        for (int i = 0; i < temp; i++)
        {
            indicts.Add(i); indicts.Add(temp); indicts.Add((i + 1) % temp);
        }
        mesh.triangles = indicts.ToArray();

        var meshfilter = ob.AddComponent<MeshFilter>();
        meshfilter.mesh = mesh;
        ob.AddComponent<MeshRenderer>().material = _meshMaterial;

        return ob;
    }
    public GameObject CreateCubeGameObject(List<Vector3> pointList)
    {
        GameObject ob=new GameObject();

        List<int> indicts = new List<int>();

        Mesh mesh = new Mesh();
        mesh.vertices = pointList.ToArray();
        int onelinelength = pointList.Count/4;
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < onelinelength-1; j++)
            {
                int temp = (i + 1) % 4;
                indicts.Add(i * onelinelength + j);
                indicts.Add(temp * onelinelength + j);
                indicts.Add(temp * onelinelength + j + 1);

                indicts.Add(i * onelinelength + j);
                indicts.Add(temp * onelinelength + j + 1);
                indicts.Add(i * onelinelength + j + 1);
            }
        }
        indicts.Add(0); indicts.Add(0 + 2 * onelinelength); indicts.Add(0 + 1 * onelinelength);
        indicts.Add(0 + 3 * onelinelength); indicts.Add(0 + 2 * onelinelength); indicts.Add(0);

        indicts.Add(3 * onelinelength - 1); indicts.Add(onelinelength - 1); indicts.Add(2 * onelinelength - 1);
        indicts.Add(onelinelength - 1); indicts.Add(onelinelength - 1); indicts.Add(3 * onelinelength - 1); 

        var meshfilter = ob.AddComponent<MeshFilter>();
        meshfilter.mesh = mesh;
        mesh.vertices = pointList.ToArray();
        mesh.triangles = indicts.ToArray();

        ob.AddComponent<MeshRenderer>().material = _meshMaterial;

        return ob;
    }

}
public enum ObscaleEnum
{
    None,
    Awl,
    Cube,
    Cylinder
}

回到pipe把响应的awake方法补齐和一些字段补齐

    private List<Vector2> _uvList; 

    <span style="background-color: rgb(255, 153, 0);">public float CurveAngle = 0;

    private List<GameObject> _obstacleObjects;
    private MeshBuilder _meshBuilder;</span>
       _uvList=new List<Vector2>();
      <span style="background-color: rgb(255, 153, 0);">  _obstacleObjects=new List<GameObject>();

        var mesh = CreateMesh(PipesegmentCount, CurvesegmentCount, Random.Range(60, 90));
        this.GetComponent<MeshFilter>().mesh = mesh;

        _meshBuilder=new MeshBuilder();
        _meshBuilder.Intilized(_meshMaterial);

        CreateObstacleItem();</span>

一个基本的sb又无聊的无限跑酷类型的游戏差不多做完了,这里只是一个demo完整度并不高,玩家的碰撞器啊,死亡判断这些我都没有去做,如果大家有时间可以做做,这个都比较简单,稍微写个碰撞检测就行了,另外没做完还有一部分原因是没有ui美术所以做不成一个完整的小游戏了。当我们做完这些然后去做一个赛车的赛道应该会比较简单。如果还有什么不懂的话可以看下面的源码链接。同时你可以qq联系我。qq:185076145  欢迎各位骚扰 哈哈。http://pan.baidu.com/s/1mirn2be

时间: 2024-10-09 04:25:18

untiy 第二个逗比又无聊的跑酷demo的相关文章

Android好奇宝宝_07_ViewPager切换动画(兼容低版本)

闲着无聊,写写Demo 想着写一个图片轮播,百度了一下基本都是用ViewPager实现的,那就用ViewPager来练手. 写完了再自定义切换效果,发现3.0以下不兼容,只好想办法. 先上效果图: 下面一步一步来: (1)写布局: <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <jjj.demo.viewpager

最近两场比赛 CF 285 &amp; TC 646

Codeforces 285 这场rating又掉了,好在只掉了十多. 题目比较水,但是我比赛时居然只艰辛地过了前两道. 504A 由于图是森林,所以一定有度为1的点,把这些点删了后图还是森林.然后就完了.比赛的时候居然把森林当成了树,交了3次才过. 504B 把排列表示为一个n元组\( (p_0, p_1, \cdots, p_{n - 1})\),其中\(0 \leqslant p_i \leqslant i \),其排名为 \[\sum_{i = 0}^{n - 1}{p_ii!}\].

XML的DTD和Schema约束

为什么要使用约束? XML是自定义的标签,有时候标签太多,记不住,所以就需要有约束来告诉我能写哪些标签,哪些标签写错了不能识别 XML中有哪几种约束? 有很多约束,其中DTD和Schema约束最为常见. 约束本质上是什么? 约束本质上也是一种xml文件. DTD约束和Schema约束的区别 特点的区别: DTD约束较为古老,简单,一些老框架使用DTD作为约束:Struts2和Hibernate都使用DTD作为其XML配置文件的约束 Schema约束功能更为强大,用的更为广泛,Tomcat和Spr

让CSS3给你的文字加上边框宽度,并实现镂空效果

这次,我主要向大家介绍一下CSS3下的-webkit-text-stroke属性,并分享几个用该属性制作的镂空文字效果. 1.-webkit-text-stroke属性简介 CSS边框的一个不足就是只有矩形的元素才能使用.-webkit-text-stroke可以为文字添加边框.它不但可以设置文字边框的宽度,也能设置其颜色.而且,配合使用color: transparent属性,你还可以创建镂空的字体. 2.一起看几个利用-webkit-text-stroke制作的文字特效 第一个CSS代码如下

vue之指令篇 ps简单的对比angular

这两天在开始vue的大型项目,发现和ng还是有许多不同,这里对比下两者的指令系统 难度系数:ng的指令难度大于vue:至少vue上暂时没发现@&=:require,compile,precompile,postcompile之类的小型地雷... 这篇文章只看表象:何为指令?这里借助ng的解释来解释vue,就是当你的项目中,需要一些dom操作,并且MVMM自带的事件指令感觉麻烦的时候,可以把一些dom操作封装到一个公共方法,这就是指令,大概用在vue上也可以说个70%: 写法,vue: Vue.d

深入理解javascript之高级定时器

setTimeout()和setInterval()可以用来创建定时器,其基本的用法这里就不再做介绍了.这里主要介绍一下javascript的代码队列.在javascript中没有任何代码是立即执行的,一旦进程空闲则尽快执行.所以说定时器中设置的时间并不代表执行时间就一定相符,而是代表代码会在指定时间间隔后加入到队列中进行等待.如果在这个时间点上,队列中没有其他东西,那么这段代码就会被执行,表面上看上去好像代码就在精确指定的时间点上执行了.所以就会产生一些问题. 重复定时器 通常,我们使用set

理清JavaScript正则表达式--上篇

在JavaScript中,正则表达式由RegExp对象表示.RegExp对象呢,又可以通过直接量和构造函数RegExp两种方式创建,分别如下: //直接量 var re = /pattern/[g | i | m]; //构造函数 var re = new RegExp(["pattern", ["g" | "i" | "m"]]); 其中,末尾的可选字符(g.i和m)分别表示: g: 模式执行一个全局匹配.简而言之,就是找到

JavaScript正则表达式详解

在JavaScript中,正则表达式由RegExp对象表示.RegExp对象呢,又可以通过直接量和构造函数RegExp两种方式创建,分别如下: //直接量 var re = /pattern/[g | i | m]; //构造函数 var re = new RegExp(["pattern", ["g" | "i" | "m"]]); 其中,末尾的可选字符(g.i和m)分别表示: g: 模式执行一个全局匹配.简而言之,就是找到

理解Javascript的动态语言特性

原文:理解Javascript的动态语言特性 Javascript是一种解释性语言,而并非编译性,它不能编译成二进制文件. 理解动态执行与闭包的概念 动态执行:javascript提供eval()函数,用于动态解释一段文本,并在当前上下文环境中执行. 首先我们需要理解的是eval()方法它有全局闭包和当前函数的闭包,比如如下代码,大家认为会输出什么呢? var i = 100; function myFunc() { var i = 'test'; eval('i = "hello."