在ios7,苹果引入了SpriteKit,一个高性能渲染2D的框架。不像中心库(专注于画图)或中心动画(专注于动画过度),SpriteKit专注于不同领域-video games,它是苹果首次涉足ios的图形游戏编程的时代。在发布ios7盒OS X10.9(Mavericks.   2013年WWDC发布)的同时,为了写程序更为简单提供了相同的API在两个平台,尽管苹果从未像SpriteKit提供了一个框架,它有明显的相似之处是Cocos2D等各种开源库。如果你使用的是Cocos2D或类似的过去,你会感觉很熟悉。

现在创建一个工程并选择Game template名为:TextShooter

(sks文件只是标准的归档文件,你可以用NSKeyedUnarchiver和NSKeyedArchiver类来写和读)

xcode会为你初始化一些方法例如:

 override func viewDidLoad() {
super.viewDidLoad() if let view = self.view as! SKView? {
// 初始化'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
// 让缩放比例填充整个窗口Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill // 加载这个场景(新场景取代旧场景)
view.presentScene(scene)
}
//当运行时,忽视父子类的关系
view.ignoresSiblingOrder = true
//在右下角显示FPS的值
view.showsFPS = true
       //在右下角显示结点(node)的个数
view.showsNodeCount = true
}
}

了解完xcode自动初始化的代码,接下来我们自己手动初始化我们自己想要的,选择GameScence.swift,我们不需要didMoveToView()这个方法,现在改成:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)//获取当前位置
}
}

xcode自带一个GameScene.sks,里面没有我们想要的属性,所以得自己创建,需要添加属性为当前游戏等级数,生活玩家的数量,一个标志,让我们知道等级是否完成,修改GameScene.swift:    private var levelNumber: Int //等级制度    private var playerLives: Int //玩家血    private var finished = false //当前游戏是否结束    class func scene(size:CGSize, levelNumber:Int) -> GameScene {        return GameScene(size: size, levelNumber: levelNumber)}

override convenience init(size:CGSize) {
self.init(size: size, levelNumber: )
}
/*
创建名为SKLabelNode类的两个实例,并选择一个字体,设置一个文本值,指定一些对齐
*/
init(size:CGSize, levelNumber:Int) {
self.levelNumber = levelNumber
self.playerLives =
super.init(size: size)
backgroundColor = SKColor.lightGray()
let lives = SKLabelNode(fontNamed: "Courier")//指定字体
lives.fontSize =
lives.fontColor = SKColor.black()
lives.name = "LivesLabel"
lives.text = "Lives: \(playerLives)"
lives.verticalAlignmentMode = .top
lives.horizontalAlignmentMode = .right
lives.position = CGPoint(x: frame.size.width,
y: frame.size.height)
addChild(lives)
let level = SKLabelNode(fontNamed: "Courier")
level.fontSize =
level.fontColor = SKColor.black()
level.name = "LevelLabel"
level.text = "Level \(levelNumber)"
level.verticalAlignmentMode = .top
level.horizontalAlignmentMode = .left
level.position = CGPoint(x: , y: frame.height)
addChild(level)
}
required init?(coder aDecoder: NSCoder) {
levelNumber = aDecoder.decodeInteger(forKey: "level")
playerLives = aDecoder.decodeInteger(forKey: "playerLives")
super.init(coder: aDecoder)
}
/*
required的使用规则:
required修饰符只能用于修饰类初始化方法
当子类含有异于父类的初始化方法时(初始化方法参数类型和数量异于父类),子类必须要实现父类的required初始化方法,并且也要使用required修饰符而不是override
当子类没有初始化方法时,可以不用实现父类的required初始化方法
*/
override func encode(with aCoder: NSCoder) {
aCoder.encode(Int(levelNumber), forKey: "level")
aCoder.encode(playerLives, forKey: "playerLives")
}
/*
我们给每个label命名,是因为init(coder:)和encode(with aCoder:)方法需要,所有SpriteKit结点,包括SKScene都遵循NSCoding协议
*/

