一款功能强大、性能强劲的物理引擎。它能都维持在一个独立的运行空间。

概述

Box2D引擎创建的物体都属于理想的刚体,即它内部之间的距离永不改变。Box2D创建的物理世界具备以下三个特点。

  1. 物理世界存在一个重力(可以为0)
  2. 物理世界可以是一个存在边界的范围
  3. 在世界中加入静态和动态物体(具有质量和位置),它们被用来模拟现实的运动规律

    概念

  4. 物理世界(World)
    一个物理世界就是由各种刚体、框架、形状互相作用的集合。
  5. 刚体(Rigid Bodies)
    理想刚体是一个有限尺寸、可以忽略形变的物体。不论是否感受到作用力,在刚体内部,点与点之间的距离都不会改变,可以认为是一个连续质量分布体。 在Box2D物理世界中,所有物体都是刚体,这些物体一旦被创建出来后,其形状就不会改变。
  6. 形状(Shapes)
    2D平面几何结构,主要用于世界里的物理碰撞的检测。
  7. 框架(Fixtures)
    框架代表物理世界中物体的固定物质形态,是连接物体和形状之间的框架,一个物体可以有多个框架,没个框架可以连接一个形状、它本身存储着物体的质量、密度、摩擦系数,同时包含碰撞标志、用户数据和是否使用碰撞检测器的标志。他存在的目的主要是为了物理引擎的运算考虑。
  8. 关节(Joins)
    关节的作用是将两个有一定运动自由度(水平、数组、转动)的物体连接起来,同时约束连接的物体。Box2D引擎支持的关节类型有旋转、棱柱、距离等等,通常具备两个共同属性:限制(Limits)和马达(Motors)
    (1) 关节限制(joint limit) 限定了一个关节的运动范围。
    (2) 关节马达(joint motor) 能依照关节的自由度来驱动所连接的物体。

    模块

    Box2D引擎由三个模块组成:公共(Common)、碰撞(Collision)和动态(Dynamics)。
    (1) Common核心模块包含了内存分配、数学计算和配置
    (2) Collision模块定义了形状(shape)、broad-phase检测盒碰撞功能/查询(collision functions/queries)
    (3) Dynamics模块提供对世界(world)、刚体(bodies)、框架(fixtures)和关节(joint)模拟

    数据单位

    Box2D引擎使用浮点数进行计算,所以为看保证它的正常工作,必须使用一些公差来保证它的正常工作。引擎能够良好的处理0.1~10米之间的移动物体。

    用户数据

    1
    2
    3
    4
    5
    6
    7
    8
    // 创建一个精灵
    CCSprite* actor = CCSprite::node();
    // 物体的定义
    b2BodyDef bodyDef;
    // 指定数据
    bodyDef.userData = actor;
    // 创建物体
    actor->body = box2Dworld->CreateBody(&bodyDef);

用户数据是可选的,并且能放入任何东西,为了保持一致性,通常保存精灵对象的指针。

物理世界World

创建一个世界

1
2
3
4
5
b2Vec2 gravity;	// 重力
gravity.Set(0.0f,-10.0f);
world = new b2World(gravity);
world->SetAllowSleeping(true); // 设置允许物体进入休眠状态
world->SetContinuonsPhysics(true); // 设置使用连续物理检测

销毁世界

1
2
delete world;
world = NULL;

世界运转起来

物理世界类中用于驱动模拟的函数为Step,调用它时,需要指定一个时间步和一个速度及位置的迭代次数。

1
2
3
4
5
6
7
8
9
10
11
12
13
float32 timeStep = 1.0f/60.0f;	// 时间步,频率
int32 velocityIterations = 10; // 速度迭代
int32 positionIterations = 8; // 位置迭代次数
myWorld->Step(timeStep,velocityIterations,positionIterations); // 驱动函数
```
在物理引擎执行一次时间步之后,最好是清除任何施加在物体上的力。可以使用`b2World::ClearForces`完成,可以去除力的持续作用效果。
## 探索世界
物理世界中存在创建工厂,工厂则会创建物体、框架和关节对象,同时世界也是容器,它会容纳工厂创建出来的所有对象。可以通过遍历的方式来获取世界中所有物体、框架和关节。
```c++
for (b2Body* b = myWorld()->GetBodyList();b;b = b->GetNext())
{
b->WakeUp(); // 唤醒物体
}

