buto > /dev/null

だいたい急に挑戦してゴールにたどり着かずに飽きる日々です

pygameでお手軽ゲーム開発

矢印キーでケーキを取るゲームを作った

初めてゲームを作ってみた! プレイヤーを矢印キーで操作してカップケーキを取りに行くゲームです

カップケーキのマスに行くと左上のスコアが加算、カップケーキは他のマスに移動 ゲーム開始から20秒後にスコアを表示して終了

f:id:butorisa:20201020171652g:plain

背景画像はこちら

f:id:butorisa:20201020171716p:plain

プレイヤー、カップケーキは「いらすとや」からダウンロードしました

import pygame
from pygame.locals import *
import sys
from collections import namedtuple
import time

def main():
    # 画面サイズ
    screen_size = namedtuple('screen_size', 'width height')
    screen_size = screen_size(width=300, height=400)

    # スコアの位置
    pos_score = [10, 10]
    
    # プレイヤーの位置
    pos_player = [150, 345]
    
    # ケーキの位置
    pos_cake = [250, 50]
    
    pygame.init()
    
    # 既定のウィンドウ、32bit
    pygame.display.set_mode(screen_size, 0, 32)
    pygame.display.set_caption('cupcake')
    screen = pygame.display.get_surface()
    
    # 背景画像
    bg = pygame.image.load('board.png').convert_alpha()
    # 透過度
    rect_bg = bg.get_rect()
    
    # スコア
    score = 0
    
    # プレイヤー
    player = pygame.image.load('valentinesday_heart_girl.png').convert_alpha()
    rect_player = player.get_rect()
    rect_player.center = pos_player
    
    # カップケーキ
    cake = pygame.image.load('sweets_cupcake.png').convert_alpha()
    rect_cake = cake.get_rect()
    rect_cake.center = pos_cake# 
    
    # タイマースタート
    start_time = time.time()
    
    while(1):
        # プレイヤーの移動
        pressed_key = pygame.key.get_pressed()
        # ←
        if pressed_key[K_LEFT]:
            pos_player[0] -= 100
        # →
        if pressed_key[K_RIGHT]:
            pos_player[0] += 100
            
        # ↑
        if pressed_key[K_UP]:
            pos_player[1] -= 100
            
        # ↓
        if pressed_key[K_DOWN]:
            pos_player[1] += 100
            
        # 画面の端だったら動かない
        if pos_player[0] < 10:
            pos_player[0] += 100
            
        if pos_player[0] > 250:
            pos_player[0] -= 100
            
        if pos_player[1] < 10:
            pos_player[1] += 100
            
        if pos_player[1] > 350:
            pos_player[1] -= 100
            
        rect_player.center = pos_player
        
        # プレイヤーがケーキにたどり着いたらケーキは移動
        if rect_player.colliderect(rect_cake):
            
            # スコア加点
            score += 100
            pos_cake[0] += 100
            pos_cake[1] -= 100
            
            # 画面の端だったら反対側に移動
            pos_cake[0] = pos_cake[0] % 300
            pos_cake[1] = pos_cake[1] % 400
            rect_cake.center = pos_cake
        
        # 画面更新間隔
        pygame.time.wait(100)
        
        screen.fill((0, 0, 0, 0))
        # 背景描画
        screen.blit(bg, rect_bg)
        # スコア描画
        sysfont = pygame.font.SysFont(None, 20)
        rect_score = sysfont.render('SCORE:' + str(score), True, (160,100,65))
        screen.blit(rect_score, pos_score)
        # ケーキ描画
        screen.blit(cake, rect_cake)
        # プレイヤー描画
        screen.blit(player, rect_player)
        
        # タイムアウト
        current_time = time.time()
        if (current_time - start_time) >= 20:
            start_flg = False
            pos_msg = [50, 150]
            font_msg = pygame.font.SysFont(None, 50)
            rect_msg = font_msg.render('SCORE:' + str(score), True, (160,100,65))
            
            screen.fill((255, 250, 165, 0))
            screen.blit(rect_msg, pos_msg)
            
        pygame.display.update()
        
        for event in pygame.event.get():
            # 閉じるボタン押下
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
                
if __name__ == '__main__':
    main()

Django テンプレート継承

base.htmlを継承してコード量を減らす

やっとテンプレート継承の恩恵を受けられた!

base.htmlには普通にHTMLタグを書く bodyタグの中は空っぽ

<!DOCTYPE html>
{% load static %}
{% load bootstrap4 %}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>TITLE</title>
    <link rel="stylesheet" href="../../static/redo/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>
  <div class="container">
    {% block content %}{% endblock %}
  </div>
</body>
</html>

継承したテンプレートはHTMLタグを省略できる (base.htmlの{% block content %}~{% endblock %}に挿入する部分だけ記述でOK)

{% extends "redo/base.html" %}
{% load bootstrap4 %}
{% block title %}類語検索{% endblock %}

{% block content %}
    <p>メッセージを入力してください</p>
    <form action="{% url 'redo:register_message' %}" method="post">{% csrf_token %}
        {% bootstrap_form form layout='horizontal' %}
        <div class="form-group row">
            <div class="offset-md-3 col-md-9">
                <button type="submit" class="btn btn-outline-primary">submit</button>
            </div>
        </div>
    </form>
    {{ message }}
{% endblock %}

継承したテンプレートに記述した入力フォームが表示された!

f:id:butorisa:20201020171507p:plain

