如何实现Sprite移动到鼠标超出屏幕边界界时,从另一边出现

碰撞检测和 sprite 动画
此内容是该系列 # 部分中的第 # 部分: HTML5 2D 游戏开发/developerworks/cn/views/global/libraryview.jsp?series_title_by=html5+2d+游戏开发敬请期待该系列的后续内容。此内容是该系列的一部分:HTML5 2D 游戏开发敬请期待该系列的后续内容。
碰撞检测和 sprite 动画是所有视频游戏的主要成分。Snail Bait(本中构建的游戏)也不例外。图 1 显示了 Snail Bait 的跑步小人与左上角的蜜蜂碰撞后发生爆炸。图 1. 碰撞检测的实际应用 在本文中,学习如何:检测碰撞将 HTML5 Canvas 上下文用于碰撞检测将碰撞检测实现为 sprite 行为处理碰撞实现 sprite 动画,比如爆炸碰撞检测过程碰撞检测是一个 4 步过程,第一步是实际检测碰撞:在游戏的 sprite 上进行迭代排除不适合碰撞检测的 sprite检测候选 sprite 之间的碰撞处理碰撞碰撞检测可能需要很高的计算量,所以,避免对不可能碰撞的 sprite 进行检测非常重要。例如,在 sprite 爆炸时,Snail Bait 的跑步小人会穿过其他 sprite。因为检查一个 sprite 是否在爆炸比执行碰撞检测所需的时间更少,Snail Bait 从碰撞检测中排除了爆炸的 sprite。我们首先将概述一下碰撞检测技术。碰撞检测技术可通过多种方式检测 sprite 之间的碰撞。可采用的三种流行技术(按先进程度和复杂度递增顺序排列)是:边界区域(在 3D 游戏中称为包围体)光线投射分离轴定理 (Separating Axis Theorem)使用边界区域的碰撞检测,检测圆圈或多边形的交点。在 图 2 中的示例中,小圆圈是表示一个 sprite(一个小球)的边界区域,大圆圈是一个桶的 sprite 的边界区域,桶比球大。当两个圆形边界区域相交时,球就会掉落到桶中。图 2. 边界区域:圆圈之间的碰撞检测两个圆圈的碰撞是所有碰撞检测技术中最简单的。如果两个圆圈中心之间距离小于圆圈的半径之和,就会相交,sprite 就会爆炸。边界区域碰撞检测很简单,但当边界区域太小或移动得太快时,检测可能失败。在这两种情况下,sprite 可在单个动画帧中彼此穿过,进而避免检测。对于小型、快速移动的 sprite,更加可靠的一种技术是光线投射,如 图 3 所示。光线投射检测两个 sprite 的速度向量的焦点。在 图 3 中的 5 个帧中,球的速度向量是以蓝色绘制的对角线,桶的速度向量是红色的水平线(桶水平移动)。在这些向量的交点位于桶顶部的开口内,并且球在开口下方时,球就会落入桶中,如 图 3 中最右边的屏幕截图中所示。图 3. 光线投射光线投射非常适合以下环境中的简单形状(比如
中球落在桶中),其中给出了两个形状的速度向量的焦点,很容易确定它们是否已经发生碰撞。对于更复杂的场景,比如任意大小和形状的多边形之间的碰撞,分离轴定理是最可靠的(和最复杂的)碰撞检测技术之一。分离轴定理是将光线从两个不同的角度照射到两个多边形上的数学描述,如 图 4 中所示。如果多边形背后的墙上的影子露出空隙,那么多边形没有发生碰撞。图 4. 分离轴定理本文不会进一步介绍光线投射或分离轴定理。您可以在 Core HTML5 Canvas(Prentice Hall,2012 年)中查阅每种方法的深入讨论。(请参阅 ,获取相关链接。)Snail Bait 的碰撞检测Snail Bait 的碰撞检测涉及到相对较大的 sprite 以较低的速度移动,所以该游戏使用边界框检测碰撞。这些边界框如 图 5 所示。图 5. Snail Bait 的碰撞检测边界框 Snail Bait 将 sprite 活动(比如跑动、跳跃和爆炸)实现为 sprite 行为,请参阅文章 “”(developerWorks,2013 年 1 月),了解有关的更多信息。而且该游戏需要使用碰撞检测。在开发 Snail Bait 的时候,跑步小人有 3 种行为:她可以跑动、跳跃并与其他 sprite 碰撞。清单 1 给出了使用这 3 种行为来实例化跑步小人 sprite 的代码。清单 1. 跑步小人的行为Sprite = function () {
this.runner = new Sprite('runner',
this.runnerArtist,
[ this.runBehavior, // behaviors
this.jumpBehavior,
this.collideBehavior
};清单 2 给出了跑步小人的 collideBehavior 的代码。清单 2. 跑步小人的碰撞行为
var SnailBait =
function () {
// Runner's collide behavior...............................................
this.collideBehavior = {
execute: function (sprite, time, fps, context) {
// sprite is the runner
var otherS
for (var i=0; i & snailBait.sprites. ++i) {
otherSprite = snailBait.sprites[i];
if (this.isCandidateForCollision(sprite, otherSprite)) {
if (this.didCollide(sprite, otherSprite, context)) {
this.processCollision(sprite, otherSprite);
};因为 collideBehavior 对象是一种 sprite 行为,所以 Snail Bait 对每个动画帧都调用了它的 execute() 方法。而且因为 collideBehavior 对象与跑步小人有关联,所以 Snail Bait 传递给 execute() 方法的 sprite 始终是跑步小人。请参阅文章 “实现 sprite 行为” 中的
一节,了解 sprite 行为的更多信息。collideBehavior 对象的 execute() 方法封装了之前列出的 。最后 3 个步骤使用以下 collideBehavior 方法表示:isCandidateForCollision(sprite, otherSprite)didCollide(sprite, otherSprite, context)processCollision(sprite, otherSprite)以下各节将讨论每个方法的实现。选择碰撞检测的候选 spriteSnail Bait sprite 在满足一下条件时有资格与跑步小人 sprite 碰撞:该 sprite 不是跑步小人该 sprite 和跑步小人均可见该 sprite 或跑步小人均未爆炸collideBehavior 对象的 isCandidateForCollision() 方法(如 清单 3 中所示)会实现此逻辑。清单 3. 选择碰撞检测的候选 sprite:isCandidateForCollision()
var SnailBait =
function () {
isCandidateForCollision: function (sprite, otherSprite) {
return sprite !== otherSprite &&
// not same
sprite.visible && otherSprite.visible &&
// visible
!sprite.exploding && !otherSprite.
// not exploding
};接下来,我们将查看如何检测合格 sprite 之间的碰撞。检测跑步小人与另一个 sprite 之间的碰撞collideBehavior 对象的 didCollide() 方法确定跑步小人是否已与另一个 sprite 碰撞,如 清单 4 所示。清单 4. 检查碰撞:didCollide()
var SnailBait =
function () {
didCollide: function (sprite,
otherSprite, // candidate for collision
context) {
// for context.isPointInPath()
var left = sprite.left + sprite.offset,
right = sprite.left + sprite.offset + sprite.width,
top = sprite.top,
bottom = sprite.top + sprite.height,
centerX = left + sprite.width/2,
centerY = sprite.top + sprite.height/2;
// All the preceding variables -- left, right, etc. -- pertain to the runner sprite.
if (otherSprite.type !== 'snail bomb') {
return this.didRunnerCollideWithOtherSprite(left, top, right, bottom,
centerX, centerY,
otherSprite, context);
return this.didSnailBombCollideWithRunner(left, top, right, bottom,
otherSprite, context);
},didCollide() 方法计算跑步小人的边界框和它的中心,依据另一个 sprite 的身份,二者随后都传递给两个方法中的一个方法。如果另一个 sprite 不是蜗牛炸弹,那么 didCollide() 会调用 didRunnerCollideWithOtherSprite(),如 清单 5 所示:清单 5. didRunnerCollideWithOtherSprite() didRunnerCollideWithOtherSprite: function (left, top, right, bottom,
centerX, centerY,
otherSprite, context) {
// Determine if either of the runner's four corners or its
// center lies within the other sprite's bounding box.
context.beginPath();
context.rect(otherSprite.left - otherSprite.offset, otherSprite.top,
otherSprite.width, otherSprite.height);
return context.isPointInPath(left,
context.isPointInPath(right,
context.isPointInPath(centerX, centerY) ||
context.isPointInPath(left,
context.isPointInPath(right,
},如果给定了跑步小人的边界框和它的中心坐标,那么 didRunnerCollideWithOtherSprite() 会检查一个边界框的角或它的中心是否位于另一个 sprite 的边界框内。确定某个点是否位于一个矩形内,这不需要大量数学敏锐力;但是,HTML5 canvas 元素的 2D 上下文通过 isPointInPath() 方法进一步简化了该操作,如果某个点位于 canvas 上下文的当前路径中,那么该方法将会返回 true。didRunnerCollideWithOtherSprite() 方法通过调用 beginPath() 和 rect() 创建了一个矩形路径来表示另一个 sprite 的边界框。didRunnerCollideWithOtherSprite() 方法随后调用 isPointInPath() 来确定跑步小人内的 5 个点中是否有 1 个点位于另一个 sprite 的边界框内。didRunnerCollideWithOtherSprite() 方法能正确识别跑步小人与其他所有 sprite 之间的碰撞,除了蜗牛炸弹之外,如 图 6 中所示。图 6. 跑步小人和蜗牛炸弹它不适用于蜗牛炸弹,因为蜗牛炸弹非常小,它可穿过跑步小人,而且跑步小人的边界框的任何角或中心都不会与炸弹接触。由于跑步小人大小与炸弹大小的比例不当,当另一个 sprite 是炸弹时, 中的 didCollide() 方法会调用 didSnailBombCollideWithRunner(),如 清单 6 中所示。清单 6. didSnailBombCollideWithRunner() 方法
didSnailBombCollideWithRunner : function (left, top, right, bottom,
snailBomb, context) {
// Determine if the center of the snail bomb lies within
// the runner's bounding box
context.beginPath();
context.rect(left, top, right - left, bottom - top); // runner's bounding box
return context.isPointInPath(
snailBomb.left - snailBomb.offset + snailBomb.width/2,
snailBomb.top + snailBomb.height/2);
},didSnailBombCollideWithRunner() 方法与 didRunnerCollideWithOtherSprite() 相反:didRunnerCollideWithOtherSprite() 检查跑步小人中的点是否在另一个 sprite 内,而 didSnailBombCollideWithRunner() 检查另一个 sprite(炸弹)的中心是否在跑步小人内。您已经了解了如何使用边界框实现碰撞检测,但该技术可以更加准确且更有效地执行。在以下各节中,将介绍如何通过修改跑步小人的边界框和分割游戏的空间,细化 Snail Bait 的碰撞检测。细化边界框从
中可以看到,碰撞检测边界框封装了它表示的 sprite。但是,在接近这些边界框的角的地方,边界框内部常常是透明的。跑步小人 sprite 就属于这种情况,如 图 7 所示。这些透明区域可能导致错误碰撞,这在两个透明区域碰撞时尤为明显。图 7. 原始的跑步小人边界框消除透明角区域导致的错误碰撞的一种方法是,缩小 sprite 的边界框大小,如 图 8 中所示。图 8. 修改后的跑步小人边界框Snail Bait 通过修改的 didCollide() 方法缩小了跑步小人的边界框的大小,如 清单 7 中所示。清单 7. 修改跑步小人的边界框var SnailBait =
function () {
didCollide: function (sprite,
otherSprite, // candidate for collision
context) {
// for context.isPointInPath()
var MARGIN_TOP = 10,
MARGIN_LEFT = 10,
MARGIN_RIGHT = 10,
MARGIN_BOTTOM = 0,
left = sprite.left + sprite.offset + MARGIN_LEFT,
right = sprite.left + sprite.offset + sprite.width - MARGIN_RIGHT,
top = sprite.top + MARGIN_TOP,
bottom = sprite.top + sprite.height - MARGIN_BOTTOM,
centerX = left + sprite.width/2,
centerY = sprite.top + sprite.height/2;
};缩小跑步小人的边界框,会使 Snail Bait 的碰撞检测更准确,因为它消除了错误碰撞。接下来看看如何让碰撞检测更有效地执行。空间分割空间分割 涉及到将一个游戏的空间分割为单元,使得只有同一个单元中的 sprite 可能发生碰撞。通过消除对位于不同单元格中的 sprite 的碰撞检测,空间分割通常会显著提高性能。Snail Bait 就是通过分割空间来提高性能的,如 图 9 中所示。图 9. Snail Bait 的空间分割如 清单 8 所示,Snail Bait 将
中右侧区域中的所有 sprite 排除在碰撞检测之外,这显著减少了游戏执行的碰撞检测次数。清单 8. 细化用于碰撞检测的 sprite 选择this.isCandidateForCollision: function (sprite, otherSprite) {
return sprite !== otherSprite &&
sprite.visible && otherSprite.visible &&
!sprite.exploding && !otherSprite.exploding &&
otherSprite.left - otherSprite.offset & sprite.left + sprite.
},现在您已了解如何高效地检测碰撞,让我们看看 Snail Bait 如何处理碰撞。处理碰撞检测到碰撞后,必须对它们进行处理。Snail Bait 的 processCollision() 用于处理跑步小人与其他 sprite 之间的碰撞,这从 清单 9 中可以看到。清单 9. 处理碰撞:processCollision()var SnailBait =
function () {
processCollision: function (sprite, otherSprite) {
if ('coin'
=== otherSprite.type
// bad guys
'sapphire' === otherSprite.type ||
'ruby' === otherSprite.type
'button' === otherSprite.type
'snail bomb' === otherSprite.type) {
otherSprite.visible =
if ('bat' === otherSprite.type
// good guys
'bee' === otherSprite.type
'snail' === otherSprite.type ||
'snail bomb' === otherSprite.type) {
snailBait.explode(sprite);
if (sprite.jumping && 'platform' === otherSprite.type) {
this.processPlatformCollisionDuringJump(sprite, otherSprite);
};当跑步小人与好的东西(金币、蓝宝石、红宝石和纽扣)或与蜗牛炸弹碰撞时,Snail Bait 会让另一个 sprite 消失不见,将它的 visible 属性设置为 false。当跑步小人与坏东西(蝙蝠、蜜蜂、蜗牛和蜗牛炸弹)碰撞时,processCollision() 使用 Snail Bait 的 explode() 方法让跑步小人爆炸。目前,explode() 方法简单地将 BOOM 打印到控制台。本系列的下一篇文章将讨论 explode() 方法的最终实现。最后,清单 10 中的 processPlatformCollisionDuringJump() 方法在跑步小人跳跃时处理平台碰撞。清单 10. processPlatformCollisionDuringJump()processPlatformCollisionDuringJump: function (sprite, platform) {
var isDescending = sprite.descendAnimationTimer.isRunning();
sprite.stopJumping();
if (isDescending) { // Collided with platform while descending
// land on platform
sprite.track = platform.
sprite.top = snailBait.calculatePlatformTop(sprite.track) - sprite.
else { // Collided with platform while ascending
sprite.fall();
};当跑步小人在跳跃时与一个平台碰撞的时候,如果她处于跳跃的下降阶段,她会停止跳跃并落在平台上。如果跑步小人正在上升,她从下面与平台碰撞,那么她会降落。现在,跑步小人的 fall() 方法的实现如 清单 11 中所示。清单 11. 用于下降的 Stopgap 方法var SnailBait =
function () {
this.runner.fall = function () {
snailBait.runner.track = 1;
snailBait.runner.top = snailBait.calculatePlatformTop(snailBait.runner.track) -
snailBait.runner.
};跑步小人的 fall() 方法直接将跑步小人放在底部轨道上,即最矮的平台上。在本系列的下一篇文章中,您将了解如何使用逼真的下落来重新实现该方法,并考虑重力因素。监视碰撞检测性能碰撞检测很容易成为性能瓶颈,尤其是对于数学计算更加密集的碰撞检测算法,比如分离轴定理。本文介绍了一些可用来提高性能的简单技术,比如细化边界框和空间分割。但不断监视游戏的性能也是一个不错的想法,这样您就可以在出现性能问题后尽快发现和修复它们。所有现代浏览器都附带了复杂的开发环境;例如,Chrome、Safari、Firefox、Internet Explorer 和 Opera 都允许您分析正在运行的代码。图 10 显示了 Chrome 的探查器,该探查器描绘了您在各个方法中花费的时间与总时间的相对比例。图 10. 碰撞检测性能在
中可以看到,Snail Bait 的 didCollide() 方法仅花了游戏时间的 0.05%。(Self 列的 didCollide() 值为 0.01%,只表示直接花费在一个方法中的时间,不包括花费在该方法调用的方法中的时间。)当跑步小人与坏东西碰撞时,就会发生爆炸。接下来看看如何实现该爆炸。Sprite 动画图 11(从上到下)演示了在跑步小人遇到坏东西(比如一只蜜蜂)时,Snail Bait 显示的爆炸动画。图 11. 跑步小人在一次碰撞后爆炸Snail Bait 使用 sprite 动画生成器 实现 sprite 动画,如
中所示的动画。sprite 动画生成器更改一个 sprite 的一段被指定持续时间绘制的单元。例如,爆炸 sprite 动画生成器在 500 毫秒内将跑步小人的动画单元更改为 图 12 中所示的单元。图 12. 来自 Snail Bait 的 spritesheet 的爆炸单元sprite 动画生成器对象的构造函数如 清单 12 中所示。清单 12. Sprite 动画生成器构造函数// Sprite Animators...........................................................
var SpriteAnimator = function (cells, duration, callback) {
this.cells =
this.duration = duration || 1000;
this.callback =
};SpriteAnimator 构造函数接受 3 个参数。第一个参数是 Snail Bait 的 spritesheet 中的一个边界框数组;这些边界框是临时动画单元,该参数是强制性的。第二和第三个参数是可选的。第二个参数是动画持续时间,第三个参数是一个回调函数,在超过动画持续时间时,sprite 动画生成器会调用该函数。SpriteAnimator 方法在对象的原型中定义,如 清单 13 中所示。清单 13. Sprite 动画生成器方法SpriteAnimator.prototype = {
start: function (sprite, reappear) {
var originalCells = sprite.artist.cells,
originalIndex = sprite.artist.cellIndex,
sprite.artist.cells = this.
sprite.artist.cellIndex = 0;
setTimeout(function() {
sprite.artist.cells = originalC
sprite.artist.cellIndex = originalI
sprite.visible =
if (self.callback) {
self.callback(sprite, self);
}, self.duration);
};SpriteAnimator 的 start() 方法会启动动画,保存原始动画单元和指向当前单元的索引,分别将它们替换为临时单元和 0。然后,在动画持续时间过去后,start() 方法将 sprite 的动画单元和原始索引恢复到动画发生之前的状态。清单 14 显示了 Snail Bait 如何使用一个 sprite 动画生成器让跑步小人爆炸。清单 14. 创建爆炸动画生成器var SnailBait =
function () {
this.canvas = document.getElementById('game-canvas'),
this.context = this.canvas.getContext('2d'),
this.RUN_ANIMATION_RATE = 17,
// frames/second
this.EXPLOSION_CELLS_HEIGHT = 62, // pixels
this.EXPLOSION_DURATION = 500,
// milliseconds
this.explosionCells = [
{ left: 1,
top: 48, width: 50, height: this.EXPLOSION_CELLS_HEIGHT },
{ left: 60,
top: 48, width: 68, height: this.EXPLOSION_CELLS_HEIGHT },
{ left: 143, top: 48, width: 68, height: this.EXPLOSION_CELLS_HEIGHT },
{ left: 230, top: 48, width: 68, height: this.EXPLOSION_CELLS_HEIGHT },
{ left: 305, top: 48, width: 68, height: this.EXPLOSION_CELLS_HEIGHT },
{ left: 389, top: 48, width: 68, height: this.EXPLOSION_CELLS_HEIGHT },
{ left: 470, top: 48, width: 68, height: this.EXPLOSION_CELLS_HEIGHT }
this.explosionAnimator = new SpriteAnimator(
this.explosionCells,
// Animation cells
this.EXPLOSION_DURATION,
// Duration of the explosion
function (sprite, animator) { // Callback after animation
sprite.exploding =
if (sprite.jumping) {
sprite.stopJumping();
else if (sprite.falling) {
sprite.stopFalling();
sprite.visible =
sprite.track = 1;
sprite.top = snailBait.calculatePlatformTop(sprite.track) - sprite.
sprite.artist.cellIndex = 0;
sprite.runAnimationRate = snailBait.RUN_ANIMATION_RATE;
}; Snail Bait 使用
中所示的动画调用创建了一个 sprite 动画生成器。该动画的持续时间为 500ms,在结束爆炸时,sprite 动画生成器调用爆炸动画生成器的回调函数,后者将跑步小人放在最底层的平台堆栈上。不幸的是,在以后的一篇文章中,我们将重新实现这个回调函数,减去一条命并重新启动当前级别。清单 15 显示了跑步小人的 explode() 方法(有点虎头蛇尾)。清单 15. Snail Bait 的 explode() 方法SnailBait.prototype = {
explode: function (sprite, silent) {
if (sprite.runAnimationRate === 0) {
sprite.runAnimationRate = this.RUN_ANIMATION_RATE;
sprite.exploding =
this.explosionAnimator.start(sprite, true);
// true means sprite reappears
};当跑步小人跳跃时,没有动画效果,因为她的动画速率为 0。explode() 方法将她的动画速率设置为标准值,以便她能够以动画形式进入爆炸单元。然后,explode() 方法将跑步小人的 exploding() 属性设置为 true 并启动爆炸动画生成器。结束语在本
的下一篇文章中,您将看到如何通过纳入重力来实现逼真的下落过程,以及如何向 Snail Bait 添加声音和音乐。
下载资源 (wa-html5-game8-code.zip | 1.2MB)相关主题(David Geary,Prentice Hall,2012 年):David Geary 的这部图书广泛介绍了 Canvas API 和游戏开发。另请参阅 。 (Wikipedia):了解空间分割。:观看 David Geary 2013 年 2 月 20 日为 Atlanta HTML 5 User Group 所做的演示。:在任何启用了 HTML5 的浏览器(最好是 Chrome V18 及以上版本)中在线玩 Snail Bait。:观看 David Geary 在 Strange Loop 2011 中所做的演示。:观看 David Geary 在 2011 年挪威开发者大会 (NDC) 上所做的演示。 (Wikipedia):了解平台游戏。 (Wikipedia):了解 side-scroller 视频游戏。:您可以下载这个面向 Android 的流行开源平台视频频游的资源。Snail Bait 的大部分 sprite 都来自 Replica Island(需要权限才能使用)。:查找涵盖各种基于 Web 的解决方案的文章。参阅 ,查找众多技术文章和技巧、教程、标准和 IBM 红皮书。:下载或 ,动手使用来自 DB2、Lotus、Rational、Tivoli 和 WebSphere 的应用程序开发工具和中间件产品。:立即加入,关注 developerWorks 推文。
添加或订阅评论,请先或。
有新评论时提醒我
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Web development, Java technologyArticleID=929120ArticleTitle=HTML5 2D 游戏开发: 碰撞检测和 sprite 动画publish-date=Unity里面为Sprite添加边框写的的shader - lynon的专栏 - CSDN博客
Unity里面为Sprite添加边框写的的shader
小boss让我写个shader加到sprite上,然后发现了一个神奇的问题,
Sprite的vertex在哪?现在考虑一种Sprite,它的内容没有占满整个
sprite的rect(就是你能拖动的rect),其他地方是透明的。这种sprite
的顶点既不是rect的四个顶点,也不在图像内容的边界上,而是系统
自动生成的一个多边形,这个多边形比图像内容大,把图像内容包括
那么我现在想弄一个效果,原sprite的背后弄个影子,对于新创建的
sprite,他的shader是内置的。只能自己新建一个material,然后把做
sprite的png图像拖到material的tex里。
主要是怎么排除多边形内部的透明部分,其实就是用 Blend One One让
该部分与当前屏幕的颜色混合就行,具体看代码。另外我又发现一个问题,
可能是个偶然会出现的bug还是什么,两个自定义的shader内容完全一致(除了
文件名字和第一行的shader“XXX”),竟然有一个会得出异常结果。
Shader&&Custom/Fragment&extend&&{
&&&&Properties&{
&&&&&&&&_Color&(&Surround&Color&,&Color)&=&(0.2,0.2,0.2,0.7)
&&&&&&&&_MainTex&(&Base&(RGB)&,&2D)&=&&white&&{}
&&&&&&&&_Range(&Range&,Range(0.1,0.3))&=&0.15
&&&&&&&&//_Range2(&Range&,Range(0.1,10))=0.5
&&&&SubShader&{
&&&&//Tags{&RenderType&=&Transparent&}
&&&&&&&&//Tags&{&Queue&=&Transparent&&&IgnoreProjector&=&True&&&RenderType&=&Transparent&&}
&&&&&&&&LOD&100
&&&&&&&&Blend&One&One
&&&&&&&&CGPROGRAM
&&&&&&&&&&&&#pragma&vertex&vert
&&&&&&&&&&&&#pragma&fragment&frag
&&&&&&&&&&&&#include&&UnityCG.cginc&
&&&&&&&&&&&&&float&_Range;
&&&&&&&&&&&&&sampler2D&_MainTex;
&&&&&&&&&&&&&float&_Range2;
&&&&&&&&&&&&&float4&_Color;
&&&&&&&&&&&&&struct&appdata_t
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&float4&vertex&:&POSITION;
&&&&&&&&&&&&&&&&//half4&color&:&COLOR;
&&&&&&&&&&&&&&&&float2&texcoord&:&TEXCOORD0;
&&&&&&&&&&&&};
&&&&&&&&&&&&struct&v2f
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&float4&vertex&:&POSITION;
&&&&&&&&&&&&&&&&//half4&color&:&COLOR;
&&&&&&&&&&&&&&&&float2&texcoord&:&TEXCOORD0;
&&&&&&&&&&&&&&&&//float2&worldPos&:&TEXCOORD1;
&&&&&&&&&&&&};
&&&&&&&&&&&&v2f&vert&(appdata_t&v)
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&v2f&o;
&&&&&&&&&&&&&&&&v.vertex.xyz+=_Range*v.vertex.xyz;
&&&&&&&&&&&&&&&&//v.vertex.xy+=_Range2;
&&&&&&&&&&&&&&&&o.vertex&=&mul(UNITY_MATRIX_MVP,v.vertex);
&&&&&&&&&&&&&&&&//o.texcoord=TRANSFORM_TEX(v.texcoord,_MainTex);
&&&&&&&&&&&&&&&&o.texcoord=v.texcoord;
&&&&&&&&&&&&&&&&return&o;
&&&&&&&&&&&&}
&&&&&&&&&&&&half4&frag&(v2f&IN)&:&COLOR
&&&&&&&&&&&&{
&&&&&&&&&&&&half4&I=tex2D(_MainTex,IN.texcoord);
&&&&&&&&&&&&if(I.a&0.4)
&&&&&&&&&&&&{
&&&&&&&&&&&&&I.rgb=0f;
&&&&&&&&&&&&&I.a=0f;
&&&&&&&&&&&&}
&&&&&&&&&&&&else
&&&&&&&&&&&&I.rgb*=_Color.rgb;
&&&&&&&&&&&&return&I;
&&&&&&&&&&&&}&
&&&&&&&&&&&&ENDCG
&&&&&&&&Pass{
&&&&&&&&Blend&One&One
&&&&&&&&CGPROGRAM
&&&&&&&&&&&&#pragma&vertex&vert
&&&&&&&&&&&&#pragma&fragment&frag
&&&&&&&&&&&&#include&&UnityCG.cginc&
&&&&&&&&&&&&&float&_Range;
&&&&&&&&&&&&&sampler2D&_MainTex;
&&&&&&&&&&&&&float4&_Color;
&&&&&&&&&&&&struct&appdata_t
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&float4&vertex&:&POSITION;
&&&&&&&&&&&&&&&&//half4&color&:&COLOR;
&&&&&&&&&&&&&&&&float2&texcoord&:&TEXCOORD0;
&&&&&&&&&&&&};
&&&&&&&&&&&&struct&v2f
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&float4&vertex&:&POSITION;
&&&&&&&&&&&&&&&&//half4&color&:&COLOR;
&&&&&&&&&&&&&&&&float2&texcoord&:&TEXCOORD0;
&&&&&&&&&&&&&&&&//float2&worldPos&:&TEXCOORD1;
&&&&&&&&&&&&};
&&&&&&&&&&&&v2f&vert&(appdata_t&v)
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&v2f&o;
&&&&&&&&&&&&&&&&//v.vertex.xyz+=_Range*v.vertex.xyz;
&&&&&&&&&&&&&&&&o.vertex&=&mul(UNITY_MATRIX_MVP,&v.vertex);
&&&&&&&&&&&&&&&&//o.texcoord=TRANSFORM_TEX(v.texcoord,_MainTex);
&&&&&&&&&&&&&&&&o.texcoord=v.texcoord;
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&return&o;
&&&&&&&&&&&&}
&&&&&&&&&&&&half4&frag&(v2f&IN)&:&COLOR
&&&&&&&&&&&&{
&&&&&&&&&&&&half4&I=tex2D(_MainTex,IN.texcoord);
&&&&&&&&&&&&if(I.a&0.4)
&&&&&&&&&&&&{
&&&&&&&&&&&&//&I.rgb=0;
&&&&&&&&&&&&//&I.a=0;
&&&&&&&&&&&&I=0;
&&&&&&&&&&&&//I.rgba=0;
&&&&&&&&&&&&}
&&&&&&&&&&&&return&I;
&&&&&&&&&&&&}&
&&&&&&&&&&&&ENDCG
&&&&&&&&//Pass{
&&&&&&&&//&&&&Tags{&Queue&=&Transparent&&&IgnoreProjector&=&True&&&RenderType&=&Transparent&}
&&&&&&&&//&&&&Blend&One&Zero
&&&&&&&&//&&&&SetTexture&[_MainTex]
&&&&&&&&//&&&&{
&&&&&&&&//&&&&&&&&Combine&Texture
&&&&&&&&//&&&&}
&&&&&&&&//}
&&&&//&third&part
&&&&FallBack&&VertexLit&
我的热门文章

我要回帖

更多关于 超时空要塞边界 的文章

 

随机推荐