見出し画像

AIリフティング対戦のルール作り

前回は、AIに対戦させてみました。
今回は、対戦ルールを作ろうと思います。

今日のハイライト


対戦ルール

・3点先取した方が勝ち
・何回リフティングしても、壁に当たってもOK
・敵陣の床にボールが当たったら得点が入る
・しばらくしたら「Ready?」を表示し空中からボールが降ってくる

簡単に

得点システム

まずは、敵陣の床にボールが当たったら得点が入るようにしてみます。

対戦用のScoreシーン(VS_Score)を作る

協力とはルールが変わるため、対戦専用のScoreシーンを作ります。

・新しいシーンをCanvasLayerで作り、名前を「VS_Score」に変更
・子ノードにラベルをつけ、名前を「ScoreLabel」に変更
・ScoreLabelのアンカーを中央上に設定
・ScoreLabelのインスペクターのTextに「0 - 0」と入力
・Label Settingの<空>を新規で選び、できたLabelSettingをクリック
・Label SettingのFontにSystemFontを選択し、Sizeを32に設定
・OutlineのSizeを3にしてColorを黒くする
・Horizontal AlignをCenterに設定

Stage_TossにVS_Scoreを追加

・Stage_Tossの子ノードのScoreを右クリックして削除を選択
・Stage_TossにVS_Scoreをドラッグ&ドロップして追加

AIキャラのスクリプトを修正

VS_Score用のパスに変更し、リフティング回数は必要なくなったのでコメントアウトします。

Pathを変更
・「AI_Toss_L」「AI_Toss_R」のスクリプト内の「Count」のパスを「Score」から「VS_Score」に変更

@onready var count = get_node("/root/Stage_Toss/VS_Score")


リフティング回数をコメントアウト
・AI_Toss_LとAI_Toss_Rの両方ともCTR+Kでコメントアウト

#func _on_area_2d_area_entered(area: Area2D) -> void:
	#if area.is_in_group("balls"): # ball
		#print("hit_balls")
		#count.increase_count()

BallAreaのスクリプトで得点の判定

・VS_ScoreとBallのPathを定義
・Ballの位置からLかRのどちらの陣地に落ちたかを判定
・VS_Scoreに得点を送る
・床でバウンドしても1点しかカウントしない処理

eextends Area2D

@onready var count = get_node("/root/Stage_Toss/VS_Score") # Scoreシーンの場所を定義
@onready var ball = get_node("/root/Stage_Toss/Ball") # Ballシーンの場所を定義

var scored = false # 得点したかどうかのフラグ

func _on_area_entered(area): # エリア内への接触を感知する関数
	if area.is_in_group("floor") and not scored: # 床に接触(得点していなければ得点)
		scored = true # 得点したかどうかフラグをON
		if ball.position.x > 320:
			count.L_Score() # Rの陣地に落ちたらLの得点
			print("Lの得点!")
		else:
			count.R_Score() # Lの陣地に落ちたらRの得点
			print("Rの得点!")

func restart():
	scored = false # 得点したかどうかのフラグを解除

VS_Scorのスクリプト

・LとRの得点を定義
・床にボールが落ちた落ちた時のLとRの得点計算を関数で定義
・スコア表示を更新

extends CanvasLayer

# スコアのラベルのパスを設定
@onready var score_label = $ScoreLabel

var SCORE_L = 0 # Lの得点
var SCORE_R = 0 # Rの得点

# Lの得点計算
func L_Score():
	SCORE_L += 1
	Update_Score()

# Rの得点計算
func R_Score():
	SCORE_R += 1
	Update_Score()

# Score表示を更新
func Update_Score():
	score_label.text = str(SCORE_L) + " - " + str(SCORE_R)

得点システムを実行

F5で実行すると、得点が加算されました。

リスタート

得点が入った後にリスタートするシステムを作ります。

VS_ScoreにMessageLabelを追加

リスタート時などにメッセージを表示するためのLabelを2個追加します。

・1つのLabelをMessageLabelに名前を変更し画面中央に配置
・MessageLabelのtextにReady?を追加
・LabelSettingを新規で追加し、fontsizeを48、outlineのsizeを3で黒に変更
・もう1つのLabelをSubLabelに名前を変更し画面中央に配置(変更不要)

※メッセージの追加の仕方については、「UIを作る」を参照

VS_Scoreにスクリプトを追加

