在第五部分我们增加了一些敌机而且给游戏者增加了武器使它能射击。在第六部分我们将增加碰撞检测来允许游戏者确实能够击落敌机。

碰撞检测是当两个对象碰撞时能够检测到,然后正确地反应。在第五部分我们给游戏者射击接近的敌机的能力。唯一的问题是那些子弹只是越过敌机。在第六部分我们将增加必要的代码来实现碰撞检测,这将让我们能够把敌机射下来。

碰撞检测看起来是非常简单地概念,但实现起来却超乎寻常地难。你将发现有很多整本整本讲测试2维和3维图形交集的书。让我们感到幸运的是我们的碰撞检测将非常简单。在屏幕上的每个对象将有一个矩形区域来检测到碰撞(“碰撞区”)。为了简单起见这个区域将和用来在屏幕上显示子图形的基础图片大小一样。一旦这些矩形重叠我们将检测到碰撞。

为了得到最好的效果这些矩形将被剪裁地尽量和显示的图片一样大。下面是在游戏中可能被用到的两幅图片。这两幅图片将完全显示一样因为在飞机周围是透明的。然而上面一张图片对于碰撞检测系统是最优的,因为它裁剪得更接近实际的飞机图形大小。下面一张将会显示好像在应该碰到其它对象之前就碰到了,因为碰撞检测系统不会注意到透明的边界部分,而且认为整个图片区域被用来作为碰撞

现在让我们看看为了实现碰撞检测需要在GameObject类中做哪些改变。

使用FLEX和Actionscript开发FLASH 游戏-碰撞检测(第二页)

GameObject.as

package

{

import flash.display.*;

import flash.events.*;

import flash.geom.*;

/* The base class for all objects in the game */

public class GameObject

{

//object position

public var position:Point=new Point(0,0);

//higher ZOrder objects are rendered on top of lower ones

public var zOrder:int=0;

//the bitmap data to diaplay

public var graphics:GraphicsResource=null;

//true if the object is active in the game

public var inuse:Boolean=false;

public var collisionArea:Rectangle;

public var collisionName:String=CollisionIdentifiers.NONE;

public function get CollisionArea():Rectangle

{

return new Rectangle(position.x,position.y,collisionArea.width,collisionArea.height);

}

public function GameObject()

{

}

public function startupGameObject(graphics:GraphicsResource,position:Poin,z:int=0):void

{

if(!inuse)

{

this.graphics=graphics;

this.zOrder=z;

this.position=position.clone();

this.inuse=true;

GameObjectManager.Instance.addGameObject(this);

setupCollision();

}

}

public function shutdown():void

{

if(inuse)

{

graphics=null

inuse=false;

GameObjectManager.Instance.removeGameObject(this);

}

}

public function copyToBackBuffer(db:BitmapData):void

{

db.copyPixels(graphics.bitmap,graphics.bitmap.rect,position,

graphics.bitmapAlpha,new Point(0,0),true);

}

public function enterFrame(dt:Number):void

{

}

public function mouseDown(event:MouseEvent):void

{

}

public function click(event:MouseEvent):void

{

}

public function mouseUp(event:MouseEvent):void

{

}

public function mouseMove(event:MouseEvent):void

{

}

protected function setupCollision():void

{

collisionArea=graphics.bitmap.rect;

}

public function collision(other:GameObject):void

{

}

}

}

我们增加了两个新的属性:碰撞区(collisionArea)和碰撞名(collisionName)。碰撞区属性代表了上文所述的描述碰撞区的矩形。碰撞名属性是赋给游戏对象用来定义它是哪种对象的名字,至少对于碰撞检测系统而言的种类。例如:被游戏者发出的子弹的碰撞名为“游戏者武器”,而一架敌机的碰撞名则是“敌人”。缺省状态下我们把它设置为“None”,使用CollisionIdentifiers类的NONE属性。

另外我们也增加了三个新的函数:碰撞(collision)、碰撞区域(CollisionArea)和设置碰撞(setupCollision)。碰撞函数是一个空函数,以待被继承类方法所覆盖。设置碰撞函数被用来负责保存碰撞检测系统下的图片的大小。碰撞区域函数返回碰撞区矩形目前在屏幕上的位置。

你可能想问为什么我们还麻烦地设置一个collsionArea属性,它实际上和graphics.bitmap.rect是完全一样的。只是因为后面(在第七章)我们将增加游戏的动画部分。动画类将用自己的转门的逻辑覆盖设置碰撞函数。虽然现在碰撞区域和图片的矩形一样。

