Cette fois, nous avons créé des détails sur le niveau de difficulté et le niveau de vitesse qui changent en fonction du tour, et avons combiné chaque mode d'écran créé dans # 5 [Conception de séquence]. Ensuite, amenez-le à l'état presque terminé (ce qui suit est un film d'image). Le code source est disponible sur GitHub, veuillez donc vous y référer.
Les spécifications du niveau de difficulté et du niveau de vitesse qui changent en fonction du tour sont les suivantes.
Cette fois, la version étrangère de la table de difficulté et le paramètre Spurt ② ne seront pas créés.
Implémentez une table de difficulté et une table de vitesse comme un tableau de taples. Ci-dessous, tous sont inclus dans la classe CgContext sauf pour la combinaison de chaque mode d'écran.
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 )
]
Extrayez les données selon le tour de ce tableau de taples et définissez-les respectivement dans les membres de la classe CgContext.
/// 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
}
La méthode pour obtenir la vitesse du joueur (Pacman) est la suivante. Modifiez la valeur à acquérir lorsque vous mangez de la nourriture puissante et inversez-la et quand elle ne l'est pas.
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
}
}
Le nombre de fantômes que Pacman a mangés depuis le début du jeu renvoie le nombre de fantômes qui apparaissent pour chaque niveau par numberOfFeedsEated.
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
}
Basculez entre ChaseMode et ScatterMode en fonction du temps compté depuis le début. Déterminez la durée du ChaseMode pour chaque niveau.
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
}
Enfin, combinez chaque mode créé jusqu'à présent dans la classe CgGameMain.
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)
}
}
}
En plus de l'introduction du personnage, il y a une démo de jeu en mode attractif. Il s'agissait d'un indicateur de démonstration qui pouvait être facilement implémenté en basculant entre une opération de balayage et une table d'opération préparée.
La table d'opération et la méthode d'acquisition sont implémentées dans la classe CgContext. La direction est retirée en fonction du nombre d'images depuis le début.
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
}
Obtenez la direction de l'opération avec la méthode getOperationForDemo et définissez-la dans le lecteur. Ajouté à la séquence sequenceUpdating de la classe CgSceneMaze.
func sequenceUpdating() {
// Operate player in demonstration automatically.
if context.demo {
let direction = context.getOperationForDemo()
if direction != .None {
player.targetDirecition = direction
}
}
//Omis ci-dessous
Enfin, il était presque terminé.
Il n'y a aucun problème avec la vitesse de fonctionnement du jeu. Le code source est toujours autour de 5000 lignes, ce qui est assez facile à faire.
La prochaine fois, je fais mon propre travail, alors j'aimerais prendre diverses dispositions pour le terminer.
Recommended Posts