Mekanika untuk mengimplementasikan platformer pada mesin Godot. Bagian 4

Halo lagi. Dalam edisi ini saya akan berbicara tentang bagaimana saya memperbaiki mekanisme pendakian yang ditunjukkan di edisi kedua, menunjukkan mekanisme interaksi untuk menciptakan pengalaman interaktif. Ini akan terus menjadi penyempurnaan karakter, sehingga dunia di sekitar akan mengalami sedikit perubahan, tetapi karakter utama akan sangat meningkat. Benar, pohon keterampilan masih jauh, jadi tetap berhubungan dan saya akan menunjukkan kepada Anda bagaimana Anda dapat menerapkan semua yang terlintas dalam pikiran.



Artikel sebelumnya:





Peningkatan Sistem Mendaki dari Set 2 dan Lainnya



Tambahkan node RayCast2D ke adegan pemain.





Seperti inilah karakter saya. Tambahkan RayCast ke awal panah.

Secara umum, saya akan menunjukkan semua kode karakter saya dan mencoba mengomentarinya sejelas mungkin.



#       ,           .

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()


Kesimpulan



Saat ini, ini adalah kode karakter paling mutakhir yang baru saja saya buat. Karena fakta bahwa kodenya sudah siap sepenuhnya, saya tidak punya apa-apa untuk ditambahkan secara terpisah. Dan karena saya mengambil pelajaran tentang jebakan dalam siklus terpisah, saya juga tidak mengatakan apa-apa tentang contoh penggunaan sistem interaksi. Saya juga bertanya-tanya apa yang ingin Anda ketahui di bagian selanjutnya dan disajikan di bawah survei yang terdiri dari ide-ide yang muncul di benak saya untuk mekanik. Terima kasih telah membaca dan sampai lain waktu.



All Articles