初期設定
・関連するパスを設定
・フラグを設定
・勝利ポイントを設定
・ボールやメッセージを非表示

extends CanvasLayer

# 関連するパスの設置
@onready var score_label = $ScoreLabel # スコアのパス
@onready var message = $MessageLabel # メッセージのパス
@onready var sub_message = $SubLabel # サブメッセージのパス
@onready var ai_l = get_node("/root/Stage_Toss/AI_Toss_L") # Lのパス
@onready var ai_r = get_node("/root/Stage_Toss/AI_Toss_R") # Rのパス
@onready var ball = get_node("/root/Stage_Toss/Ball") # ボールのパス
@onready var ball_area = get_node("/root/Stage_Toss/Ball/BallArea") # ボールの当たり判定のパス

var SCORE_L = 0 # Lの得点
var SCORE_R = 0 # Rの得点
var reset_turn = false # ターンをリセットするフラグ
var game_start = true # ゲームスタートかどうかのフラグ

var win_score = 3 # 勝利ポイント

# 準備
func _ready() -> void:
	game_start = true # スタートフラグをON
	ball.hide() # ボールを非表示
	message.hide() # メッセージを非表示
	reset() # リセットへ

ターンのリセット処理
・ゲーム開始時のメッセージ処理
・ゲーム途中でのスコア表示
・勝利ポイントに達していたらゲームオーバー処理へ
・ゲームオーバーでなければ、スタートへ進む

func reset():
	if not reset_turn: # リセットが繰り返さないようにフラグ管理
		reset_turn = true # リセットされたのでフラグをON
		message.show() # メッセージを表示
		if game_start == true: # ゲーム開始時だったらタイトルを表示
			message.text = "Kick Ball"
		else:
			score_label.hide() # スコアを非表示
			message.text = str(SCORE_L) + " - " + str(SCORE_R) # 中央に大きくスコア表示
	
		await get_tree().create_timer(2).timeout # 2秒待つ

		if SCORE_L >= win_score or SCORE_R >= win_score: # 勝利ポイントが入っていたらゲームオーバーへ
			game_over()
			
		else:
			game_start = false # スタートフラグをOFFしてスタートへ
			start()	

ターンのスタート処理
・スタートの合図「Ready?」を表示
・少し待ってからボールをランダム位置から落とす

func start():
	message.show() # メッセージを表示
	message.text = "Ready?"
	ball.hide() # ボールを非表示
	PhysicsServer2D.set_active(false) # 物理を切る

	await get_tree().create_timer(1).timeout # 1秒待つ
	message.hide() # メッセージを非表示
	ball.show() # ボールを表示
	PhysicsServer2D.set_active(true) # 物理を作動
	
	var start_x = randi_range(100, 540) # ランダムなx座標からボールを落とす
	if start_x > 240 and start_x < 400:
		start_x = 240
	var start_y = 0

	ball.global_position = Vector2(start_x, start_y) # ボールを移動
	ball.linear_velocity = Vector2.ZERO # ボールの移動速度をゼロに
	ball.angular_velocity = 0 # 角速度もゼロにして自由落下でスタート
	print("ball  ", str(ball.position.x, ball.position.y))	# デバッグ用
	ball_area.restart() # ボールの床判定を再開
	score_label.show() # スコアを表示
	reset_turn = false # ターンリセットのフラグをOFF  

ゲームオーバー処理
・勝利メッセージを表示
・少し待って「Presss Escape」を表示
・Escapeキーが押されたら、ゲームをリスタート

func game_over():
	if SCORE_L >= win_score:
		message.show() # Lが勝った時の処理
		message.text = "Blue won!"
	else:
		message.show() # Rが勝った時の処理
		message.text = "Red won!"
	
	await get_tree().create_timer(2).timeout	#2秒待つ
	sub_message.text = "Press Escape" # Escapeキーを押したらリスタート

ゲームの流れが完成

スパイクの打ち合いを制したBlueが先制点を取る

2-1と後がないRedは長いラリーを粘って同点に追いつく

最後はラリーを制してRedが逆転勝利!


Godotで一通りの流れが作れたかな。。。

AIに個性つけたり、プレイヤーと対戦してみたりもできますね。

誰かの参考になれば幸いです。


使用ツール

アドバイザー


いいなと思ったら応援しよう!

この記事が参加している募集