AABB查询

Box2D引擎当中提供了AABB查询的方式,需要得出一个区域内所有对象时的解决方法。为此专门使用broad-phase的数据结构,它提供了一个log(N)复杂度的快速查询方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyQueryCallback : public b2QueryCallback
{
public:
bool ReportFixture(b2Fixture* fixture)
{
b2Body* body = fixture->GetBody();
body->WakeUp();
return ture; // 继续查询
}
}

b2AABB aabb;
aabb.lowerBound.Set(-1.0f,-1.0f); // 设置AABB的上边界
aabb.upperBound.Set(1.0f,1.0f); // 设置AABB的下边界
myWorld->Query(&callback,aabb);

光线投射(Ray Casts)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class MyRayCastCallBack : public b2RayCastCallback
{
public:
MyRayCastCallback()
{
m_fixture = NULL;
}
float32 ReportFixture(b2Fixture* fixture,const b2Vec2& point,const b2Vec2& normal,float32 fraction)
{
// 保存框架
m_fixture = fixture;
// 保存交点
m_point = point;
// 保存法向量
m_normal = normal;
// 保存光线通过的分数距离
m_fraction = fraction;
return fraction;
}
b2xFixture* m_fixture;
b2Vec2 m_point;
b2Vec2 m_normal;
float32 m_fraction;
};
// 回调函数
MyRayCastCallback callback;
// 光线投射的起始点
b2Vec2 point(-1.0f,0.0f);
// 光线投射的结束点
b2Vec2 point(3.0f,1.0f);
// 开始光线的投射
myWorld->RayCast(&callback,point1,point2);

形状Shapes

形状是物体的包围盒,描述了可相互碰撞的几何对象的外形,它通常会是一个几何图形。被Shape是形状的基类,Box2D引擎中各种形状类都是继承自这个基类。此基类定义了几个常用函数:

  1. 判断一个点与形状是否有重叠
  2. 在形状上执行光线投射
  3. 计算形状的AABB
  4. 计算形状的质量
    所有形状都有两个成员变量:类型(type)和半径(radius),引擎存在两种类型的形状:圆形和多边形。

    圆形(Circle Shapes)

    圆形形状(b2CircleShape)是一个由位置和半径表示的集合图形。圆形形状都是实心的,主要的参数就是半径。
    1
    2
    3
    b2CircleShape circle;// 创建圆形形状的对象
    circle.m_p.Set(1.0f,2.0f,3.0f);// 设置位置
    circle.m_radius = 0.5f;// 设置半径

多边形(Polygon Shape)

多边形(b2PolygonShape)是实现的凸(Convex)多边形。数学的定义:在多边形内部任意选择两点,作一线段,如果所有线段都跟多边形的边不想交,这个多边形就是凸多边形。在Box2D引擎中一个多边形形状是通过顶点来描述的。

1
2
3
4
5
b2PolygonDef triangleDef;
triangleDef.vertexCont = 3;
triangleDef.vertices[0].Set(-1.0f,0.0f);
triangleDef.vertices[1].Set(1.0f,0.0f);
triangleDef.vertices[2].Set(0.0f,2.0f);

在创建多边形时,顶点必须是逆时针排列。创建多边形时,顶点的数据可以通过数组来传递,数组中的顶点数最大值是核心模块中定义的b2maxPolygonVertices,默认情况下此数值是8。

1
2
3
4
5
6
7
8
9
b2Vec2 vertices[4];
vertices[0].Set(0.0f,0.0f);
vertices[1].Set(1.0f,0.0f);
vertices[2].Set(0.0f,1.0f);
vertices[3].Set(1.0f,1.0f);

