[Python] Make a simple maze game with Pyxel-Make enemies appear-

Previous article [Python] The first step to making a game with Pyxel [Python] Make a game with Pyxel-Use an editor- [Python] Make a simple maze game with Pyxel

Introduction

Let's make an enemy character appear in a game that follows a maze and aims for a goal. I'd like to make it a little more game-like by making the game over when it hits.

Preparation

Added an enemy character with a scary face. Increase the walls to make it look like a maze. The base code. The enemy hasn't appeared yet.

import pyxel

class Player:
    def __init__(self, x, y):
        self.x = x
        self.y = y

        self.dx = 0
        self.dy = 0
        self.move_count = 0

    def move(self):
        self.x += self.dx
        self.y += self.dy

class App:
    def __init__(self):
        pyxel.init(128, 128)

        pyxel.load("assets/sample.pyxres")

        self.player = Player(16, 16)
        
    def run(self):
        pyxel.run(self.update, self.draw)

    def update_move(self):
        if self.player.move_count == 0:
            if pyxel.btnp(pyxel.KEY_LEFT):
                self.player.dx = -1
            elif pyxel.btnp(pyxel.KEY_RIGHT):
                self.player.dx = 1
            elif pyxel.btnp(pyxel.KEY_UP):
                self.player.dy = -1
            elif pyxel.btnp(pyxel.KEY_DOWN):
                self.player.dy = 1

            if self.player.dx != 0 or self.player.dy != 0:
                self.player.move_count = 16

            if pyxel.tilemap(0).get(
                    self.player.x / 8 + self.player.dx * 2,
                    self.player.y / 8 + self.player.dy * 2) == 6:
                self.player.dx = 0
                self.player.dy = 0
                self.player.move_count = 0
        else:
            self.player.move()
            self.player.move_count -= 1

            if self.player.move_count == 0:
                self.player.dx = 0
                self.player.dy = 0

    def update(self):
        self.update_move()

    def draw(self):
        pyxel.cls(0)

        pyxel.bltm(0, 0, 0, 0, 0, 16, 16, 0)

        pyxel.blt(self.player.x, self.player.y, 0, 0, 0, 16, 16, 0)

        if pyxel.tilemap(0).get(self.player.x / 8,self.player.y / 8) == 2:
            pyxel.rect(0, 0, 128, 16, 8)
            pyxel.text(40, 5, "GAME CLEAR!!", 7)

App().run()

Show enemies

class App:
    def __init__(self):
        pyxel.init(128, 128)

        pyxel.load("assets/sample.pyxres")

        self.player = Player(16, 16)

        #Generate an instance of an enemy character
        self.enemy = Player(16, 96)
#Omission
    def draw(self):
        pyxel.cls(0)

        pyxel.bltm(0, 0, 0, 0, 0, 16, 16, 0)

        pyxel.blt(self.player.x, self.player.y, 0, 0, 0, 16, 16, 0)

        #Drawing of enemy characters
        pyxel.blt(self.enemy.x, self.enemy.y, 0, 0, 16, 16, 16, 0)

Create an instance of the Player class to manage the coordinates of the enemy character. The y coordinate of the initial position is 128 at the bottom of the screen, so set it to 96, which is 2 squares higher than that. And add the function to draw the enemy in the drawing function. Of the arguments (x, y, img, u, v, w, h, colkey), x, y specifies the variable of enemy, and u, v specifies 16,16. To do.

Move the enemy

The enemy will move randomly. The movement of the character is managed by the update_move function, so we will fix this. If you look closely, it seems that you can use it as it is except for the part of the first block that "determines the direction of movement by the pressed key". Therefore, cut out the part that "determines the direction of movement" as a separate function, and call different functions depending on whether your player moves or the enemy character moves. The function that "determines the direction of movement" is as follows. (Since the random module is used, write import random at the beginning.)

    #Your player decides the direction of movement by the key
    def move_manual(self, player):
        if pyxel.btnp(pyxel.KEY_LEFT):
            player.dx = -1
        elif pyxel.btnp(pyxel.KEY_RIGHT):
            player.dx = 1
        elif pyxel.btnp(pyxel.KEY_UP):
            player.dy = -1
        elif pyxel.btnp(pyxel.KEY_DOWN):
            player.dy = 1

    #Enemy characters randomly decide the direction of movement
    def move_auto(self, player):
        rand = random.randint(1, 4)
        if rand == 1:
            player.dx = -1
        elif rand == 2:
            player.dx = 1
        elif rand == 3:
            player.dy = -1
        elif rand == 4:
            player.dy = 1

