Godot Engine 学习笔记 激光效果

激光效果

  • 激光效果
    • 主要材料
    • 原理
    • 制作
    • 脚本
    • 改进

激光效果

效果图:
Godot Engine 学习笔记 激光效果_第1张图片

主要材料

Line2D 节点 官方文档3.1版
RayCast2D 节点 官方文档3.1版

原理

通过使用 RayCast2D 节点获取与光线相交的最近的交点, 再使用 Line2D 画出以 RayCast2D 节点位置和交点位置两点为端点的线段。

制作

  1. 场景创建
character 场景:
  • Node2D (character)
    • Sprite (person)
      • Sprite (gun)
        • RemoteTransform2D (remote)
    • RayCast2D (raycast)
    • Line2D (laser)

main 场景
  • Node2D (main)
    • TileMap (tilmap)
    • Character (character)

2.设置节点属性

main 场景

  • TileMap (tilmap) 节点
    主要用于激光的碰撞检测。
  • Character (character) 节点
    主要用于激光的碰撞检测。

character 场景

  • Sprite (person) 节点
    人物纹理显示,并且坐标与鼠标坐标组成激光发射方向。
  • Sprite (gun) 节点
    激光枪纹理显示,中心点偏移至枪尾部,节点旋转时激光枪纹理将绕中心点旋转,枪口位置作为激光的起始点。
  • RemoteTransform2D (remote) 节点
    position 移动到为 gun 的枪口,作为 gun 的子节点其 global_position 将随 gun 旋转而移动,作用是遥控 laser 节点的 global_position 值与自身一致,注意:属性 Update 只要勾选 position
  • RayCast2D (raycast) 节点
    cast_to 属性的方向应与激光发射的方向向量一致,并且 cast_to 应有足够的长度与墙发生碰撞,与墙的碰撞点将作为激光的结束点。(cast_to 在代码中设置)
    勾选属性 Collision With 下的 Bodies ,表示节点将反馈与 PhysicsBody2D 的碰撞。
  • Line2D (laser) 节点
    根据获得的激光起始点、结束点、激光纹理图片等绘制激光。
    1. 设置 Width 属性将改变激光宽度;
    2. 设置 Default Color 属性将改变激光的默认颜色;
    3. 属性 Fill 下设置 Gradient 将赋予激光渐变色(同时 Default Color 属性将失效);
    4. 属性 Fill 下设置 Texture 将赋予激光纹理;
    5. 属性 Fill 下设置 Texture Mode 设置激光纹理模式:`
      1. None不使用纹理;
      2. Tile纹理平铺;
      3. Stretch` 纹理拉伸。
    6. 属性 CappingJoint Mode 设置为 Sharp 使线是尖的;
    7. 属性 BorderSharp Limit 设为 0,使它变为斜面接点。

脚本

  • 添加脚本
    为 character 场景的根节点( character 节点)添加脚本:

extends Node2D

onready var person = $person
onready var gun = $person/gun
onready var raycast = $raycast
onready var laser = $laser

export(int) var raycast_length = 1000

func _ready():
	pass # Replace with function body.

func _process(delta):
	#激光碰撞检测方向,初始值为person中心点到鼠标的方向向量(激光的发射方向)
	var raycast_rotation = person.get_local_mouse_position()
	#初始化laser接点列表
	var point_array = []
	
	#设置gun节点的旋转
	gun.rotation = raycast_rotation.angle()
	#向laser接点列表添加laser的起始点
	point_array.append(laser.global_position)
	
	#设置raycast的坐标点
	raycast.global_position = person.global_position
	#设置raycast的检测方向和长度
	raycast.cast_to = raycast_rotation.normalized() * raycast_length
	#更新raycast
	raycast.force_raycast_update()
	#激光若未发生碰撞则沿设raycast_rotation方向延长raycast_length长度
	if !raycast.is_colliding():
		point_array.append(raycast.global_position + raycast_rotation.normalized() * raycast_length)
		create_laser(laser.global_position, point_array)
		return
	#向laser接点列表添加laser的结束点
	point_array.append(raycast.get_collision_point())
	
	#通过接点列表绘制laser
	create_laser(laser.global_position, point_array)
	pass

