一、绘制背景
import pygame
import os
import random
import time
def get_pic(path):
pic_path=os.path.join("D:\planewar\img",path)
return pygame.image.load(pic_path)
if __name__=='__main__':
pygame.init()
screen=pygame.display.set_mode((480,650))
pygame.display.set_caption("飞机大战")
pygame.display.set_icon(get_pic("icon72x72.png"))
pygame.key.set_repeat(20,30)
while True:
bg=get_pic("bj.jpg")
screen.blit(bg,(0,0))
pygame.display.update()
运行结果:
二、绘制飞机(有些代码步骤怕少写,我提前写了)
import pygame
import os
import random
import time
def get_pic(path): # 拼接图片路径
pic_path=os.path.join("D:\planewar\img",path)
return pygame.image.load(pic_path) # 返回pygame对象
class HeroPlane(): #英雄战机类
def __init__(self,x,y,screen):
self.x = x
self.y = y
self.screen = screen
self.normal_image_list = ["hero1.png", "hero2.png"] #插入英雄战机图片
self.normal_image_index = 0
self.is_bomb = False # 碰撞检测 (后续的代码,怕忘了,提前打的)
self.bullet_list = []
def draw(self):
if self.is_bomb == False: # 如果没有爆炸
pic = get_pic(self.normal_image_list[self.normal_image_index]) # 获取图片
self.screen.blit(pic, (self.x, self.y)) # 绘制英雄战机
self.normal_image_index = (self.normal_image_index + 1) % len(self.normal_image_list) # 利用取余运算进行循环
class EnemyPlane(): #敌机类
def __init__(self,x,y,screen):
self.x=x
self.y=y
self.screen=screen
self.normal_image_list=["enemy1.png"]
self.normal_image_index=0
self.is_bomb=False
self.bullet_list=[]
self.direct="左"
def draw(self):
if self.is_bomb==False: # 如果没有爆炸
pic=get_pic(self.normal_image_list[self.normal_image_index]) # 获取图片
self.screen.blit(pic,(self.x,self.y)) # 绘制敌机战机
self.normal_image_index=(self.normal_image_index+1)%len(self.normal_image_list)# 利用循环让敌机进行循环
if __name__=='__main__':
pygame.init()
screen=pygame.display.set_mode((480,650))
pygame.display.set_caption("飞机大战")
pygame.display.set_icon(get_pic("icon72x72.png"))
pygame.key.set_repeat(20,30)
hero_plane = HeroPlane(190, 526, screen)
enemy_plane = EnemyPlane(480//2-69//2,0,screen)
while True:
bg=get_pic("bj.jpg")
screen.blit(bg,(0,0))
hero_plane.draw()
enemy_plane.draw()
pygame.display.update()
运行结果:
三、飞机的移动
import pygame
import os
import random
import time
def get_pic(path): # 拼接图片路径
pic_path=os.path.join("D:\planewar\img",path)
return pygame.image.load(pic_path) # 返回pygame对象
class HeroPlane(): #英雄战机类
def __init__(self,x,y,screen):
self.x = x
self.y = y
self.screen = screen
self.normal_image_list = ["hero1.png", "hero2.png"] #插入英雄战机图片
self.normal_image_index = 0
self.is_bomb = False # 碰撞检测 (后续的代码,怕忘了,提前打的)
self.bullet_list = []
def draw(self):
if self.is_bomb == False: # 如果没有爆炸
pic = get_pic(self.normal_image_list[self.normal_image_index]) # 获取图片
self.screen.blit(pic, (self.x, self.y)) # 绘制英雄战机
self.normal_image_index = (self.normal_image_index + 1) % len(self.normal_image_list) # 利用取余运算进行循环
def deal_event(self, event_list):
for event in event_list:
if event.type == pygame.QUIT: # 如果是退出事件
exit(0)
elif event.type == pygame.KEYDOWN:# 检测鼠标按下事件
if event.key == pygame.K_LEFT:# 向左移动
self.x = self.x - 5 if self.x >= 5 else 0
elif event.key == pygame.K_RIGHT:# 向右移动
self.x = self.x + 5 if self.x <= 375 else 380
elif event.key == pygame.K_DOWN:# 向下移动
self.y = self.y + 5 if self.y <= 521 else 526
elif event.key == pygame.K_UP: # 向上移动
self.y = self.y - 5 if self.y >= 5 else 0
class EnemyPlane(): #敌机类
def __init__(self,x,y,screen):
self.x=x
self.y=y
self.screen=screen
self.normal_image_list=["enemy1.png"]
self.normal_image_index=0
self.is_bomb=False
self.bullet_list=[]
self.direct="左"
def draw(self):
if self.is_bomb==False: # 如果没有爆炸
pic=get_pic(self.normal_image_list[self.normal_image_index]) # 获取图片
self.screen.blit(pic,(self.x,self.y)) # 绘制敌机战机
self.normal_image_index=(self.normal_image_index+1)%len(self.normal_image_list)# 利用循环让敌机进行循环
self.move()
def move(self): #让敌机移动
if self.direct=="左":
self.x-=5
if self.x<=0:
self.direct="右"
elif self.direct=="右":
self.x+=5
if self.x>=480-69:
self.direct="左"
if __name__=='__main__':
pygame.init() # 游戏初始化
screen=pygame.display.set_mode((480,650))
pygame.display.set_caption("飞机大战") # 设置标题
pygame.display.set_icon(get_pic("icon72x72.png")) # 设置图标
pygame.key.set_repeat(20,30) # 设置按键灵敏度
hero_plane = HeroPlane(190, 526, screen) # 实例化英雄飞机对象
enemy_plane = EnemyPlane(480//2-69//2,0,screen) # 实例化敌机对象
while True:
bg=get_pic("bj.jpg") # 绘制背景图
screen.blit(bg,(0,0))
hero_plane.draw()
enemy_plane.draw()
hero_plane.deal_event(pygame.event.get()) # 事件检测
pygame.display.update()
运行结果:
四、飞机的子弹
import pygame
import os
import random
import time
def get_pic(path): # 拼接图片路径
pic_path=os.path.join("D:\planewar\img",path)
return pygame.image.load(pic_path) # 返回pygame对象
class HeroBullet(): # 英雄机子弹的类
def __init__(self,x,y,screen):
self.x=x
self.y=y
self.screen=screen
self.pic=get_pic("bullet.png")
def draw(self):
self.screen.blit(self.pic,(self.x,self.y))
self.move()
def move(self):
self.y-=5
class EnemyBullet(): #"敌机子弹类"
def __init__(self,x,y,screen):
self.x = x
self.y = y
self.screen = screen
self.pic = get_pic("bomb-1.gif")
def draw(self):
self.screen.blit(self.pic,(self.x,self.y))
self.move()
def move(self):
self.y += 5
class HeroPlane(): #英雄战机类
def __init__(self,x,y,screen):
self.x = x
self.y = y
self.screen = screen
self.normal_image_list = ["hero1.png", "hero2.png"] #插入英雄战机图片
self.normal_image_index = 0
self.is_bomb = False # 碰撞检测 (后续的代码,怕忘了,提前打的)
self.bullet_list = []
def draw(self):
if self.is_bomb == False: # 如果没有爆炸
pic = get_pic(self.normal_image_list[self.normal_image_index]) # 获取图片
self.screen.blit(pic, (self.x, self.y)) # 绘制英雄战机
self.normal_image_index = (self.normal_image_index + 1) % len(self.normal_image_list) # 利用取余运算进行循环
def deal_event(self, event_list):
for event in event_list:
if event.type == pygame.QUIT: # 如果是退出事件
exit(0)
elif event.type == pygame.KEYDOWN:# 检测鼠标按下事件
if event.key == pygame.K_LEFT:# 向左移动
self.x = self.x - 5 if self.x >= 5 else 0
elif event.key == pygame.K_RIGHT:# 向右移动
self.x = self.x + 5 if self.x <= 375 else 380
elif event.key == pygame.K_DOWN:# 向下移动
self.y = self.y + 5 if self.y <= 521 else 526
elif event.key == pygame.K_UP: # 向上移动
self.y = self.y - 5 if self.y >= 5 else 0
elif event.key == pygame.K_SPACE:
one_bullet = HeroBullet(self.x+39,self.y-22,screen)
self.bullet_list.append(one_bullet)
# 绘制子弹
for bullet in self.bullet_list:
bullet.draw()
self.bullet_list.remove(bullet) if bullet.y <0 else ""
class EnemyPlane(): #敌机类
def __init__(self,x,y,screen):
self.x=x
self.y=y
self.screen=screen
self.normal_image_list=["enemy1.png"]
self.normal_image_index=0
self.is_bomb=False
self.bullet_list=[]
self.direct="左"
def draw(self):
if self.is_bomb==False: # 如果没有爆炸
pic=get_pic(self.normal_image_list[self.normal_image_index]) # 获取图片
self.screen.blit(pic,(self.x,self.y)) # 绘制敌机战机
self.normal_image_index=(self.normal_image_index+1)%len(self.normal_image_list)# 利用循环让敌机进行循环
self.fire()
self.move()
def move(self): #让敌机移动
if self.direct=="左":
self.x-=5
if self.x<=0:
self.direct="右"
elif self.direct=="右":
self.x+=5
if self.x>=480-69:
self.direct="左"
def fire(self): #敌机子弹
x = random.randint(0, 100) # 产是生随机数
if x == 5 or x == 78:
enemy_bullet = EnemyBullet(self.x +69//2-32//2,self.y+89,screen) # 实例化一个子弹
self.bullet_list.append(enemy_bullet)# 产生的每一个子弹放到一个列表里
for bullet in self.bullet_list:
bullet.draw() # 绘制子弹
self.bullet_list.remove(bullet) if bullet.y>650-89-32//2 else "" # 让子弹到最下面的时候消失
if __name__=='__main__':
pygame.init() # 游戏初始化
screen=pygame.display.set_mode((480,650))
pygame.display.set_caption("飞机大战") # 设置标题
pygame.display.set_icon(get_pic("icon72x72.png")) # 设置图标
pygame.key.set_repeat(20,30) # 设置按键灵敏度
hero_plane = HeroPlane(190, 526, screen) # 实例化英雄飞机对象
enemy_plane = EnemyPlane(480//2-69//2,0,screen) # 实例化敌机对象
while True:
bg=get_pic("bj.jpg") # 绘制背景图
screen.blit(bg,(0,0))
hero_plane.draw()
enemy_plane.draw()
hero_plane.deal_event(pygame.event.get()) # 事件检测
pygame.display.update()
运行结果:
五、飞机的爆炸
import pygame
import os
import random
import time
def get_pic(path): # 拼接图片路径
pic_path=os.path.join("D:\planewar\img",path)
return pygame.image.load(pic_path) # 返回pygame对象
class HeroBullet(): # 英雄机子弹的类
def __init__(self,x,y,screen):
self.x=x
self.y=y
self.screen=screen
self.pic=get_pic("bullet.png")
def draw(self):
self.screen.blit(self.pic,(self.x,self.y))
self.move()
def move(self):
self.y-=5
class EnemyBullet(): #"敌机子弹类"
def __init__(self,x,y,screen):
self.x = x
self.y = y
self.screen = screen
self.pic = get_pic("bomb-1.gif")
def draw(self):
self.screen.blit(self.pic,(self.x,self.y))
self.move()
def move(self):
self.y += 5
class HeroPlane(): #英雄战机类
def __init__(self,x,y,screen):
self.x = x
self.y = y
self.screen = screen
self.normal_image_list = ["hero1.png","hero2.png"] #插入英雄战机图片
self.normal_image_index = 0
self.is_bomb = False # 碰撞检测 (后续的代码,怕忘了,提前打的)
self.bullet_list = []
self.bomb_image_list = ["hero_blowup_n1.png","hero_blowup_n2.png","hero_blowup_n3.png","hero_blowup_n4.png"]
self.bomb_image_index = 0
def draw(self):
if self.is_bomb == False: # 如果没有爆炸
pic = get_pic(self.normal_image_list[self.normal_image_index]) # 获取图片
self.screen.blit(pic, (self.x, self.y)) # 绘制英雄战机
self.normal_image_index = (self.normal_image_index + 1) % len(self.normal_image_list) # 利用取余运算进行循环
else:
if self.bomb_image_index == len(self.bomb_image_list): # 当敌机爆炸图片的下表和图片总数相同时,说明爆炸图片已经绘制结束
time.sleep(0.2)
exit()
enemy_bomb_img = get_pic(self.bomb_image_list[self.bomb_image_index])# 加载英雄爆炸图片
screen.blit(enemy_bomb_img, (self.x, self.y))# 绘制敌机爆炸图片
self.bomb_image_index += 1
time.sleep(0.2)
def deal_event(self, event_list):
for event in event_list:
if event.type == pygame.QUIT: # 如果是退出事件
exit(0)
elif event.type == pygame.KEYDOWN:# 检测鼠标按下事件
if event.key == pygame.K_LEFT:# 向左移动
self.x = self.x - 5 if self.x >= 5 else 0
elif event.key == pygame.K_RIGHT:# 向右移动
self.x = self.x + 5 if self.x <= 375 else 380
elif event.key == pygame.K_DOWN:# 向下移动
self.y = self.y + 5 if self.y <= 521 else 526
elif event.key == pygame.K_UP: # 向上移动
self.y = self.y - 5 if self.y >= 5 else 0
elif event.key == pygame.K_SPACE:
one_bullet = HeroBullet(self.x+39,self.y-22,screen)
self.bullet_list.append(one_bullet)
# 绘制子弹
for bullet in self.bullet_list:
bullet.draw()
self.bullet_list.remove(bullet) if bullet.y <0 else ""
def check_collide(self, bullet_list):#碰撞检测
hero_rect = pygame.rect.Rect(self.x, self.y, 100, 124)
print(hero_rect)
for bullet in bullet_list:
enemy_bullet_rect = pygame.rect.Rect(bullet.x, bullet.y, 9, 21) # 定义英雄子弹的rect
flag = enemy_bullet_rect.colliderect(hero_rect)# 检测敌机和子弹的矩形是否相交
if flag:
print("英雄机爆炸了.....")
self.is_bomb = True # 英雄机爆炸条件为真
bullet_list.remove(bullet) # 移除敌机子弹
class EnemyPlane(): #敌机类
def __init__(self,x,y,screen):
self.x=x
self.y=y
self.screen=screen
self.normal_image_list=["enemy1.png"]
self.normal_image_index=0
self.is_bomb=False
self.bullet_list=[]
self.direct="左"
self.bomb_image_list = ["enemy1_down1.png","enemy1_down2.png","enemy1_down3.png","enemy1_down4.png"]
self.bomb_image_index = 0
def draw(self):
if self.is_bomb==False: # 如果没有爆炸
pic=get_pic(self.normal_image_list[self.normal_image_index]) # 获取图片
self.screen.blit(pic,(self.x,self.y)) # 绘制敌机战机
self.normal_image_index=(self.normal_image_index+1)%len(self.normal_image_list)# 利用循环让敌机进行循环
else:
if self.bomb_image_index == len(self.bomb_image_list): # 当敌机爆炸图片的下表和图片总数相同时,说明爆炸图片已经绘制结束
time.sleep(0.2)
exit(0)# 结束程序
enemy_bomb_img = get_pic(self.bomb_image_list[self.bomb_image_index]) # 加载敌机爆炸图片
screen.blit(enemy_bomb_img, (self.x, self.y))
self.bomb_image_index += 1
time.sleep(0.2)
self.fire() # 敌机开火
self.move()# 调用移动函数
def move(self): #让敌机移动
if self.direct=="左":
self.x-=5
if self.x<=0:
self.direct="右"
elif self.direct=="右":
self.x+=5
if self.x>=480-69:
self.direct="左"
def fire(self): #敌机子弹
x = random.randint(0, 100) # 产是生随机数
if x == 5 or x == 78:
enemy_bullet = EnemyBullet(self.x +69//2-32//2,self.y+89,screen) # 实例化一个子弹
self.bullet_list.append(enemy_bullet)# 产生的每一个子弹放到一个列表里
for bullet in self.bullet_list:
bullet.draw() # 绘制子弹
self.bullet_list.remove(bullet) if bullet.y>650-89-32//2 else "" # 让子弹到最下面的时候消失
def check_collide(self, bullet_list):#碰撞检测
enemy_rect = pygame.rect.Rect(self.x, self.y, 50, 56) # 定义敌机精灵的rect
print(enemy_rect)
for bullet in bullet_list:
hero_bullet_rect = pygame.rect.Rect(bullet.x, bullet.y, 22, 22) # 定义英雄子弹的rect
flag = hero_bullet_rect.colliderect(enemy_rect) # 检测敌机和战机子弹的矩形是否相交
if flag:
print("敌机爆炸了......")
self.isBomb = True #爆炸条件为真
bullet_list.remove(bullet) #移除战机子弹
if __name__=='__main__':
pygame.init() # 游戏初始化
screen=pygame.display.set_mode((480,650))
pygame.display.set_caption("飞机大战") # 设置标题
pygame.display.set_icon(get_pic("icon72x72.png")) # 设置图标
pygame.key.set_repeat(20,30) # 设置按键灵敏度
hero_plane = HeroPlane(190, 526, screen) # 实例化英雄飞机对象
enemy_plane = EnemyPlane(480//2-69//2,0,screen) # 实例化敌机对象
while True:
bg=get_pic("bj.jpg") # 绘制背景图
screen.blit(bg,(0,0))
hero_plane.draw()
enemy_plane.draw()
hero_plane.deal_event(pygame.event.get()) # 事件检测
hero_plane.check_collide(enemy_plane.bullet_list)# 英雄机碰撞检测
enemy_plane.check_collide(hero_plane.bullet_list)# 敌机碰撞检测
pygame.display.update()
运行结果:
完整代码:
import pygame
import os
import random
import time
def get_pic(path): # 拼接图片路径
pic_path=os.path.join("D:\planewar\img",path)
return pygame.image.load(pic_path) # 返回pygame对象
class HeroBullet(): # 英雄机子弹的类
def __init__(self,x,y,screen):
self.x=x
self.y=y
self.screen=screen
self.pic=get_pic("bullet.png")
def draw(self):
self.screen.blit(self.pic,(self.x,self.y))
self.move()
def move(self):
self.y-=5
class EnemyBullet(): #"敌机子弹类"
def __init__(self,x,y,screen):
self.x = x
self.y = y
self.screen = screen
self.pic = get_pic("bullet1.png")
def draw(self):
self.screen.blit(self.pic,(self.x,self.y))
self.move()
def move(self):
self.y += 5
class HeroPlane(): #英雄战机类
def __init__(self,x,y,screen):
self.x = x
self.y = y
self.screen = screen
self.normal_image_list = ["hero1.png","hero2.png"] #插入英雄战机图片
self.normal_image_index = 0
self.is_bomb = False # 碰撞检测 (后续的代码,怕忘了,提前打的)
self.bullet_list = []
self.bomb_image_list = ["hero_blowup_n1.png","hero_blowup_n2.png","hero_blowup_n3.png","hero_blowup_n4.png"]
self.bomb_image_index = 0
def draw(self):
if self.is_bomb == False: # 如果没有爆炸
pic = get_pic(self.normal_image_list[self.normal_image_index]) # 获取图片
self.screen.blit(pic, (self.x, self.y)) # 绘制英雄战机
self.normal_image_index = (self.normal_image_index + 1) % len(self.normal_image_list) # 利用取余运算进行循环
else:
if self.bomb_image_index == len(self.bomb_image_list): # 当敌机爆炸图片的下表和图片总数相同时,说明爆炸图片已经绘制结束
time.sleep(0.2)
exit()
enemy_bomb_img = get_pic(self.bomb_image_list[self.bomb_image_index])# 加载英雄爆炸图片
screen.blit(enemy_bomb_img, (self.x, self.y))# 绘制敌机爆炸图片
self.bomb_image_index += 1
time.sleep(0.2)
def deal_event(self, event_list):
for event in event_list:
if event.type == pygame.QUIT: # 如果是退出事件
exit(0)
elif event.type == pygame.KEYDOWN:# 检测鼠标按下事件
if event.key == pygame.K_LEFT:# 向左移动
self.x = self.x - 5 if self.x >= 5 else 0
elif event.key == pygame.K_RIGHT:# 向右移动
self.x = self.x + 5 if self.x <= 375 else 380
elif event.key == pygame.K_DOWN:# 向下移动
self.y = self.y + 5 if self.y <= 521 else 526
elif event.key == pygame.K_UP: # 向上移动
self.y = self.y - 5 if self.y >= 5 else 0
elif event.key == pygame.K_SPACE:
one_bullet = HeroBullet(self.x+39,self.y-22,screen)
self.bullet_list.append(one_bullet)
# 绘制子弹
for bullet in self.bullet_list:
bullet.draw()
self.bullet_list.remove(bullet) if bullet.y <0 else ""
def check_collide(self, bullet_list):#碰撞检测
hero_rect = pygame.rect.Rect(self.x, self.y, 100, 124)
print(hero_rect)
for bullet in bullet_list:
enemy_bullet_rect = pygame.rect.Rect(bullet.x, bullet.y, 9, 21) # 定义英雄子弹的rect
flag = enemy_bullet_rect.colliderect(hero_rect)# 检测敌机和子弹的矩形是否相交
if flag:
print("英雄机爆炸了.....")
self.is_bomb = True # 英雄机爆炸条件为真
bullet_list.remove(bullet) # 移除敌机子弹
class EnemyPlane(): #敌机类
def __init__(self,x,y,screen):
self.x=x
self.y=y
self.screen=screen
self.normal_image_list=["enemy1.png"]
self.normal_image_index=0
self.is_bomb=False
self.bullet_list=[]
self.direct="左"
self.bomb_image_list = ["enemy1_down1.png","enemy1_down2.png","enemy1_down3.png","enemy1_down4.png"]
self.bomb_image_index = 0
def draw(self):
if self.is_bomb==False: # 如果没有爆炸
pic=get_pic(self.normal_image_list[self.normal_image_index]) # 获取图片
self.screen.blit(pic,(self.x,self.y)) # 绘制敌机战机
self.normal_image_index=(self.normal_image_index+1)%len(self.normal_image_list)# 利用循环让敌机进行循环
else:
if self.bomb_image_index == len(self.bomb_image_list): # 当敌机爆炸图片的下表和图片总数相同时,说明爆炸图片已经绘制结束
time.sleep(0.2)
exit(0)# 结束程序
enemy_bomb_img = get_pic(self.bomb_image_list[self.bomb_image_index]) # 加载敌机爆炸图片
screen.blit(enemy_bomb_img, (self.x, self.y))
self.bomb_image_index += 1
time.sleep(0.2)
self.fire() # 敌机开火
self.move()# 调用移动函数
def move(self): #让敌机移动
if self.direct=="左":
self.x-=5
if self.x<=0:
self.direct="右"
elif self.direct=="右":
self.x+=5
if self.x>=480-69:
self.direct="左"
def fire(self): #敌机子弹
x = random.randint(0, 100) # 产是生随机数
if x == 5 or x == 78:
enemy_bullet = EnemyBullet(self.x +69//2-32//2,self.y+89,screen) # 实例化一个子弹
self.bullet_list.append(enemy_bullet)# 产生的每一个子弹放到一个列表里
for bullet in self.bullet_list:
bullet.draw() # 绘制子弹
self.bullet_list.remove(bullet) if bullet.y>650-89-32//2 else "" # 让子弹到最下面的时候消失
def check_collide(self, bullet_list):#碰撞检测
enemy_rect = pygame.rect.Rect(self.x, self.y, 50, 56) # 定义敌机精灵的rect
print(enemy_rect)
for bullet in bullet_list:
hero_bullet_rect = pygame.rect.Rect(bullet.x, bullet.y, 22, 22) # 定义英雄子弹的rect
flag = hero_bullet_rect.colliderect(enemy_rect) # 检测敌机和战机子弹的矩形是否相交
if flag:
print("敌机爆炸了......")
self.isBomb = True #爆炸条件为真
bullet_list.remove(bullet) #移除战机子弹
if __name__=='__main__':
pygame.init() # 游戏初始化
screen=pygame.display.set_mode((480,650))
pygame.display.set_caption("飞机大战") # 设置标题
pygame.display.set_icon(get_pic("icon72x72.png")) # 设置图标
pygame.key.set_repeat(20,30) # 设置按键灵敏度
hero_plane = HeroPlane(190, 526, screen) # 实例化英雄飞机对象
enemy_plane = EnemyPlane(480//2-69//2,0,screen) # 实例化敌机对象
while True:
bg=get_pic("bj.jpg") # 绘制背景图
screen.blit(bg,(0,0))
hero_plane.draw()
enemy_plane.draw()
hero_plane.deal_event(pygame.event.get()) # 事件检测
hero_plane.check_collide(enemy_plane.bullet_list)# 英雄机碰撞检测
enemy_plane.check_collide(hero_plane.bullet_list)# 敌机碰撞检测
pygame.display.update()
文章评论