Then modify the update_move function. Until now, there was only one object of the Player class, so I was directly manipulating self.player. This time, I have two objects, myself and the enemy, so I will be able to select which object to move. So, I made an object of the Player class to move and a Boolean value indicating whether to move manually or automatically.

    def update_move(self, player, is_manual):
        #Branch the function to call depending on whether it is manual movement or automatic movement
        if player.move_count == 0:
            if is_manual:
                self.move_manual(player)
            else:
                self.move_auto(player)

            #No change from here to below(However, self.Changing player to player)
            if player.dx != 0 or player.dy != 0:
                player.move_count = 16

            if pyxel.tilemap(0).get(
                    player.x / 8 + player.dx * 2,
                    player.y / 8 + player.dy * 2) == 6:
                player.dx = 0
                player.dy = 0
                player.move_count = 0
        else:
            player.move()
            player.move_count -= 1

            if player.move_count == 0:
                player.dx = 0
                player.dy = 0

Finally, modify the inside of the update function.

    def update(self):
        self.update_move(self.player, True)
        self.update_move(self.enemy, False)

The enemy character is now moving.

Game over if you hit an enemy

If you hit an enemy, try to make the game over. Whether or not you have hit is determined by the relationship between the position coordinates of yourself and the enemy. It's the so-called "collision detection".

    #Determine if you hit an enemy
    def check_hit(self, player, enemy):
        dx = player.x - enemy.x
        dy = player.y - enemy.y
        if -16 < dx < 16 and -16 < dy < 16:
            return True
        else:
            return False

