在Godot引擎上实现平台游戏的机制。第4部分

再一次问好。在本期中,我将讨论如何修复第二期中显示的攀爬机制,展示交互机制以创建交互式体验。这仍然是角色的完善,因此周围的世界将受到最小的变化,但是主要角色将得到极大的改善。的确,技能树还很遥远,所以保持联系,我将向您展示如何实现想到的一切。



以前的文章:





从Set 2和更高版本中进行的爬升系统改进



在玩家场景中添加一个RayCast2D节点,





这就是我的角色的样子。将RayCast添加到箭头的开头。

通常,我将显示角色的所有代码,并尝试对其进行尽可能清晰的注释。



#       ,           .

extends KinematicBody2D

signal timer_ended #      _process

const UP_VECTOR: Vector2 = Vector2(0, -1) 	#  
const GRAVITY: int = 40						#  
const MOVE_SPEED: int = 100				#  
const JUMP_POWER: int = 480				#  
const CLIMB_SPEED: int = 40				#  
const WALL_JUMP_SPEED: int = 80			#    

enum States {ON_FLOOR, ON_WALL} #   ,     2 

onready var ray_cast: Object = $RayCast2D #      .   
var velocity: Vector2 = Vector2.ZERO # .
var walls: Array = [false, false, false] #   .  ,  ,  .

var timer_enabled: bool = false	#    
var climbing: bool = false		#    ,     
var is_wall_jump: bool = false		#     ,  
var is_double_jump: bool = true 	#   

var right_pressed: float = 0		#        ,    
var left_pressed: float = 0

var timer: float = 0				# 
var prev_direction: float = 0		#  .          
var direction: float = 0			#   .

var keys: int = 0 						#  .    , 
var current_state: int = States.ON_FLOOR	#   

func _ready():
	ray_cast.add_exception($WallLeft) #       ray_cast
	ray_cast.add_exception($WallRight)
	ray_cast.add_exception(self)

func _process(_delta: float) -> void: #  _process
	if timer > 0 or timer_enabled:
		timer -= _delta		#    _delta
	if timer <= 0 and timer_enabled:
		timer_enabled = false
		timer = 0		#     
		emit_signal("timer_ended") #   .
	if self.direction != 0:
		self.ray_cast.cast_to *= -1
		self.prev_direction = self.direction	#        0
func _physics_process(_delta: float) -> void:
	self.control_character()
	self.pause_opened()	#    -   
	if (!self.climbing):			#   ,  
		if (!self.is_wall_jump): 	#       self.velocity.y  
			self.velocity.y += GRAVITY
		else:				#    4  
			self.velocity.y += float(GRAVITY) / 4
	self.velocity = self.move_and_slide(self.velocity, UP_VECTOR) 	#  self.velocity   

func check_states() -> void:
	if self.is_on_floor():
		self.current_state = States.ON_FLOOR
		is_double_jump = true
	elif self.is_on_wall():
		self.current_state = States.ON_WALL
		is_double_jump = true
	elif self.is_on_floor() and self.is_on_wall():
		self.current_state = States.ON_WALL

func fall() -> void:
	self.velocity.y += GRAVITY

func update_controls(): 	#       ""  "" 
	if !is_wall_jump: 	#       - 
		self.left_pressed = Input.get_action_strength("ui_left")
		self.right_pressed = Input.get_action_strength("ui_right")

func control_character() -> void:	#     
	check_states()				#  
	update_controls()			#         
	self.interact_with()			#    +
	match current_state:
		States.ON_WALL:
			self.climb()
			self.move()
			if !climbing:
				self.jump()
				self.fall()
			self.wall_jump()
#		States.IN_AIR: #     
#			self.jump()
#			self.move()
#			self.fall()
		States.ON_FLOOR:
			self.jump()
			self.move()

func climb():
	if (walls[0] or walls[2]):	#      - self.climbing =    "ui_climb".       
		self.climbing = Input.is_action_pressed("ui_climb")
	else:				#    
		self.climbing = false