我们配置了两个SKLabelNode,是时候让它们现身了,选择GameView.swift并添加以下代码:

override func viewDidLoad() {
super.viewDidLoad()
let scene = GameScene(size: view.frame.size, levelNumber: 1) //configure the view
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true //Sprite Kit applies additional optimizations to improve rendering performance
skView.ignoresSiblingOrder = true //Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill skView.presentScene(scene)
}

现在你可以顺便了解下override var prefersStatusBarHidden,return true就是状态栏隐藏,反之。现在可以运行下,正常的结果:

背景有了,接下来可以添加一些互动了,毕竟是游戏,我们先添加一个发射子弹的头部,创建Cocoa Touch class 并以SKNode为父类,命名为playerNode,添加一下代码:

import SpriteKit

class PlayerNode: SKNode {
override init() {
super.init()
name = "Player \(self)"
initNodeGraph() //初始化一个结点,内容为"^"(将V旋转180度)作为发射子弹的头部 }
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func initNodeGraph() {
let label = SKLabelNode(fontNamed: "Courier") //指定字体
label.fontColor = SKColor.blue
label.fontSize =
label.text = "v"
label.zRotation = CGFloat(Double.pi) //绕z轴旋转180度
label.name = "label"
self.addChild(label)
}
}

跟刚才添加level,lives一样,在GameScene,swift里实例化(实现)playerNode:

在addChild(level)后面加上这两行:

playerNode.position = CGPoint(x: frame.midX, y: frame.height * 0.1)

addChild(playerNode)

现在运行你就会看到如下场景:

现在我们来讨论如何用手指来移动它,这边插个题外话,在web前端里面坐标轴是已左上角为基准,但在SpriteKit我测试了下,添加一个结点并设置position(x:0,y:0),效果如下图所示:

所以这里的坐标是以左下角为基准。

我们假设当手指在屏幕下方的0.2部分(以下)滑动的时候就是有意要让发射器移动,下面这段代码就是这个意思:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if location.y < frame.height * 0.2 {
let target = CGPoint(x: location.x, y: playerNode.position.y)
playerNode.moveToward(target) //移动到手指当前位置
}
}
}

并且在playerNode类添加:

    func moveToward(_ location: CGPoint) {
removeAction(forKey: "movement")
let distance = pointDistance(position, location) //计算当前位置和发射器位置的直线距离
let screenWidth = UIScreen.main.bounds.size.width
let duration = TimeInterval( * distance/screenWidth) //转换为时间间隔专用的单位,例如:毫秒
run(SKAction.move(to: location, duration: duration),
withKey:"movement")//duration:指定移动过程需要的时间,可以自己指定
}

可以发现上面的pointDistance()并没有定义,这边可以创建一个swift文件专门放置计算点或向量之类的算法,我的算法代码如下:

import UIKit

// Takes a CGVector and a CGFLoat.
// 返回一个新向量(旧向量的x,y分量乘以参数CGPoint)
func vectorMultiply(_ v: CGVector, _ m: CGFloat) -> CGVector {
return CGVector(dx: v.dx * m, dy: v.dy * m)
}
// Takes two CGPoints.
// Returns a CGVector representing a direction from p1 to p2. func vectorBetweenPoints(_ p1: CGPoint, _ p2: CGPoint) -> CGVector {
return CGVector(dx: p2.x - p1.x, dy: p2.y - p1.y)
}
// Takes a CGVector.
// Returns a CGFloat containing the length of the vector, calculated using
// Pythagoras' theorem.
//√(x^2+y^2)
func vectorLength(_ v: CGVector) -> CGFloat {
return CGFloat(sqrtf(powf(Float(v.dx), ) + powf(Float(v.dy), )))
}
// Takes two CGPoints. Returns a CGFloat containing the distance between them,
// calculated with Pythagoras' theorem.
//√(x^2+y^2)
func pointDistance(_ p1: CGPoint, _ p2: CGPoint) -> CGFloat {
return CGFloat(
sqrtf(powf(Float(p2.x - p1.x), ) + powf(Float(p2.y - p1.y), )))
}