int32 count = 4;
b2PolygonShape polygon;
polygon.Set(vertices,count);

为了使用方便引擎还提供了一些定义好的初始化函数来创建固定的多边形形状:箱子(box)和边缘(edge,就是线段)

1
2
3
void SetAsbox(float32 hx,float32 hy);
void SetAsBox(float32 hx,float32 hy,const b2Vec2& center,float32 angle);
void SetAsEdge(const b2Vec2& v1,const b2Vec& v2);

框架Fixtures

Fixture是动态模块中重要的概念,用来物理模拟。
动态模块包含的内容:

  • 框架(Fixtures)
  • 物体(Bodies)
  • 接触(Contacts)
  • 关节(Joints)
  • 世界(World)
  • 监听器(Listener)
    框架主要用于建立形状与物体之间的连接和进行物理模拟。

    密度(Density)

    框架的密度用来计算物体的质量属性,密度可以为零或者其他整数。

    摩擦(Friction)

    Box2D支持静态摩擦和动态摩擦,两者都使用的相同的摩擦系数作为参数。摩擦的强度与正交力成正比。摩擦系数经常会设置为0到1之间,0意味着没有摩擦,1会产生强摩擦。当计算两个形状之间的摩擦时,引擎必须计算两个形状的摩擦参数。
    1
    2
    float32 friction;
    friction = sqrtf(shape1->friction * shape2->friction);

恢复(Resitution)

为反弹的参数,它可以使对象弹起。恢复的值通常设置在0到1之间。恢复就是一个物体碰撞后反弹大小的参数,其值为0表示小球不会弹起,这称为非弹性碰撞。值为1表示小球的速度大小一样,只是方向相反,这称为完全弹性碰撞。

1
2
float32 resitution;
restitution = b2Max(shape1->resitution,shape2->resitution);

帅选(Filtering)

用来设置某些游戏对象相互碰撞的关系。Box2D支持最多十六个种群进行筛选。在引擎中碰撞筛选是通过掩码来完成的。

1
2
3
4
playerFixtureDef.filter.categoryBits = 0x0002;
playerFixtureDef.filter.maskBits = 0x0004;
monsterFixturDef.filter.categoryBits = 0x0004;
monsterFixturDef.filter.maskBits = 0x0002;

还可以进行分组,可以让同一组内的所有框架总是互相碰撞(正索引)或者永不碰撞(负索引)

1
2
3
4
fixture1Def.filter.groupIndex = 2;
fixture2Def.filter.groupIndex = 2;
fixture3Def.filter.groupIndex = -8;
fixture4Def.filter.groupIndex = -8;

  1. 静态物体上的框架永远不会与两一个静态物体上的框架发生碰撞,因为静态物体根本不会移动
  2. 同一个物体上的框架永远不会相互碰撞
  3. 如果物体用关节连接起来了,物体上的框架可以选择启用或禁止它们之间相互碰撞。

    感应器(Sensors)

    感应器是用来检测两个框架是否相交的对象。可以将任何一个框架对象设置为感应器,感应器可以是静态或者动态的。感应器发生碰撞时,是不会生成接触点的。
    1
    2
    b2Contact::IsTouching	// 这个函数可以得到感应器是否接触
    b2ContactListener::BeginContact和EndContact // 开始接触点和结束接触点

物体Bodies

Box2D的物体均为刚体,它具有质量和惯性,运动状态由重心和受力决定,动态速度由线速度和角速度控制,可分为三类

  1. 静态物体(b2_staticBody)质量为0,在模拟时,静态不可移动,不过可以手动设置移动。速度为零。另外它不会和其他静态、平台物体碰撞。
  2. 平台物体(b2_kinematicBody)
    是按照固定轨迹在运动的物体,其质量也为零,可以预设一个速度,它也不会和其他的静态或平台物体相互碰撞。
  3. 动态物体(b2_dynamicBody)
    具有质量、速度、摩擦等,它将会参与引擎中的碰撞检测与物理模拟。可以与物理世界中任何对象发生碰撞。
    上述物体都可以被施加外力(forces)、扭矩(torques)、冲量(impulses)

    位置和角度(Position and Angle)

    是物体的最基本的属性,也就是物理世界都不会缺少这两个属性。
    物体的两个主要有两个属性是最最主要的:
  4. 第一个是物体的原点
  5. 第二个是物体的知心,可以显式地通过b2MassData来设置。
    1
    2
    bodyDef.position.Set(0.0f,2.0f); 	// body的原点
    bodyDef.angle = 0.25f * b2_pi; // 弧度制下body的角