#绘制laser
#offset laser节点的全局坐标
#arr 绘制激光的接点坐标
func create_laser(var offset: Vector2, var arr: Array):
	laser.clear_points()
	for pos in arr:
		laser.add_point(pos - offset)
		
  • 效果

Godot Engine 学习笔记 激光效果_第2张图片

改进

改进脚本,使激光发生碰撞后能反弹,并可设置反弹的次数

  • 改进原理
  1. 循环步骤 2-5 直到超出设置的反弹数;
  2. 判断前次反弹或发射的激光是否有碰撞点,若无则进行步骤 6;
  3. 通过前次反弹或发射的激光方向向量以及碰撞后返回的碰撞面法线来获取反弹后的新的激光方向向量;
  4. 通过前次反弹或发射的激光碰撞点作为起始点以及新的激光方向向量来检测本次反弹后的碰撞点;
  5. 保存本次的碰撞点,碰撞法线已经方向向量供下次反弹使用,并将本次的碰撞点存入绘制激光的接点数组;
  6. 通过绘制激光的接点数组绘制激光。
  • 改进脚本


extends Node2D

onready var person = $person
onready var gun = $person/gun
onready var raycast = $raycast
onready var laser = $laser

#激光反弹次数
export (int) var reflect_count = 3
#激光的碰撞检测长度
export(int) var raycast_length = 1000

func _ready():
	pass # Replace with function body.

func _process(delta):
	#激光碰撞检测方向,初始值为person中心点到鼠标的方向向量(激光的发射方向)
	var raycast_rotation = person.get_local_mouse_position()
	#初始化laser接点列表
	var point_array = []
	
	#设置gun节点的旋转
	gun.rotation = raycast_rotation.angle()
	#向laser接点列表添加laser的起始点
	point_array.append(laser.global_position)
	
	#设置raycast的坐标点
	raycast.global_position = person.global_position
	#设置raycast的检测方向和长度
	raycast.cast_to = raycast_rotation.normalized() * raycast_length
	#更新raycast
	raycast.force_raycast_update()
	#获取raycast检测到的碰撞点(减去长度为1的方向向量是为了使接点不在墙内,以及防止反弹时的检测异常)
	var raycast_point = raycast.get_collision_point() - raycast_rotation.normalized()
	#获取raycast碰撞点处相交对象形状的法线
	var raycast_normal = raycast.get_collision_normal()
	#激光若未发生碰撞则沿设raycast_rotation方向延长raycast_length长度
	if !raycast.is_colliding():
		point_array.append(raycast.global_position + raycast_rotation.normalized() * raycast_length)
		create_laser(laser.global_position, point_array)
		return
	#向laser接点列表添加laser的碰撞点
	point_array.append(raycast_point)
	
	for i in range(reflect_count):
		#设置raycast的坐标点
		raycast.global_position = raycast_point
		#获得根据上次碰撞的发现计算反弹后的激光碰撞检测方向
		raycast_rotation = raycast_rotation.bounce(raycast_normal)
		#设置raycast的检测方向和长度
		raycast.cast_to = raycast_rotation.normalized() * raycast_length
		#更新raycast
		raycast.force_raycast_update()
		#获取raycast检测到的碰撞点(减去长度为1的方向向量是为了使接点不在墙内,以及防止反弹时的检测异常)
		raycast_point = raycast.get_collision_point() - raycast_rotation.normalized()
		#获取raycast碰撞点处相交对象形状的法线
		raycast_normal = raycast.get_collision_normal()
		if !raycast.is_colliding():
			point_array.append(raycast.global_position + raycast_rotation.normalized() * raycast_length)
			create_laser(laser.global_position, point_array)
			return
		#向laser接点列表添加laser的碰撞点
		point_array.append(raycast_point)
	
	#通过接点列表绘制laser
	create_laser(laser.global_position, point_array)
	pass

#绘制laser
#offset laser节点的全局坐标
#arr 绘制激光的接点坐标
func create_laser(var offset: Vector2, var arr: Array):
	laser.clear_points()
	for pos in arr:
		laser.add_point(pos - offset)
		
  • 改进效果

你可能感兴趣的:(Godot,Engine)