现在运行可以用手指轻触屏幕下方可以移动发射器了(当然在屏幕下方的0.2部分),并且移动速度也还不错,但在移动的过程中这个发射器什么都不会做,我们可以给它添加一些动作,翻转什么的:

func moveToward(_ location: CGPoint)
{
removeAction(forKey: "movement") let distance = pointDistance(position, location)
let screenWidth = UIScreen.main.bounds.size.width
let duration = TimeInterval( * distance/screenWidth) //转换为时间间隔专用的单位,例如:毫秒
run(SKAction.move(to: location, duration: duration),
withKey:"movement") //duration:指定移动过程需要的时间,可以自己指定 let wobbleTime = 0.3
let halfWobbleTime = wobbleTime/
let wobbling = SKAction.sequence([
SKAction.scaleX(to: 0.2, duration: halfWobbleTime),
SKAction.scaleX(to: 1.0, duration: halfWobbleTime)
])//接收一个action队列(数组)
let wobbleCount = Int(duration/wobbleTime)
//当duration大于wobbleTime时才会大于1,才会执行,所以当距离比较近的时候是不会旋转的,这个可以自由发挥
run(SKAction.repeat(wobbling, count: wobbleCount), withKey: "wobbling") }

现在运行的效果就比较好看一点,现在改添加一些敌人了,创建一个父类为SKNode,命名为:EnemyNode,并添加以下代码:

import SpriteKit

class EnemyNode: SKNode {
override init() {
super.init()
name = "Enemy \(self)"
initNodeGraph()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func initNodeGraph() {
let topRow = SKLabelNode(fontNamed: "Courier-Bold")
topRow.fontColor = SKColor.brown
topRow.fontSize =
topRow.text = "x x"
topRow.position = CGPoint(x: -20, y: )//为了不显示在屏幕所以设定-20
addChild(topRow) let middleRow = SKLabelNode(fontNamed: "Courier-Bold")
middleRow.fontColor = SKColor.brown
middleRow.fontSize = 20
       middleRow.position = CGPoint(x: -20, y: 0)
middleRow.text = "x"
addChild(middleRow) let bottomRow = SKLabelNode(fontNamed: "Courier-Bold")
bottomRow.fontColor = SKColor.brown
bottomRow.fontSize =
bottomRow.text = "x x"
bottomRow.position = CGPoint(x: -20, y: -)
addChild(bottomRow)
       //三个SKLabelNode构成一个敌人
        }
}

跟刚才一样在GameScene.swift加载该结点,并为这个结点设置一个函数随机生成x,y坐标来来生成敌人:

在addChild(playerNode)后面添加

spawnEnemies()//随机生成敌人

addChild(enemies)

private func spawnEnemies() {                      
let count = Int(log(Float(levelNumber))) + levelNumber
for _ in ..<count {
let enemy = EnemyNode()
let size = frame.size;
let x = arc4random_uniform(UInt32(size.width * 0.8))
+ UInt32(size.width * 0.1) //随机生成x坐标,范围0.1屏幕宽度~0.8屏幕宽度
let y = arc4random_uniform(UInt32(size.height * 0.5))
+ UInt32(size.height * 0.5) //随机生成y坐标,范围0.5屏幕高度~0.5屏幕高度
enemy.position = CGPoint(x: CGFloat(x), y: CGFloat(y))
enemies.addChild(enemy)
}
}

发射器有了,敌人也有了,现在该弄子弹了,创建一个BulletNode继承于SKNode:

//
// BulletNode.swift
// otherGame
//
// Created by 陈金伙 on 2017/4/8.
// Copyright © 2017年 cjh. All rights reserved.
// import SpriteKit
class BulletNode: SKNode {
var thrust:CGVector = CGVector(dx: , dy: ) override init() {
super.init()
let dot = SKLabelNode(fontNamed: "Courier")
dot.fontColor = SKColor.black
dot.fontSize =
dot.text = "."
addChild(dot)
let body = SKPhysicsBody(circleOfRadius: )
body.isDynamic = true
body.categoryBitMask = PlayerMissileCategory //用于定义物理主体所属的类别
body.contactTestBitMask = EnemyCategory //一个掩码,定义哪些类别的物体引起与这个物理体的交集通
body.collisionBitMask = EnemyCategory //定义哪些类别的物理机构可以与这个物理体碰撞
body.fieldBitMask = GravityFieldCategory //定义哪些类别的物理领域可以施加力量在这个物理机构
body.mass = 0.01 //以千克为单位的物体
physicsBody = body
name = "Bullet \(self)" } required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let dx = aDecoder.decodeFloat(forKey: "thrustX")
let dy = aDecoder.decodeFloat(forKey: "thrustY")
thrust = CGVector(dx: CGFloat(dx), dy: CGFloat(dy))
} override func encode(with aCoder: NSCoder) {
super.encode(with: aCoder)
aCoder.encode(Float(thrust.dx), forKey: "thrustX")
aCoder.encode(Float(thrust.dy), forKey: "thrustY")
} class func bullet(from start: CGPoint, toward destination: CGPoint) -> BulletNode {
let bullet = BulletNode()
bullet.position = start
let movement = vectorBetweenPoints(start, destination) //差的向量
let magnitude = vectorLength(movement) //两点之间的距离
let scaledMovement = vectorMultiply(movement, /magnitude) //缩放向量
let thrustMagnitude = CGFloat(100.0)
bullet.thrust = vectorMultiply(scaledMovement, thrustMagnitude)//扩大向量,无论屏幕多大都能发射到
bullet.run(SKAction.playSoundFileNamed("shoot.wav",
waitForCompletion: false))
return bulle
} func applyRecurringForce() {
physicsBody!.applyForce(thrust) //对物理体的重心施加力量,如果没有这个函数,发射的子弹会向下滑
} }