在引擎运转过程中,物体的位置和角度也会随时地改变。也可以通过物体类中的函数来改变。

1
void SetTransform(const b2Vec2& position,float32 angle);

阻尼(Damping)

用于表示减小物体的世界中的速度的数值。阻尼和摩擦有所不同,摩擦仅在物体有接触的时候才会发生,而阻尼却时时刻刻阻碍着物体运动,比如空气阻力。阻尼参数的数值范围可以是从零到无穷大。通常来说阻尼的值应该在0~0.1之间。

1
2
bodyDef.linearDamping = 0.0f;
bodyDef.angularDamping = 0.01f;

休眠参数(Sleep Parameters)

确定一个物体已经停止了移动时,物体就会进入休眠状态,休眠物体只消耗很小的CPU开销。接触到一个醒着的物体,物体就会被唤醒,物体上艹关节或触点被销毁的时候,也会醒来。

1
2
bodyDef.allowSleep = true;	// 可以休眠
bodyDef.awake = ture; // 休眠物体

固定旋转(Fixed Rotation)

通过bodyDef.fixedRotation = ture物体的转动惯量设置成零,物体会保持初始化的角度,而不会发生旋转。

子弹(Bullets)

子弹通常指一类速度很快而尺寸较小的物体,容易击穿其他物体。bodyDef.bullet = true

活动状态(Activation)

一个非活动状态的物体,将完全地与世隔绝,不会参与物理模拟和碰撞检测,关节也不会被迷你。bodyDef.active = true

用户数据(User Data)

一个存放用户数据的void指针,通常保存精灵对象

1
2
b2BodyDef bodyDef;
bodyDef.userData = &myActor;

关节(Joints)

关节是将两个或两个以上物体连接在一起的对象,主要有三个作用

  1. 用于连接物体
  2. 用于限制物体的移动,是一种约束
  3. 它本身是一个能够活动的对象

    关节的定义(JointDef)

    关节包含一个用户数据的void指针,可以指定游戏元素,希望关节上的两个物体也能够发生碰撞,可以设置collideConnected布尔值来允许连接的物体之间进行碰撞。

界面

界面简介

菜单和工具条


管理Android Studio的显示窗口
按下ctrl+shift+a(mac为command+shift+a)会触发一个命令提示框,输入想要执行的命令的前缀,可以找到自己的命令

更改常用操作的快捷键

在设置中烧到keymap,可以选择为eclipse的快捷键

常用创建方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
bool MyScene::init()
{
Size size = Director::getInstance()->getWinSize();

Sprite *sp1 = Sprite::create("icon.png");
sp1->setPosition(Vec2(size.with*0.2,size.height*0.7));
this->addChild(sp1);

Sprite *sp2 = Sprite::create("icon.png",Rect(10,30,28,28));
sp2->setPosition(Vec2(size.width*0.4,size.height*0.7));
this->addChild(sp2);
// 创建纹理
Texture2D *texture = TextureCache::sharedTextureCache()->addImage("icon.png");

Sprite *sp3 = Sprite::createWithTexture(texture);
sp3->setPosition(Vec2(size.width*0.6,size.height*0.7));
this.addChild(sp3);

Sprite *sp4 = Sprite::createWithTexture(texture,Rect(0,0,40,40));
sp4->setPosition(Vec2(size.width*0.8,size.height*0.7));
this.addChild(sp4);

SpriteFrame *frame = SpriteFrame::create("icon.png",Rect(0,0,57,57));
Sprite *sp5 = Sprite::createWithSpriteFrame(frame);
sp5->setPosition(Vec2(size.width*0.3,size.height*0.3));
this.addChild(sp5);

Sprite *sp6 = Sprite::createWithSpriteFrame("icon.png");
sp6->setPosition(Vec2(size.width*0.3,size.height*0.3));
this->addChild(sp6);

return true;
}

