当前位置:  编程技术>移动开发
本页文章导读:
    ▪(译)怎么使用CCRenderTexture来创建动态纹理        (译)如何使用CCRenderTexture来创建动态纹理 免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播。同时,转载时不要移除本申.........
    ▪ Bit地图总结        Bitmap总结   android Bitmap学习总结 BitMap类: public void recycle()——回收位图占用的内存空间,把位图标记为Dead public final boolean isRecycled() ——判断位图内存是否已释放 public final int getWidth()—.........
    ▪ 获取图库相片       获取图库照片 当要进分享照片功能时,点击一个按钮,然后进入图库选择照片, 要进行这样的操作,改怎么完成呢,要解决2个问题: 1、该如何进入图库 2、改如何取得照片 =====================.........

[1](译)怎么使用CCRenderTexture来创建动态纹理
    来源: 互联网  发布时间: 2014-02-18
(译)如何使用CCRenderTexture来创建动态纹理

免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播。同时,转载时不要移除本申明。如产生任何纠纷,均与本博客所有人、发表该翻译稿之人无任何关系。谢谢合作!

原文链接地址:http://www.raywenderlich.com/3857/how-to-create-dynamic-textures-with-ccrendertexture

教程截图:

 

  对于事先制作好的背景图片,我想你已经非常熟知如何把它们添加进游戏里面了。但是,你有没有想过动态地创建背景图片并且修改它们的颜色,梯度(gradients)及实时改变效果呢?

  如果你玩过App Store 上面,由Andreas Illiger制作的Tiny Wings游戏的话,实际上你已经体验过上面提及的想法了。

  在这个系列的教程中,你将会学习到所有这些技术要点:

  • 如何用代码实时动态创建纹理
  • 如何使用Gimp创建无缝拼接的纹理
  • 如何混合阴影和光照来增强现实效果
  • 如何创建带状纹理
  • 如何制作重复纹理
  • 还有更多!

  这个教程是基于Sergey Tikhonov在cocos2d论坛里面讨论“如何制作Tiny Wings”时所制作的一个样例工程来制作的。

  Sergey在demo工程上面做了一件非常好的工作,因此,为了不重复发明轮子,我将把他的代码转换成一个系列的教程,同时还添加了一些很酷的特性。

  这个教程假设你对于cocos2d已经非常熟悉了。如果你对cocos2d还很陌生的话,建议你先看看我博客上面的其它cocos2d 教程。

