Lazy dungeon

Iš wiki.angis.net.
Jump to navigation Jump to search

Lazy Dungeon žaidimas

Lazy Dungeon žaidimo aplinka

Ši programa demonstruoja, kaip susikurti klasikinį Dungeon stiliaus žaidimą, kuriame veikėjas kovoja su priešais, keliasi lygį ir savo galią. Taip pradėdamas nuo silpniausių priešų - žurkių, pagrindinis kovotojas sustiprėja ir gali kautis su zombiais, o vėliau ir su pagrindinio lygio bosu.

Šioje programėlėje panaudoti keli skirtingi vaizdo failai ir garsai, kurie atsiranda priklausomai nuo atlikto veiksmo.

Žaisti Lazy Dungeon

Žaidimui reikalingi failai

Visus garsus ir vaizdus panaudotus šiame žaidime galima atsisiųsti čia.

Lazy Dungeon žaidimo kodas

import angis
import žaidimas
import random
# Buvau entity klases iškėlęs į atskirus modulius ir mėginau juos importuoti
# Bet tuomet tų klasių nepavykdavo užnaudoti main scripte
# Gali būti, kad tiesiog nemoku aprašyti python modulių, bet vistiek verta būtų pažiūrėti
# Jei importas veikia super būtų tabų palaikymas ir kad būtų galima kelis failus redaguoti projekte
# Arba bent, kad būtų galima atidaryti kitus failus redagavimui, kad ir tame pačiame lange

class Asset:
    grassGraphics = 'pav/plyt/43.png'
    dirtGraphics = 'pav/plyt/14.png'

    stoneGraphics = 'pav/stat/akmuo3.png'
    knightGraphics = 'pixil-frame-0.png'
    ratGraphics = 'rat.png'
    zombieGraphics = 'zombie.png'
    necromancerGraphics = 'necromancer.png'

    dungeonMusic = 'dungeon-music.mp3'

class MonsterType:
    rat = 'rat'
    zombie = 'zombie'
    necromancer = 'necromancer'

class Entity:
    entityRef = None

    health = 0
    xp = 0
    attackStrength = 0

class WarriorEntity(Entity):
    health = 10
    xp = 0
    attackStrength = 4

    level = 1
    currentXP = 0

    lastPosition = None

    stepLength = 50
    movementSpeed = 10

    healthStatsDisplay = None
    levelDisplay = None

    isAlive = True
    isWin = False

    gameRef = None

    isDebugMode = False

    def __init__(self, gameRef, x = 100, y = 100, debugMode = False):
        self.isDebugMode = debugMode

        self.gameRef = gameRef

        self.entityRef = self.gameRef.Veikėjas(Asset.knightGraphics)
        self.entityRef.nustatykKliūtį(x=1, y=1, plotis=48, aukštis=48)
        self.lastPosition = [x, y]
        self.entityRef.atsirask(x, y)

        if self.isDebugMode:
            self.entityRef.rodykZonas()

        self.initPlayerStatsDisplay()

    # Atrodo, kad nesuveikia destruktoriai
    # def __del__(self):
    #     self.entityRef.atsirask(5000, 5000)
    #     self.entityRef.slėpkis()

    def destroy(self):
        self.entityRef.atsirask(5000, 5000)
        self.entityRef.slėpkis()

    def initPlayerStatsDisplay(self):
        statsColor = "#FF0000"

        self.healthStatsDisplay = self.gameRef.Tekstas()
        self.healthStatsDisplay.atsirask(0, 600)
        self.healthStatsDisplay.dydis(40)
        self.healthStatsDisplay.spalva(statsColor)

        self.levelDisplay = self.gameRef.Tekstas()
        self.levelDisplay.atsirask(450, 600)
        self.levelDisplay.dydis(40)
        self.levelDisplay.spalva(statsColor)

        self.redrawStats()

    def back(self):
        self.move(180)

    def forward(self):
        self.move(0)

    def up(self):
        self.move(90)

    def down(self):
        self.move(270)

    def move(self, direction):
        if self.isAlive and not self.isWin:
            self.setLastPosition()
            self.entityRef.judėk(self.stepLength, direction, self.movementSpeed)

    def setLastPosition(self):
        x, y = self.entityRef.duokKoordinates()
        self.lastPosition = [x, y]

    def teleportPlayerToLastPosition(self):
        lastPosition = self.lastPosition
        self.entityRef.atsirask(lastPosition[0], lastPosition[1])

    def attack(self, enemy):
        def enemyAttack(a, b, c):
            # Nesuveikia trumpi garso įrašai
            # TODO: Papildyti su pvz
            # Nebeturėjau laiko įdėti pvz, bet kai garso įrašas trumpas (1-3 sec)
            # Jis nesugroja
            dmg, enemyXP, isWin = enemy.attack(self.getAttackDamage())
            self.isWin = isWin
            self.health = self.health - dmg            
            self.currentXP = self.currentXP + enemyXP
            self.teleportPlayerToLastPosition()
            self.checkState()
            self.redrawStats()

        return enemyAttack

    def getAttackDamage(self):
        return self.attackStrength + round(((self.level - 1) * self.attackStrength) * 0.5)

    def onColisionAttach(self, enemy):
        self.entityRef.susidūrus(enemy.entityRef, self.attack(enemy))

    def drawHealth(self):
        healthVisual = '|' * self.health
        self.healthStatsDisplay.užrašas("HP: " + healthVisual)

    def drawLevel(self):
        self.levelDisplay.užrašas("LVL: " + str(self.level))

    def checkState(self):
        if self.health < 1:
            self.isAlive = False
            print('You died!')
            print('To restart press R')

        if self.currentXP >= self.level * 10 + (pow(2, self.level - 1) - 1 ) * 10:
            self.health = 10 + self.level * 2
            self.level = self.level + 1 
        
        if self.isWin:
            print('Congratulations! You beat the evil necromancer!')
            print('To restart press R')

    def redrawStats(self):
        self.drawHealth()
        self.drawLevel()