CollisionIdentifiers.as

package

{

public class CollisionIdentifiers

{

public static const NONE:String="None";

public static const PLAYER:String="Player";

public static const PLAYERWEAPON:String="PlayerWeapon";

public static const ENEMYWEAPON:String="EnemyWeapon";

public static const ENEMY:String="Enemy";

public static const POWERUP:String="Powerup";

}

}

就像ZOrders类一样,CollisionIdentifiers类被用来保存一些预定义的静态属性;这里就是碰撞名。这么做的目的还是为了促进自文档化。CollisionIdentifiers.PLAYER的意思不言自明,然而字符串“Player”却没有同样的内在含义。

现在让我们看看在GameObjectManager类中做的改变。

GameObjectManager.as

package

{

import flash.display.*;

import flash.events.*;

import flash.utils.*;

import mx.collections.*;

import mx.core.*;

public class GameObjectManager

{

//double buffer

public var backBuffer:BitmapData;

//colour to use to clear backbuffer with

public var clearColour:uint=0xFF0043AB;

//static instance

protected static var instance:GameObjectManager=null;

//the last frame time

protected var lastFrame:Date;

//a collection of the GameObjects

protected var gameObjects:ArrayCollection=new ArrayCollection();

// a collection where new GameObjects are placed,to void adding items

//to gameObjects while in the gameObjects collection while it is in a loop

protected var newGameObjects:ArrayCollection=new ArrayCollection();

//a collection where removed GameObjects are placed,to avoid removing items

//to gameObjects while in the gameObjects collection while it is in a loop

protected var removedGameObjects:ArrayCollection=new ArrayCollection();

protected var collisionMap:Dictionary=new Dictionary();

static public function get Instance():GameObjectManager

{

if(instance==null)

instance=new GameObjectManager();

return instance;

}

public function GameObjectManager()

{

if(instance!=null)

throw new Error("Only one Singleton instance should be instantiated");

backBuffer=new BitmapData(Application.application.width,Application.application.height,false);

}

public function startup():void

{

lastFrame=new Date();

}

public function shutdown():void

{

shutdownAll();

}

public function enterFrame():void

{

//Calculate the time since the last frame

var thisFrame:Date=new Date();

var seconds:Number=(thisFrame.getTime()-lastFrame.getTime())/1000.0;

lastFrame=thisFrame;

removeDeletedGameObjects();

insertNewGameObjects();

Level.Instance.enterFrame(seconds);

checkCollisions();

//now allow objects to update themselves

for each(var gameObject:GameObject in gameObjects)

{

if(gameObject.inuse)

gameObject.enterFrame(seconds);

}

drawObjects();

}

public function click(event:MouseEvent):void

{

for each(var gameObject:GameObject in gameObjects)

{

if(gameObject.inuse)

gameObject.click(event);

}

}

public function mouseDown(event:MouseEvent):void

{

for each(var gameObject:GameObject in gameObjects)

{

if(gameObject.inuse)

gameObject.mouseDown(event);

}

}

public function mouseUp(event:MouseEvent):void

{

for each(var gameObject:GameObject in gameObjects)

{

if(gameObject.inuse)

gameObject.mouseUp(event);

}

}

public function mouseMove(event:MouseMove):void

{

for each(var gameObject:GameObject in gameObjects)

{

if(gameObject.inuse)

gameObject.mouseMove(event);

}

}

protected function drawObjects():void

{

backBuffer.fillRect(backBuffer.rect,clearColor);

//draw the objects

for each(var gameObject:GameObject in gameObjects)

{

if(gameObject.inuse)

gameObject.copyToBackBuffer(backBuffer);

}

}

public function addGameObject(gameObject:GameObject):void

{

newGameObjects.addItem(gameObject);

}

public function removeGameObject(gameObject:GameObject):void

{

removedGameObjects.addItem(gameObject);

}

protected function shutdownAll():void

{

//don't dispose objects twice

for each(var gameObject:GameObject in gameObjects)

{

var found:Boolean=false;

for each(var removedObject:GameObject in removedGameObjects)

{

if(removedObject==gameObject)

{

found=true;

break;

}

}

if(!found)

gameObject.shutdown();

}

}

protected function insertNewGameObjects():void

{

for each(var gameObject:GameObject in newGameObjects)

{

for(var i:int=0;i<gameObjects.length;++i)

{

if(gameObjects.getItemAt(i).zOrder>gameObject.zOrder||

gameObjects.getItemAt(i).zOrder==-1

break;

}

gameObjects.addItemAt(gameObject,i);

}

newGameObjects.removeAll();

}

protected function removeDeletedGameObjects():void

{

//insert the object according to it's z position

for each(var removedObject:GameObject in removedGameObjects)

{

var i:int=0;

for (i=0;i<gameObjects.length;++i)

{

if(gameObjects.getItemAt(i)==removedObject)

{

gameObjects.removeItemAt(i);

break;

}

}

}

removedGameObjects.removeAll();

}

public function addCollidingPair(collider1:String,collider2:String):void

{

if(collisionMap[collider1]==null)

collisionMap[collider1]=new Array();

if(collisionMap[collider2]==null)

collisionMap[collider2]=new Array();

collisionMap[collider1].push(collider2);

}

protected function checkCollision():void

{

for(var i:int=0;i<gameObjects.length;++i)

{

var gameObjectI:GameObject=gameObjects.getItemAt(i) as GameObject;

for(var j:int=i+1;j<gameObjects.length;++j)

{

var gameObjectJ:GameObject=gameObjects.getItemAt(j) as GameObject;

//early out for non=colliders

var collisionNameNotNothing:Boolean=gameObjectI.collisionName!=

CollisionIdentifiers.NONE;

//objects can still exist in the gameObjects collection after being disposed,

so check

var bothInUse:Boolean=gameObjectI.inuse&&gameObjectJ.inuse;

//make sure we have an entry in the collisionMap

var collisionMapEntryExists:Boolean=collisionMap

[gameObject.collisionName]!=null;

//make sure the two objects are set to collide

var testForCollision:Boolean=collisionMapEntryExists&&collisionMap

[gameObjectI.collisionName].indexOf(gameObjectJ.collsionName)!=-1

if(collisionNameNotNothing&&

bothInUse&&

collisionMapEntryExists&&

testForCollision)

{

if(gameObjectI.CollisionArea.intersects(gameObjectJ.CollisionArea))

{

gameObjectI.collision(gameObjectJ);

gameObjectJ.collision(gameObjectI);

}

}

}

}

}

}

}

我们已经给GameObjectManager增加了一个属性:collisionMap。这是一个字典属性其关键码为游戏对象的碰撞名,而且值是一个所有可能与之碰撞的游戏对象的碰撞名的数组。当数量增加时它看起来像下面的形式。

关键码:”Player”值:{“Enemy”,”EnemyWeapon”,”Powerup”}

关键码:”Enemy”值:{“Player”,”PlayerWeapon”}

关键码:”PlayerWeapon”值:{“Enemy”}

关键码:”Powerup”值:{“Player”}

等等诸如此类。

addCollidingPair函数被用来填充collisionMap字典。我们将在main.mxml文件中的creationComplete函数中调用它。checkCollision函数用来实际检测出碰撞,而且同时游戏对象被告知。函数看起来比较复杂,实际上非常简单。

最初它在gameObjects集合(包括所有活跃的GameObjects)上循环两次,在这样的结构上来把所有的游戏对象和其它的对象比较一遍。它做了下面一系列的检查:

l         是否两个游戏对象的碰撞名都是”None”?两个游戏对象都需要其碰撞名为None来参与一个碰撞。

l         是不是两个游戏对象都是使用状态?(即它们在游戏中都是活跃的)这应该总是情况属实,但是也不影响检测。

l         是否游戏对象的碰撞名在collisionMap中都已经作为碰撞者注册了?collisionMap的目的是决定与之碰撞的对象是哪些

如果所有这些检测都是为真,那么我们使用矩形的重叠函数来看是否游戏对象实际上碰撞。如果他们是碰撞了那么通过它们的collision函数被告知。

正如我之前在论文中提过的碰撞检测是一个被用来整本整本探讨的主题。我们不会使用哪些很聪明的方式来优化碰撞检测系统。我们在这里的用到的是一种简单的检测系统,但是它也是很有用的因为我们在整个屏幕中在任何时候拥有的最多的游戏对象不会超过两打(24个)。

为了能够检测到所有的碰撞我们需要调用addColllidingPair函数。这将在我们的应用程序对象的creationComplete函数中调用。现在让我们看看所做的一些变化。

Level.as

package

{

import flash.events.*;

import flash.geom.*;

import flash.media.*;

import flash.net.*;

import flash.utils.*;

import mx.collections.ArrayCollection;

import mx.core.*;

public class Level

{

protected static var instance:Level=null;

protected static const TimeBetweenLevelElements:Number=2;

protected static const TimeBetweenEnemies:Number=3;

protected static const TimeBetweenClouds:Number=2.5;

protected static const TimeToLevelEnd:Number=2;

protected var timeToNextLevelElement:Number=0;

protected var levelElementGraphics:ArrayCollection=new ArrayCollection();

protected var timeToNextEnemy:Number=0;

protected var enemyElementGraphics:ArrayCollection=new ArrayCollection();

protected var timeToNextCloud:Number=0;

protected var timeToLevelEnd:Number=0;

public var levelEnd:Boolean=false;

static public function get Instance():Level

{

if(instance==null)

instance=new Level();

return instance;

}

public function Level(caller:Function=null)

{

if(Level.instance!=null)

throw new Error("Only one Singleton instance should be instantiated");

levelElementGraphics.addItem(ResourceManager.SmallIslandGraphics);

levelElementGraphics.addItem(ResourceManager.BigIslandGraphics);

levelElementGraphics.addItem(ResourceManager.VolcanoIslandGraphics);

enemyElementGraphics.addItem(ResourceManager.SmallBluePlaneGraphics);

enemyElementGraphics.addItem(ResourceManager.SmallGreenPlaneGraphics);

enemyElementGraphics.addItem(ResourceManager.SmallWhitePlaneGraphics);

}

public function startup():void

{

timeToNextLevelElement=0;

new Player().startupPlayer();

timeToLevelEnd=TimeToLevelEnd;

levelEnd=false;

}

public function shutdown():void

{

}

public function enterFrame(dt:Number):void

{

//add a background element

timeToNextLevelElement-=dt;

if(timeToNextLevelElement<=0)

{

timeToNextLevelElement=TimeBetweenLevelElements;

var graphics:GraphicsResource=levelElementGraphics.getItemAt

(MathUtils.randomInteger(0,levelElementGraphics.length))as GraphicsResource;

var backgroundLevelElement:BackgroundLevelElement=

BackgroundLevelElement.pool.ItemFromPool as BackgroundLevelElement;

backgroundLevelElement.startupBackgroundLevelElement(

graphics,

new Point(Math.random()*Application.application.width,-graphics.bitmap.height),

ZOrders.BackgroundZOrder,

50);

}

//add an enemy

timeToNextEnemy-=dt;

if(timeToNextEnemy<=0)

{

timeToNextEnemy=TimeBetweenEnemies;

var enemygraphics:GraphicsResource=enemyElementGraphics.getItemAt

(MathUtils.randomInteger(0,enemyElementGraphics.length))as GraphicsResource;

var enemy:Enemy=Enemy.pool.ItemFromPool as Enemy;

enemy.startupBasicEnemy(

enemygraphics,

new Point(Math.random()*Application.application.width,-

enemygraphics.bitmap.height),

55);

}

//add cloud

timeToNextCloud-=dt;

if(timeToNextCloud<=dt)

{

timeToNextCloud=TimeBetweenClouds;

var cloudsBackgroundLevelElement:BackgroundLevelElement=

BackgroundLevelElement.pool.ItemFromPool as BackgroundLevelElement;

cloudBackgroundLevelElement.startupBackgroundLevelElement(

ResourceManager.CloudGraphics,

new Point(Math.random()*Application.application.width,-

ResourceManager.CloudGraphics.bitmap.height),

ZOrders.CloudsBelowZOrder,

75);

}

if(levelEnd)

timeToLevelEnd-=dt;

if(timeToLevelEnd<=0)

Application.application.currentState="MainMenu";

}

}

}

在Level类中做的改变仅仅让它在游戏者死亡时通过levelEnd属性被告知。当在enterFrame函数中使用timeToLevelEnd属性设置一个倒数计数器时,而且当timeToLevelEnd为0时状态被返回到MainMenu让我们回到主菜单屏幕。

碰撞检测在任何动作游戏中都是基本的。在本系列论文中我们实现了一个简单的,但是有效的碰撞检测系统,使得游戏者现在可以和游戏中的其他元素交互作用了,看起来就好像能够射下敌机。不幸的是目前的射下敌机实际上不是很令人满意,因为它们只是消失了。在本系列第七部分我们将增加一些动画到游戏里,来做一个好的爆炸效果。

在 http://flexfighters.sourceforge.net/flexfighters6.html处可查看最终效果,从 https://sourceforge.net/project/showfiles.php?group_id=241490&package_id=293860&release_id=632042处可下载资源。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/literza/archive/2009/06/05/4241517.aspx

main.mxml

<?xml version="1.0" encoding="utf-8"?>

<mx:Application

xmlns:ms="http://www.adobe.com/2006/mxml"

layout="absolute"

width="600"

height="400"

frameRate="100"

creationComplete="creationComplete()"

enterFrame="enterFrame(event)"

click="click(event)"

mouseDown="mouseDown(event)"

mouseUp="mouseUp(event)"

mouseMove="mouseMove(event)"

currentState="MainMenu">

<mx:states>

<mx:State

name="Game"

enterState="enterGame(event)"

exitState="exitGame(event)"

</mx:State>

<mx:State name="MainMenu">

<mx:AddChild relativeTo="{myCanvas}" position="lastChild">

<mx:Button x="525" y="368" label="Start" id="btnStart" click="startGameClicked(event)"/>

</mx:AddChild>

</mx:State>

</mx:states>

<mx:Canvas x="0" y="0" width="100%" height="100%" id="myCanvas"/>

<mx:Script>

<![CDATA[

protected var inGame:Boolean=false;

public function creationComplete():void

{

GameObjectManager.Instance.addCollidingPair(CollisionIdentifiers.PLAYER,CollisionIdentifiers.ENEMY);

GameObjectManager.Instance.addCollidingPair(CollisionIdentifiers.ENEMY,CollisionIdentifiers.PLAYERWEAPON);

GameObjectManager.Instance.addCollidingPair(CollisionIdentifiers.PLAYER,CollisionIdentifiers.ENEMYWEAPON);

}

public function enterFrame(event:Event):void

{

if(inGame)

{

GameObjectManager.Instance.enterFrame();

myCanvas.graphics.clear();

myCanvas.graphics.begingBitmapFill(GameObjectManager.Instance.backBuffer,null,false,false);

myCanvas.graphics.drawRect(0,0,this.width,this.height);

myCanvas.graphics.endFill();

}

}

privated function click(event:MouseEvent):void

{

GameObjectManager.Instance.click(event);

}

privated function mouseDown(event:MouseEvent):void

{

GameObjectManager.Instance.mouseDown(event);

}

privated function mouseUp(event:MouseEvent):void

{

GameObjectManager.Instance.mouseUp(event);

}

privated function mouseMove(event:MouseEvent):void

{

GameObjectManager.Instance.mouseMove(event);

}

protected function startGameClicked(event:Event):void

{

currentState="Game"

}

protected function enterGame(event:Event):void

{

Mouse.hide();

GameObjectManager.Instance.startup();

Level.Instance.startup();

inGame=true;

}

protected function exitGame(event:Event):void

{

Mouse.show();

Level.Instance.shutdown();

GameObjectManager.Instance.shutdown();

inGame=false;

}

]]>

</mx:Script>

</mx:Application>

就如你所见的要指定两个游戏对象碰撞只需要调用GameObjectManager的addCollidingPair函数。这里我们指定了游戏者会同敌机碰撞,敌机会同游戏者子弹碰撞,游戏者也会与敌机子弹碰撞。

那么现在既然我们可以检测到碰撞我们就需要更新游戏者、子弹和敌机类的代码,来设置他们的碰撞名以及当检测到时的反应。现在让我们看看游戏者类。

使用FLEX和Actionscript开发FLASH 游戏-碰撞检测相关推荐

  1. 使用FLEX 和 Actionscript开发FLASH 游戏(一)

    使用FLEX 和 Actionscript开发FLASH 游戏 开始 本系列包括1至10部分:使用FLEX开发游戏 写自Matthew Casperson Casperson 2008年10月31日出 ...

  2. [新闻资讯] 使用Flex和Actionscript开发Flash游戏——重复背景绘制

    [新闻资讯] 使用Flex和Actionscript开发Flash游戏--重复背景绘制 Flex, Flash, Actionscript, 游戏, 开发 资讯类型: 翻译 来源页面: http:// ...

  3. [原创]flex 3 + .net开发flash Remoting一 --- 开发环境

    flex 3 + .net开发flash Remoting一 --- 开发环境 本篇文章将介绍flash Remoting 开发的必备的运行环境和相关配置过程: 一.开发必备环境.     1. fl ...

  4. java开发flash游戏_FLASH+JAVA开发实时网络游戏

    FLASH+JAVA开发实时网络游戏 本文分两部分:FLASH编程 和 Java编程,此文记录的仅仅是我在探索中的一些收获,其中用了很多个人化的描述语言,并不是业界标准的用语. :) 探索笔记: 目前 ...

  5. flash html游戏开发,flash游戏制作|Flash AS3.0教你射击类游戏的制作_好特教程

    解析打飞机游戏的制作过程 (一) 演示: 这款游戏可能大家都玩过.敌机在蓝天上来回飞行,左右箭头键控制火炮在草地上左右移动.按下空格键发射子弹,击中敌机后,敌机爆炸.得分:记录击中的敌机数.剩余子弹: ...

  6. Flash、HTML和Unity开发网页游戏的现实比较

    2011-11-21 这一天对于全球的flash开发者来说是一个黑暗的日子,因为Adobe宣布它将停止对移动浏览器上flash的支持.在此之前一天,Adobe刚刚宣布大规模裁员,这看起来似乎不是什么大 ...

  7. 用Flash、HTML5和Unity开发网页游戏的现实

    今天对于全球的Flash开发者来说是黑暗的一天,因为Adobe宣布将不再对移动设备上的浏览器进行Flash技术支持.在这之前,Adobe刚刚宣布了公司范围内的大幅度裁员.尽管这似乎并不是什么严重的问题 ...

  8. JAVA能做flash游戏吗_FLASH+JAVA开发实时网络游戏 (转:闪客帝国)

    简介: 实时网络游戏也属于大型应用程序范畴,一个关键环节就是建立实时主动通信环境,在此Socekt API就成为了首选.通过调用XMLSocket方法,FLASH就可以和一些由强大语言编写的服务器应用 ...

  9. 快速创建精彩的Flash游戏(一) Flash2D游戏引擎简介

    原文链接:http://xiazhihui321.blog.163.com/blog/static/81328893201141851158857/ Adobe Flash自诞生之日就与游戏结下不解之 ...