常用的类方法:

  • setScale(float fScale) 缩放
  • setRotation(float fRotation) 旋转
  • setSkew(float s) 倾斜
  • setAnchorPoint(const Point& another) 设置锚点
  • setVisible(bool bvisible) 是否可见
  • setColor(const cccolor3B& color3) 设置颜色
  • setOpacity(Glubvte Opacity) 透明度设置 0-255 0表示完全透明,255表示不透明
  • setTexture(CCTexture2D *texture) 更改图片

  • ui_print(msg1,…,msgN) 用于在Recovery界面输出字符串,不定参数。
  • run_program(prog,arg1,…,argN) 用于执行程序,其中prog参数表示执行的程序文件(要写完整路径),arg1,…argN表示执行程序的参数,prog是必须的,arg是可选的
  • delete(file1,…fileN) 用于删除一个或多个文件
  • package)extract_dir(package_path,desination_path) 用于提取刷机包中的pack_path指定的目录。其中package_path参数表示刷机包中的目录,destination_path表示目标目录
  • set_perm(uid,gid,mode,file1,file2,…fileN) 用于设置一个或多个文件的权限,其中uid参数表示用户ID,gid表示用户组ID。如果想让文件的用户和用户组都是root,uid和gid需要都为0。mode参数表示设置的权限,与chmod命令类似。
  • mount(fs_type,partion_type,location,mount_point) 挂载分区
  • unmount(mount_point) 用于解除挂载,mount_point参数表示文件系统

仿Path带动画效果的扇形菜单

用法

1
2
3
4
5
6
7
8
9
ArcMenu menu = (ArcMenu) findViewById(R.id.arc_menu);
final int itemCount = ITEM_DRAWABLES.length;
for (int i = 0; i < itemCount; i++) {
ImageView item = new ImageView(this);
item.setImageResource(ITEM_DRAWABLES[i]);
menu.addItem(item,new OnClick(View v){
Toast.makeText(MainActivity.this, "position:" + position, Toast.LENGTH_SHORT).show();
});
}

改变外观可以在xml中

1
2
3
custom:childSize="50px"
custom:fromDegrees="0.0"
custom:toDegrees="300.0"

或者在java中

1
2
arcLayout.setChildSize(50);
arcLayout.setArc(0.0f,300.0f);


ArcMenu

一个拥有丰富动画的对话框

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 获取一个对话框对象
NiftyDialogBuilder dialogBuilder = NiftyDialogBuilder.getInstance(this);
dialogBuilder.withTitle("弹出框") // 标题
.withTitleColor("# FFFFFF") // 标题的颜色
.withDividerColor("# 11000000") // 分隔栏的颜色
.withMessage("这是信息文本。") // 文本信息
.withMessageColor("# FFFFFF") // 文本信息的颜色
.withIcon(getResources().getDrawable(R.drawable.icon)) // 标题栏的图标
.isCancelableOnTouchOutside(true) // 外部点击退出
.withDuration(500) // 动画延迟
.withEffect(effect) // 动画类别
.withButton1Text("确定") // 按钮1的文本
.withButton2Text("取消") // 按钮2的文本
.setCustomView(R.layout.custom_view, v.getContext()) // 设置自定义view
.setButton1Click(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "确定",
Toast.LENGTH_SHORT).show();
}
}).setButton2Click(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "取消",
Toast.LENGTH_SHORT).show();
}
}).show();

自定义内容

NiftyDialogEffects的color文件内可以修改对话框的颜色