同理的向GameScene.swift添加

private let playerBullets = SKNode()

addChild(playerbullets)

并在

touchesBegan()中添加else(默认不移动发射器就是发射子弹)

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if location.y < frame.height * 0.2 {
let target = CGPoint(x: location.x, y: playerNode.position.y)
playerNode.moveToward(target) //移动到手指当前位置
}
else { //没有移动发射器就默认发射子弹
let bullet = BulletNode.bullet(from: playerNode.position, toward: location)//从发射器当前位置发射到手指的位置
playerBullets.addChild(bullet)
}
}
}

现在我们考虑当子弹飞出屏幕时可以让它消失(从内存中撤销)在GameScene的update()添加:

override func update(_ currentTime: TimeInterval) {
updatebullets()
}
private func updatebullets() {
var bulletsToRemove:[BulletNode] = []
for bullet in playerBullets.children as! [BulletNode] { if !frame.contains(bullet.position) {
// 当子弹离开屏幕时放入一个数组
bulletsToRemove.append(bullet)
continue
}
// 对物理体的重心施加力量
bullet.applyRecurringForce()
}
playerBullets.removeChildren(in: bulletsToRemove)
}

现在的子弹遇到敌人并没有攻击性,因为我们只给BulletNode指定物理性质,现在该轮到PlayerNode,EnemyNode了,选择EnemyNode,并添加以下代码:

 private func initPhysicsBody() {
let body = SKPhysicsBody(rectangleOf: CGSize(width: , height: ))
body.affectedByGravity = false
body.categoryBitMask = EnemyCategory
body.contactTestBitMask = PlayerCategory | EnemyCategory //发射器和子弹可以与之碰撞
body.mass = 0.2 //本身重量
body.angularDamping = //阻力
body.linearDamping =
body.fieldBitMask =
physicsBody = body
}

