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

2024-05-30 19:15:14

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

Flex, Flash, Actionscript, 游戏, 开发

  • 资讯类型: 翻译
  • 来源页面: http://www.brighthub.com/internet/web-development/articles/12615.aspx
  • 资讯原标题: Flash Game Development with Flex and Actionscript - Tiled Background Rendering
  • 资讯原作者: Matthew Casperson

    我的评论:最后一篇~作者的架构的思想是很好的~涵盖了游戏的诸多方面,很细致。
    对这篇文你有啥看法,跟贴说说吧!欢迎口水和板砖,哈哈。欢迎大家和我们一同分享更多资讯。


    这一部分,我们要加入一个可以滚动的重复的背景。

    第9部分中,我们添加了关卡的按时调用功能构成的关卡结构。这个绘制主要用来显示界面上的敌机,但是对于背景的显示并不是很有用。这个部分,我们要绘制预定义的可重复的背景。

    重复背景由一系列很小的可重复的图片排列而成,在这里,就是按网格排列。这样做有几个优点,最重要的就是可以减小内存的需求。用一张很小的图像来渲染背景,每一关能减小内存好几兆,同时保留了高细节的呈现。只不过背景并不响应单块的互动事件,只是被关卡载入。与此相对,重复背景占用内存小,设计师同样可以利用这一特点制作出相当好看的背景。

    第一步就是绘制一个可自重复的背景图片。我发现了很多不错的图片 http://lostgarden.com/labels/free%20game%20graphics.html。站点上还有一些其它有趣的资源。

    下一步是找一个关卡编辑器,提供我们交互界面操作。当然也可以自己开发(这个可以再写一系列文章了)。幸好,有人已经做了这个工作。TaT自重复地图编辑器:http://kotisivu.dnainternet.net/ttilli/tilemapeditor/download.htm
    其中的层编辑和xml导出都很好用。

    当然,我们需要在游戏中加代码了~首先是存储背景数据。TiledBackgroundDefinition类来了~看看代码:

    TiledBackgroundDefinition.as

    1. package
    2. {
    3. public class TiledBackgroundDefinition
    4. {
    5. public var tiles:Array = null;
    6. public var tileScrollRate:Number = 0;
    7. public var tileWidth:int = 0;
    8. public var tileHeight:int = 0;
    9. }
    10. }

    复制代码

    tiles属性是一个多维数组,包含了GraphicsResources的引用,这些用来绘制背景,三维分别表示层、行和列。例如:tiles[1][4][5]指向GraphicsResource到第六列,第五行,第二层——从0开始索引的。tileWidth和tileHeight属性定义了关卡北京的尺寸。tileScrollRate定义了关卡滚动速度。

    现在我们可以存储定义自重复背景了。LevelDefinitions类用来存储定义。让我们看看代码:
    LevelDefinitions.as

    1. LevelDefinitions.as
    2. package
    3. {
    4. import flash.geom.*;
    5. import flash.utils.*;
    6. public class LevelDefinitions
    7. {
    8. protected static var instance:LevelDefinitions = null;
    9. protected var levelDefinitions:Dictionary = new Dictionary();
    10. public var levelTileMaps:Dictionary = new Dictionary();
    11. static public function get Instance():LevelDefinitions
    12. {
    13. if ( instance == null )
    14. instance = new LevelDefinitions();
    15. return instance;
    16. }
    17. public function LevelDefinitions()
    18. {
    19. }
    20. public function addLevelDefinition(levelID:int, element:LevelDefinitionElement):void
    21. {
    22. if (levelDefinitions[levelID] == null)
    23. levelDefinitions[levelID] = new Array();
    24. (levelDefinitions[levelID] as Array).push(element);
    25. levelDefinitions[levelID].sort(LevelDefinitionElement.sort);
    26. }
    27. public function getNextLevelDefinitionElements(levelID:int, lastTime:Number):Array
    28. {
    29. var returnArray:Array = new Array();
    30. var nextTime:Number = -1;
    31. if (levelDefinitions[levelID] != null)
    32. {
    33. for each (var levelDefElement:LevelDefinitionElement in levelDefinitions[levelID])
    34. {
    35. if (levelDefElement.time > lastTime && nextTime == -1)
    36. {
    37. returnArray.push(levelDefElement);
    38. nextTime = levelDefElement.time;
    39. }
    40. else if (levelDefElement.time == nextTime)
    41. {
    42. returnArray.push(levelDefElement);
    43. }
    44. else if (levelDefElement.time > nextTime && nextTime != -1)
    45. break;
    46. }
    47. }
    48. return returnArray.length == 0?null:returnArray;
    49. }
    50. public function getNextLevelID(levelID:int):int
    51. {
    52. if (levelDefinitions[levelID + 1] == null) return 0;
    53. return levelID + 1;
    54. }
    55. public function startup():void
    56. {
    57. GameObjectManager.Instance.addCollidingPair( CollisionIdentifiers.PLAYER, CollisionIdentifiers.ENEMY);
    58. GameObjectManager.Instance.addCollidingPair( CollisionIdentifiers.ENEMY, CollisionIdentifiers.PLAYERWEAPON);
    59. GameObjectManager.Instance.addCollidingPair( CollisionIdentifiers.PLAYER, CollisionIdentifiers.ENEMYWEAPON);
    60. defineLevel1();
    61. defineLevel2();
    62. }
    63. public function shutdown():void
    64. {
    65. }
    66. protected function defineLevel1():void
    67. {
    68. var level1Tiles:TiledBackgroundDefinition = new TiledBackgroundDefinition();
    69. levelTileMaps[1] = level1Tiles;
    70. level1Tiles.tileScrollRate = 25;
    71. level1Tiles.tileHeight = 40;
    72. level1Tiles.tileWidth = 40;
    73. level1Tiles.tiles =
    74. [
    75. [
    76. [ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1]
    77. ...
    78. ,[ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1, ResourceManager.GreenGraphicsID1]
    79. ]
    80. ,[
    81. [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]
    82. ...
    83. ,[null, ResourceManager.GreenGraphicsID62, ResourceManager.GreenGraphicsID63, ResourceManager.GreenGraphicsID64, null, ResourceManager.GreenGraphicsID48, ResourceManager.GreenGraphicsID49, null, null, null, null, null, null, null, null]
    84. ]
    85. ];
    86. LevelDefinitions.Instance.addLevelDefinition(
    87. 1,
    88. new LevelDefinitionElement(
    89. 4,
    90. function():void
    91. {
    92. for each (var xPos:int in [150, 350])
    93. {
    94. (Enemy.pool.ItemFromPool as Enemy).startupBasicEnemy(
    95. ResourceManager.SmallBluePlaneGraphics,
    96. new Point(xPos, -ResourceManager. SmallBluePlaneGraphics.bitmap.height),
    97. 55);
    98. }
    99. }
    100. ));
    101. ...
    102. }
    103. protected function defineLevel2():void
    104. {
    105. ...
    106. }
    107. }
    108. }

    复制代码

    (待续)

    1

    评分次数

    • 威望 + 1 点 银子 + 20 两

      达达

    本主题由 达达 于 昨天 12:43 审核通过
    收藏 分享 评分