func climb_up() -> void:		#    
	self.velocity.y = (CLIMB_SPEED)

func climb_down() -> void:	#    
	self.velocity.y = (-CLIMB_SPEED)

func move() -> void: 		# .   ,    
	self.direction = self.right_pressed - self.left_pressed
	if (self.climbing and !self.is_wall_jump):
		if self.walls[0]:		#   
			if direction > 0:	#    -  
				climb_up()
			elif direction < 0:	#     -  
				climb_down()
			else:			#      
				self.velocity.y = 0
		elif self.walls[2]:	#          ,    
			if direction < 0:
				climb_up()
			elif direction > 0:
				climb_down()
			else:
				self.velocity.y = 0
#		else:	#      ,     
#			self.velocity.y = 0
	else: #             
		self.velocity.x = self.direction * float(MOVE_SPEED) * (1 + (float(self.is_wall_jump) / 2))
	if !(climbing): # 
		if direction == 0:
			$AnimatedSprite.flip_h = (-self.prev_direction >= 0)
			$AnimatedSprite.play("idle")
		else:
			$AnimatedSprite.flip_h = direction < 0
			$AnimatedSprite.play("run")
	return

func jump() -> void: #        
	if Input.is_action_just_pressed("ui_accept"):
		if is_on_floor():
			self.velocity.y = -JUMP_POWER
		if !is_on_floor() and is_double_jump:
			is_double_jump = false
			self.velocity.y = -JUMP_POWER

func wall_jump() -> void:
	if Input.is_action_just_pressed("ui_accept") and Input.is_action_pressed("ui_climb"):
		self.is_wall_jump = true
		self.velocity.y = -JUMP_POWER
		if walls[0]:
			self.timer = 0.3
			self.timer_enabled = true
			self.right_pressed = 1		#        -    
			yield(self, "timer_ended")	#   
			self.right_pressed = Input.get_action_strength("ui_right") 
			#    
		elif walls[2]:
			self.timer = 0.3
			self.timer_enabled = true
			self.left_pressed = 1		#        -    
			yield(self, "timer_ended")
			self.left_pressed = Input.get_action_strength("ui_left")
			#    
		self.is_wall_jump = false #    

func interact_with() -> void: 						#  
	if Input.is_action_pressed("ui_use"):			#    
		var coll: Object = self.ray_cast.get_collider()	#   
		if coll:								#     null
			if coll.has_method("open"):			# ,     
				use_key(coll)
			elif coll.has_method("interact"):
				use_object(coll)

func use_object(collider: Object) -> void:	#  
	collider.interact(self)				#      

func use_key(collider: Object) -> void:	#    .
	if self.keys > 0:				#   
		collider.open()				#  
		self.keys -= 1				#       

func key_picked_up():
	self.keys += 1
func _on_WallRight_body_entered(_body):	#       .
	if (_body.name != self.name):			#    -  -   
		self.walls[2] = true				#    walls  true  false.
func _on_WallRight_body_exited(_body):	# 
	self.walls[2] = false					#
func _on_WallLeft_body_entered(_body):	#
	if (_body.name != self.name):			#
		self.walls[0] = true				#
func _on_WallLeft_body_exited(_body):		#
	self.walls[0] = false					#

func dead():
	# $Particles2D.emitting = true #      -   
	LevelMgr.goto_scene("res://scenes/dead_screen/dead_screen.tscn") #    .          

func pause_opened(): #   
	if Input.is_action_just_pressed("ui_cancel"): #    
		$PositionResetter/WindowDialog.popup_centered()


结论



目前,这是我刚刚创建的最新字符代码。由于代码已完全准备就绪,因此我无须单独添加任何内容。而且由于我是在一个单独的周期中上陷阱的,因此我也无话可说。我还想知道您希望在下一部分中找到什么,并在下面介绍了一个由我想到的有关机械构想的调查。感谢您的阅读,直到下一次。



All Articles