4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Python】pyxelを使ってシューティングゲーム

Last updated at Posted at 2020-10-12

#はじめに
ゲームを作ったのが初めてなので、参考資料を元に制作しました。

#動画

#ソースコード

from random import random

import pyxel

#画面の大きさ
SCENE_TITLE = 0
SCENE_PLAY = 1
SCENE_GAMEOVER = 2

#星の数、手前の星の色、奥の星の色
STAR_COUNT = 50
STAR_COLOR_HIGH = 10
STAR_COLOR_LOW = 4

# プレイヤーの大きさ、動きの速さ
PLAYER_WIDTH = 8
PLAYER_HEIGHT = 8
PLAYER_SPEED = 2

#弾の大きさ、色、速さ
BULLET_WIDTH = 2
BULLET_HEIGHT = 5
BULLET_COLOR = 8
BULLET_SPEED = 4

#敵の大きさ、速さ
ENEMY_WIDTH = 8
ENEMY_HEIGHT = 8
ENEMY_SPEED = 1.5

#爆発の大きさ
BLAST_START_RADIUS = 1
BLAST_END_RADIUS = 8
BLAST_COLOR_IN = 7
BLAST_COLOR_OUT = 10

#敵のリスト
enemy_list = []
#弾のリスト
bullet_list = []
#爆発のリスト
blast_list = []

#更新
def update_list(list):
    for elem in list:
        elem.update()

#描画 
def draw_list(list):
    for elem in list:
        elem.draw()

#初期化
def cleanup_list(list):
    i = 0
    while i < len(list):
        elem = list[i]
        if not elem.alive:
            list.pop(i)
        else:
            i += 1
#背景
class Background:
    def __init__(self):
        self.star_list = []
        for i in range(STAR_COUNT):
            self.star_list.append(
                (random() * pyxel.width, random() * pyxel.height, random() * 1.5 + 1)  
            )
            
    def update(self):
        for i, (x, y, speed) in enumerate(self.star_list):
            y += speed
            if y >= pyxel.height:
                y -= pyxel.height
            self.star_list[i] = (x, y, speed)
    
    def draw(self):
        for (x, y, speed) in self.star_list:
            pyxel.pset(x, y, STAR_COLOR_HIGH if speed > 1.8 else STAR_COLOR_LOW)

#プレイヤー  
class Player:
    def __init__(self, x, y):
        self.x = x  
        self.y = y
        self.w = PLAYER_WIDTH
        self.h = PLAYER_HEIGHT
        self.alive = True
        
    def update(self):
        if pyxel.btn(pyxel.KEY_LEFT):
            self.x -= PLAYER_SPEED
            
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.x += PLAYER_SPEED
            
        if pyxel.btn(pyxel.KEY_UP):
            self.y -= PLAYER_SPEED
            
        if pyxel.btn(pyxel.KEY_DOWN):
            self.y += PLAYER_SPEED
            
        self.x = max(self.x, 0)
        self.x = min(self.x, pyxel.width - self.w)
        self.y = max(self.y, 0)
        self.y = min(self.y, pyxel.height - self.h)
        
        if pyxel.btnp(pyxel.KEY_SPACE):
            Bullet(
                self.x + (PLAYER_WIDTH - BULLET_WIDTH) / 2, self.y - BULLET_HEIGHT / 2
            )
            
            pyxel.play(0, 0)
            
    def draw(self):
        pyxel.blt(self.x, self.y, 0, 0, 0, self.w, self.h, 0)
        
        
#弾      
class Bullet:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.w = BULLET_WIDTH
        self.h = BULLET_HEIGHT
        self.alive = True
        
        bullet_list.append(self)
        
    def update(self):
        self.y -= BULLET_SPEED
        
        if self.y + self.h - 1 < 0:
            self.alive = False
            
    def draw(self):
        pyxel.rect(self.x, self.y, self.w, self.h, BULLET_COLOR)
#敵  
class Enemy:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.w = ENEMY_WIDTH
        self.h = ENEMY_HEIGHT
        self.dir = 1
        self.alive = True
        self.offset = int(random() * 60)
        
        enemy_list.append(self)
        
    def update(self):
        if(pyxel.frame_count + self.offset) % 60 < 30:
            self.x += ENEMY_SPEED
            self.dir = 1 
            
        else:
            self.x -= ENEMY_SPEED
            self.dir = -1
            
        self.y += ENEMY_SPEED
        
        if self.y > pyxel.height - 1:
            self.alive = False
            
    def draw(self):
        pyxel.blt(self.x, self.y, 0, 8, 0, self.w * self.dir, self.h, 0)

#爆発           
class Blast:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.radius = BLAST_START_RADIUS
        self.alive = True
        
        blast_list.append(self)
        
    def update(self):
        self.radius += 1
        
        if self.radius > BLAST_END_RADIUS:
            self.alive = False
    
    def draw(self):
        pyxel.circ(self.x, self.y, self.radius, BLAST_COLOR_IN)
        pyxel.circb(self.x, self.y, self.radius, BLAST_COLOR_OUT)
        