画面に何も表示されない時は

継承元テンプレート(base.html)と継承するテンプレートで使っているタグ名が違っているはず! (継承元:{% block content %} 継承先:{% block contents %}など)

これに気づかず30分くらいハマった。。。

AWS Elastic Beanstalk起動時にエラー

Elastic Beanstalk

作成したアプリをささっとデプロイできるサービス Elastic Beanstalkを利用すると自動でサーバ(EC2)構築、ネットワーク設定もしてくれる

チュートリアルをやってみる

Amazon Elastic Beanstalk を使用したアプリケーションの起動 数分でアプリの実行環境ができるらしいけど、10分以上待っても状態が「Pending」だ…

The EC2 instances failed to communicate with AWS Elastic Beanstalk, either because of configuration problems with the VPC or a failed EC2 instance. Check your VPC configuration and try launching the environment again.

なんかエラー出た。。チュートリアル通り進んだはずなのに

インターネット接続が原因ぽい

エラーメッセージで検索をするとAWS公式ドキュメントに対処法があった Amazon EC2 インスタンスが Elastic Beanstalk との通信に失敗したときに表示されるエラーを解決する方法を教えてください。

作成したElastic Beanstalkインスタンスがインターネット接続できてないのがエラーの原因かな

解決方法 1. Elastic Beanstalkに紐づくネットワークACLにアウトバウンド接続が許可されているか? OK 1. Elastic Beanstalkを作成したVPCにはサブネットが紐づいているか? OK 1. EC2がパブリックの場合は、ルートテーブルにインターネットへのルートがあるか? NG

ルーティングの設定し忘れでした InternetGateway(IGW)を作って満足していたのですが、IGWに向かってね~の設定がないので データ送受信ができず、Elastic Beanstalkの起動時にエラーになっていた (そういえば、No data っていうメッセージも出ていたな)

IGWへ向かうルートを追加してあげて解決

  1. VPCコンソールから[ルートテーブル]をクリック
  2. Elastic BeanstalkがあるVPCに紐づくルートテーブルを選択
  3. 送信先「0.0.0.0/0」ターゲット「対象のIGW」のルートを追加
  4. Elastic Beanstalkメニューで[環境再構築]
  5. 環境が作成された!!

AWS PostgreSQLに接続できない

公式チュートリアルPostgreSQLの作成・起動をした

PostgreSQL データベースを作成、接続する 説明に従ってポチポチ、作成と起動はできたがクライアントツールからDBに接続できない。。。

原因は以下 - DBを作成していなかった(DBインスタンスだけ作成していた) - 5432ポートの通信を許可するセキュリティグループを作成していなかった

セキュリティグループ

AWSドキュメントによると

セキュリティグループは、インスタンスの仮想ファイアウォールとして機能し、インバウンドトラフィックとアウトバウンドトラフィックをコントロールします。

インスタンスごとに設定するファイアウォールのことか 最初、VPCのセキュリティグループをPostgreSQLインスタンスにも適用するように設定していて、 このセキュリティグループが「TCP通信 ポート:5432」を許可する設定がなかったのが原因

PostgreSQLインスタンスを作成する時に、セキュリティグループは「新規作成」にしてあげると このインスタンスでのTCP通信を許可する設定がされたファイアウォールが作成された! (VPCのセキュリティグループにも送信元IP、ポートを設定すればいけそうだ)

PostgreSQLインスタンス用のセキュリティグループが作成されたら無事、接続成功しました!

デザインパターン入門 Adapter

Adapter

メソッドが違うなどして継承できない2つのクラスの仲介をする 既存のクラスは修正せず、仲介するAdapterを作ることで修正範囲を最小限にできる

デザインパターン ~Adapter~ 内部処理用のBeanクラスと画面から値が入ってくるBeanクラス同士が 直接、継承などで結び付けられない時に使うのか!

新規の画面と入力値がやりとりできないから、とかで新しくBeanを作ったことがあるような…

デザインパターン入門 Singleton

Singleton

クラスのコンストラクタをprivateにして他クラスからインスタンスを生成できないようにする (シングルなインスタンスインスタンス同士が作用して不具合が発生する可能性があるので、Singletonパターンで防ぐ

インスタンスの相互作用から発生しうる不具合

思いついたのはこんな不具合 - static変数(グローバル変数)が書き換えられてしまう - static変数にはfinalキーワードをつけましょうって習ったな - 排他制御で処理が実行できない - DB更新をするインスタンスが複数あると、一方のインスタンス排他制御をしていてもう一方ではDB更新が行えない

デザインパターン入門 Prototype

Prototype

インスタンスの生成をnew Class()でなく、インスタンスから別のインスタンスを生成する 雛形を作っておき、それをコピーして使う 例が思い浮かばなかったのでTECHSCOREの記事を使います

図形描画で「直線を描画するクラス」と直線を組み合わせて「図形を描画するクラス」がある 図形描画クラスで定義した三角、星などの図形を描画する処理を 雛形管理クラスでmap.put("star",星型の描画処理)のようにインスタンスを保存する → 星型をたくさん描画したい時はmap("star")だけでOK

f:id:butorisa:20201020170930j:plain

図形ごとにクラスを作成するとクラス数が多すぎて保守性が下がるのでPrototypeパターンを使う

業務で「クラス名が違うだけでプロパティは同じ」複数のクラスを作ってしまったことがある… 次からはPrototypeパターンが使えないか検討しよう