我是小辛~
回复 引用

订阅 报告 道具 TOP

立刻订阅天地会人人快报,时刻同步全球RIA技术与资讯热点! RSS订阅地址: http://feeds.feedburner.com/9RIAnews
我们添加了一个新的属性levelTileMaps,这是一个Dictionary类型,用来将TiledBackgroundDefinitions映射至LevelID(和第9部分levelDefinitions属性类似)。

同样的,我们增加了两个新方法:defineLevel1和defineLevel2。这两个方法用于分别定义levels,看上去新的自重复的背景定义有点累赘。在这两个方法中,我们创建TiledBackgroundDefinition对象,初始化它们并赋值到levelTileMaps属性上。

当你使用TaT创建关卡时,会得到两个很重要的文件:tileset.xml(定义了单个的字重复图像)和一个 你关卡的名字.xml文件(定义了图片在关卡中的排列情况)。我们要把 你关卡的名字.xml文件的数据放到tiles数组中。

你可能会奇怪,怎样才能把xml数据存到多维数组中。简单说,我创建另一个程序,将xml转换成Actionscript代码,然后创建数组。为什么不选择在程序中解析XML呢?理由和我不选择用xml定义关卡结构是一样的:解析xml并转换数据类型是一个很复杂的过程,而转换xml为actionscript要简单很多。这里我就不讲解转换程序的代码了,你可以在这里下载到:http://flexfighters.svn.sourcefo ... /TatResourceParser/

