在ios中常常遇到些小的动画效果,比如点击一个按钮后,按钮上的三角形图片就旋转了。这种简单的小动画,常常通过更改view的transform属性来实现。这个transform属性,就是一个仿射变化矩阵。

什么是AffineTransform呢?先看看百度上的说法:

AffineTransform类描述了一种二维仿射变换的功能,它是一种二维坐标到二维坐标之间的线性变换,保持二维图形的“平直性”和“平行性”。仿射变换可以通过一系列的原子变换的复合来实现。

  1. .
  2. | a, b, |
  3. {x',y',}={x,y,} x | c, d, |
  4. | tx, ty, |

我们平常遇到的2d变化,比如:平移(Translation)、缩放(Scale)、翻转(Flip)、旋转(Rotation)和错切(Shear),都可以通过不同的仿射矩阵进行变化。其实,在ios中,系统为我们提供了不少的函数,可以根据需要,创建不同的变换矩阵。比如CGAffineTransformRotate等等。

下面举例说明几个仿射矩阵:

1 view的默认仿射矩阵是

  1. | , , |
  2. | , , |
  3. | , , |

那么 x' = 1*x+0*y+0  ;   y' = 0*x +1*y +0;

2 平移的放射矩阵是

  1. | , , |
  2. | , , |
  3. |tx, ty, |

这种变化有2种看法:即可以看成坐标系不变,图形相对于原点进行位移;也可以看做系统移动了坐标系,并在新的坐标系上绘图。第一种理解方法更为直接,不容易出错。

3 看一张通用变换的图解,同样出自百度

这张图,表示了从 P点从S坐标系的坐标,经过变化,转化为T坐标系的坐标的计算过程。

在这个顺时针旋转的例子中,Xtp = Ysp*sin0y + Xsp*cos0x + Xto,可以看出,如果x轴和y轴的转动角度相同,那么坐标变换矩阵中的 b和a的比值,就是tan0,也就是说,向量(a,b)可以表示旋转的方向。这一点可以在许多动画中用到,比如下列代码

  1. -(void)fireBullet
  2. {
  3. // Don't fire bullets if the ship is destroyed.
  4. if(_ship == nil) return;
  5.  
  6. // This is sort of a fancy math way to figure out where to fire the bullet from.
  7. // You could figure this out with more code, but I wanted to have fun with some maths.
  8. // This gets the transform of one of the "gunports" that I marked in the CCB file with a special node.
  9. CGAffineTransform transform = _ship.gunPortTransform;
  10.  
  11. // An affine transform looks like this when written as a matrix:
  12. // | a, c, tx |
  13. // | b, d, ty |
  14. // The first column, (a, b), is the direction the new x-axis will point in.
  15. // The second column, (c, d), is the direction the new y-axis will point in.
  16. // The last column, (tx, ty), is the location of the origin of the new transform.
  17.  
  18. // The position of the gunport is just the matrix's origin point (tx, ty).
  19. CGPoint position = ccp(transform.tx, transform.ty);
  20.  
  21. // The original sprite pointed downwards on the y-axis.
  22. // So the transform's y-axis, (c, d), will point in the opposite direction of the gunport.
  23. // We just need to flip it around.
  24. CGPoint direction = ccp(-transform.c, -transform.d);
  25.  
  26. // So by "fancy math" I really just meant knowing what the numbers in a CGAffineTransform are. ;)
  27. // When I make my own art, I like to align things on the positive x-axis to make the code "prettier".
  28.  
  29. // Now we can create the bullet with the position and direction.
  30. Bullet *bullet = (Bullet *)[CCBReader load:@"Bullet"];
  31. bullet.position = position;
  32. //bullet.rotation = -CC_RADIANS_TO_DEGREES(ccpToAngle(direction));
  33.  
  34. // Make the bullet move in the direction it's pointed.
  35. bullet.physicsBody.velocity = ccpMult(direction, bullet.speed);
  36.  
  37. [_physics addChild:bullet];
  38. [_bullets addObject:bullet];
  39.  
  40. // Give the bullet a finite lifetime.
  41. [bullet scheduleBlock:^(CCTimer *timer){
  42. [self destroyBullet:bullet];
  43. } delay:bullet.duration];
  44.  
  45. // Make some noise. Add a little chromatically tuned pitch bending to make it more musical.
  46. int half_steps = (arc4random()%(* + ) - );
  47. float pitch = pow(2.0f, half_steps/12.0f);
  48. [[OALSimpleAudio sharedInstance] playEffect:@"Laser.wav" volume:1.0 pitch:pitch pan:0.0 loop:NO];
  49. }

这段代码是cocos2d-iphone官网demo的一部分代码,它的作用就是用户点击屏幕时,根据当前飞船的位置和方向,设置子弹精灵的旋转角度和起始坐标,让子弹看起来像是从飞船中发射出的。注意这里的  CGPoint direction = ccp(-transform.c, -transform.d); 它的原理就是利用了放射变换矩阵的数学意义,得到了飞船的y轴旋转方向,并利用这个向量旋转子弹精灵。

