使用godot制作超级马里奥1-1之物理世界

1,155 阅读2分钟

首先的话如果你玩过之前的原版的马里奥,马里奥会吃蘑菇变大,在那种墙壁跟地面只有一个小的马里奥的位置,如果吃蘑菇变大是不会卡死在哪里,并且可以被挤出。如图

动画.gif 如果你是使用这个godot引擎自带的那个物理功能,改变碰撞体积的时候你就会发现马里奥会卡在墙壁里面,所以这个功能只能自己实现,我的实现比较的简单,复杂的暂时没想到,我使用Rect2来作为碰撞的盒子。给每个需要检测碰撞的对象加上Rect2,到时调用intersects来判断是否有碰撞,这些都是godot自带的功能。以下是基本属性

#游戏中所有物体的基本类
var debug=false
var rect=Rect2(Vector2.ZERO,Vector2.ZERO)
#var visible=true #是否可见
var isCollide=true #是否碰撞
var type=constants.empty  #类型
var gravity=0  #重力
var xVel=0 #x轴速度
var yVel=0 #y轴速度
var offsetX=0
var offsetY=0
var collisionShow=false  #测试的时候显示是否碰撞

物体的运动主要是马里奥和敌人之类的运动,马里奥的运动有加速度,这个分为x轴和y轴的方向,y轴就是重力,y轴速度需要设置最大速递。那么改变速度就是在每帧的时候,改变速度的值,如果这个值是不断变化的那就是变速运动,如果是不变的就是匀速运动,以下是马里奥走路时的代码,就是按键时改变速度的大小,左边xVel为负,右边为正。

func walk(delta):
	if xVel>0 || xVel<0:
		ani.speed_scale=1+abs(xVel)/constants.marioAniSpeed
	
	if Input.is_action_pressed("ui_action"):
		acceleration=constants.runAcceleration
		maxXVel=constants.marioRunMaxSpeed
		if fire&&allowShoot:
			shootFireball(false)
			allowShoot=false
	else:
		acceleration=constants.acceleration
		maxXVel=constants.marioWalkMaxSpeed	
		allowShoot=true
		
	#跳跃
	if Input.is_action_pressed("ui_jump"):
		yVel=-constants.marioJumpSpeed
		gravity=constants.marioJumpGravity
		status=constants.jump
		playJumpSound()
#		print('walk jump')
		return
	
	if Input.is_action_pressed("ui_down") &&big:
		startCrouch()
		return
	elif isCrouch and big:
		rect=Rect2(Vector2(-11,-30),Vector2(22,60))	
		position.y-=14
		ani.position.y=0
		isCrouch=false
	
	if Input.is_action_pressed("ui_left"):
		if xVel>0: #反方向
			animation("slide")
			acceleration=constants.slideFriction
		else:
			acceleration=constants.acceleration
			dir=constants.left
			animation('walk')
			
		if 	xVel>-maxXVel:
			xVel-=acceleration*delta
			
	elif Input.is_action_pressed("ui_right"):
		if xVel<0:
			animation("slide")
			acceleration=constants.slideFriction
		else:
			dir=constants.right
			acceleration=constants.acceleration
			animation('walk')
			
		if 	xVel<maxXVel:
			xVel+=acceleration*delta
	else:
		if dir==constants.right:
			if	xVel>0:
				xVel-=acceleration*delta
				animation("walk")
			else:
				ani.speed_scale=1
				status=constants.stand	
		else:
			if xVel<0:
				xVel+=acceleration*delta
				animation("walk")
			else:
				ani.speed_scale=1
				status=constants.stand	
		
	position.x+=xVel*delta
		
#	position.y+=yVel*delta	
	if !isOnFloor:
		ani.stop()
		status=constants.fall
	pass

具体所有的物体的移动基本上都是这样,可以在代码中发现。那么很重套的一点就是碰撞后,需要对一些物体的位置进行重新调整,这个东西比较的麻烦,我参考一篇文章, developer.ibm.com/technologie… 勉强的找到了解决方案,但是还是不完善。碰撞的时候就是要判断到底是左右的碰撞还是上下的碰撞,这样的话才能决定到时是调整x轴还是y轴。

QQ图片20220315112101.png

具体看下map场景里面update的函数。只有调整了位置后,这个物理世界的功能才能是正常的运行下去。其他具体想到在补充。 参考资料:developer.ibm.com/technologie…