If both the x and y coordinates are between -16 and 16, it is judged that they have collided. (For the first time, I learned that you can write by connecting comparison operators like -16 <dx <16. It's convenient.) By the way, you can omit the argument and use self.player and self.enemy, but if there are multiple enemies, it will not be flexible, so I try to specify the object to be judged as the argument. ..

    def draw(self):
        pyxel.cls(0)

        pyxel.bltm(0, 0, 0, 0, 0, 16, 16, 0)

        pyxel.blt(self.player.x, self.player.y, 0, 0, 0, 16, 16, 0)

        pyxel.blt(self.enemy.x, self.enemy.y, 0, 0, 16, 16, 16, 0)

        if pyxel.tilemap(0).get(self.player.x / 8,self.player.y / 8) == 2:
            pyxel.rect(0, 0, 128, 16, 8)
            pyxel.text(40, 5, "GAME CLEAR!!", 7)

        #Game over if you hit an enemy
        if self.check_hit(self.player, self.enemy):
            pyxel.rect(0, 0, 128, 16, 8)
            pyxel.text(40, 5, "GAME OVER...", 7)

At the end of draw, I added a part to judge whether the game is over. If you hit an enemy with this, the game is over.

Finish

As is the case when the game is cleared, the game will continue even if the game is over. When the game is cleared or the game is over, the game will end and it will not move.

    def __init__(self):
        pyxel.init(128, 128)

        pyxel.load("assets/sample.pyxres")

        self.player = Player(16, 16)

        self.enemy = Player(16,96)

        #Flag indicating the end of the game
        self.game_end = False

#Omission
    def update(self):
        #Update only if the game is not over
        if self.game_end == False:
            self.update_move(self.player, True)
            self.update_move(self.enemy, False)

    def draw(self):
        pyxel.cls(0)

        pyxel.bltm(0, 0, 0, 0, 0, 16, 16, 0)

        pyxel.blt(self.player.x, self.player.y, 0, 0, 0, 16, 16, 0)

        #Drawing of enemy characters
        pyxel.blt(self.enemy.x, self.enemy.y, 0, 0, 16, 16, 16, 0)

        if pyxel.tilemap(0).get(self.player.x / 8,self.player.y / 8) == 2:
            pyxel.rect(0, 0, 128, 16, 8)
            pyxel.text(40, 5, "GAME CLEAR!!", 7)
            self.game_end = True

        #Game over if you hit an enemy
        if self.check_hit(self.player, self.enemy):
            pyxel.rect(0, 0, 128, 16, 8)
            pyxel.text(40, 5, "GAME OVER...", 7)
            self.game_end = True

When the game was over, the update stopped and the game could not be continued. The difficulty level has become quite high. Below is the full code. It may be a little difficult to read because the function name is appropriate.

import pyxel
import random

class Player:
    def __init__(self, x, y):
        self.x = x
        self.y = y

        self.dx = 0
        self.dy = 0
        self.move_count = 0

    def move(self):
        self.x += self.dx
        self.y += self.dy

class App:
    def __init__(self):
        pyxel.init(128, 128)

        pyxel.load("assets/sample.pyxres")

        self.player = Player(16, 16)
        self.enemy = Player(16, 96)

        self.game_end = False
        
    def run(self):
        pyxel.run(self.update, self.draw)

    def update_move(self, player, is_manual):
        if player.move_count == 0:
            if is_manual:
                self.move_manual(player)
            else:
                self.move_auto(player)

            if player.dx != 0 or player.dy != 0:
                player.move_count = 16

            if pyxel.tilemap(0).get(
                    player.x / 8 + player.dx * 2,
                    player.y / 8 + player.dy * 2) == 6:
                player.dx = 0
                player.dy = 0
                player.move_count = 0
        else:
            player.move()
            player.move_count -= 1

            if player.move_count == 0:
                player.dx = 0
                player.dy = 0
    
    def move_manual(self, player):
        if pyxel.btnp(pyxel.KEY_LEFT):
            player.dx = -1
        elif pyxel.btnp(pyxel.KEY_RIGHT):
            player.dx = 1
        elif pyxel.btnp(pyxel.KEY_UP):
            player.dy = -1
        elif pyxel.btnp(pyxel.KEY_DOWN):
            player.dy = 1

    def move_auto(self, player):
        rand = random.randint(1, 4)
        if rand == 1:
            player.dx = -1
        elif rand == 2:
            player.dx = 1
        elif rand == 3:
            player.dy = -1
        elif rand == 4:
            player.dy = 1

    def check_hit(self, player, enemy):
        dx = player.x - enemy.x
        dy = player.y - enemy.y
        if -16 < dx < 16 and -16 < dy < 16:
            return True
        else:
            return False

    def update(self):
        if self.game_end == False:
            self.update_move(self.player, True)
            self.update_move(self.enemy, False)

    def draw(self):
        pyxel.cls(0)

        pyxel.bltm(0, 0, 0, 0, 0, 16, 16, 0)

        pyxel.blt(self.player.x, self.player.y, 0, 0, 0, 16, 16, 0)
        pyxel.blt(self.enemy.x, self.enemy.y, 0, 0, 16, 16, 16, 0)

        if pyxel.tilemap(0).get(self.player.x / 8,self.player.y / 8) == 2:
            pyxel.rect(0, 0, 128, 16, 8)
            pyxel.text(40, 5, "GAME CLEAR!!", 7)
            self.game_end = True

        if self.check_hit(self.player, self.enemy):
            pyxel.rect(0, 0, 128, 16, 8)
            pyxel.text(40, 5, "GAME OVER...", 7)
            self.game_end = True

App().run()

(Added 2021/1/12) Comments suggest code improvements. Please look.

reference

https://github.com/kitao/pyxel/blob/master/README.ja.md Making a Pac-Man-like game with Pyxel Part 1 Making a Sokoban game with Pyxel (Part 1)

Recommended Posts

[Python] Make a simple maze game with Pyxel-Make enemies appear-
[Python] Make a simple maze game with Pyxel
Let's make a simple game with Python 3 and iPhone
Let's make a shiritori game with Python
[Python] Make a game with Pyxel-Use an editor-
I want to make a game with Python
Make a fortune with Python
Make a simple Slackbot with interactive button in python
What is God? Make a simple chatbot with python
Let's make a GUI with python.
How to make a simple Flappy Bird game with pygame
Make a recommender system with python
Let's make a graph with python! !!
Rubyist tried to make a simple API with Python + bottle + MySQL
Make a simple OMR (mark sheet reader) with Python and OpenCV
Creating a simple PowerPoint file with Python
Let's make a voice slowly with Python
Let's make a simple language with PLY 1
Let's make a web framework with Python! (1)
Make a desktop app with Python with Electron
Let's make a Twitter Bot with Python!
I made a roguelike game with Python
Let's make a web framework with Python! (2)
I made a simple blackjack with Python
Make a simple pixel art generator with Flask
Start a simple Python web server with Docker
Try to make a "cryptanalysis" cipher with Python
Make a rock-paper-scissors game in one line (python)
Let's replace UWSC with Python (5) Let's make a Robot
Try to make a dihedral group with Python
A simple to-do list created with Python + Django
I made a bin picking game with Python
I tried to make a simple mail sending application with tkinter of Python
Make a squash game
Make a Tetris-style game!
Try to make a command standby tool with python
I made a Christmas tree lighting game with Python
[Practice] Make a Watson app with Python! # 2 [Translation function]
How to make a shooting game with toio (Part 1)
[Super easy] Let's make a LINE BOT with Python.
[Vagrant] Set up a simple API server with python
[Mac] I want to make a simple HTTP server that runs CGI with Python
Let's make a websocket client with Python. (Access token authentication)
Associate Python Enum with a function and make it Callable
Experiment to make a self-catering PDF for Kindle with Python
I made a simple book application with python + Flask ~ Introduction ~
Make Puyo Puyo AI with Python
Make a bookmarklet in Python
Create a simple video analysis tool with python wxpython + openCV
I made a puzzle game (like) with Tkinter in Python
[Python] The first step to making a game with Pyxel
Simple typing game with DragonRuby
Create a directory with python
Let's make a rock-paper-scissors game
I tried a stochastic simulation of a bingo game with Python
Make a fire with kdeplot
[5th] I tried to make a certain authenticator-like tool with python
I made a simple circuit with Python (AND, OR, NOR, etc.)
[Python] Make a graph that can be moved around with Plotly
If you know Python, you can make a web application with Django
[2nd] I tried to make a certain authenticator-like tool with python