当前位置:网站首页>Pgzero aircraft war
Pgzero aircraft war
2022-07-29 02:51:00 【CairBin】
Pgzero Aircraft battle
Tips
About Pgzero For more basic things, please refer to my previous article
utilize pgzero Play a little game of catching the ball - Colorful world CairBin’s Blog
problem
Problem solved & characteristic :
In this project, I wrote it myself gameObject Base class replaced pgzero Medium Actor class , And all objects in the project inherit this class
The reason for this is , Because I found out Actor Unable to zoom the picture , I use pygame.transform.scale That solved the problem
Questions to be considered :
- The most incomprehensible part of this project is the precise collision . Originally, I wanted to pass pygame Of mask.overlap To achieve precise collision , But no matter how I change it offset The vertical and horizontal coordinates of the coordinate difference tuple are 0, If there is any way, please let me know in the article or in a private letter
- I judge the overlap of two rectangles according to coordinates to realize collision detection , But the white space around the picture will also trigger , Therefore, this method is not an accurate detection
- There is no explosion effect when the enemy explodes , The reason is that I forgot to write (doge). It's also easy to implement , My idea is to change it into an explosion picture when it explodes , It is best to gif type ( I don't like it pgzero Built in animation class , It feels strange to use ), Then the effect disappears after a certain time
Code
resources
Resources come from the Internet ( Non commercial use ), I pack and upload to Baidu cloud 、CSDN Resources , Or directly from GitHub Get on the
Baidu cloud Extraction code :6d1r
CSDN resources Points are required , If you want to “ sponsorship ” The author , You can download in this way (doge)
define.py
file define.py Some constants are defined ( Not a real constant ), Easy to maintain code
# Window parameters
WINDOW_TITLE = 'plane war'
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 500
BG_COLOR = 'white'
# Block size Long / wide
BLOCK_SIZE = 50
# Aircraft HP
PLANE_HP = 3
# Bullet parameters
BULLET_SPEED = 10
BULLET_SIZE = (10, 10)
BULLET_MOVE_LENGTH = -20
BULLET_AGRES = 1
# Enemy parameters
ENEMY_SPEEED = 5
ENEMY_CREATE_TIME = 30
# Blood volume
HEART_SIZE = 30
gameObject.py
file gameObject.py Used to create common properties and methods that all objects have ( Parent class )
from typing import Tuple
from numpy import rec
import pygame
from enum import Enum
# Coordinate anchor
class posAnchor(Enum):
TOP_LEFT = 0 # upper left
TOP = 1 # Just above
TOP_RIGHT = 2 # upper right
LEFT = 3 # Left
CENTER = 4 # center
RIGHT = 5 # Right
BOTTOM_LEFT = 6 # lower left
BOTTOM = 7 # Directly below
BOTTOM_RIGHT = 8 # Lower right
# Game base class
class gameObject:
def __init__(self, img, init_pos:tuple, size:tuple, screen = None, pos_anchor=posAnchor.TOP_LEFT) -> None:
self.img = img # pgzero Image objects
self.size = size # size , Tuples ( wide , high )
self.screen = screen # screen
self.destroy = False # Used to detect whether it is destroyed ,spiritGroup Medium checkDestroy Method to detect this property , by True Will be taken from spiritGroup Be removed in the
self.__anchor = pos_anchor # anchor
self.__pos = self.__getTruePos(init_pos, self.__anchor) # Draw coordinates
self.__userPos = init_pos # Anchor coordinates
# Picture container object , Need to import pygame
self.obj = pygame.transform.scale(self.img, self.size)
# initialization , stay pgzero update() Call in
def update(self, screen):
self.initScreen(screen)
self.draw()
# initialization screen
def initScreen(self, screen):
self.screen = screen
# draw
def draw(self):
self.screen.blit(self.obj, self.__pos)
# modify location ( Anchor point required , Prevent coordinate confusion )
def changePos(self, pos: tuple, pos_anchor):
self.__pos = self.__getTruePos(pos, pos_anchor)
self.__userPos = pos
# Get the width
def width(self):
return self.size[0]
# Get height
def height(self):
return self.size[1]
# Get size
def getSize(self):
return self.size
# Get abscissa ( Anchor coordinates )
def x(self):
return self.__userPos[0]
# Get ordinate ( Anchor coordinates )
def y(self):
return self.__userPos[1]
# Get the coordinates of the upper left corner
def getTopLeftPos(self):
return self.__pos
# obtain rect
def getRect(self):
return self.obj.get_rect()
# obtain mask
def getMask(self):
return pygame.mask.from_surface(self.obj)
# Get anchors
def getAnchor(self):
return self.__anchor
# Change the destroy attribute
def setDestroy(self, choose:bool):
self.destroy = choose
# Get destroy attribute
def getDestroy(self)->bool:
return self.destroy
# collision detection
def collisionDetection(self, other):
this_pos = self.getTopLeftPos()
other_pos = other.getTopLeftPos()
this_center_pos = (this_pos[0]+self.width()/2, this_pos[1]+self.height()/2)
other_center_pos = (other_pos[0]+other.width()/2, other_pos[1]+other.height()/2)
# Determine the intersection of rectangles
if abs(this_center_pos[0] - other_center_pos[0]) <= (self.width() + other.width())/2 and abs(this_center_pos[1] - other_center_pos[1]) <= (self.height() + other.height())/2:
return True
else:
return False
def move(*args):
pass
# Give the coordinates according to the anchor and , Get the coordinates of the upper left corner
def __getTruePos(self, pos: tuple, pos_anchor):
if pos_anchor == posAnchor.TOP_LEFT:
return pos
elif pos_anchor == posAnchor.TOP:
return (pos[0]-self.size[0]/2, pos[1])
elif pos_anchor == posAnchor.TOP_LEFT:
return (pos[0]-self.size[0], pos[1])
elif pos_anchor == posAnchor.LEFT:
return (pos[0], pos[1]-self.size[1]/2)
elif pos_anchor == posAnchor.CENTER:
return (pos[0]-self.size[0]/2, pos[1]-self.size[1]/2)
elif pos_anchor == posAnchor.RIGHT:
return (pos[0]-self.size[0], pos[1]-self.size[1]/2)
elif pos_anchor == posAnchor.BOTTOM_LEFT:
return (pos[0], pos[1]-self.size[1])
elif pos_anchor == posAnchor.BOTTOM:
return (pos[0]-self.size[0]/2, pos[1]-self.size[1])
elif pos_anchor == posAnchor.BOTTOM_RIGHT:
return (pos[0]-self.size[0], pos[1]-self.size[1])
else:
return None
# Spirit group
class spiritGroup:
def __init__(self) -> None:
self.__spiritList = []
# ---------------------- The list of operations
# Additional
def append(self, spirit: gameObject):
self.__spiritList.append(spirit)
# Indexes
def index(self, g_obj: gameObject):
return self.__spiritList.index(g_obj)
# Insert
def insert(self, num):
self.__spiritList.insert(num)
# remove
def remove(self, g_obj: gameObject):
self.__spiritList.remove(g_obj)
# Remove by index
def removeAsIndex(self, num):
self.remove(self.index(num))
# Element number
def size(self):
return len(self.__spiritList)
# Empty
def clear(self):
self.__spiritList.clear()
# ---------------------- Operator overloading
# []
def __getitem__(self, index) -> gameObject:
return self.__spiritList[index]
# in
def __contains__(self, elem):
return
# +
def __add__(self, other):
new_g_obj = spiritGroup()
for i in self.__spiritList:
new_g_obj.append(i)
for i in other:
new_g_obj.append(i)
return new_g_obj
# ---------------------- Basic operation
# initialization (draw)
def update(self, screen):
for i in self.__spiritList:
i.update(screen)
# draw
def draw(self):
for i in self.__spiritList:
i.draw()
# collision detection
def collisionDetection(self, other, collided = None, args=()):
for e in self.__spiritList:
for i in other:
if e.collisionDetection(i) == True:
if collided == None:
e.setDestroy(True)
i.setDestroy(True)
else:
collided(e, i, *args)
# Move
def move(self, *args):
for i in self.__spiritList:
i.move(*args)
# Detect whether the element should be destroyed ( remove ), And implement
def checkDestroy(self):
for i in self.__spiritList:
if i.getDestroy():
temp = i
self.remove(i)
del i
actors.py
file actors.py Define the class of the specific creation object in the game , For example, aircraft , Bullets, etc
import define
import gameObject
# Bullets
class bullet(gameObject.gameObject):
def __init__(self, img, init_pos: tuple, size: tuple, screen=None, pos_anchor=...) -> None:
super().__init__(img, init_pos, size, screen, pos_anchor)
self.speed = define.BULLET_MOVE_LENGTH
self.agres = define.BULLET_AGRES # Bullet power
def move(self, *args):
self.changePos((self.x(), self.y()+self.speed), self.getAnchor())
pos = self.getTopLeftPos()
if pos[1]+self.height() < 0:
self.setDestroy(True)
# Aircraft
class plane(gameObject.gameObject):
def __init__(self, img, init_pos: tuple, size: tuple, screen=None, pos_anchor=...) -> None:
super().__init__(img, init_pos, size, screen, pos_anchor)
self.hp = define.PLANE_HP # Player aircraft HP
def move(self, *args):
# Boundary judgment
pos = list((args[0][0]-self.width()/2, args[0][1]-self.height()/2))
if pos[0] <0:
pos[0] = 0
if pos[0]+self.width() > define.WINDOW_WIDTH:
pos[0] = define.WINDOW_WIDTH-self.width()
if pos[1]<0:
pos[1] = 0
if pos[1]+self.height() > define.WINDOW_HEIGHT:
pos[1] = define.WINDOW_HEIGHT-self.height()
self.changePos(tuple(pos), gameObject.posAnchor.TOP_LEFT)
# FireStarter , The parameter is bullet pgzero Image objects
def fire(self, bullet_img):
pos = self.getTopLeftPos()
bullet_pos = (pos[0]+self.width()/2, pos[1])
bull = bullet(bullet_img, bullet_pos, define.BULLET_SIZE, screen = self.screen, pos_anchor=gameObject.posAnchor.BOTTOM)
return bull
# Enemy human
class enemy(gameObject.gameObject):
def __init__(self, img, hp, init_pos: tuple, size: tuple, screen=None, pos_anchor=...) -> None:
super().__init__(img, init_pos, size, screen, pos_anchor)
self.hp = hp
self.speed = define.ENEMY_SPEEED
self.destroy = False
def move(self, *args):
if self.destroy == False:
self.changePos((self.x(), self.y()+self.speed),
gameObject.posAnchor.CENTER)
pos = self.getTopLeftPos()
if pos[1] > define.WINDOW_HEIGHT:
self.setDestroy(True)
# Blood volume class , Used for display hp
class heart(gameObject.gameObject):
def __init__(self, img, init_pos: tuple, size: tuple, screen=None, pos_anchor=...) -> None:
super().__init__(img, init_pos, size, screen, pos_anchor)
main.py
main.py The main entry of the program is in this file
import random
import pgzrun
import define
import actors
import pygame, sys
# Basic window configuration , pgzero The variables here will be called to set the window
TITLE = define.WINDOW_TITLE
WIDTH = define.WINDOW_WIDTH
HEIGHT = define.WINDOW_HEIGHT
# Picture mapping dictionary
images_dict = {
'plane': images.plane,
'bullet': images.bullet,
'enemy': images.enemy,
'heart': images.heart
}
# Bullet group
bullet_list = actors.gameObject.spiritGroup()
# Enemy group
enemy_list = actors.gameObject.spiritGroup()
# Blood volume display group
heart_list = actors.gameObject.spiritGroup()
# Character plane
plane = actors.plane(images_dict['plane'], (define.WINDOW_WIDTH/2, define.WINDOW_HEIGHT*3/4),
(define.BLOCK_SIZE, define.BLOCK_SIZE), pos_anchor=actors.gameObject.posAnchor.CENTER)
# Generate enemy interval
enemy_time = 0
# Game score
player_scores = 0
# ------------------------------------------------- Game control ----------------------------------- #
# Randomly generate enemies
def creatEnemy():
global enemy_time
if enemy_time <= 0:
# The blood volume here is random 1-2
enemy_list.append(actors.enemy(images_dict['enemy'], random.randint(1,2),
(random.randint(5, define.WINDOW_WIDTH-define.BLOCK_SIZE), 0), (define.BLOCK_SIZE, define.BLOCK_SIZE),
pos_anchor=actors.gameObject.posAnchor.TOP_LEFT))
enemy_time = define.ENEMY_CREATE_TIME
else:
enemy_time -= 1
# Display blood volume
def showHp():
hp = plane.hp
i = 0
heart_list.clear()
while i<hp:
he = actors.heart(images_dict['heart'], (i*define.HEART_SIZE, 0), (define.HEART_SIZE,
define.HEART_SIZE), pos_anchor=actors.gameObject.posAnchor.TOP_LEFT)
heart_list.append(he)
i+=1
# score
def getScores():
global player_scores
player_scores += 1
# Game over
def gameOver():
global player_scores
pygame.quit()
print('Game Over')
print('Your scores are {}'.format(player_scores))
sys.exit()
# Callback function of bullets colliding with enemy aircraft
# The default collision detection directly deletes objects , If you set the amount of blood for the enemy to deduct blood according to the power of the bullet, you need to provide an external callback function
def bulletCollidedEnemy(bullet: actors.bullet, enemy: actors.enemy, getScore):
enemy.hp -= bullet.agres
bullet.setDestroy(True) # Destroy bullets
# Judge whether the enemy is destroyed according to the amount of blood
if enemy.hp <= 0:
enemy.setDestroy(True)
getScore() # score
# Enemy planes collide with players
# There is no spirit group in the player plane , So write the collision event directly in Update() Call in
def enemyCollidedPlane():
# Traverse and detect collisions
for i in enemy_list:
if i.collisionDetection(plane):
plane.hp -= 1 # Blood deduction
i.setDestroy(True)
# Check whether the blood volume returns to zero to end the game
if plane.hp == 0:
gameOver()
# -------------------------------------------------pgzero built-in ----------------------------------- #
def update():
plane.update(screen)
bullet_list.update(screen)
bullet_list.move()
creatEnemy()
enemy_list.update(screen)
enemy_list.move()
enemy_list.checkDestroy()
showHp()
heart_list.update(screen)
bullet_list.collisionDetection(enemy_list, collided=bulletCollidedEnemy, args=(getScores,))
bullet_list.checkDestroy()
enemyCollidedPlane()
def draw():
screen.fill(define.BG_COLOR)
plane.draw()
bullet_list.draw()
enemy_list.draw()
heart_list.draw()
def on_mouse_move(pos):
plane.move(pos)
def on_key_down(key):
# The space plane fired bullets
if key == keys.SPACE:
bullet_list.append(plane.fire(images_dict['bullet']))
# ------------------------------------------------- function -----------------------------------#
pgzrun.go()
Open source
Github:
边栏推荐
- ECCV 2022 | airdet: a small sample target detection method without fine tuning
- QT屏幕自适应自动布局,拖动窗口自动变大变小(一)
- 工科男生:20岁未满,平凡但不平庸
- Cloud development workers must go to work fishing and paddling wechat applet source code
- Introduction to network foundation
- OSPF实验
- C language: Little Lele and Euclid
- 【luogu P8352】小 N 的独立集(DP套DP)(性质)
- Ffmpeg+sdl+qt is a simple video player
- DataGrip 如何导出和恢复整个数据库数据,使用单个 SQL 文件
猜你喜欢