并在init()里添加刚才我们加的initPhysicsBody(),同理,在PlayerNode添加以下代码:

 private func initPhysicsBody() {
let body = SKPhysicsBody(rectangleOf: CGSize(width: , height: ))
body.affectedByGravity = false
body.categoryBitMask = PlayerCategory
body.contactTestBitMask = EnemyCategory
body.collisionBitMask =
body.fieldBitMask =
physicsBody = body
}

并在init()添加initPhysicsBody(),现在可以运行试试看效果,当你把屏幕唯一的敌人打掉之后,你就应该想到下一步该设定升级了,当我们把敌人打出屏幕时,也应该像子弹那样从内存中移除,在GameScene添加以下代码:

private func updateEnemies() {
var enemiesToRemove:[EnemyNode] = []
for node in enemies.children as! [EnemyNode] {
if !frame.contains(node.position) {
enemiesToRemove.append(node)
continue
}
}
enemies.removeChildren(in: enemiesToRemove)
}

并更新update()函数的内容:

 override func update(_ currentTime: TimeInterval) {
if finished {
return
}
updatebullets()
updateEnemies()
checkForNextlevel()
}
private func checkForNextlevel() { //查看是否还有敌人存活
if enemies.children.isEmpty {
goToNextLevel()
}
} private func goToNextLevel() { //进入下一级
finished = true let label = SKLabelNode(fontNamed: "Courier")
label.text = "Level Complete!"
label.fontColor = SKColor.blue
label.fontSize =
label.position = CGPoint(x: frame.size.width * 0.5, y: frame.size.height * 0.5)
addChild(label) let nextLevel = GameScene(size: frame.size, levelNumber: levelNumber + ) //等级不断增加
nextLevel.playerLives = playerLives                       //生命值不变
view!.presentScene(nextLevel, transition: SKTransition.flipHorizontal(withDuration: 1.0))
}

这个游戏里的每个结点都是模拟现实物理的,所以我们还要考虑当我们用子弹打到第一个敌人时,敌人会被打飞,被打飞的过程中或许会碰撞到另一个敌人又或许会随重力下滑,掉落到发射器上,即玩家生命值减一操作,这就需要委托了,因为委托事件里面有contact事件对当前阶段很好用,添加