最新文章

  1. 基于javaGUI的文档识别工具制作
  2. 百度云盘上传文件和下载文件慢的解决办法
  3. vim复制内容到系统剪贴板
  4. C#开发的高性能EXCEL导入、导出工具DataPie(支持MSSQL、ORACLE、ACCESS,附源码下载地址)...
  5. python获取路径下所有文件_Python获取路径下所有文件名
  6. onTextChanged参数解释及实现EditText字数监听
  7. 滴滴配合警方调证不超 10 分钟;苹果否认恶意芯片报道;贝索斯建火箭中心 | 极客头条...
  8. 安装黑苹果时提示未能与服务器,黑苹果安装提示:不能验证这个“安装 OS X EI Capitan”应用程序副本解决方法 _ 黑苹果乐园...
  9. g5500服务器装系统,联想G50笔记本U盘重装win10系统教程
  10. 创建室内导航地图的9个步骤
  11. matlab hist3 密度图,Matlab中hist3
  12. matlab eig函数_MATLAB作图实例:14:绘制虚数和复数图
  13. axure 折线图部件_Axure教程:折线图
  14. 【Linux】 ubuntu16.04系统使用印象笔记
  15. python使用xlwings库操作Excel常见操作
  16. uni-APP 联系我们
  17. QImage 如何设置图片的透明度
  18. python保存requests请求的文件的实战代码
  19. R语言实战学习--回归
  20. SpringMVC框架个人笔记之响应数据、文件上传

热门文章

  1. 什么是源文件什么是头文件_那是什么文件
  2. v9 手机门户内容无法显示
  3. 有关vlk、vol、oem 的版本意思
  4. spf13-vim 介绍及常用快捷键
  5. Python实现圆环面积求解
  6. linux系统句柄数命令
  7. Tomcat 系统架构与设计模式,第 2 部分: 设计模式分析
  8. word自动生成章节标题
  9. IOS开发之——画板-清屏/撤销/橡皮擦/保存(88)
  10. 如何在 Windows 上的 VirtualBox 中安装 macOS Big Sur