1
2
3
4
5
6
7
<color name="text_color"># FFFFFF</color>
<color name="divider_color"># 11000000</color>
<color name="msg_color"># FFFFFFFF</color>
<color name="dialog_bg"># FF4FC1E9</color>

<color name="btn_press_color"># FF4FC1E9</color>
<color name="btn_unpress_color"># FF3BAFDA</color>

===
NiftyDialogEffects

使用

1
2
3
4
5
6
7
8
9
10
11
LayoutInflater inflator = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflator.inflate(R.layout.custom_ab,null);
tabBarView = (TabBarView) v.findViewById(R.id.tab_bar);

getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_SUSTOM);
getActionBar().setCustomView(v);

mSectionsPagerAdapter = new SectionsPagerAdapter(getFramentManager());

mViewPager = (ViewPager) findViewById(R.id.pager);
tabBarView.setViewPager(mViewPager);

实现一个adapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class SectionsPagerAdapter extends FragmentPagerAdapter implements IconTabProvider {
private intp[] tab_icons = {R.drawable.ic_tab1,R.drawable.ic_tab2,R.drawable.ic_tab3};

public SectionsPagerAdapter(FragmentManager fm){
super(fm);
}

@Override
public Fragment getItem(int position) {
return PlaceholderFragment.newInstance(position + 1);
}

@Override
public int getCount() {
return tab_icons.length;
}

@Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
return getString(R.string.title_section2).toUpperCase(l);
case 2:
return getString(R.string.title_section3).toUpperCase(l);
}
return null;
}
}

===
TabBarView

测光与聚焦区域

如果设备支持自动对焦,可以使用setFocusMode方法传入一个Camera.Parameters.FOCUS_MODE_*常量来指定对焦模式。根据不同设备的支持,使用getSupportedFocusMode方法找到可用的对焦模式。使用自动对焦可以使用AutoFocusCallback回调。

1
2
3
4
5
6
7
8
9
10
Camera.Parameters parameters = camera.getParameters();
if(parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)){
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);

camer.autoFocus(new AutoFocusCallback(){
public void onAutoFocus(boolean success,Camera camera){
//
}
});
}

getMaxNumFocusAreas方法来确定涉笔是否支持定义对焦区域。getMaxNumMeteringAreas来确定摄像头是否支持测光区域。

1
2
3
4
5
6
7
8
9
10
11
if(params.getMaxNumMeteringAreas() > 0) { // 检查是否支持测光区域
List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();

Rect areaRect1 = new Rect(-100,-100,100,100); // 在图像的中心指定一个区域
meteringAreas.add(new Camera.Area(areaRect1,600)); // 设置宽度待60%
Rect areaRect2 = new Rect(800,-1000,1000,-800); // 在图像的右上角指定一个区域
meteringAreas.add(new Camera.Area(areaRect2,400)); // 设置宽度为40%
params.setMeteringAreas(meteringAreas);
}

mCamera.setParameters(params);

Camera.Area对象包含两个参数:一个Rect对象指定了相机视图中的一个区域,还有一个宽度,告诉相机在测光或聚焦计算中此区域的重要程度。
Camera.Area对象的Rect描述了一个矩形区域在一个2000*2000个单元格组成的区域中的映射位置。坐标-1000,-1000表示左上角,1000,1000表示右下角。不会随变焦大小改变。

人脸识别

调用getMaxNumDetectedFaces()来检测是否支持面部检测特性