class GameScene: SKScene, SKPhysicsContactDelegate {

并在init(size:CGSize, levelNumber:Int) { 添加

physicsWorld.gravity = CGVector(dx: 0, dy: -1) //设置重力向下

physicsWorld.contactDelegate = self

这边我们可以先想想碰撞的特效xcode提供自带的文件,创建SpriteKit partical file命名MissleExplosion,并在inspector属性进行调整,这边是我的(随便调的,自由发挥):

同理再创建一个命名为EnemyExplosion,并在inspector属性进行调整(自由发挥)

选择GameScene添加以下代码:

func didBegin(_ contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask == contact.bodyB.categoryBitMask {
//一样的种类
let nodeA = contact.bodyA.node!
let nodeB = contact.bodyB.node!
}
else {
var attacker: SKNode
var attackee: SKNode if contact.bodyA.categoryBitMask > contact.bodyB.categoryBitMask {//种类的大小,下面有给图说明
// A attack B
attacker = contact.bodyA.node!
attackee = contact.bodyB.node! }
else {
//B attack A
attacker = contact.bodyB.node!
attackee = contact.bodyA.node!
}
if attackee is PlayerNode {
playerLives -=
} //What do we do with the attacker and the attackee?
attackee.receiveAttacker(attacker, contact: contact)//扩展类的方法,下面有给
playerBullets.removeChildren(in: [attacker])
enemies.removeChildren(in: [attacker]) }
}

四种大小分别代表不同的种类,在我们给他们的physicBody初始化时就有给他们指定,接下来扩展SKnode类,为什么要扩展SKNode?,因为在SpriteKit每个对象都是一个结点,所以扩展SKNode,可以对敌人,发射器,子弹都好操作,新建一个swift file命名SKNode+Extra并添加以下代码:

import SpriteKit

extension SKNode {
func receiveAttacker(_ attacker: SKNode, contact: SKPhysicsContact)
{
// Default implementation does nothing physicsBody!.affectedByGravity = true
let force = vectorMultiply(attacker.physicsBody!.velocity, contact.collisionImpulse) let myContact = scene!.convert(contact.contactPoint, to: self)
physicsBody!.applyForce(force, at: myContact) let path = Bundle.main.path(forResource: "MissileExplosion", ofType: "sks") let explosion = NSKeyedUnarchiver.unarchiveObject(withFile: path!)
as! SKEmitterNode
explosion.numParticlesToEmit = //默认为0,无限粒子,这边指定20颗粒子
explosion.position = contact.contactPoint //在子弹击中的部位出现粒子
scene!.addChild(explosion)
} func friendlyBumpFrom(_ node: SKNode) {
// Default implementation does nothing
physicsBody!.affectedByGravity = true }
}

现在运行你会发现一切都良好,就是尽管敌人掉落到发射器上,玩家的血是没有扣的,我记得明明有添加

if attackee is PlayerNode {

playerLives -= 1

}

可是不起作用,其实是有起作用的,不信你可以调试下在后台输出playerLives,只是没有实时更新到界面,

private var playerLives: Int {

didSet {

let lives = childNode(withName: "LivesLabel") as! SKLabelNode

lives.text = "Lives: \(playerLives)"

}

}

更改私有属性变成属性观察者,一旦playerlives有变化就执行didSet里面的代码,现在可以了,但是生命值会一直减,没有尽头的,就像是无敌模式,是时候给这个游戏来个收尾了,

创建cocoa touch class命名GameOverScene,并以SKScene为父类,添加以下代码:

import SpriteKit

class GameOverScene: SKScene {
override init(size: CGSize) {
super.init(size: size)
backgroundColor = SKColor.purple
let text = SKLabelNode(fontNamed: "Courier")
text.text = "Game Over"
text.fontColor = SKColor.white
text.fontSize =
text.position = CGPoint(x: frame.size.width/, y: frame.size.height/)
addChild(text)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}

这就是结束界面,在GameScene里面来实现它:

private func triggerGameOve() {
finished = true let path = Bundle.main.path(forResource:"EnemyExplosion",
ofType: "sks")
let explosion = NSKeyedUnarchiver.unarchiveObject(withFile: path!)
as! SKEmitterNode
explosion.numParticlesToEmit = //当生命值为0时,爆炸变的更大
explosion.position = playerNode.position
scene!.addChild(explosion)
playerNode.removeFromParent() let transition = SKTransition.doorsOpenVertical(withDuration: )
let gameOver = GameOverScene(size: frame.size)
view!.presentScene(gameOver, transition: transition)
} private func checkForGame() -> Bool { //添加到update(),实时监测
if playerLives == {
triggerGameOve()
return true
}
return false
} override func update(_ currentTime: TimeInterval) {
if finished {
return
}
updatebullets()
updateEnemies()
if (!checkForGame()) {
checkForNextlevel()
} }

现在基本可以完了,要是想要美观的话可以搞个开始界面,这边就不搞了。

要下载全部的代码请到我的github库:https://github.com/TypeInfos/SpriteKit-Game

Simple Games Using SpriteKit的更多相关文章

  1. iPhone Tutorials

    http://www.raywenderlich.com/tutorials This site contains a ton of fun written tutorials – so many t ...

  2. How I came to find Linux

    http://ianmurdock.com/post/how-i-came-to-find-linux/ lan murdock August 17, 2015 I saw my first Sun ...

  3. Intro to Airplane Physics in Unity 3D – 2017 and 2018

    Info:DescriptionHave you ever wanted to build your own Airplane Physics using the Rigidbody componen ...

  4. How do I learn machine learning?

    https://www.quora.com/How-do-I-learn-machine-learning-1?redirected_qid=6578644   How Can I Learn X? ...

  5. 非常优秀的iphone学习文章总结!

    This site contains a ton of fun tutorials – so many that they were becoming hard to find! So I put t ...

  6. Tetris

    he Tetris game is one of the most popular computer games ever created. The original game was designe ...

  7. [转]Using OData from ASP.NET

    本文转自:http://www.drdobbs.com/windows/using-odata-from-aspnet/240168672 By Gastón Hillar, July 01, 201 ...

  8. Exercises for IN1900

    Exercises for IN1900October 14, 2019PrefaceThis document contains a number of programming exercises ...

  9. 【英语魔法俱乐部——读书笔记】 1 初级句型-简单句(Simple Sentences)

    第一部分 1 初级句型-简单句(Simple Sentences):(1.1)基本句型&补语.(1.2)名词短语&冠词.(1.3)动词时态.(1.4)不定式短语.(1.5)动名词.(1 ...

随机推荐

  1. 项目详解4—haproxy 详解

    一.企业服务架构图及负载均衡的要求 1.场景说明 在企业生产环境中,每天会有很多的需求变更,比如增加服务器.新业务上线.url路由修改.域名配置等等,对于前端负载均衡设备来说,容易维护,复杂度低,是首 ...

  2. UVA434 - Matty's Blocks

    题意:已知前视图和右视图,求最少需要几个正方体以及至多可以再增加几个正方体. 分析:先对于最小木块数,要想用最少的立方体搭建,那就意味着前视图中的每一竖立方体的高度最好都要被右视图中的高度所利用到.所 ...

  3. MySQL查看和修改表的存储引擎(转载+加点东西)

    1 查看系统支持的存储引擎 show engines; 2 查看表使用的存储引擎 两种方法: a.show table status from YOUR_DB_NAME where name='YOU ...

  4. upload 上传类

    <?php/**file: fileupload.class.php 文件上传类FileUpload本类的实例对象用于处理上传文件,可以上传一个文件,也可同时处理多个文件上传 */class U ...

  5. 获取串口映射的COM端口号

    背景:近期由于项目需要,需要操作短信猫,当短信猫插入电脑后,会根据当前PC状况,映射COM口,这里需动态获取短信猫映射的COM端口号. 编程语言C#: 具体代码如下 public enum Hardw ...

  6. 学习python登录demo

    要求编写登录接口 : 1. 输入用户名和密码 2.认证成功后显示欢迎信息 3.用户名输错,提示用户不存在,重新输入(5次错误,提示尝试次数过多,退出程序) 4.用户名正确,密码错误,提示密码错误,重新 ...

  7. gulp杂记

    一.什么是gulp gulp是前端开发过程中对代码进行构建的工具,是自动化项目的构建利器:她不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成:使用她,我们不仅可以很愉 ...

  8. 简陋的斗地主,js实现

    最近闲了两天没事做,用js写了个斗地主,练习练习.代码和功能都很简陋,还有bug,咋只是聊聊自己的思路. 这里说说斗地主主要包含的功能:洗牌,发牌,玩家出牌.电脑出牌,出牌规则的验证,输赢啥的没有判断 ...

  9. C++ stack

    stack 栈,一种后进先出的数据结构,在c++ stl里作为容器适配器,string,vector,deque,在内存中是连续的 声明方式 stack<int,deque<T>&g ...

  10. 倒水问题 (FillUVa 10603) 隐式图

    题意:本题的题意是给你三个杯子,第一二个杯子是空的,第三个杯子装满水,要求是量出一定容量d升的水.若是得不到d升的水,那就让某一个杯子里面的水达到d',使得d'尽量接近d升. 解题思路:本题是给出初始 ...