概述

SpriteKit制作瓦片地图游戏,深入了解2D游戏制作过程

详细

代码下载:http://www.demodashi.com/demo/10703.html

说实话这个2D游戏实战的入门看的我脑浆子都沸腾了, 好多新的概念涌入, 没做过游戏开发的我表示真的难以接受, 吸收效率与之前相比也下降好多, 不过越往后学, 就能够加深对之前知识的掌握, 这可能也是看书的好处吧, 今天我也把对瓦片地图的一些学习经验记录下来供大家探讨.

说实话, 我很推荐Ray家的资源, 由浅入深手把手的教学, 内容前后呼应, 看几本书就能涵盖国内4个月培训班的课程体系. 遵循本系列一贯的风格, 我们还是从基础的API开始看起, 对API掌握熟练的话, 多敲两个Demo就能够基本的上手任何项目了.

一、瓦片地图技术要点

1、SKTileMapNode

@available(iOS 10.0, *)
open class SKTileMapNode : SKNode, NSCopying, NSCodingpublic init(tileSet: SKTileSet, columns: Int, rows: Int, tileSize: CGSize)open var numberOfColumns: Intopen var numberOfRows: Intopen var tileSize: CGSizeopen var mapSize: CGSize { get }open var tileSet: SKTileSetopen var colorBlendFactor: CGFloatopen func tileDefinition(atColumn column: Int, row: Int) -> SKTileDefinition?open func tileGroup(atColumn column: Int, row: Int) -> SKTileGroup?open func setTileGroup(_ tileGroup: SKTileGroup?, forColumn column: Int, row: Int)open func tileColumnIndex(fromPosition position: CGPoint) -> Intopen func tileRowIndex(fromPosition position: CGPoint) -> Intopen func centerOfTile(atColumn column: Int, row: Int) -> CGPoint
  • init(tileSet: SKTileSet, columns: Int, rows: Int, tileSize: CGSize) 瓦片地图节点的初始化方法

  • numberOfColumns 瓦片地图的列数

  • numberOfRows 瓦片地图的行数

  • tileSize 瓦片地图中每个瓦片的尺寸

  • mapSize 瓦片地图的尺寸

  • tileSet 瓦片地图的瓦片集

  • colorBlendFactor 瓦片的渲染着色

  • tileDefinition(atColumn column: Int, row: Int) -> SKTileDefinition? 根据列数和行数返回瓦片定义

  • tileGroup(atColumn column: Int, row: Int) -> SKTileGroup? 根据列数和行数返回瓦片组

  • setTileGroup(_ tileGroup: SKTileGroup?, forColumn column: Int, row: Int) 根据列数和行数设置瓦片组

  • tileColumnIndex(fromPosition position: CGPoint) -> Int 根据瓦片位置返回瓦片在瓦片地图中列数下标

  • tileRowIndex(fromPosition position: CGPoint) -> Int 根据瓦片位置返回瓦片在瓦片地图中行数下标

2、SKTileSet

@available(iOS 10.0, *)
open class SKTileSet : NSObject, NSCopying, NSCoding public init(tileGroups: [SKTileGroup])open var tileGroups: [SKTileGroup]open var name: String?open var defaultTileGroup: SKTileGroup?open var defaultTileSize: CGSizeopen var type: SKTileSetType@available(iOS 10.0, *)
public enum SKTileSetType : UInt {case gridcase isometriccase hexagonalFlatcase hexagonalPointy
}
  • init(tileGroups: [SKTileGroup]) 根据瓦片组初始化瓦片集

  • tileGroups 瓦片组

  • name 瓦片集的标识

  • defaultTileGroup 瓦片集默认瓦片组

  • defaultTileSize 瓦片集默认瓦片尺寸

  • type 瓦片集类型 - 网格, 等值, 六边形

3、SKTileGroup