用于校园流浪猫信息记录和分享的小程序源码/微信云开发中大猫谱小程序源码

MySQL - count(字段)、count(主键)、count(1)、count(*)的区别

Some new ideas about time complexity

DHCP协议详细解析

QT screen adaptive automatic layout, drag the window to automatically grow larger and smaller (I)

idea配置web容器与war打包

数仓中概念术语解析

新版海螺影视主题模板M3.1全解密版本多功能苹果CMSv10后台自适应主题开源全解密版

Interpretation of ue4.25 slate source code

Asemi rectifier bridge s25vb100, s25vb100 parameters, s25vb100 application
随机推荐
Implement encapsulated public method global call in laravel framework
新版海螺影视主题模板M3.1全解密版本多功能苹果CMSv10后台自适应主题开源全解密版
数仓中概念术语解析
Idea replaces the contents of all files
owt-server源码剖析(三)--video模块分析之Mixer In
Introduction to network foundation
OSPF实验
《微信小程序-进阶篇》Lin-ui组件库源码分析-Button组件(二)
vim常用命令
Youxuan software appoints Huang Zhijun as the general manager of the company
QT compilation of IOT management platform 48 characteristic function design
idea替换所有文件中的内容
(job) C language: Simulation Implementation of ATOI and strncpy, strncat, strncmp
Plug in --- line segment sloth marking board + simple mathematical reasoning
Redis队列实现秒杀
第九天笔记
ECCV 2022 | airdet: a small sample target detection method without fine tuning
NVIDIA-VPI(Vision Programming Interface)
h. 264 code stream explanation
etcd实现大规模服务治理应用实战