class EnemyEntity(Entity):
    isNecromancer = False

    gameRef = None

    number = 0

    isDebugMode = False

    def __init__(self, gameRef, x, y, z, debugMode = False, sprite = Asset.stoneGraphics):
        self.isDebugMode = debugMode

        self.gameRef = gameRef

        self.entityRef = self.gameRef.Daiktas(sprite)
        self.entityRef.nustatykKliūtį(x=25, y=25, plotis=1, aukštis=1)
        self.entityRef.atsirask(x, y)

        if self.isDebugMode:
            self.entityRef.rodykZonas()

        self.number = z

    def destroy(self):
        self.sendToGraveyard()

    def attack(self, dmg):
        self.life = self.life - dmg
        if self.life < 1:
            self.sendToGraveyard()
            return 0, self.xp, self.isNecromancer
        return self.attackStrength, 0, False

    def sendToGraveyard(self):
        self.entityRef.atsirask(1000 + (50 * self.number), 1000)
        self.entityRef.slėpkis()

class Rat(EnemyEntity):
    life = 5
    attackStrength = 1
    xp = 2

    def __init__(self, gameRef, x, y, z, debugMode = False):
        EnemyEntity.__init__(self, gameRef, x, y, z, debugMode, Asset.ratGraphics)

class Zombie(EnemyEntity):
    life = 12
    attackStrength = 2
    xp = 4

    def __init__(self, gameRef, x, y, z, debugMode = False):
        EnemyEntity.__init__(self, gameRef, x, y, z, debugMode, Asset.zombieGraphics)

class Necromancer(EnemyEntity):
    life = 20
    attackStrength = 5
    xp = 10
    isNecromancer = True

    def __init__(self, gameRef, x, y, z, debugMode = False):
        EnemyEntity.__init__(self, gameRef, x, y, z, debugMode, Asset.necromancerGraphics)