@available(iOS 10.0, *)
open class SKTileGroup : NSObject, NSCopying, NSCodingopen class func empty() -> Selfpublic init(tileDefinition: SKTileDefinition)public init(rules: [SKTileGroupRule])open var name: String?
  • empty() 返回一个空的瓦片组

  • init(tileDefinition: SKTileDefinition) 根据瓦片定义初始化瓦片组

  • init(rules: [SKTileGroupRule]) 根据瓦片组规则初始化瓦片组

  • name 瓦片组的标识

4、SKTileGroupRule

@available(iOS 10.0, *)
open class SKTileGroupRule : NSObject, NSCopying, NSCodingpublic init(adjacency: SKTileAdjacencyMask, tileDefinitions: [SKTileDefinition])open var adjacency: SKTileAdjacencyMaskopen var tileDefinitions: [SKTileDefinition]open var name: String?
  • init(adjacency: SKTileAdjacencyMask, tileDefinitions: [SKTileDefinition]) 根据瓦片链接和瓦片定义初始化瓦片组规则

  • adjacency 瓦片链接

  • tileDefinitions 瓦片规则

  • name 瓦片组规则标识

5、SKTileDefinition

@available(iOS 10.0, *)
open class SKTileDefinition : NSObject, NSCopying, NSCodingpublic init(texture: SKTexture)public init(textures: [SKTexture], normalTextures: [SKTexture], size: CGSize, timePerFrame: CGFloat)open var userData: NSMutableDictionary?open var name: String?open var size: CGSizeopen var timePerFrame: CGFloatopen var rotation: SKTileDefinitionRotationopen var flipVertically: Boolopen var flipHorizontally: Bool
  • init(texture: SKTexture) 根据纹理初始化瓦片定义

  • init(textures: [SKTexture], normalTextures: [SKTexture], size: CGSize, timePerFrame: CGFloat) 根据纹理集合, 尺寸, 和帧率初始化瓦片定义

  • userData 瓦片定义的用户数据

  • name 瓦片定义的标识

  • timePerFrame 瓦片定义的帧率

  • rotation 瓦片定义的旋转规则

  • flipVertically 是否垂直翻转

  • flipHorizontally 是否水平翻转

二、程序实现

API, 了解一些基本的就够了, 如果要深究可以打开头文件逐个尝试, 我们现在就来实现一个小游戏, 这个游戏中包含了3个场景, 控制人物在规定时间内消灭所有的害虫, 我们着手进行游戏的开发吧!

1、step1 设置游戏场景的属性

class GameScene: SKScene {var background: SKTileMapNode! //背景瓦片地图节点var obstaclesTileMap: SKTileMapNode? //障碍物瓦片地图节点var bugsprayTileMap: SKTileMapNode? //杀虫喷剂瓦片地图节点var bugsNode = SKNode() //害虫的节点var player = Player() //玩家的节点var hud = HUD() //文字说明var firebugCount: Int = 0 //高级害虫的节点数var timeLimit: Int = 10 //时间限制var elapsedTime: Int = 0 //经过时间var startTime: Int? //开始时间var currentLevel: Int = 1 //当前关卡等级var gameState: GameState = .initial { //游戏状态默认为初始状态didSet { hud.updateGameState(from: oldValue, to: gameState) //更新游戏状态}}...
}

2、step2 加载游戏场景的初始化设置