1
2
3
4
5
6
7
8
class MyFaceDetectionoListener implements Camera.FaceDetectionListener {
@Override
public void onFaceDetection(Face[] faces,Camera camera) {
if (faces.length > 0) {
Log.d("FaceDetection","face detected:" + faces.length + "face 1 Location x:" + faces[0].rect.centerX() + "Y:" + faces[0].rect.centerY());
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class Preview extends ViewGroup implements SurfaceHolder.Callback {
SurfaceView mSurfaceView;
SurfaceHolder mHolder;

Perview(Context context){
super(context);

mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

}

public void setCamera(Camera camera) {
if (mCamera == camera) { return; }

stopPreviewAndFreeCamera();

mCamera = camera;

if (mCamera != null) {
List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportedPreviewSizes = localSizes;
requestLayout();

try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
mCamera.startPreview();
}
}
// 修改相机设置
public void surfaceChanged(SurfaceHolder holder,int format,int w,int h) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.with,mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
// 设置预览方向 setCameraDisplayOrientation()方法 Android Api level 14之前 必须先体质预览

// 拍摄照片
Camera.takePicture()拍下图片
创建Camera.PictureCallback与Camera.ShutterCallback 对象并传递到Camera.takePocture()中
如果想做连拍动作,可以创建一个Camera.PreviewCallback并实现onPerviewFrame()
// 停止预览并释放相机
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null) {
mCamera.stopPreview();
}
}
public void stopPreviewAndFreeCamera() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}

  • ccp(x,y) 创建一个向量
  • ccpFromSize(s) 以size s的width为x,height为y创建一个向量
  • ccpAdd(v1,v2) 向量之间的加法
  • ccpSub(v1,v2) 向量之间的减法
  • ccpNeg(v) 向量取反
  • ccpMult(v,s) 数乘,等价于ccp(v.xs,v.ys) s是一个浮点数
  • ccpMidpoint(v1,v2) 取中点
  • ccpDot(v1,v2) 点乘 等价于 v1.xv2.x + v1.yv2.y
  • ccpCross(v1,v2) 叉乘 等价于 v1.xv2.y - v1.yv2.x
  • ccpProject(v1,v2) 返回向量v1在向量v2的投影向量
  • ccpLength(v) 返回向量v的长度
  • ccpLengthSQ(v) 返回向量v的长度的平方
  • ccpDistance(v1,v2) 返回点v1到v2的距离
  • cppDistanceSQ(v1,v2) 返回点v1到v2距离的平方
  • ccpNormalize(v) 返回v的标准化向量,就是长度为1

  • ccpRotate(v1,v2) 向量v1旋转过向量v2的角度并且乘上向量v2的长度。当v2是一个长度为1的标准向量时就是正常的旋转了,可以配套地用ccpForAngle

  • ccpPerp(v) 等价于 ccp(-v.y, v.x); (因为opengl坐标系是左下角为原点,所以向量v是逆时针旋转90度)
  • ccpRPerp(v) 等价于 ccp(v.y, -v.x); 顺时针旋转90度

  • ccpForAngle(a) 返回一个角度为弧度a的标准向量

  • ccpToAngle(v) 返回向量v的弧度
  • ccpAngle(a, b) 返回a,b向量指示角度的差的弧度值
  • ccpRotateByAngle(v, pivot, angle) 返回向量v以pivot为旋转轴点,按逆时针方向旋转angle弧度

  • CC_RADIANS_TO_DEGREES(a) 弧度转角度

  • CC_DEGREES_TO_RADIANS(a) 角度转弧度
  • CCRANDOM_MINUS1_1() 产生-1到1之间的随机浮点数
  • CCRANDOM_0_1() 产生0到1之间的随机浮点数

  • CCAssert(cond,msg) 断言表达式cond为真,如果不为真,则显示字符串msg信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CCArray* _array;  
CCObject* _object; // 用来遍历数组的临时变量
CCARRAY_FOREACH(_array, _object) // 正向遍历
{
// todo with _object....
}

CCARRAY_FOREACH_REVERSE(_array, _object) // 反向遍历
{
// todo with _object....
}
CCDictionary* _dict;
CCDictElement* _elmt; // 遍历表的临时变量
CCDICT_FOREACH(_dict, _elmt)
{
  // todo with elmt;
}
  • CREATE_FUNC() 创建构造函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # define CREATE_FUNC(__TYPE__)
    static __TYPE__* create()
    {
    __TYPE__ *pRet = new __TYPE__();
    if (pRet && pRet->init())
    {
    pRet->autorelease();
    return pRet;
    }
    else
    {
    delete pRet;
    pRet = NULL;
    return NULL;
    }
    }