Dieses Mal haben wir Details zum Schwierigkeitsgrad und zum Geschwindigkeitslevel erstellt, die sich je nach Runde ändern, und jeden in # 5 [Sequenzdesign] erstellten Bildschirmmodus kombiniert. Bringen Sie es dann in den fast vollständigen Zustand (das Folgende ist ein Bildfilm). Der Quellcode ist auf GitHub verfügbar. Bitte beziehen Sie sich darauf.
Die Spezifikationen des Schwierigkeitsgrades und des Geschwindigkeitsniveaus, die sich je nach Runde ändern, sind wie folgt.
Dieses Mal werden die Fremdversion der Schwierigkeitsgradtabelle und die Einstellung spurt ② nicht erstellt.
Implementieren Sie eine Schwierigkeits- und eine Geschwindigkeitstabelle als Array von Taples. Im Folgenden sind alle in der CgContext-Klasse enthalten, mit Ausnahme der Kombination der einzelnen Bildschirmmodi.
enum EnLevel: Int {
case Level_A = 0, Level_B, Level_C, Level_D
}
let table_difficultySettings: [(round: Int, levelOfSpeed: EnLevel, timeWithPower: Int, numberOfFeedsRemaingToSpurt: Int, levelOfAppearance: EnLevel, kindOfSpecialTarget: CgSpecialTarget.EnSpecialTarget, timeNotToEat: Int, intermission: Int)] = [
//round, speedLevel, PowerTime[ms], Spurtfeeds, GhostAppear, SpecialTarget, NoEatTime[ms], Intermission
( 1, .Level_A, 6000, 20, .Level_A, .Cherry, 4000, 0 ),
( 2, .Level_B, 5000, 30, .Level_B, .Strawberry, 4000, 1 ),
( 3, .Level_B, 4000, 40, .Level_C, .Orange, 3000, 0 ),
( 4, .Level_B, 3000, 40, .Level_C, .Orange, 3000, 0 ),
( 5, .Level_C, 2000, 40, .Level_C, .Apple, 3000, 2 ),
( 6, .Level_C, 5000, 50, .Level_C, .Apple, 3000, 0 ),
( 7, .Level_C, 2000, 50, .Level_C, .Melon, 3000, 0 ),
( 8, .Level_C, 2000, 50, .Level_C, .Melon, 3000, 0 ),
( 9, .Level_C, 1000, 60, .Level_C, .Galaxian, 3000, 3 ),
( 10, .Level_C, 5000, 60, .Level_C, .Galaxian, 3000, 0 ),
( 11, .Level_C, 2000, 60, .Level_C, .Bell, 3000, 0 ),
( 12, .Level_C, 1000, 80, .Level_C, .Bell, 3000, 0 ),
( 13, .Level_C, 1000, 80, .Level_C, .Key, 3000, 3 ),
( 14, .Level_C, 3000, 80, .Level_C, .Key, 3000, 0 ),
( 15, .Level_C, 1000, 100, .Level_C, .Key, 3000, 0 ),
( 16, .Level_C, 1000, 100, .Level_C, .Key, 3000, 0 ),
( 17, .Level_C, 0, 100, .Level_C, .Key, 3000, 3 ),
( 18, .Level_C, 1000, 100, .Level_C, .Key, 3000, 0 ),
( 19, .Level_C, 0, 100, .Level_C, .Key, 3000, 0 ),
( 20, .Level_C, 0, 100, .Level_C, .Key, 3000, 0 ),
( 21, .Level_C, 0, 100, .Level_C, .Key, 3000, 0 ),
( 22, .Level_D, 0, 100, .Level_C, .Key, 3000, 0 )
]
let table_speedSettings: [ (eatNone: Int, eatFeed: Int, eatPow: Int, eatNoneInPow: Int, eatFeedInPow: Int, eatPowInPow: Int,
ghost: Int, ghostInSpurt: Int, ghostInPow: Int, ghostInWarp: Int) ]
= [
// Level A
( eatNone: 16, eatFeed: 15, eatPow: 13, eatNoneInPow: 18, eatFeedInPow: 17, eatPowInPow: 15,
ghost: 15, ghostInSpurt: 16, ghostInPow: 10, ghostInWarp: 8 ),
// Level B
( eatNone: 18, eatFeed: 17, eatPow: 15, eatNoneInPow: 19, eatFeedInPow: 18, eatPowInPow: 16,
ghost: 17, ghostInSpurt: 18, ghostInPow: 11, ghostInWarp: 9 ),
// Level C
( eatNone: 20, eatFeed: 19, eatPow: 17, eatNoneInPow: 20, eatFeedInPow: 19, eatPowInPow: 17,
ghost: 19, ghostInSpurt: 20, ghostInPow: 12, ghostInWarp: 10 ),
// Level D
( eatNone: 18, eatFeed: 17, eatPow: 15, eatNoneInPow: 18, eatFeedInPow: 17, eatPowInPow: 15,
ghost: 19, ghostInSpurt: 20, ghostInPow: 10, ghostInWarp: 9 )
]
Extrahieren Sie die Daten gemäß der Runde aus diesem Array von Taples und legen Sie sie in den Mitgliedern der CgContext-Klasse fest.
/// Set difficulty of the round
func setDifficulty() {
let index = demo ? 0 : round-1
let count = table_difficultySettings.count
let table = (index < count) ? table_difficultySettings[index] : table_difficultySettings[count-1]
levelOfSpeed = table.levelOfSpeed
timeWithPower = table.timeWithPower
numberOfFeedsRemaingToSpurt = table.numberOfFeedsRemaingToSpurt
levelOfAppearance = table.levelOfAppearance
kindOfSpecialTarget = table.kindOfSpecialTarget
timeNotToEat = table.timeNotToEat
intermission = table.intermission
}
Die Methode, um die Geschwindigkeit des Spielers (Pacman) zu ermitteln, ist wie folgt. Ändern Sie den Wert, der erworben werden soll, wenn Sie Power Food essen, und kehren Sie ihn um, wenn dies nicht der Fall ist.
func getPlayerSpeed(action: CgPlayer.EnPlayerAction, with power: Bool ) -> Int {
let index = levelOfSpeed.rawValue
let count = table_speedSettings.count
let table = (index < count) ? table_speedSettings[index] : table_speedSettings[count-1]
switch action {
case .Walking where !power : return table.eatNone
case .Walking where power : return table.eatNoneInPow
case .EatingFeed where !power : return table.eatFeed
case .EatingFeed where power : return table.eatFeedInPow
case .EatingPower where !power : return table.eatPow
case .EatingPower where power : return table.eatPowInPow
case .EatingFruit where !power : return table.eatNone
case .EatingFruit where power : return table.eatNoneInPow
default: return 16
}
}
Die Anzahl der Geister, die Pacman seit Beginn des Spiels gegessen hat, gibt die Anzahl der Geister zurück, die für jedes Level von numberOfFeedsEated angezeigt werden.
func getNumberOfGhostsForAppearace() -> Int {
let numberOfGhosts: Int
// Miss Bypass Sequence
if playerMiss {
if numberOfFeedsEatedByMiss < 7 {
numberOfGhosts = 1
} else if numberOfFeedsEatedByMiss < 17 {
numberOfGhosts = 2
} else if numberOfFeedsEatedByMiss < 32 {
numberOfGhosts = 3
} else {
playerMiss = false
numberOfGhosts = getNumberOfGhostsForAppearace()
}
} else {
switch levelOfAppearance {
case .Level_A:
if numberOfFeedsEated < 30 {
numberOfGhosts = 2
} else if numberOfFeedsEated < 90 {
numberOfGhosts = 3
} else {
numberOfGhosts = 4
}
case .Level_B:
if numberOfFeedsEated < 50 {
numberOfGhosts = 3
} else {
numberOfGhosts = 4
}
case .Level_C: fallthrough
default:
numberOfGhosts = 4
}
}
return numberOfGhosts
}
Wechseln Sie je nach der von Anfang an gezählten Zeit zwischen ChaseMode und ScatterMode. Bestimmen Sie die ChaseMode-Zeit für jede Ebene.
func judgeGhostsWavyChase(time: Int) -> Bool {
var chaseMode: Bool = false
switch levelOfSpeed {
case .Level_A:
chaseMode = (time >= 7000 && time < 27000) || (time >= 34000 && time < 54000)
|| (time >= 59000 && time < 79000) || (time >= 84000)
case .Level_B:
chaseMode = (time >= 7000 && time < 27000) || (time >= 34000 && time < 54000)
|| (time >= 59000)
case .Level_C: fallthrough
case .Level_D:
chaseMode = (time >= 5000 && time < 25000) || (time >= 30000 && time < 50000)
|| (time >= 55000)
}
return chaseMode
}
Kombinieren Sie abschließend jeden bisher erstellten Modus in der CgGameMain-Klasse.
--Attract Mode: CgSceneAttractMode --Kreditmodus: CgSceneCreditMode * Diesmal zu GameSequences.swift hinzugefügt --Startmodus: CgSceneMaze --Play-Modus: CgSceneMaze wird ausgeführt
class CgGameMain : CgSceneFrame {
enum EnMainMode: Int {
case AttractMode = 0, CreditMode, WaitForStartButton, StartMode, PlayMode
}
enum EnSubMode: Int {
case Character = 0, StartDemo, PlayDemo
}
private var scene_attractMode: CgSceneAttractMode!
private var scene_creditMode: CgSceneCreditMode!
private var scene_maze: CgSceneMaze!
private var subMode: EnSubMode = .Character
init(skscene: SKScene) {
super.init()
// Create SpriteKit managers.
self.sprite = CgSpriteManager(view: skscene, imageNamed: "pacman16_16.png ", width: 16, height: 16, maxNumber: 64)
self.background = CgCustomBackgroundManager(view: skscene, imageNamed: "pacman8_8.png ", width: 8, height: 8, maxNumber: 2)
self.sound = CgSoundManager(binding: self, view: skscene)
self.context = CgContext()
scene_attractMode = CgSceneAttractMode(object: self)
scene_creditMode = CgSceneCreditMode(object: self)
scene_maze = CgSceneMaze(object: self)
}
/// Event handler
/// - Parameters:
/// - sender: Message sender
/// - id: Message ID
/// - values: Parameters of message
override func handleEvent(sender: CbObject, message: EnMessage, parameter values: [Int]) {
if message == .Touch {
if let mode: EnMainMode = EnMainMode(rawValue: getSequence()) {
if mode == .AttractMode || mode == .WaitForStartButton {
goToNextSequence()
}
}
}
}
/// Handle sequence
/// To override in a derived class.
/// - Parameter sequence: Sequence number
/// - Returns: If true, continue the sequence, if not, end the sequence.
override func handleSequence(sequence: Int) -> Bool {
guard let mode: EnMainMode = EnMainMode(rawValue: sequence) else { return false }
switch mode {
case .AttractMode: attarctMode()
case .CreditMode: creditMode()
case .WaitForStartButton: break // Forever loop
case .StartMode: startMode()
case .PlayMode: playMode()
}
// Continue running sequence.
return true
}
// ============================================================
// Execute each mode.
// ============================================================
func attarctMode() {
switch subMode {
case .Character:
scene_attractMode.resetSequence()
scene_attractMode.startSequence()
subMode = .StartDemo
case .StartDemo:
if !scene_attractMode.enabled {
context.demo = true
sound.enableOutput(false)
scene_maze.resetSequence()
scene_maze.startSequence()
subMode = .PlayDemo
}
case .PlayDemo:
if !scene_maze.enabled {
subMode = .Character
}
}
}
func creditMode() {
context.demo = false
if scene_attractMode.enabled {
scene_attractMode.stopSequence()
scene_attractMode.clear()
}
if scene_maze.enabled {
scene_maze.stopSequence()
scene_maze.clear()
}
context.credit += 1
scene_creditMode.resetSequence()
scene_creditMode.startSequence()
sound.enableOutput(true)
sound.playSE(.Credit)
goToNextSequence()
}
func startMode() {
context.credit -= 1
scene_creditMode.stopSequence()
scene_maze.resetSequence()
scene_maze.startSequence()
goToNextSequence()
}
func playMode() {
if !scene_maze.enabled {
subMode = .Character
goToNextSequence(EnMainMode.AttractMode.rawValue)
}
}
}
Zusätzlich zur Charaktereinführung gibt es eine Spieldemo im Attraktionsmodus. Dies war ein Demo-Flag, das leicht implementiert werden konnte, indem zwischen einer Swipe-Operation und einer vorbereiteten Operationstabelle gewechselt wurde.
Die Operationstabelle und die Erfassungsmethode sind in der CgContext-Klasse implementiert. Die Richtung wird entsprechend der Anzahl der Frames von Anfang an herausgenommen.
let table_operationInDemo: [ (frameCount: Int, direction: EnDirection) ] = [
(9, .Left), (36, .Down), (61, .Right), (82, .Down), (109, .Right), (133, .Up), (162, .Right),
(189, .Up), (215, .Right), (238, .Down), (261, .Right), (308, .Down), (335, .Left), (523, .Up),
(555, .Right), (569, .Up), (609, .Left), (632, .Up), (648, .Right), (684, .Up), (732, .Left),
(831, .Down), (864, .Left), (931, .Up), (948, .Left), (970, .Up), (1063, .Right), (1113, .Down),
(1157, .Right), (1218, .Down)
]
func getOperationForDemo() -> EnDirection {
guard(demoSequence < table_operationInDemo.count) else { return .None }
let table = table_operationInDemo[demoSequence]
var direction: EnDirection = .None
if counterByFrame >= table.frameCount {
direction = table.direction
demoSequence += 1
}
return direction
}
Rufen Sie die Operationsrichtung mit der Methode getOperationForDemo ab und legen Sie sie im Player fest. Zur sequenceUpdating-Sequenz der CgSceneMaze-Klasse hinzugefügt.
func sequenceUpdating() {
// Operate player in demonstration automatically.
if context.demo {
let direction = context.getOperationForDemo()
if direction != .None {
player.targetDirecition = direction
}
}
//Unten weggelassen
Endlich war es fast fertig.
Es gibt kein Problem mit der Betriebsgeschwindigkeit des Spiels. Der Quellcode besteht immer noch aus 5000 Zeilen, was ziemlich einfach ist.
Das nächste Mal mache ich meine eigene Arbeit, daher möchte ich verschiedene Vorkehrungen treffen, um sie fertigzustellen.
Recommended Posts