required init?(coder aDecoder: NSCoder) {super.init(coder: aDecoder)background =childNode(withName: "background") as! SKTileMapNode //通过节点名读取背景瓦片地图节点obstaclesTileMap = childNode(withName: "obstacles") as? SKTileMapNode //通过节点名读取障碍物瓦片地图节点if let timeLimit =userData?.object(forKey: "timeLimit") as? Int {self.timeLimit = timeLimit //通过节点的用户数据设置每个场景的时间限制}// 1let savedGameState = aDecoder.decodeInteger(forKey: "Scene.gameState") //解档保存游戏状态if let gameState = GameState(rawValue: savedGameState), gameState == .pause { //当解档保存游戏状态为暂停时self.gameState = gameState //赋值游戏状态firebugCount = aDecoder.decodeInteger(forKey: "Scene.firebugCount") //解档高级害虫数elapsedTime = aDecoder.decodeInteger(forKey: "Scene.elapsedTime") //解档经过时间currentLevel = aDecoder.decodeInteger(forKey: "Scene.currentLevel") //解档当前关卡等级// 2player = childNode(withName: "Player") as! Player //根据节点名读取玩家节点hud = camera!.childNode(withName: "HUD") as! HUD //根据节点名读取文字说明bugsNode = childNode(withName: "Bugs")! //根据节点名读取害虫节点bugsprayTileMap = childNode(withName: "Bugspray") as? SKTileMapNode //通过节点名读取杀虫喷雾瓦片地图节点}addObservers() //添加观察者}deinit {NotificationCenter.default.removeObserver(self) //移除观察者}

3、step3 当场景移动到屏幕时的设置

override func didMove(to view: SKView) {if gameState == .initial { //当游戏状态为初始状态时addChild(player) //添加玩家到场景setupWorldPhysics() //添加物理世界createBugs() //添加害虫setupObstaclePhysics() //添加障碍物if firebugCount > 0 { //如果有高级害虫createBugspray(quantity: firebugCount + 10) //添加杀虫喷雾}setupHUD() //添加文字说明gameState = .start //设置游戏状态为开始状态}setupCamera() //添加摄像头}

4、step4 物理世界的设置

func setupWorldPhysics() {background.physicsBody =SKPhysicsBody(edgeLoopFrom: background.frame) //设置边缘物理体background.physicsBody?.categoryBitMask = PhysicsCategory.Edge //设置物理体标识为边缘physicsWorld.contactDelegate = self //物理世界代理}

5、step5 创建害虫的设置

func createBugs() {guard let bugsMap = childNode(withName: "bugs")as? SKTileMapNode else { return } //校验害虫瓦片地图节点// 1for row in 0..<bugsMap.numberOfRows { //逐行遍历害虫瓦片地图for column in 0..<bugsMap.numberOfColumns { //逐列遍历害虫瓦片地图// 2guard let tile = tile(in: bugsMap,at: (column, row)) else { continue } //校验瓦片地图中的每个瓦片// 3let bug: Bug if tile.userData?.object(forKey: "firebug") != nil { //从用户数据中判断是否为高级害虫bug = Firebug() //将害虫设置为高级害虫firebugCount += 1 //高级害虫书自增} else {bug = Bug() //将害虫设置为普通害虫}bug.position = bugsMap.centerOfTile(atColumn: column,row: row) //从害虫瓦片地图中读取位置并赋值bugsNode.addChild(bug) //添加节点bug.moveBug() //移动害虫}}// 4bugsNode.name = "Bugs" //设置害虫节点标识addChild(bugsNode) //添加父节点到场景// 5bugsMap.removeFromParent() //删除害虫瓦片地图地图节点}

6、step6 添加障碍物的设置

func setupObstaclePhysics() {guard let obstaclesTileMap = obstaclesTileMap else { return } //校验障碍物瓦片地图节点// 1for row in 0..<obstaclesTileMap.numberOfRows {for column in 0..<obstaclesTileMap.numberOfColumns {// 2guard let tile = tile(in: obstaclesTileMap,at: (column, row))else { continue }guard tile.userData?.object(forKey: "obstacle") != nilelse { continue }// 3let node = SKNode() //创建节点node.physicsBody = SKPhysicsBody(rectangleOf: tile.size) 根据瓦片尺寸创建物理体node.physicsBody?.isDynamic = false //不进入物理世界node.physicsBody?.friction = 0 //摩擦系数为0node.physicsBody?.categoryBitMask =PhysicsCategory.Breakable //设置物理体标识node.position = obstaclesTileMap.centerOfTile(atColumn: column, row: row)obstaclesTileMap.addChild(node)}}}

7、step7 添加杀虫喷雾的设置

func createBugspray(quantity: Int) {// 1let tile = SKTileDefinition(texture:SKTexture(pixelImageNamed: "bugspray")) //创建瓦片定义// 2let tilerule = SKTileGroupRule(adjacency:SKTileAdjacencyMask.adjacencyAll, tileDefinitions: [tile]) //创建瓦片组规则// 3 let tilegroup = SKTileGroup(rules: [tilerule]) //创建瓦片组// 4let tileSet = SKTileSet(tileGroups: [tilegroup]) //创建瓦片集// 5let columns = background.numberOfColumns //读取背景瓦片地图节点的列数let rows = background.numberOfRows //读取背景瓦片地图节点的行数bugsprayTileMap = SKTileMapNode(tileSet: tileSet, columns: columns,rows: rows,tileSize: tile.size) //创建新的瓦片地图节点// 6for _ in 1...quantity { let column = Int.random(min: 0, max: columns-1) //随机列数let row = Int.random(min: 0, max: rows-1) //随机行数bugsprayTileMap?.setTileGroup(tilegroup,forColumn: column, row: row) //在新额的瓦片地图节点上随机生成瓦片组}// 7bugsprayTileMap?.name = "Bugspray" //设置瓦片地图节点的标识addChild(bugsprayTileMap!) //将瓦片地图添加到场景}

8、step8 添加摄像头设置

func setupCamera() {guard let camera = camera, let view = view else { return }let zeroDistance = SKRange(constantValue: 0)let playerConstraint = SKConstraint.distance(zeroDistance,to: player) //对玩家进行约束// 1let xInset = min(view.bounds.width/2 * camera.xScale,background.frame.width/2)let yInset = min(view.bounds.height/2 * camera.yScale,background.frame.height/2)// 2let constraintRect = background.frame.insetBy(dx: xInset,dy: yInset)// 3let xRange = SKRange(lowerLimit: constraintRect.minX,upperLimit: constraintRect.maxX)let yRange = SKRange(lowerLimit: constraintRect.minY,upperLimit: constraintRect.maxY)let edgeConstraint = SKConstraint.positionX(xRange, y: yRange)edgeConstraint.referenceNode = background// 4camera.constraints = [playerConstraint, edgeConstraint]}

9、step9 获取瓦片的一些帮助方法

func tile(in tileMap: SKTileMapNode,at coordinates: TileCoordinates)-> SKTileDefinition? {return tileMap.tileDefinition(atColumn: coordinates.column,row: coordinates.row)}func tileCoordinates(in tileMap: SKTileMapNode,at position: CGPoint) -> TileCoordinates {let column = tileMap.tileColumnIndex(fromPosition: position)let row = tileMap.tileRowIndex(fromPosition: position)return (column, row)}func tileGroupForName(tileSet: SKTileSet, name: String)-> SKTileGroup? {let tileGroup = tileSet.tileGroups.filter { $0.name == name }.firstreturn tileGroup}

10、step10 点击场景的设置

override func touchesBegan(_ touches: Set<UITouch>,with event: UIEvent?) {guard let touch = touches.first else { return }switch gameState {// 1case .start: //开始状态gameState = .play //切换成游戏状态isPaused = false //开始startTime = nilelapsedTime = 0// 2case .play: //游戏状态player.move(target: touch.location(in: self)) //移动玩家case .win: //获胜状态transitionToScene(level: currentLevel + 1) //切换场景case .lose: //落败状态transitionToScene(level: 1) //切换场景case .reload: //唤醒状态// 1if let touchedNode =atPoint(touch.location(in: self)) as? SKLabelNode {// 2if touchedNode.name == HUDMessages.yes { //如果点击的节点是YESisPaused = falsestartTime = nilgameState = .play// 3} else if touchedNode.name == HUDMessages.no { //如果点击的节点是NOtransitionToScene(level: 1)}}default:break}}

11、step11 切换场景的设置

func transitionToScene(level: Int) {// 1guard let newScene = SKScene(fileNamed: "Level\(level)")as? GameScene else {fatalError("Level: \(level) not found")}// 2newScene.currentLevel = levelview!.presentScene(newScene,transition: SKTransition.flipVertical(withDuration: 0.5))}

12、step12 刷帧

override func update(_ currentTime: TimeInterval) {if gameState != .play  {isPaused = true //如果不是游戏状态就暂停刷帧return}if !player.hasBugspray {updateBugspray() //如果玩家没有杀虫喷雾, 就进行更新}advanceBreakableTile(locatedAt: player.position) //更新障碍物的物理体状态updateHUD(currentTime: currentTime) //更新文字说明checkEndGame() //检查是否达到胜负条件}

13、step13 更新杀虫喷雾

func updateBugspray() {guard let bugsprayTileMap = bugsprayTileMap else { return }let (column, row) = tileCoordinates(in: bugsprayTileMap,at: player.position)if tile(in: bugsprayTileMap, at: (column, row)) != nil {bugsprayTileMap.setTileGroup(nil, forColumn: column,row: row)player.hasBugspray = true}}

14、step14 更新障碍物的物理体状态

func advanceBreakableTile(locatedAt nodePosition: CGPoint) {guard let obstaclesTileMap = obstaclesTileMap else { return }// 1let (column, row) = tileCoordinates(in: obstaclesTileMap,at: nodePosition)// 2let obstacle = tile(in: obstaclesTileMap,at: (column, row))//3guard let nextTileGroupName =obstacle?.userData?.object(forKey: "breakable") as? Stringelse { return }// 4if let nextTileGroup =tileGroupForName(tileSet: obstaclesTileMap.tileSet,name: nextTileGroupName) {obstaclesTileMap.setTileGroup(nextTileGroup, forColumn: column, row: row) //设置新的瓦片组到瓦片地图中}}

15、step15 更新文字说明

func updateHUD(currentTime: TimeInterval) {// 1if let startTime = startTime {// 2elapsedTime = Int(currentTime) - startTime} else {// 3startTime = Int(currentTime) - elapsedTime}// 4hud.updateTimer(time: timeLimit - elapsedTime) //对文字说明进行更新}

16、step16 检查是否达到胜负条件

func checkEndGame() {if bugsNode.children.count == 0 { //是否消灭全部害虫player.physicsBody?.linearDamping = 1gameState = .win} else if timeLimit - elapsedTime <= 0 { //是否时间用完player.physicsBody?.linearDamping = 1gameState = .lose}}

17、step17 物理世界代理的设置

extension GameScene : SKPhysicsContactDelegate {func remove(bug: Bug) { //消灭害虫bug.removeFromParent()background.addChild(bug)bug.die()hud.updateBugCount(with: bugsNode.children.count)}func didBegin(_ contact: SKPhysicsContact) {let other = contact.bodyA.categoryBitMask== PhysicsCategory.Player ?contact.bodyB : contact.bodyAswitch other.categoryBitMask {case PhysicsCategory.Bug:if let bug = other.node as? Bug {remove(bug: bug) //当玩家接触到普通害虫, 消灭普通害虫}case PhysicsCategory.Firebug:if player.hasBugspray {if let firebug = other.node as? Firebug {remove(bug: firebug)player.hasBugspray = false //当玩家手持杀虫喷雾接触高级害虫才能消灭高级害虫}}case PhysicsCategory.Breakable:if let obstacleNode = other.node {// 1advanceBreakableTile(locatedAt: obstacleNode.position) //更新障碍物// 2obstacleNode.removeFromParent() //删除原障碍物}default:break}if let physicsBody = player.physicsBody {if physicsBody.velocity.length() > 0 {player.checkDirection() //进行玩家方向的设置}}}
}

18、step18 观察者的设置

extension GameScene {func applicationDidBecomeActive() {print("* applicationDidBecomeActive")if gameState == .pause {gameState = .reload //重新进入, 进行游戏重载}}func applicationWillResignActive() {print("* applicationWillResignActive")isPaused = trueif gameState != .lose {gameState = .pause  //暂停游戏进程}}func applicationDidEnterBackground() {print("* applicationDidEnterBackground")if gameState != .lose {saveGame() //进入后台保存游戏进度}}func addObservers() {NotificationCenter.default.addObserver(self,selector: #selector(applicationDidBecomeActive),name: .UIApplicationDidBecomeActive, object: nil)NotificationCenter.default.addObserver(self,selector: #selector(applicationWillResignActive),name: .UIApplicationWillResignActive, object: nil)NotificationCenter.default.addObserver(self,selector: #selector(applicationDidEnterBackground),name: .UIApplicationDidEnterBackground, object: nil)}}

19、step19 游戏的存储设置

extension GameScene {func saveGame() {// 1let fileManager = FileManager.defaultguard let directory =fileManager.urls(for: .libraryDirectory,in: .userDomainMask).firstelse { return }// 2let saveURL = directory.appendingPathComponent("SavedGames")// 3do {try fileManager.createDirectory(atPath: saveURL.path,withIntermediateDirectories: true,attributes: nil)} catch let error as NSError {fatalError("Failed to create directory: \(error.debugDescription)")}// 4let fileURL = saveURL.appendingPathComponent("saved-game")print("* Saving: \(fileURL.path)")// 5NSKeyedArchiver.archiveRootObject(self, toFile: fileURL.path) //文件处理器新建路径并归档}override func encode(with aCoder: NSCoder) { /对关键属性的归档aCoder.encode(firebugCount,forKey: "Scene.firebugCount")aCoder.encode(elapsedTime,forKey: "Scene.elapsedTime")aCoder.encode(gameState.rawValue,forKey: "Scene.gameState")aCoder.encode(currentLevel,forKey: "Scene.currentLevel")super.encode(with: aCoder)}class func loadGame() -> SKScene? { //重新加载存储游戏进程print("* loading game")var scene: SKScene?// 1let fileManager = FileManager.defaultguard let directory =fileManager.urls(for: .libraryDirectory,in: .userDomainMask).firstelse { return nil }// 2let url = directory.appendingPathComponent("SavedGames/saved-game")// 3if FileManager.default.fileExists(atPath: url.path) {scene = NSKeyedUnarchiver.unarchiveObject(  //根据路径进行解档游戏进程withFile: url.path) as? GameScene_ = try? fileManager.removeItem(at: url)}return scene}}

三、运行效果与文件截图

1、运行效果

2、文件截图

PestControl文件里的截图:

PestControl.xcodeproj文件里的截图:

四、其他补充

Notice: 忽略了一些节点的设置, 但不影响瓦片地图的理解.

代码下载:http://www.demodashi.com/demo/10703.html

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

[SpriteKit] 制作瓦片地图小游戏相关推荐

  1. python连连看小游戏_利用Python制作一个连连看小游戏,边学边玩!

    导语 今天我们将制作一个连连看小游戏,让我们愉快地开始吧~ 开发工具 Python版本:3.6.4 相关模块: pygame模块: 以及一些Python自带的模块 环境搭建 安装Python并添加到环 ...

  2. c语言使用easyX图形库制作打气球小游戏

    大一c语言使用easyX图形库制作打气球小游戏 如果你是入门easyX图形库,那么这个打气球小游戏将会是和不错的入门项目选择,easyX开创了可视化窗口,使用户更加直观的了解到对象的变化,总代码以及素 ...

  3. C# 制作贪吃蛇小游戏,最简单的实现

    C# 制作贪吃蛇小游戏 目录 画蛇 实现蛇的上下左右移动 随机生成目标物 开始游戏 计分 重新开始 增加难度 死亡判定 1.1 画蛇的一节 Class Element()Graphics g;publ ...

  4. 小福利,用Excel VBA编程制作一个变色小游戏

    小福利,用Excel VBA编程制作一个变色小游戏 设计思想:在正方形的四条边上都是设置循环函数,不断改变颜色和单元格里面的数值. Option ExplicitSub 按钮1_Click() Dim ...

  5. 【源代码】Python制作的赛车小游戏,逆行飙车

    python制作的赛车小游戏,逆行飙车,通过键盘方向键控制 程序运行截图 源代码 import pygame, sys, time, random# pygame 初始化 pygame.init() ...

  6. android打地鼠设计报告,android开发中利用handler制作一个打地鼠小游戏

    android开发中利用handler制作一个打地鼠小游戏 发布时间:2020-11-25 15:21:11 来源:亿速云 阅读:136 作者:Leah 这期内容当中小编将会给大家带来有关androi ...

  7. Python制作的赛车小游戏源代码,逆行飙车

    python制作的赛车小游戏,逆行飙车,通过键盘方向键控制 程序运行截图: 源代码 import pygame, sys, time, random# pygame 初始化 pygame.init() ...

  8. 【游戏开发实战】使用Unity 2019制作仿微信小游戏飞机大战(七):主角飞机碰撞与爆炸

    文章目录 零.教程目录 一.前言 二.本篇目标 三.飞机机碰撞组件:BoxCollider2D.Rigidbody2D 四.添加Tag:Enemy 五.主角飞机碰撞处理:OnTriggerEnter2 ...

  9. 如何制作三子棋小游戏

    首先,一个游戏的制作,必须由大化小,分步完成. 当我们想要制作三子棋小游戏时,必须先搞清楚这个小游戏的逻辑和原理. 三子棋是黑白棋的一种.三子棋是一种民间传统游戏,又叫九宫棋.圈圈叉叉.一条龙.井字棋 ...

  10. c语言扔骰子随机数的相加,C语言编程学习:制作掷骰子小游戏

    C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...

最新文章

  1. 结构体类型、联合体类型
  2. 学习手记(2018.11.30~2019.6.6)——养老时间
  3. 详解STL中的空间配置器(SGI版本)
  4. ssm实训报告心得_Java开发学习心得(一):SSM环境搭建
  5. 信息学奥赛一本通(2029:【例4.15】水仙花数)
  6. php html显示mysql数据库_从数据库调出数据显示到页面 PHP+Mysql+Html(简单实例)...
  7. json接口文档模板_在.Net Core WebAPI下给Swagger增加导出离线文档功能
  8. DeepChem手册3.10 MoleculeNet
  9. VTracer - 将图片转化为矢量 SVG 图形的免费开源工具
  10. java近义词,虚拟的近义词
  11. Leetcode 每日一题——845. 数组中的最长山脉
  12. 【论文阅读】Stroke Controllable Fast Style Transfer with Adaptive Receptive Fields
  13. 关于Microsoft Edge 浏览器无法使用selenium调用问题
  14. sci写作之前的记录
  15. 25k~50k,比特大陆招人啦!这次会是你吗?
  16. 2022年全球及中国天然橡胶产业供需趋势及行业期货市场走势:预计供需双增长,价格上行[图]
  17. android相机故障代码解决方法,Android相机服务器死机和相机错误 – 100
  18. 18650电池正负反接保护电路如何做原理图参考图
  19. 解决Margin塌陷问题方法
  20. Jmeter—监听器之察看结果数、聚合报告

热门文章

  1. Python GUI学习感想
  2. 图片如何转化为pdf格式?
  3. 豪迪QQ群发通杀破解补丁使用教程
  4. CSDN好的blog
  5. 夜神模拟器报错 daemon still not running error: cannot connect to daemon
  6. 离散数学程序实现——求关系矩阵的自反和对称闭包——c
  7. 惯性导航技术, IMU, AHRS
  8. 班主任直接把奖学金名额给了我?就因为我用Python给她写了一个自动阅卷脚本
  9. max计算机什么函数,计算机max函数使用方法
  10. python导入自定义模块_python引入不同文件夹下的自定义模块方法