TaT编辑器创建的第二个xml定义了组成关卡的单个的自重复图像。使用上面的程序,我们也可以将其转换成actionscript代码,嵌入图像然后用ResourceManager创建与之对应的GraphicsResource对象。新的代码重复部分很多,下面我只写一小部分不一样的:

ResourceManager.as (新代码示例)

  1. [Embed(source="../media/Green26.png")]
  2. public static var GreenID65:Class;
  3. public static var GreenGraphicsID65:GraphicsResource = new GraphicsResource(new GreenID65());
  4. [Embed(source="../media/Green5.png")]
  5. public static var GreenID11:Class;
  6. public static var GreenGraphicsID11:GraphicsResource = new GraphicsResource(new GreenID11(), 1, 1, new Rectangle(0, 0, 40, 40));
  7. public static var GreenGraphicsID12:GraphicsResource = new GraphicsResource(new GreenID11(), 1, 1, new Rectangle(40, 0, 40, 40));
  8. public static var GreenGraphicsID17:GraphicsResource = new GraphicsResource(new GreenID11(), 1, 1, new Rectangle(0, 40, 40, 40));
  9. public static var GreenGraphicsID18:GraphicsResource = new GraphicsResource(new GreenID11(), 1, 1, new Rectangle(40, 40, 40, 40));

复制代码

我是小辛~
新手看过来:天地会入会必读
回复 引用

报告 道具 TOP

 
哪位有好的游戏素材提取的方法或经验啊,想找素材来作作实验
医学教育网
互联互动实验室
回复 引用

报告 道具 TOP

 
代码与其它资源定义相同,除了传给ResourceManager新的参数。这是为了适应TaT引用的结构——加入关卡的图片比自重复的图片尺寸大。所以,例如一个字重复图片大小是40x40像素,但是整个树的图像可以是40x80像素。在这种情况下,树的图片要引用两个独立的图片,按照定义,一个在上面,一个在下面。为了让GraphicsResouce指向相同大小的区域,我们可以将其指向相同的自重复图片。

现在,我们可以定义并保存自重复图像了。接下来就是要绘制了。请看代码:

TiledBackground.as

  1. package
  2. {
  3. import flash.display.*;
  4. import flash.geom.*;
  5. import mx.collections.*;
  6. import mx.core.*;
  7. public class TiledBackground extends BaseObject
  8. {
  9. public var scrolling:Boolean = true;
  10. protected var yOffset:Number = 0;
  11. protected var definition:TiledBackgroundDefinition = null;
  12. static public var pool:ResourcePool = new ResourcePool(NewTiledBackground);
  13. static public function NewTiledBackground():TiledBackground
  14. {
  15. return new TiledBackground();
  16. }
  17. public function TiledBackground()
  18. {
  19. super();
  20. }
  21. public function startupTiledBackground(definition:TiledBackgroundDefinition):void
  22. {
  23. super.startupBaseObject(ZOrders.BACKGROUNDZORDER);
  24. this.definition = definition;
  25. this.yOffset = 0;
  26. this.scrolling = true;
  27. }
  28. override public function shutdown():void
  29. {
  30. super.shutdown();
  31. }
  32. override public function enterFrame(dt:Number):void
  33. {
  34. if (scrolling)
  35. {
  36. var mapHeight:int = definition.tiles[0].length * definition.tileHeight;
  37. var mapOverlap:int = mapHeight - Application.application.height;
  38. yOffset += definition.tileScrollRate * dt;
  39. if (yOffset > mapOverlap)
  40. {
  41. scrolling = false;
  42. yOffset = mapOverlap;
  43. }
  44. }
  45. }
  46. override public function copyToBackBuffer(db:BitmapData):void
  47. {
  48. var startRow:int = yOffset / definition.tileHeight;
  49. var startRowNumber:Number = yOffset / definition.tileHeight;
  50. var startRowHeight:int = definition.tileHeight * (startRowNumber - startRow);
  51. var drawnHeight:int = 0;
  52. var drawnWidth:int = 0;
  53. var layer:int = 0;
  54. var row:int = startRow;
  55. var col:int = 0;
  56. // loop through each layer
  57. for (layer = 0; layer < definition.tiles.length; ++layer)
  58. {
  59. // loop through each row
  60. var count:int = 0;
  61. for (row = (definition.tiles[layer] as Array).length - 1 - startRow; row >= 0 ; --row)
  62. {
  63. // loop through each column of the current row
  64. for (col = 0; col < (definition.tiles[layer][row] as Array).length; ++col)
  65. {
  66. var graphics:GraphicsResource = definition.tiles[layer][row][col] as GraphicsResource;
  67. var top:int = Application.application.height - drawnHeight - definition.tileHeight + startRowHeight;
  68. if (graphics != null)
  69. {
  70. db.copyPixels(
  71. graphics.bitmap,
  72. graphics.drawRect,
  73. new Point(
  74. col * definition.tileWidth,
  75. top),
  76. graphics.bitmapAlpha,
  77. new Point(
  78. graphics.drawRect.x,
  79. graphics.drawRect.y),
  80. true);
  81. }
  82. drawnWidth += definition.tileWidth;
  83. if (drawnWidth >= Application.application.width)
  84. break;
  85. }
  86. drawnWidth = 0;
  87. drawnHeight += definition.tileHeight;
  88. if (drawnHeight >= Application.application.height + definition.tileHeight)
  89. break;
  90. }
  91. drawnHeight = 0;
  92. }
  93. }
  94. }
  95. }

复制代码

我是小辛~
回复 引用

报告 道具 TOP

 
不错!用的是魔兽的地图吧?
回复 引用

报告 道具 TOP

 
这里要讲解3个属性。scrolling属性标记关卡是否在滚动(true),false表示level已经滚动到了尽头。yOffset属性用来保存level滚动了多少。definition属性保存了到一个自重复background definitions的引用,在Level类中创建。

enterFrame方法和copyToBackBuffer方法做了大量的工作。等执行enterFrame方法时,TiledBackground根据TiledBackgroundDefinition类(定义了滚动速度)的tileScrollRate属性向下滚动。一旦探测到滚动到了尽头,就把scrolling设置为false然后停止更新yOffset。copyToBackBuffer方法决定在哪里绘制自重复图像。第一次是层的循环,然后是行和列,将它们绘制到正确的位置。

TiledBackground实例的创建也需要分割老的GameObject类。原先GameObject表示每一个元素都由一个GrphicsResource类实例表示。而现在TiledBackground可能会访问很多很多的GraphicsResources在屏幕上绘制它们。为了适应这个情况,我们创建一个新类叫BaseObject,保存了所有通用的属性,不包括GraphicsResource。TiledBackground和GameObject同时继承自BaseObject,而Player和Enemy保持不变。

Level类将所有的工作融合到一起,并在合适的地方创建TiledBackground。来看看代码:

Level.as

  1. package
  2. {
  3. import flash.events.*;
  4. import flash.geom.*;
  5. import flash.media.*;
  6. import flash.net.*;
  7. import flash.utils.*;
  8. import mx.core.*;
  9. public class Level
  10. {
  11. protected static var instance:Level = null;
  12. protected static const TimeBetweenLevelElements:Number = 2;
  13. protected static const TimeBetweenClouds:Number = 2.5;
  14. protected static const TimeToLevelEnd:Number = 2;
  15. protected var nextDefinitions:Array = null;
  16. protected var levelID:int = 0;
  17. protected var totalTime:Number = 0;
  18. protected var timeToNextCloud:Number = 0;
  19. protected var timeToLevelEnd:Number = 0;
  20. protected var backgroundMusic:SoundChannel = null;
  21. public var levelEnd:Boolean = false;
  22. static public function get Instance():Level
  23. {
  24. if ( instance == null )
  25. instance = new Level();
  26. return instance;
  27. }
  28. public function Level()
  29. {
  30. }
  31. public function startup(levelID:int):void
  32. {
  33. new Player().startupPlayer();
  34. timeToLevelEnd = TimeToLevelEnd;
  35. levelEnd = false;
  36. backgroundMusic = ResourceManager.Track1FX.play(0, int.MAX_VALUE);
  37. this.totalTime = 0;
  38. this.levelID = levelID;
  39. nextDefinitions = LevelDefinitions.Instance.getNextLevelDefinitionElements(levelID, 0);
  40. var tileDefinition:TiledBackgroundDefinition = LevelDefinitions.Instance.levelTileMaps[levelID] as TiledBackgroundDefinition;
  41. if (tileDefinition != null)
  42. (TiledBackground.pool.ItemFromPool as TiledBackground).startupTiledBackground(tileDefinition);
  43. }
  44. public function shutdown():void
  45. {
  46. backgroundMusic.stop();
  47. backgroundMusic = null;
  48. }
  49. public function enterFrame(dt:Number):void
  50. {
  51. totalTime += dt;
  52. if (nextDefinitions == null)
  53. {
  54. if (Enemy.pool.NumberOfActiveObjects == 0)
  55. levelEnd = true;
  56. }
  57. else
  58. {
  59. var nextLevelDefTime:Number = (nextDefinitions[0] as LevelDefinitionElement).time;
  60. if (totalTime >= nextLevelDefTime)
  61. {
  62. for each (var levelDefElement:LevelDefinitionElement in nextDefinitions)
  63. levelDefElement.func();
  64. nextDefinitions = LevelDefinitions.Instance.getNextLevelDefinitionElements(levelID, nextLevelDefTime);
  65. }
  66. }
  67. // add cloud
  68. timeToNextCloud -= dt;
  69. if (timeToNextCloud <= dt)
  70. {
  71. timeToNextCloud = TimeBetweenClouds;
  72. var cloudBackgroundLevelElement:BackgroundLevelElement = BackgroundLevelElement.pool.ItemFromPool as BackgroundLevelElement;
  73. cloudBackgroundLevelElement.startupBackgroundLevelElement(
  74. ResourceManager.CloudGraphics,
  75. new Point(Math.random() * Application.application.width, -ResourceManager.CloudGraphics.bitmap.height),
  76. ZOrders.CLOUDSBELOWZORDER,
  77. 75);
  78. }
  79. if (levelEnd)
  80. {
  81. timeToLevelEnd -= dt;
  82. var scale:Number = timeToLevelEnd / TimeToLevelEnd;
  83. if (scale < 0) scale = 0;
  84. var transform:SoundTransform = backgroundMusic.soundTransform;
  85. transform.volume = scale;
  86. backgroundMusic.soundTransform = transform;
  87. }
  88. if (timeToLevelEnd <= 0)
  89. Application.application.currentState = "LevelEnd";
  90. }
  91. }
  92. }