class Organizer:
    angisRef = None
    gameRef = None

    width = 600
    tileWidth = 50

    warriorEntity = None

    enemyList = []

    enemyCount = 0
    occupiedLocations = [[1, 1]]

    music = None
    musicPlaying = False

    isDebugMode = False

    def __init__(self, angisRef, gameRef, width, debugMode = False):
        self.isDebugMode = debugMode

        self.angisRef = angisRef
        self.gameRef = gameRef
        self.width = width

        self.angisRef.naudosiuFailus(
            [
                Asset.grassGraphics,
                Asset.dirtGraphics,
                
                Asset.stoneGraphics,
                Asset.knightGraphics,
                Asset.ratGraphics,
                Asset.zombieGraphics,
                Asset.necromancerGraphics,

                Asset.dungeonMusic
            ])

        self.initMusic()
        self.initMap()
        self.spawnPlayer()
        self.spawnMapEnemies()

    def destroy(self):
        self.warriorEntity.destroy()

        for enemy in self.enemyList:
            enemy.destroy()

    def initMusic(self):
        self.music = angis.Garsas(Asset.dungeonMusic)
        self.music.lygis(25)
        self.music.grokFone()
        self.musicPlaying = True

        self.angisRef.paspaudus('m', self.toggleMusic)

    def initMap(self):
        self.gameRef.scena = self.gameRef.Scena(
            plotis = self.width,
            aukštis = self.width + 50,
            plytelėsPlotis = self.tileWidth,
            plytelėsAukštis = self.tileWidth
        )

        k1 = self.gameRef.Plytelė(Asset.grassGraphics)
        k2 = self.gameRef.Plytelė(Asset.dirtGraphics)

        maze = [
            [k1, k1, k1, k1, k1, k1, k1, k1, k1, k1, k1, k1],
            [k1, k2, k2, k2, k2, k2, k2, k2, k2, k2, k2, k1],
            [k1, k2, k2, k2, k2, k2, k2, k2, k2, k2, k2, k1],
            [k1, k2, k2, k2, k2, k2, k2, k2, k2, k2, k2, k1],
            [k1, k2, k2, k2, k2, k2, k2, k2, k2, k2, k2, k1],
            [k1, k2, k2, k2, k2, k2, k2, k2, k2, k2, k2, k1],
            [k1, k2, k2, k2, k2, k2, k2, k2, k2, k2, k2, k1],
            [k1, k2, k2, k2, k2, k2, k2, k2, k2, k2, k2, k1],
            [k1, k2, k2, k2, k2, k2, k2, k2, k2, k2, k2, k1],
            [k1, k2, k2, k2, k2, k2, k2, k2, k2, k2, k2, k1],
            [k1, k2, k2, k2, k2, k2, k2, k2, k2, k2, k2, k1],
            [k1, k1, k1, k1, k1, k1, k1, k1, k1, k1, k1, k1]
        ]

        self.gameRef.scena.pridėkPlyteles(maze)

        if self.isDebugMode:
            self.gameRef.scena.showGrid()

        for x in range(12):
            self.addStoneBoundary(x * self.tileWidth, 0)
            self.addStoneBoundary(x * self.tileWidth, self.width - self.tileWidth)


        for x in range(1, 11):
            self.addStoneBoundary(0, x * self.tileWidth)
            self.addStoneBoundary(self.width - self.tileWidth, x * self.tileWidth)

    def addStoneBoundary(self, x, y):
        stone = self.gameRef.Daiktas(Asset.stoneGraphics)
        stone.atsirask(x, y)
        stone.nustatykKliūtį(x=1, y=1, plotis=48, aukštis=48)

        if self.isDebugMode:
            stone.rodykZonas()

    def spawnPlayer(self):
        self.warriorEntity = WarriorEntity(self.gameRef, 100, 100, self.isDebugMode)

        self.angisRef.paspaudus('a', self.warriorEntity.back)
        self.angisRef.paspaudus('w', self.warriorEntity.up)
        self.angisRef.paspaudus('s', self.warriorEntity.down)
        self.angisRef.paspaudus('d', self.warriorEntity.forward)

    def spawnMapEnemies(self):
        self.spawnEnemy(MonsterType.rat)
        self.spawnEnemy(MonsterType.rat)
        self.spawnEnemy(MonsterType.rat)
        self.spawnEnemy(MonsterType.zombie)
        self.spawnEnemy(MonsterType.zombie)
        self.spawnEnemy(MonsterType.zombie)
        self.spawnEnemy(MonsterType.zombie)
        self.spawnEnemy(MonsterType.zombie)
        self.spawnEnemy(MonsterType.zombie)
        self.spawnEnemy(MonsterType.necromancer)

    def spawnEnemy(self, monsterType):
        while True:
            x = random.randint(3, 10)
            y = random.randint(3, 10)

            if [x, y] in self.occupiedLocations:
                continue
            
            self.spawnEnemyInCoordinates(monsterType, x * 50, y * 50)
            self.occupiedLocations.append([x, y])
            break

    def toggleMusic(self):
        if self.musicPlaying:
            self.music.stok()
            self.musicPlaying = False
        else:
            self.music.grokFone()
            self.musicPlaying = True


    def spawnEnemyInCoordinates(self, monsterType, x, y):
        self.enemyCount = self.enemyCount + 1

        enemy = None

        if monsterType == MonsterType.rat:
            enemy = Rat(self.gameRef, x, y, self.enemyCount, self.isDebugMode)
        elif monsterType == MonsterType.zombie:
            enemy = Zombie(self.gameRef, x, y, self.enemyCount, self.isDebugMode)
        elif monsterType == MonsterType.necromancer:
            enemy = Necromancer(self.gameRef, x, y, self.enemyCount, self.isDebugMode)
        else:
            enemy = EnemyEntity(self.gameRef, x, y, self.enemyCount, self.isDebugMode)

        self.warriorEntity.onColisionAttach(enemy)

        self.enemyList.append(enemy)


debugMode = False
mapWidth = 600

organizer = Organizer(angis, žaidimas, mapWidth, debugMode)

def restartGame(organizerObj):
    def restartGameFunction():
        if(organizerObj.musicPlaying):
            organizerObj.music.stok()

        organizerObj.destroy()
        organizer = Organizer(angis, žaidimas, mapWidth, debugMode)

    return restartGameFunction

angis.paspaudus('r', restartGame(organizer))

Svarbu! Nepamiršk įsikelti žaidime naudojamus paveiksliukus ir garsus per failų tvarkyklę. Visi Lazy Dungeon žaidimui reikalingi failai yra čia.