class App:
    def __init__(self):
        pyxel.init(120, 160, caption="シューティングゲーム")
        
        pyxel.image(0).set(
            0,
            0,
            [
                "00c00c00",
                "0c7007c0",
                "0c7007c0",
                "c703b07c",
                "77033077",
                "785cc587",
                "85c77c58",
                "0c0880c0",   
            ],
        )
        
        pyxel.image(0).set(
            8,
            0,
            [
                "00088000",
                "00ee1200",
                "08e2b180",
                "02882820",
                "00222200",
                "00012280",
                "08208008",
                "80008000",
            ],
        )
        pyxel.sound(0).set("a3a2c1a1", "p", "7", "s", 5)
        pyxel.sound(1).set("a3a2c2c2", "n", "7742", "s", 10)
        
        self.scene = SCENE_TITLE
        self.score = 0
        self.background = Background()
        self.player = Player(pyxel.width / 2, pyxel.height - 20)
        
        pyxel.run(self.update, self.draw)
    
    def update(self):
        if pyxel.btnp(pyxel.KEY_Q):
            pyxel.quit()
        self.background.update()
        
        if self.scene == SCENE_TITLE:
            self.update_title_scene()
        elif self.scene == SCENE_PLAY:
            self.update_play_scene()
        elif self.scene == SCENE_GAMEOVER:
            self.update_gameover_scene()
            
        
    def update_title_scene(self):
        if pyxel.btnp(pyxel.KEY_ENTER):
            self.scene = SCENE_PLAY
            
    def update_play_scene(self):
        if pyxel.frame_count % 6 == 0:
            Enemy(random() * (pyxel.width - PLAYER_WIDTH), 0)
        
        for a in enemy_list:
            for b in bullet_list:
                if (
                    a.x + a.w > b.x
                    and b.x + b.w > a.x
                    and a.y + a.h > b.y
                    and b.y + b.h > a.y
                ):
                    a.alive = False
                    b.alive = False
                    
                    # 自機の爆発を生成する
                    blast_list.append(
                        Blast(a.x + ENEMY_WIDTH / 2, a.y + ENEMY_HEIGHT / 2)
                    )
            
                    pyxel.play(1, 1)
                    self.score += 10
        
        for enemy in enemy_list:
            if(
                self.player.x + self.player.w > enemy.x
                and enemy.x + enemy.w > self.player.x
                and self.player.y + self.player.h > enemy.y
                and enemy.y + enemy.h > self.player.y
            ):
                enemy.alive = False
                
                blast_list.append(
                    Blast(
                        self.player.x + PLAYER_WIDTH / 2,
                        self.player.y + PLAYER_HEIGHT / 2,
                    )
                )
                pyxel.play(1, 1)
                
                self.scene = SCENE_GAMEOVER
        
        self.player.update()
        update_list(bullet_list)
        update_list(enemy_list)
        update_list(blast_list)
        
        cleanup_list(enemy_list)
        cleanup_list(bullet_list)
        cleanup_list(blast_list)
        
    def update_gameover_scene(self):
        update_list(bullet_list)
        update_list(enemy_list)
        update_list(blast_list)
        
        cleanup_list(enemy_list)
        cleanup_list(bullet_list)
        cleanup_list(blast_list)
        
        if pyxel.btnp(pyxel.KEY_ENTER):
            self.scene = SCENE_PLAY
            self.player.x = pyxel.width / 2
            self.player.y = pyxel.height - 20
            self.score = 0
            
            enemy_list.clear()
            bullet_list.clear()
            blast_list.clear()
            
    def draw(self):
        pyxel.cls(0)
        
        self.background.draw()
        
        if self.scene == SCENE_TITLE:
            self.draw_title_scene()
        elif self.scene == SCENE_PLAY:
            self.draw_play_scene()
        elif self.scene == SCENE_GAMEOVER:
            self.draw_gameover_scene()
            
        pyxel.text(39, 4, "SCORE {:5}".format(self.score), 7)
    
    def draw_title_scene(self):
        pyxel.text(50, 66, "Shooter", pyxel.frame_count % 16)
        pyxel.text(31, 126, "- PRESS ENTER -", 14)
    
    def draw_play_scene(self):
        self.player.draw()
        draw_list(bullet_list)
        draw_list(enemy_list)
        draw_list(blast_list)
        
    def draw_gameover_scene(self):
        draw_list(bullet_list)
        draw_list(enemy_list)
        draw_list(blast_list)
        
        pyxel.text(43, 66, "GAMEOVER", 11)
        pyxel.text(31, 126, "- PRESS ENTER -", 12)
        
        
App()

#最後に
初めてのゲーム制作だったので時間がかかりエラーも多く大変でしたが、なんとか動いて良かったです。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?