复制代码

我是小辛~
回复 引用

报告 道具 TOP

 
只用了3行代码来表示创建BackgroundLevelElement。

加入了自重复背景的绘制后,我们的游戏有了一个好看的背景,同时不会消耗太多的内存。多亏了免费的地图编辑器和资源。

结果:http://flexfighters.sourceforge.net/flexfighters10.html
源码:http://sourceforge.net/projects/ ... ers/FlexFighters10/

【全系列完~】

[新闻资讯] 使用Flex和Actionscript开发Flash游戏——重复背景绘制相关推荐

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

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

  2. 使用FLEX和Actionscript开发FLASH 游戏-碰撞检测

    在第五部分我们增加了一些敌机而且给游戏者增加了武器使它能射击.在第六部分我们将增加碰撞检测来允许游戏者确实能够击落敌机. 碰撞检测是当两个对象碰撞时能够检测到,然后正确地反应.在第五部分我们给游戏者射 ...

  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. c语言什么意思 app 视频 新闻,开发新闻资讯APP需要哪些功能?

    原标题:开发新闻资讯APP需要哪些功能? 在过去,人们获取新闻信息的方式一般是通过电视.报纸.广播之类的媒介,而在当今的互联网时代,人们获取信息的途径主要来源于各种新闻资讯APP. 这类APP相较于传 ...

  7. 短视频APP开发:我想打造新闻资讯短视频APP

    现在,还有多少人喜欢看新闻了? 六十年代,新闻是人们看世界的唯一窗口,八十年代,看新闻是全家人的集体活动,现在,短视频成了人们的手中宝,新闻,不是年轻人的范儿. 当抖音引爆全球,鸡汤灌满朋友圈,报纸逐 ...

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

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

  9. pbootcms黑色风格响应式新闻资讯博客整站源码

    演示 (自适应手机版)响应式新闻资讯技术博客织梦模板 游戏新闻网站源码下载51138.cn 更适合新手上传即用可改mysql数据库语言程序:PHP 5.2+ SQLite前端规范:html+css+j ...

最新文章

  1. R算数运算符:+、-、*、/、%%、%/%、^
  2. Struts2利用stream直接输出Excel
  3. Android动态方式破解apk进阶篇(IDA调试so源码)
  4. 设计的核心任务之二:信息隐藏
  5. boost::core模块实现分配器重新绑定的实例
  6. Java并发编程(一)线程的各种创建方式
  7. php兼容编码,PHP截取字符串编码(兼容utf-8和gb2312)
  8. 总结 一下UML 类图的关系
  9. phpstorm编辑器乱码问题解决
  10. Elasticsearch 不属于 Elastic
  11. bat中ERRORLEVEL的使用介绍
  12. NYOJ-769乘数密码,逆元解法;
  13. 太牛逼了!这个开源项目,可以把我从视频中移除!
  14. 解决前端浏览器字体小于12px办法
  15. 高中数学知识点总结归纳之立体几何
  16. GPS导航知识——DGPS
  17. linux备份mysql部分表数据,mysqldump导出表的部分数据库
  18. app.use()方法详解
  19. 滴滴交通云落地济南 提速城市“智慧交通”建设
  20. 所谓键位冲突和无冲突的各种原理

热门文章

  1. mysql 插入记录时自动生成8位随机数字
  2. 设置input只能输入数字
  3. 微信小程序——多人协同和版本管理
  4. 关于链接的较为全面的介绍
  5. [微语21.01.02] 清醒
  6. python拟合反比例函数_Python 数据处理(八)—— 应用函数
  7. 视频虚拟主播怎们搞?体验报告全记录;一图掌握SD应用精髓;Chat效率工具大汇总;品牌营销进入AI时代 | ShowMeAI日报
  8. python 多继承中方法的调用顺序
  9. IBM宣布造出全球首颗2nm EUV芯片
  10. 利用ssh命令建立SOCKS5代理服务器