简单的2d图形变换--仿设变换AffineTransform的更多相关文章

  1. SVG 2D入门6 - 坐标与变换

    坐标系统 SVG存在两套坐标系统:视窗坐标系与用户坐标系.默认情况下,用户坐标系与视窗坐标系的点是一一对应的,都为原点在视窗的左上角,x轴水平向右,y轴竖直向下:如下图所示: SVG的视窗位置一般是由 ...

  2. Quartz 2D编程指南(5) - 变换(Transforms)

    Quartz 2D 绘制模型定义了两种独立的坐标空间:用户空间(用于表现文档页)和设备空间(用于表现设备的本地分辨率).用户坐标空间用浮点数表示坐标,与设备空间的像素分辨率没有关系.当我们需要一个点或 ...

  3. JavaScript图形实例:图形的扇形变换和环形变换

    1.1  扇形变换 将如图1所示的上边长方形的图形变换为下边的扇形图形的变换称为扇形变换. 设长方形图形中任一点P1(X1,Y1)变换为扇形图形上的点P2(X2,Y2),长方形的长为X,扇形圆心坐标为 ...

  4. 2D图形如何运动模拟出3D效果

    一.先看看实现效果图 (左边的2d图片如何运动出右边3d的效果)                                      引言: 对于这个题目,真的很尴尬,不知道取啥,就想了这个题目 ...

  5. 为什么要进行傅立叶变换?傅立叶变换究竟有何意义?如何用Matlab实现快速傅立叶变换

    写在最前面:本文是我阅读了多篇相关文章后对它们进行分析重组整合而得,绝大部分内容非我所原创.在此向多位原创作者致敬!!!一.傅立叶变换的由来关于傅立叶变换,无论是书本还是在网上可以很容易找到关于傅立叶 ...

  6. autoCAD绘制简单三维立体图形

    第一步: 首先绘制一个简单的(封闭的)二维图形: 第二步: 变换观察视角,比如修改为 变换后的视角: 第三步: 选中闭合图形边框,使用组合键"ctrl + shift + E",然 ...

  7. 【Android】第21章 2D图形和动画

    分类:C#.Android.VS2015: 创建日期:2016-03-19 一.简介 Android系统定义了一系列独立的图形处理类,其中,2D图形处理类分别位于以下命名空间: Android.Gra ...

  8. Shadertoy 教程 Part 5 - 运用SDF绘制出更多的2D图形

    Note: This series blog was translated from Nathan Vaughn's Shaders Language Tutorial and has been au ...

  9. Shadertoy 教程 Part 4 - 绘制多个2D图形和混入

    Note: This series blog was translated from Nathan Vaughn's Shaders Language Tutorial and has been au ...

随机推荐

  1. hdu4287 字典树

    #include<stdio.h> #include<string.h> #include<stdlib.h> #define maxn 10 struct tri ...

  2. Java设计模式-中介者模式(Mediator)

    中介者模式也是用来降低类类之间的耦合的,因为如果类类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改一个对象,其它关联的对象都得进行修改.如果使用中介者模式,只需关心和Mediator类的关系 ...

  3. 使用FMDB事务批量更新数据库

    今天比较闲看到大家在群里讨论关于数据库操作的问题,其中谈到了“事务”这个词,坦白讲虽然作为计算机专业的学生,在上学的时候确实知道存储过程.触发器.事务等等这些名词的概念,但是由于毕业后从事的不是服务器 ...

  4. Oracle使用JDBC进行增删改查

    数据库和表 create table USERS(  USERNAME VARCHAR2(20) not null,  PASSWORD VARCHAR2(20))alter table USERS  ...

  5. c++实现gray code(格雷码)

    今天别人问的一道题,强调用分治法实现 =.= 百度了一下格雷码,然后写了一下. 关于格雷码大家看百度的吧,特别详细,贴个图: 代码如下(header_file.h是我自己写的一个头文件,包括常见的ve ...

  6. Ognl基本使用

    ---恢复内容开始--- Ognl默认是从“根”中取数据的 下面Demo中用的是 Ognl.getValue(String expression, Map context, Object root) ...

  7. JavaScript入门培训材料(Copy至此以作备份)

    JavaScript简明学习教程 2014年5月31日 目录 一.说明... 2 二.准备知识... 2 (一)HTML. 2 (二)DOM.. 3 三.JavaScript简介... 3 四.Jav ...

  8. Oracle 常用入侵命令

    1.查看当前数据库实例名称:select * from v$instance;2.查看当前用户的角色:select * from user_role_privs;3.查看当前用户下所有的表:selec ...

  9. ThinkPHP邮件发送函数示例

    ThinkPHP邮件发送函数示例详解 /** * 发送邮件 * @param $tomail * @param $subject * @param $body * @param string $con ...

  10. Base64封装类

    using System;using System.Collections.Generic;using System.Linq;using System.Web; /// <summary> ...