使用CCRenderTexture来动态创建纹理

  Tiny Wings有一个很酷的特性就是,每一天都会改变纹理,就如同下面的游戏截屏一下:

  但是,你怎么在cocos2d里面来动态创建纹理呢?好吧,其实有一个很酷的类,叫CCRenderTexture,它允许你来动态创建纹理,并且可以在游戏中重用这些纹理。

  使用 CCRenderTexture非常简单 – 你只需要做以下5步就行了:

  • 创建一个新的CCRenderTexture. 这里,你可以指定将要创建的纹理的宽度和高度。.
  • 调用 CCRenderTexture:begin. 这个方法会启动OpenGL,并且接下来,任何绘图的命令都会渲染到CCRenderTexture里面去,而不是画到屏幕上。
  • 绘制纹理. 你可以使用原始的OpenGL调用来绘图,或者你也可以使用cocos2d对象里面已经定义好的visit方法。(这个visit方法就会调用一些opengl命令来绘制cocos2d对象)
  • 调用 CCRenderTexture:end. 这个方法会渲染纹理,并且会关闭渲染至CCRenderTexture的通道。
  • 从生成的纹理中创建一个sprite. 你现在可以用CCRenderTexture的sprite.texture属性来轻松创建新的精灵了。
  •   让我们来实践一下具体这个过程是如何工作的,我们先来创建一个简单的单色的纹理。

      但是,首先,你需要一个新的工程!因此,打开Xcode,点击File\New\New Project,然后选择 iOS\cocos2d\cocos2d_box2d template。尽管这个教程并没有使用到box2d,但是,我们后续的教程会用到,所以,我在这里就提前先建立好。

      把工程命名为TinySeal,点击Next,然后选择磁盘上的一个文件夹并点击Create。

      然后,打开HelloWorldLayer.h,并用以下内容替换之:

    #import "cocos2d.h"

    @interface HelloWorldLayer : CCLayer
    {
    CCSprite * _background;
    }

    +(CCScene *) scene;

    @end

      这里移除掉了"Hello,World“box2d的代码,并且往里面添加了一个实例变量来追踪我们将要动态创建的背景。

      接下来,打开HelloWorldLayer.m,并把它替换成下面的样子:(只需要把box2d相关代码全部删除并且得到一个空的场景就可以了)  

    #import "HelloWorldLayer.h"

    @implementation HelloWorldLayer

    +(CCScene *) scene {
    CCScene *scene = [CCScene node];
    HelloWorldLayer *layer = [HelloWorldLayer node];
    [scene addChild: layer];
    return scene;
    }

    -(id) init {
    if((self=[super init])) { 
    }
    return self;
    }
    @end

      你现在可以编译并运行一下,你将会看到一个黑色的屏幕。

      接下来,在init方法的上面添加下面的新方法:

    -(CCSprite *)spriteWithColor:(ccColor4F)bgColor textureSize:(float)textureSize {

    // 1: Create new CCRenderTexture
    CCRenderTexture *rt = [CCRenderTexture renderTextureWithWidth:textureSize height:textureSize];

    // 2: Call CCRenderTexture:begin
    [rt beginWithClear:bgColor.r g:bgColor.g b:bgColor.b a:bgColor.a];

    // 3: Draw into the texture
    // We'll add this later

    // 4: Call CCRenderTexture:end
    [rt end];

    // 5: Create a new Sprite from the texture
    return [CCSprite spriteWithTexture:rt.sprite.texture];

    }

      你可以看到,这里动态创建纹理所采用的五个步骤和我们之前讨论的一模一样。

      注意,我们这里不是调用的CCRenderTexture:begin方法,而是调用另外一个较方便的方法beginWithClear:g:b:a:,这个方法可以用给定的颜色来清除纹理的背景,相当于设置画布的颜色。

      我们还没有在画布上画任何东西--目前为止,我们仅仅是看看纯色纹理看起来是什么样子.

      把上面所讨论的一起打包起来,并且添加一些新的方法,然后把init方法改成下面的样子:

    - (ccColor4F)randomBrightColor {

    while (true) {
    float requiredBrightness =192;
    ccColor4B randomColor = 
    ccc4(arc4random() %255,
    arc4random() %255, 
    arc4random() %255, 
    255);
    if (randomColor.r > requiredBrightness || 
    randomColor.g > requiredBrightness ||
    randomColor.b > requiredBrightness) {
    return ccc4FFromccc4B(randomColor);

    }

    }

    - (void)genBackground {

    [_background removeFromParentAndCleanup:YES];

    ccColor4F bgColor = [self randomBrightColor];
    _background = [self spriteWithColor:bgColor textureSize:512];

    CGSize winSize = [CCDirector sharedDirector].winSize;
    _background.position = ccp(winSize.width/2, winSize.height/2); 
    [self addChild:_background z:-1];

    }

    -(id) init {
    if((self=[super init])) { 
    [self genBackground];
    self.isTouchEnabled = YES; 
    }
    return self;
    }

    - (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    [self genBackground];

    }

      randomBrightColor方法是一个辅助方法,用来创建一种随机颜色。注意,这里使用ccc4B(因此,我们能够在0-255的范围内指定R/G/B/A值),同时确保至少有一个颜色分量是大于192的,这样的话,我们就不会得到较暗的颜色。

      然后,genBackground调用我们之前写的spriteWithColor方法,同时把它加屏幕中央。

      至于init函数,它调用genBackground方法,同时激活touches事件,这样的话,你就可以通过点击屏幕来获得另外的随机背景了。

      编译并运行,这样你每一次点击屏幕,你都可以得到一张不同的单色背景图片啦!

    往纹理里面加点噪声

      在Tiny Wings里面,你可能已经注意到了,那纹理并不只是纯粹的单色---而是被一些噪声所修饰了一下,这样,看起来的话就会有阴影和光照。

      你可以用代码来动态地生成了一些噪声,但是,如果使用一些预先制作的噪声的话,那样速度会更快一些--这也是我接下来将要在教程里所使用的方法:

      一种比较简单的方法,就是使用一个免费的图片处理程序,叫做Gimp。接下来这一部分将向您展示如何动手制作这样一个噪声纹理,如果你不乐意自己动手制作那张蒙板,可以用我提供的这张。

      当然,你也可以下载我已经做好了的噪声图片,并且把它添加到工程里面去,同时可以跳过接下来的部分了:)

      如果你想继续,那么先下载Gimp,并且安装好。

      安装好之后,打开Gimp,选择 File\New,然后创建一张新的512*512的图片。然后选择 Filter\Render\Clouds\Solid Noise,并且可以调节一些参数来看看效果,调好之后就点击Ok吧。

      你可以会得到和下图差不多的图片:

      我们将使用这张图片去乘以纹理的颜色。因此,噪声图片中白色的部分,纹理中的颜色就会被显示出来,而噪声图片中黑色的地方,纹理图片对应部位的颜色就会被变暗。

      上图中可以看出,黑色部分占太多了,这样会影响我们的原图效果。因此,我们要把黑色的部位去掉一些,选择 Colors\Levels,然后”Output Levels“的最左边的滑动条,把它拖到右边去一点,这样我们的噪声图片就会明亮一些啦。

      当你做完之后就点击ok,然后,还有最后一步,这个噪声图片纹理要制作成无缝拼接的,因此,这样我们才能制作无限滚动的背景。

      Gimp使用得这个功能变得非常简单。只需要点击Filters\Map\Make Seamless就行了!

      使用File\Save As来保存你的图片为Noise.png。然后使用Finder打开并拖到TinySeals工程中去。确保“Copy items into destination group’s folder”被复选中,然后点击Finish。

      恭喜你,现在你有一张噪声纹理了,位下来,你可以使用它来创建更加真实的纹理效果了!

      现在,你知道怎么动态创建纹理了,并且你可以使用Gimp的滤镜来制作一些不同的效果!

    往纹理中添加噪声

      现在,你有一张带噪声的图片了,接下来,让我们把它添加到CCRenderTexture里去吧。

      在spriteWithColor:textureSize方法里面,我们在注释中所示的第3步,添加下列代码:

    CCSprite *noise = [CCSprite spriteWithFile:@"Noise.png"];
    [noise setBlendFunc:(ccBlendFunc){GL_DST_COLOR, GL_ZERO}];
    noise.position = ccp(textureSize/2, textureSize/2);
    [noise visit];

      这里使用噪声纹理来创建一个精灵,然后把它放置在render texture的中心位置,并且调用visit方法。这个visit方法就是一系列的opengl调用,且这些调用是用来画这个纹理的。

      这里只有一个诡异的地方----就是"setBlendFunc“方法。这玩意儿倒底干吗的呢?

      好吧,这第一个常量(GL_DST_COLOR)指定如何乘以输入图像/源图像的颜色数据(也就是指噪声图像),第二个参数(GL_ZERO)指定如何乘以已经存在的图像/目标图像颜色数据(实际上就是之前的单色纹理)。

      因此,阐述一下:

    • 已经存在的颜色乘以GL_ZERO,那意味着已经存在的颜色将会被清除掉。
    • 噪声纹理颜色乘以GL_DST_COLOR。而GL_DST_COLOR意味着已经存在的颜色,因此噪声颜色会乘以已经存在的颜色。所以,如果噪声中白色越多,那么对应位置的源图像位置显示的颜色也就越亮。如果噪声颜色中越多黑色,那么源图像的颜色就会变得越暗。
    • 上面提及的两种颜色叠加到一起,但是,由于指点一个参数是0,所以,实际上还是看第二个参数的影响。

      顺便提一下,我发现这些混合常量非常容易使人迷惑,但是,我们很幸运,这里有一款免费的在线工具,可以用来动态地配置每种常量的效果。

      不管怎么说,这就是你所需要的全部东西啦!编译并运行你的代码,现在,你可以看到纹理的一些阴影效果了。注意,这个在模拟器上看起来效果通常不是很好,你可能需要在实际的设备上尝试一下会比较好。

    往纹理中添加梯度

      为了使纹理看起来更好看,让我们从上至下添加一些梯度吧,具体的效果是纹理从上到下,会变得越来越暗。

      我们也可以使用Gimp来修改我们的噪声图片,但是,这一次,我们可以在代码中来完成,这样会变得更加动态,并且可以很容易地修改。

      基本的想法就是,我们在纹理的顶部画一个黑色的矩形,但是,它将会是上部完全透明的,并且底部完全不透明。这样会使得上面比较亮,而慢慢得往下变暗。

      为了实现这个目标,我们需要使用一些opengl命令。如果你对opengl不熟悉的话,也不用担心---我会帮你写好这些代码,并且在高层向你解释具体是如何工作的。在教程的结尾,你会得到一些参考资料,通过它们你可以获得更多的信息。

      在spriteWithColor:textureSize里面,在创建噪声精灵之前,添加下列代码:

    glDisable(GL_TEXTURE_2D);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    float gradientAlpha =0.7; 
    CGPoint vertices[4];
    ccColor4F colors[4];
    int nVertices =0;

    vertices[nVertices] = CGPointMake(0, 0);
    colors[nVertices++] = (ccColor4F){0, 0, 0, 0 };
    vertices[nVertices] = CGPointMake(textureSize, 0);
    colors[nVertices++] = (ccColor4F){0, 0, 0, 0};
    vertices[nVertices] = CGPointMake(0, textureSize);
    colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};
    vertices[nVertices] = CGPointMake(textureSize, textureSize);
    colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};

    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glColorPointer(4, GL_FLOAT, 0, colors);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)nVertices);

    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glEnable(GL_TEXTURE_2D);

      第一件事情就是禁用GL_TEXTURE_2D 和 GL_TEXTURE_COORD_ARRA两个opengl状态,因为,我们接下来只需要绘制颜色---这与纹理无关。

      一个比较奇怪的事就是,这里绘制纹理的时候,左上角是坐标原点(0,0)---而不是我们在cocos2d里面使用的,0,0点在左下角。

      因此,接下来,我们定义纹理的四个顶点坐标左上、右上、左下、右下--并且同时指定每一个点的颜色值。

      你可能会奇怪,为什么顶点会以这样的顺序被定义出来。但是因为,我们将按下图的方式来画两个三角形,当然这两个三角形拼成了一个矩形:

      我们的将使用GL_TRIANGLE_STRIP来画这些三角形,那意味着,顶点数组中的前三个顶点组成第一个三角形,而第二个三角形就是前面2,3号顶点,再加上下一个新的顶点组成第二个三角形。

      因此,第一个三角形是由顶点v0,v1,v2组成,而第二个则由v1,v2,v3组成。

      在定义完顶点数组和颜色数组以后,我们把它们传给glVertexPointer opengl调用(每一个顶点用2个浮点数标识)和glColorPointer调用(每个颜色值指定4个浮点数),然后调用glDrawArrays,并且指定 GL_TRIANGLE_STRIP为参数来绘制三角形带。

      最后,我们重新激活GL_TEXTURE_COORD_ARRAY 和 GL_TEXTURE_2D两个状态,这样做的话是保持和之前调用的对称,并且不会破坏opengl状态机。

      编译并运行代码,然后你会看到一个整齐的带有梯度的纹理啦!

    创建带状纹理

      在我们开始写代码来绘制带状纹理之前,让我们先花上一分钟时间来想一想我们的策略。

      我们将从指定纹理为一种颜色开始(如下图的蓝色部分),然后,我们将以对角线的方向画一些三角带子(如下图绿色部分),如图所示:

      注意,因为带子是呈对角线的,我们实际上将要在纹理的边界之外就绘制这条带子。(如上图v0,v1,v2所示)

      还有一点需要注意,为了获得一个比较好的45度的效果,我们将把V0偏移原点texture size的距离。

      好了,让我们来看看实际的代码是什么样子的吧。在init的方法上面添加一个新的方法,如下所示:

    -(CCSprite *)stripedSpriteWithColor1:(ccColor4F)c1 color2:(ccColor4F)c2 textureSize:(float)textureSize stripes:(int)nStripes {

    // 1: Create new CCRenderTexture
    CCRenderTexture *rt = [CCRenderTexture renderTextureWithWidth:textureSize height:textureSize];

    // 2: Call CCRenderTexture:begin
    [rt beginWithClear:c1.r g:c1.g b:c1.b a:c1.a];

    // 3: Draw into the texture 

    // Layer 1: Stripes
    glDisable(GL_TEXTURE_2D);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);

    CGPoint vertices[nStripes*6];
    int nVertices =0;
    float x1 =-textureSize;
    float x2;
    float y1 = textureSize;
    float y2 =0;
    float dx = textureSize / nStripes *2;
    float stripeWidth = dx/2;
    for (int i=0; i<nStripes; i++) {
    x2 = x1 + textureSize;
    vertices[nVertices++] = CGPointMake(x1, y1);
    vertices[nVertices++] = CGPointMake(x1+stripeWidth, y1);
    vertices[nVertices++] = CGPointMake(x2, y2);
    vertices[nVertices++] = vertices[nVertices-2];
    vertices[nVertices++] = vertices[nVertices-2];
    vertices[nVertices++] = CGPointMake(x2+stripeWidth, y2);
    x1 += dx;
    }

    glColor4f(c2.r, c2.g, c2.b, c2.a);
    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glDrawArrays(GL_TRIANGLES, 0, (GLsizei)nVertices);

    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glEnable(GL_TEXTURE_2D);

    // Layer 2: Noise 
    CCSprite *noise = [CCSprite spriteWithFile:@"Noise.png"];
    [noise setBlendFunc:(ccBlendFunc){GL_DST_COLOR, GL_ZERO}];
    noise.position = ccp(textureSize/2, textureSize/2);
    [noise visit];

    // 4: Call CCRenderTexture:end
    [rt end];

    // 5: Create a new Sprite from the texture
    return [CCSprite spriteWithTexture:rt.sprite.texture];

    }

      这个方法的大部分内容都是重温如何创建一个CCRenderTexture,只有创建带状层的代码是新加的。所以让我们来讨论一下。

      它首先创建了一个顶点数组--对于每一条带子,我们需要6个顶点--3个顶点*2个三角形。我们这里不能使用三角形带,因为,带子不是邻接在一起的。

      第一个顶点的坐标是 (-textureSize, textureSize),上面的图示中也可以看出来,接下来一个顶点就是 (-textureSize+stripWidth, textureSize).第三个顶点是(0,0),而第四个顶点是(stripeWidth, textureSize).这些就是我们画一个带子所需要的全部顶点,而且每一次我们往前递增两个带子的长度,并且继续,直至所有的带子都制作完成。

      现在,你可以把genBackground修改成下面的样子了:

    - (void)genBackground {

    [_background removeFromParentAndCleanup:YES];

    ccColor4F bgColor = [self randomBrightColor];
    ccColor4F color2 = [self randomBrightColor];
    //_background = [self spriteWithColor:bgColor textureSize:512];
    int nStripes = ((arc4random() %4) +1) *2;
    _background = [self stripedSpriteWithColor1:bgColor color2:color2 textureSize:512 stripes:nStripes];

    self.scale =0.5;

    CGSize winSize = [CCDirector sharedDirector].winSize;
    _background.position = ccp(winSize.width/2, winSize.height/2); 
    [self addChild:_background];

    }

      这里调用新的方法,同时修改层的scale为0.5,这样的话就能看到512*512的纹理的全貌。

      编译并运行,现在,你每点击一下屏幕都可以得到一张不同的带状的纹理了!

    重复背景

      对于带状背景和梯度背景,我们都希望它比实际定义的512*512的区域要大。

      一种比较简单的方式就是我们创建多个CCSprites,然后把它们链接在一起。但是,那看起来太疯狂了,因为,我们有更加简单的方法---我们可以设置纹理并让它们重复。

      打开HelloWorldLayer.m,并作如下修改:

     

    // Add to genBackground, right BEFORE the call to addChild
    ccTexParams tp = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT};
    [_background.texture setTexParameters:&tp];

    // Add to bottom of init
    [self scheduleUpdate];

    // Add after init
    - (void)update:(ccTime)dt {

    float PIXELS_PER_SECOND =100;
    staticfloat offset =0;
    offset += PIXELS_PER_SECOND * dt;

    CGSize textureSize = _background.textureRect.size;
    [_background setTextureRect:CGRectMake(offset, 0, textureSize.width, textureSize.height)];

    }

      这里最重要的就是纹理参数:

    • GL_LINEAR 是说“当显示纹理时,显示的大小大于或者小于原纹理的尺寸时,使用邻近像素点来插值补点”
    • GL_REPEAT是说“如果你想显示纹理边界之外的像素点时,把它旁边的纹理像素点平铺过去"

      同时,调用一个update定时器,更新纹理的x轴坐标,使前不断地前移。这样会使得纹理看起来随着时间不断地往前移动。

      编译并运行代码,这时你可以看到一个连续滚动的无限重复的背景纹理了!你也可以用带有梯度的纹理来尝试一下,一样可以跑起来。

    免费的光照

      如果你看一看Tiny Wings的山丘纹理实现,你会发现山的顶部有一些光照,同时从上到下还有一些梯度,并且这一切看起来非常棒!因此, 让我们修改我们前面的带状纹理。

      在stripedSpriteWithColor1方法中,紧接着glDrawArrays之后,添加下面代码:

    // layer 2: gradient
    glEnableClientState(GL_COLOR_ARRAY);

    float gradientAlpha =0.7; 
    ccColor4F colors[4];
    nVertices =0;

    vertices[nVertices] = CGPointMake(0, 0);
    colors[nVertices++] = (ccColor4F){0, 0, 0, 0 };
    vertices[nVertices] = CGPointMake(textureSize, 0);
    colors[nVertices++] = (ccColor4F){0, 0, 0, 0};
    vertices[nVertices] = CGPointMake(0, textureSize);
    colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};
    vertices[nVertices] = CGPointMake(textureSize, textureSize);
    colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};

    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glColorPointer(4, GL_FLOAT, 0, colors);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)nVertices);

    // layer 3: top highlight 
    float borderWidth = textureSize/16;
    float borderAlpha =0.3f;
    nVertices =0;

    vertices[nVertices] = CGPointMake(0, 0);
    colors[nVertices++] = (ccColor4F){1, 1, 1, borderAlpha};
    vertices[nVertices] = CGPointMake(textureSize, 0);
    colors[nVertices++] = (ccColor4F){1, 1, 1, borderAlpha};

    vertices[nVertices] = CGPointMake(0, borderWidth);
    colors[nVertices++] = (ccColor4F){0, 0, 0, 0};
    vertices[nVertices] = CGPointMake(textureSize, borderWidth);
    colors[nVertices++] = (ccColor4F){0, 0, 0, 0};

    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glColorPointer(4, GL_FLOAT, 0, colors);
    glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)nVertices);

      这段代码应该又是重新温习一遍啦,但是,第一部分和我们之前创建的梯度背景差不多,而第二部分创建光照的时候,我们从上至下添加,使之有太阳晒着的感觉。

      编译并运行代码,现在,你应该发现我们的带状纹理更加逼真了,有梯度变化又有光照效果!

    何去何从?

      这里有本教程的样例工程。

      如果你愿意的话,你可以尝试着修改一下噪声纹理,看一看你能不能创建出更酷的效果出来?或者,你可以修改一下上面的代码,调节调节参数,看看能不能得到更好的效果。如果你实践了,请你在评论部分分享你的结果。

      接下,我们将使用这些动态创建的纹理来制作一个类似Tiny Wings的游戏。请看本系列下一篇教程。

     

    著作权声明:本文由http://www.cnblogs.com/andyque翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!


        
    [2] Bit地图总结
        来源: 互联网  发布时间: 2014-02-18
    Bitmap总结

     


    android Bitmap学习总结


    BitMap类: 
    public void recycle()——回收位图占用的内存空间,把位图标记为Dead 
    public final boolean isRecycled() ——判断位图内存是否已释放 
    public final int getWidth()——获取位图的宽度 
    public final int getHeight()——获取位图的高度 
    public final boolean isMutable()——图片是否可修改 
    public int getScaledWidth(Canvas canvas)——获取指定密度转换后的图像的宽度 
    public int getScaledHeight(Canvas canvas)——获取指定密度转换后的图像的高度 
    public boolean compress(CompressFormat format, int quality, OutputStream stream)——按指定的图片格式以及画质,将图片转换为输出流。
    format:Bitmap.CompressFormat.PNG或Bitmap.CompressFormat.JPEG 
    quality:画质,0-100.0表示最低画质压缩,100以最高画质压缩。对于PNG等无损格式的图片,会忽略此项设置。 

    常用的静态方法:
  • public static Bitmap createBitmap(Bitmap src) ——以src为原图生成不可变得新图像 
  • public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, 
  •             int dstHeight, boolean filter)——以src为原图,创建新的图像,指定新图像的高宽以及是否可变。 
  • public static Bitmap createBitmap(int width, int height, Config config)——创建指定格式、大小的位图
  • public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height)以source为原图,创建新的图片,指定起始坐标以及新图像的高宽。
  • public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
  •              Matrix m, boolean filter)
  • 复制代码
    BitmapFactory工厂类: 
    Option 参数类: 
    public boolean inJustDecodeBounds——如果设置为true,不获取图片,不分配内存,但会返回图片的高度宽度信息。 
    public int inSampleSize——图片缩放的倍数。如果设为4,则宽和高都为原来的1/4,则图是原来的1/16。 
    public int outWidth——获取图片的宽度值 
    public int outHeight——获取图片的高度值 
    —————————————————————————————— 
    public int inDensity——用于位图的像素压缩比 
    public int inTargetDensity——用于目标位图的像素压缩比(要生成的位图) 
    public boolean inScaled——设置为true时进行图片压缩,从inDensity到inTargetDensity。 

    读取一个文件路径得到一个位图。如果指定文件为空或者不能解码成文件,则返回NULL。
  • public static Bitmap decodeFile(String pathName, Options opts) 
  • public static Bitmap decodeFile(String pathName)
  • 复制代码
    读取一个资源文件得到一个位图。如果位图数据不能被解码,或者opts参数只请求大小信息时,则返回NuLL。 
    (即当Options.inJustDecodeBounds=true,只请求图片的大小信息。)
  • public static Bitmap decodeResource(Resources res, int id) 
  • public static Bitmap decodeResource(Resources res, int id, Options opts)
  • 复制代码
    从输入流中解码位图 
    public static Bitmap decodeStream(InputStream is) 
    从字节数组中解码生成不可变的位图
  • public static Bitmap decodeByteArray(byte[] data, int offset, int length)
  • 复制代码
    BitmapDrawable类:继承于Drawable,你可以从文件路径、输入流、XML文件以及Bitmap中创建。 
    常用的构造函数: 
    Resources res=getResources();//获取资源 
    public BitmapDrawable(Resources res)——创建一个空的drawable。(Response用来指定初始时所用的像素密度)替代public BitmapDrawable()方法(此方法不处理像素密度)
  • public BitmapDrawable(Resources res, Bitmap bitmap)——Create drawable from a bitmap
  • public BitmapDrawable(Resources res, String filepath)——Create a drawable by opening a given file path and decoding the bitmap.
  • public BitmapDrawable(Resources res, java.io.InputStream is)——Create a drawable by decoding a bitmap from the given input stream.
  • 复制代码
    转:http://blog.csdn.net/xxxx1243/article/details/5834187 
    首先介绍我们最常用的Bitmap(位图)。位图是我们开发中最常用的资源,毕竟一个漂亮的界面对用户是最有吸引力的。按照对位图的操作,分为以下几个功能分别介绍: 
    从资源中获取位图 
    获取位图的信息 
    显示位图 
    位图缩放 
    位图旋转 
    1. 从资源中获取位图 
    可以使用BitmapDrawable或者BitmapFactory来获取资源中的位图。 
    当然,首先需要获取资源: Resources res=getResources(); 
    使用BitmapDrawable获取位图 
       1. 使用BitmapDrawable (InputStream is)构造一个BitmapDrawable; 
       2. 使用BitmapDrawable类的getBitmap()获取得到位图; 
    通过Resource的函数:InputStream  openRawResource(int id)获取得到资源文件的数据流后,也可以通过2种方法来获取Bitmap,如下:
    使用BitmapDrawable 
    (A Drawable that wraps a bitmap and can be tiled, stretched, or aligned.) 
    使用BitmapDrawable (InputStream is)构造一个BitmapDrawable; 
    使用BitmapDrawable类的getBitmap()获取得到位图; 
    BitmapDrawable也提供了显示位图等操作。 
    Java代码:
  • InputStream is=res.openRawResource(R.drawable.pic180);  // 读取资源文件获取输入流 
  • BitmapDrawable bmpDraw=new BitmapDrawable(is);   
  • Bitmap bmp=bmpDraw.getBitmap(); 
  • 或者: 
  • BitmapDrawable bmpDraw=(BitmapDrawable)res.getDrawable(R.drawable.pic180);   
  • Bitmap bmp=bmpDraw.getBitmap();
  • 复制代码
    使用BitmapFactory 
    (Creates Bitmap objects from various sources, including files, streams, and byte-arrays.)
    使用BitmapFactory类decodeStream(InputStream is)解码位图资源,获取位图。 
    使用BitmapFactory类Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic180); 方法解码位图资源。
    BitmapFactory的所有函数都是static,这个辅助类可以通过资源ID、路径、文件、数据流等方式来获取位图。 
    以上方法在编程的时候可以自由选择,在Android SDK中说明可以支持的图片格式如下:png (preferred), jpg (acceptable), gif (discouraged),虽然bmp格式没有明确说明,但是在Android SDK Support Media Format中是明确说明了。
    代码: 
    方法1: 

    2. 获取位图的信息 
    要获取位图信息,比如位图大小、是否包含透明度、颜色格式等,获取得到Bitmap就迎刃而解了,这些信息在Bitmap的函数中可以轻松获取到。Android SDK中对Bitmap有详细说明,阅读起来也比较容易,不在此详细说明,这里只是辅助说明以下2点:
    在Bitmap中对RGB颜色格式使用Bitmap.Config定义,仅包括ALPHA_8、ARGB_4444、ARGB_8888、RGB_565,缺少了一些其他的,比如说RGB_555,在开发中可能需要注意这个小问题;
    Bitmap还提供了compress()接口来压缩图片,不过AndroidSAK只支持PNG、JPG格式的压缩;其他格式的需要Android开发人员自己补充了。
    3. 显示位图 
    显示位图可以使用核心类Canvas,通过Canvas类的drawBirmap()显示位图,或者借助于BitmapDrawable来将Bitmap绘制到Canvas。当然,也可以通过BitmapDrawable将位图显示到View中。
    转换为BitmapDrawable对象显示位图
  •      // 获取位图 
  •         Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic180); 
  •         // 转换为BitmapDrawable对象 
  •         BitmapDrawable bmpDraw=new BitmapDrawable(bmp); 
  •         // 显示位图 
  •         ImageView iv2 = (ImageView)findViewById(R.id.ImageView02); 
  •        iv2.setImageDrawable(bmpDraw);
  • 复制代码
    使用Canvas类显示位图 
    这儿采用一个继承自View的子类Panel,在子类的OnDraw中显示 
    Java代码
  • public class MainActivity extends Activity {   
  •      
  •     @Override  
  •     public void onCreate(Bundle savedInstanceState) {   
  •         super.onCreate(savedInstanceState);   
  •         setContentView(new Panel(this));   
  •     }   
  •        
  •     class Panel extends View{            
  •         public Panel(Context context) {     
  •             super(context);    
  •         }         
  •         public void onDraw(Canvas canvas){     
  •             Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180);    
  •              canvas.drawColor(Color.BLACK);     
  •             canvas.drawBitmap(bmp, 10, 10, null);     
  •         }     
  •     }    
  • }  
  • 复制代码
    4. 位图缩放 
    (1)将一个位图按照需求重画一遍,画后的位图就是我们需要的了,与位图的显示几乎一样:drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)。
    (2)在原有位图的基础上,缩放原位图,创建一个新的位图:CreateBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
    (3)借助Canvas的scale(float sx, float sy) (Preconcat the current matrix with the specified scale.),不过要注意此时整个画布都缩放了。
    (4)借助Matrix: 
    Java代码
  • Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180);    
  • Matrix matrix=new Matrix();   
  • matrix.postScale(0.2f, 0.2f);   
  • Bitmap dstbmp=Bitmap.createBitmap(bmp,0,0,bmp.getWidth(), 
  • bmp.getHeight(),matrix,true);   
  • canvas.drawColor(Color.BLACK);     
  • canvas.drawBitmap(dstbmp, 10, 10, null);   
  • 复制代码
    5. 位图旋转 
    同样,位图的旋转也可以借助Matrix或者Canvas来实现。Matrix在线性代数中都学习过,Android SDK提供了Matrix类,可以通过各种接口来设置矩阵。结合上面的例子程序,将位图缩放例子程序在显示位图的时候前,增加位图旋转功能,修改代码如下:
  • Matrix matrix = new Matrix(); 
  • //matrix.postScale(0.5f, 0.5f); 
  • matrix.setRotate(90,120,130); 
  • canvas.drawBitmap(mbmpTest, matrix, mPaint);
  • 复制代码

    旋转后的位图显示如下: 

    除了这种方法之外,我们也可以在使用Bitmap提供的函数如下: 
    public static Bitmap createBitmap (Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter),在原有位图旋转的基础上,创建新位图。
    总结说明 
    对位图的操作,结合Android SDK中的类,详细的介绍完了。最后还需要强调的是:这篇文章只是对Android SDK中代码阅读分析,它代替不了你阅读Android SDK,深入的学习还是要仔细的阅读Android SDK。

     

    转自:http://bbs.chinaunix.net/thread-3682769-1-1.html

     

     


        
    [3] 获取图库相片
        来源: 互联网  发布时间: 2014-02-18
    获取图库照片

    当要进分享照片功能时,点击一个按钮,然后进入图库选择照片,

    要进行这样的操作,改怎么完成呢,要解决2个问题:

    1、该如何进入图库

    2、改如何取得照片

    ==================================================

    进入图库:

     

                    Intent intent = new Intent();  

                    intent.setType("image/*");  

                    intent.setAction(Intent.ACTION_GET_CONTENT);   

                    /* 取得相片后返回本画面 */  

                    startActivityForResult(intent, 1);

     选取照片:

                   当点击照片后,会返回一个intent,那么,用getData();获得一个URI的数据,这个uri就是图片在数据库中的位置

                   然后该怎么通过这个uri操作,得到图片和路径呢??看下面源码吧

    ====================================================

    最后详细的见源码

     

    public class StartActivityForResult extends Activity {

        /** Called when the activity is first created. */

        @Override

        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

            

            Button button = (Button)findViewById(R.id.btn);  

            button.setText("选择图片");  

            button.setOnClickListener(new Button.OnClickListener(){  

                @Override  

                public void onClick(View v) {  

                   Intent intent = new Intent();  

                    intent.setType("image/*");  

                    intent.setAction(Intent.ACTION_GET_CONTENT);   

                    /* 取得相片后返回本画面 */  

                    startActivityForResult(intent, 1);  

     

                }  

                  

            });  

        }  

          

        @Override  

        protected void onActivityResult(int requestCode, int resultCode, Intent data) {  

            if (resultCode == RESULT_OK) {  

                Uri uri = data.getData();  

                Log.e("uri", uri.toString()); 

                Log.e("uri", uri.getPath());  

                ContentResolver cr = this.getContentResolver(); 

     

                //获得照片,并显示

                try {  

                    Bitmap bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri));  

                    ImageView imageView = (ImageView) findViewById(R.id.iv);  

                    /* 将Bitmap设定到ImageView */  

                    imageView.setImageBitmap(bitmap);  

                } catch (FileNotFoundException e) {  

                    Log.e("Exception", e.getMessage(),e);  

                }

                

                //获得照片路径

                //get the picture path

                String[] projection = { MediaStore.Images.Media.DATA };

                Cursor cursor = managedQuery(uri, projection, null, null, null);

                int column_index = cursor

                        .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);

                cursor.moveToFirst();

                System.out.println("image path ===>" + cursor.getString(column_index));

                

            }  

            super.onActivityResult(requestCode, resultCode, data);  

        }  

    }


        
    最新技术文章:
    ▪Android开发之登录验证实例教程
    ▪Android开发之注册登录方法示例
    ▪Android获取手机SIM卡运营商信息的方法
    ▪Android实现将已发送的短信写入短信数据库的...
    ▪Android发送短信功能代码
    ▪Android根据电话号码获得联系人头像实例代码
    ▪Android中GPS定位的用法实例
    ▪Android实现退出时关闭所有Activity的方法
    ▪Android实现文件的分割和组装
    ▪Android录音应用实例教程
    ▪Android双击返回键退出程序的实现方法
    ▪Android实现侦听电池状态显示、电量及充电动...
    ▪Android获取当前已连接的wifi信号强度的方法
    ▪Android实现动态显示或隐藏密码输入框的内容
    ▪根据USER-AGENT判断手机类型并跳转到相应的app...
    ▪Android Touch事件分发过程详解
    ▪Android中实现为TextView添加多个可点击的文本
    ▪Android程序设计之AIDL实例详解
    ▪Android显式启动与隐式启动Activity的区别介绍
    ▪Android按钮单击事件的四种常用写法总结
    ▪Android消息处理机制Looper和Handler详解
    ▪Android实现Back功能代码片段总结
    ▪Android实用的代码片段 常用代码总结
    ▪Android实现弹出键盘的方法
    ▪Android中通过view方式获取当前Activity的屏幕截...
    ▪Android提高之自定义Menu(TabMenu)实现方法
    ▪Android提高之多方向抽屉实现方法
    ▪Android提高之MediaPlayer播放网络音频的实现方法...
    ▪Android提高之MediaPlayer播放网络视频的实现方法...
    ▪Android提高之手游转电视游戏的模拟操控
     


    站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3