diff --git a/scenes/car.tscn b/scenes/car.tscn index 9e15165..f9a13dc 100644 --- a/scenes/car.tscn +++ b/scenes/car.tscn @@ -39,7 +39,6 @@ target_position = Vector2(256, 128) collision_mask = 2 [node name="resetTimer" type="Timer" parent="CharacterBody_Car"] -wait_time = 2.0 one_shot = true [node name="RayCast_Car" type="RayCast2D" parent="CharacterBody_Car"] diff --git a/scenes/game.tscn b/scenes/game.tscn index 52b4fe9..e7f9dae 100644 --- a/scenes/game.tscn +++ b/scenes/game.tscn @@ -7,26 +7,48 @@ script = ExtResource("1_7syh4") [node name="hud" type="CanvasLayer" parent="."] -[node name="speedlabel" type="Label" parent="hud"] +[node name="debuglabel" type="Label" parent="hud"] z_index = 8 -offset_left = 38.0 -offset_top = 541.0 -offset_right = 454.0 -offset_bottom = 586.0 -theme_override_font_sizes/font_size = 32 +offset_left = 14.0 +offset_top = 535.0 +offset_right = 430.0 +offset_bottom = 580.0 +theme_override_font_sizes/font_size = 20 text = "adsf" vertical_alignment = 1 -[node name="speedlabel2" type="Label" parent="hud"] +[node name="timer" type="Label" parent="hud"] z_index = 8 -offset_left = 40.0 -offset_top = 582.0 -offset_right = 456.0 -offset_bottom = 627.0 -theme_override_font_sizes/font_size = 32 -text = "adsf" +offset_left = 17.0 +offset_top = 562.0 +offset_right = 433.0 +offset_bottom = 631.0 +theme_override_font_sizes/font_size = 50 +text = "0.000" vertical_alignment = 1 +[node name="countdown_label" type="Label" parent="hud"] +offset_left = 604.0 +offset_top = 312.0 +offset_right = 644.0 +offset_bottom = 342.0 +theme_override_font_sizes/font_size = 50 +text = "3" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="times_container" type="HFlowContainer" parent="hud"] +offset_left = 29.0 +offset_top = 29.0 +offset_right = 69.0 +offset_bottom = 69.0 + [node name="Camera2D" type="Camera2D" parent="."] [node name="cars" type="Node" parent="."] + +[node name="countdown" type="Timer" parent="."] +wait_time = 3.0 +one_shot = true + +[connection signal="timeout" from="countdown" to="." method="_on_countdown_timeout"] diff --git a/scenes/map_01.tscn b/scenes/map_01.tscn index d54cd66..c9067ed 100644 --- a/scenes/map_01.tscn +++ b/scenes/map_01.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=6 format=4 uid="uid://dghq8c8asg7h1"] +[gd_scene load_steps=9 format=4 uid="uid://dghq8c8asg7h1"] [ext_resource type="TileSet" uid="uid://beswbm12qkkxk" path="res://sprites/spritesheet_road/bg_road.tres" id="2_i1338"] [ext_resource type="TileSet" uid="uid://buu8w8n61kbxf" path="res://sprites/spritesheet_road/markings.tres" id="3_ktygs"] @@ -8,7 +8,16 @@ tile_size = Vector2i(128, 128) [sub_resource type="RectangleShape2D" id="RectangleShape2D_daqun"] -size = Vector2(23, 106.5) +size = Vector2(23, 222) + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_dltky"] +size = Vector2(19, 108) + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_uys5r"] +size = Vector2(20, 126) + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_82iti"] +size = Vector2(20, 231) [node name="Map" type="Node"] @@ -45,22 +54,30 @@ tile_set = ExtResource("4_r58io") collision_layer = 4 collision_mask = 4 -[node name="CollisionShape2D" type="CollisionShape2D" parent="area_finish"] -position = Vector2(89.5, -0.5) +[node name="CollisionShape2D_Fin" type="CollisionShape2D" parent="area_finish"] +position = Vector2(89.5, -1) shape = SubResource("RectangleShape2D_daqun") +[node name="area_cp0" type="Area2D" parent="."] +collision_layer = 4 +collision_mask = 4 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="area_cp0"] +position = Vector2(278, 575) +shape = SubResource("RectangleShape2D_dltky") + [node name="area_cp1" type="Area2D" parent="."] collision_layer = 4 collision_mask = 4 [node name="CollisionShape2D" type="CollisionShape2D" parent="area_cp1"] -position = Vector2(267, 575.5) -shape = SubResource("RectangleShape2D_daqun") +position = Vector2(194, 840) +shape = SubResource("RectangleShape2D_uys5r") [node name="area_cp2" type="Area2D" parent="."] collision_layer = 4 collision_mask = 4 [node name="CollisionShape2D" type="CollisionShape2D" parent="area_cp2"] -position = Vector2(235, 833.75) -shape = SubResource("RectangleShape2D_daqun") +position = Vector2(-384, 0) +shape = SubResource("RectangleShape2D_82iti") diff --git a/scripts/car.gd b/scripts/car.gd index 71840d2..84d4556 100644 --- a/scripts/car.gd +++ b/scripts/car.gd @@ -2,6 +2,7 @@ extends CharacterBody2D #Tutorial: https://www.youtube.com/watch?v=mJ1ZfGDTMCY t=15s +signal car_finished(playerid,finalTime) const COLLISIONMASK_FINISH=3 #set in road_overlay const COLLISIONMASK_CHECKPOINT=4 #set in road_overlay @@ -12,16 +13,21 @@ var checkpointtimes :Array[float]=[] const ROAD_R_NAME="road_r" const ROAD_L_NAME="road_l" + +const COLLISION_SLOWDOWN_CAR=1.01 +const COLLISION_SLOWDOWN_WALL=1.2 + + const STANDSTILLSPEED=0.5 var wheel_base = 60*0.5 -var engine_power = 350 +var engine_power = 500 var friction = -0.5 var drag = -0.0005 var braking = -200 var max_speed_reverse = 100 -var slip_speed = 200 +var slip_speed = 100 var traction_fast = 0.1 #traction when above slip_speed var traction_slow = 0.5 @@ -46,6 +52,7 @@ var resetcar_steerangle=120 #Variables +var running=false var acceleration = Vector2.ZERO var steer_direction=0 @@ -64,10 +71,11 @@ var autosteer_enabled=false @onready var collision_enable_timer: Timer = $collisionEnableTimer var playerid=0 +var finalTime=-1 func _ready() -> void: collision_shape.disabled=true #disable collisions on start. also to avoid collision when initially setting position - + finalTime=-1 func _physics_process(delta: float) -> void: @@ -80,6 +88,14 @@ func _physics_process(delta: float) -> void: #velocity = transform.x * 200 #vel = move_and_slide() move_and_slide() + + for i in get_slide_collision_count(): + var collision = get_slide_collision(i) + #if $".".name==collision.get_collider().name: #collided with another car + # velocity-=COLLISION_SLOWDOWN_CAR + if ROAD_R_NAME==collision.get_collider().name or ROAD_L_NAME==collision.get_collider().name: #collided with road + velocity/=COLLISION_SLOWDOWN_WALL + if get_slide_collision_count()>0: velocity/=2 #for i in get_slide_collision_count(): @@ -95,7 +111,6 @@ func _physics_process(delta: float) -> void: func _on_reset_timer_timeout() -> void: - print("resetting car") autoreset=true func apply_friction(): @@ -143,6 +158,7 @@ func get_input(): steer_direction=0 #drive straight # Manual steering here + ''' var turn = 0 if Input.is_action_pressed("ui_right"): turn += 1 @@ -150,26 +166,26 @@ func get_input(): turn -= 1 if turn!=0: steer_direction = turn*deg_to_rad(steering_angle) - + ''' - - if Input.is_action_pressed("ui_up") or Input.is_action_pressed(Gamestate.userinput_prefix+str(playerid)): - #velocity = transform.x * 500 - acceleration = transform.x * engine_power - - if not autosteer_enabled: #start autosteer when accelerate is pressed - autosteer_enabled=true - collision_enable_timer.start() - - if autoreset: - print("Cancel autoreset") - autoreset=false - if Input.is_action_pressed("ui_down"): - acceleration = transform.x * braking + if running: + if Input.is_action_pressed(Gamestate.userinput_prefix+str(playerid)): + #velocity = transform.x * 500 + acceleration = transform.x * engine_power + + if not autosteer_enabled: #start autosteer when accelerate is pressed + autosteer_enabled=true + collision_enable_timer.start() + + if autoreset: + print("Cancel autoreset") + autoreset=false + #if Input.is_action_pressed("ui_down"): + #acceleration = transform.x * braking - if autoreset: + if autoreset and running: acceleration = transform.x * braking #drive backwards if distance_min>=resetcar_distance: #nothing in front of car @@ -210,28 +226,38 @@ func check_markers(): #if ray_cast_car.get_collision_mask_value(COLLISIONMASK_CHECKPOINT): var rcc_collidername=ray_cast_car.get_collider().name if rcc_collidername=="area_finish": - - var num_cp_collected=0 - for cpt in checkpointtimes: - if cpt>0: - num_cp_collected+=1 #print("Player "+str(playerid)+" drove through Finish") - if num_cp_collected==checkpointtimes.size(): + if getNextCPindex()==-1 and finalTime==-1: #all checkpoints have times and did not finish print("Player "+str(playerid)+" Finished") - #TODO: get final time - checkpointtimes.fill(0) - elif rcc_collidername.begins_with("area_cp"): + print("Final Time: "+str(Gamestate.getTimeElapsed())) + running=false + finalTime=Gamestate.getTimeElapsed() + car_finished.emit(playerid,finalTime) + + elif rcc_collidername.begins_with("area_cp"): + var nextcp_i=getNextCPindex() var checkpoint_i=checkpoints.find(rcc_collidername) - if checkpoint_i>=0 and checkpointtimes[checkpoint_i]==0: #found and no time for this cp yet - checkpointtimes[checkpoint_i]=10 # TODO: set actual time here - print("Player "+str(playerid)+" Checkpoint "+str(ray_cast_car.get_collider().name)) + if checkpoint_i>=0 and nextcp_i>=0: #found and there is a next checkpoint time free + if (nextcp_i%checkpoints.size())==checkpoint_i: #this cp is next cp + checkpointtimes[nextcp_i]=Gamestate.getTimeElapsed() + print("Player "+str(playerid)+" Checkpoint "+str(ray_cast_car.get_collider().name)) + print("New CP array "+str(checkpointtimes)) func constrain(val,a,b): var vmin=min(a,b) var vmax=max(a,b) return min(vmax,max(vmin,val)) - +func getNextCPindex(): + #returns index of first 0 value in times array + #-1 if all cps have times + #[10.2,15.5,12.2,0,0,0,0] -> 3 + var i=0 + for cpt in checkpointtimes: + if cpt==0: + return i + i+=1 + return -1 func _on_collision_enable_timer_timeout() -> void: collision_shape.disabled=false diff --git a/scripts/car_node.gd b/scripts/car_node.gd index 1f659a5..dafaa8a 100644 --- a/scripts/car_node.gd +++ b/scripts/car_node.gd @@ -16,9 +16,9 @@ func setPlayerinformation(playerid, playercolor): cbcar.playerid=playerid carbody.modulate = playercolor -func setCheckpoints(cps): +func setCheckpoints(cps,rounds): cbcar.checkpoints=cps - cbcar.checkpointtimes.resize(cps.size()) + cbcar.checkpointtimes.resize(cps.size()*rounds) cbcar.checkpointtimes.fill(0.0) func move_and_slide(): @@ -28,3 +28,12 @@ func printDebug(): for i in cbcar.get_slide_collision_count(): var collision = cbcar.get_slide_collision(i) print(""+str(cbcar.playerid)+" Collided with: "+ str( collision.get_collider().name)+" pid="+str(collision.get_collider().playerid)+" pos="+str(collision.get_collider().position)) + +func setRunning(r:bool): + cbcar.running=r + +func getCharacterBody(): + return cbcar + +func hasFinished(): + return cbcar.finalTime!=-1 diff --git a/scripts/game.gd b/scripts/game.gd index 61faa40..ae721c7 100644 --- a/scripts/game.gd +++ b/scripts/game.gd @@ -1,22 +1,31 @@ extends Node2D @onready var camera: Camera2D = $Camera2D -#@onready var car: Node2D = $car_0 +@onready var countdown: Timer = $countdown +@onready var countdown_label: Label = $hud/countdown_label @onready var cars: Node = $cars +@onready var times_container: HFlowContainer = $hud/times_container const caroffset= 32+4 #space cars on start line -var viewCarMargin=Vector2(0.05,0.05) #proportions of viewsize. 0,0 = adjust when cars are outside view, 1,1=infinite zoom out -var viewCarMargin_zoomstart=viewCarMargin+Vector2(0.2,0.2) -var zoomspeed=0.5 -var zoomspeed_backup=0.1 +var viewCarMargin=Vector2(0.1,0.1) #proportions of viewsize. 0,0 = adjust when cars are outside view, 1,1=infinite zoom out +var viewCarMargin_zoomstart=viewCarMargin+Vector2(0.05,0.05) +var zoomspeed=1.0 +var zoomspeed_backup=0.2 var zoom_normal=2 +const CAMERA_POSITION_SPEED=0.98 #0.0 - 1.0, higher=faster + +var running=false + +var rounds=3 + # Called when the node enters the scene tree for the first time. func _ready() -> void: - + countdown.start() + countdown_label.visible=true #Load Map #var num_checkpoints=0 @@ -40,7 +49,8 @@ func _ready() -> void: newcarinstance.setPlayerinformation(i,player.color) newcarinstance.setPosition(Vector2(0,ceil(i/2.0)*(fmod(i,2)-0.5)*2.0*caroffset)) - newcarinstance.setCheckpoints(checkpoints) + newcarinstance.setCheckpoints(checkpoints,rounds) + newcarinstance.getCharacterBody().car_finished.connect(_on_car_finished) #print("Position car "+str(i)+" = "+str(ceil(i/2.0)*(fmod(i,2)-0.5)*2.0*caroffset)) @@ -51,34 +61,46 @@ func _ready() -> void: # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta: float) -> void: + if running: + Gamestate.addTimeElapsed(delta) + if !countdown.is_stopped(): + countdown_label.text=str(round(countdown.time_left)) + var cars=cars.get_children() var meanCarPosition=Vector2.ZERO var displayedCarCount=0 var maxCarSpeed=0 var minPos=Vector2.ZERO #min/max x and y position of all cars var maxPos=Vector2.ZERO + + var oneDriving=false + for c in cars: #check if any one car is still driving + if !c.hasFinished(): + oneDriving=true + for c in cars: - var carpos = c.getPosition() - meanCarPosition+=carpos - - maxCarSpeed=max(maxCarSpeed,c.getSpeed()) - if displayedCarCount==0: - minPos.x=carpos.x - minPos.y=carpos.y - maxPos.x=carpos.x - maxPos.y=carpos.y - else: - minPos.x=min(minPos.x,carpos.x) - minPos.y=min(minPos.y,carpos.y) - maxPos.x=max(maxPos.x,carpos.x) - maxPos.y=max(maxPos.y,carpos.y) - - displayedCarCount+=1 + if !c.hasFinished() or !oneDriving: + var carpos = c.getPosition() + meanCarPosition+=carpos + + maxCarSpeed=max(maxCarSpeed,c.getSpeed()) + if displayedCarCount==0: + minPos.x=carpos.x + minPos.y=carpos.y + maxPos.x=carpos.x + maxPos.y=carpos.y + else: + minPos.x=min(minPos.x,carpos.x) + minPos.y=min(minPos.y,carpos.y) + maxPos.x=max(maxPos.x,carpos.x) + maxPos.y=max(maxPos.y,carpos.y) + + displayedCarCount+=1 meanCarPosition/=displayedCarCount #camera.position=car.getPosition() - camera.position=meanCarPosition + camera.position=lerp(camera.position,meanCarPosition,CAMERA_POSITION_SPEED*delta) #rint("zoom = "+str(camera.zoom)) #camera.zoom=Vector2(1.5,1.5) @@ -103,14 +125,8 @@ func _process(delta: float) -> void: if camera.zoom.x void: + running=true + var cars=cars.get_children() + for c in cars: + c.setRunning(true) + countdown_label.visible=false + +func _on_car_finished(playerid,finalTime) -> void: + print("Finished "+str(playerid)+" final time="+str(finalTime)) + var place=times_container.get_child_count()+1 + print("New Label. Place "+str(place)) + var newlabel= Label.new() + times_container.add_child(newlabel) + newlabel.set("theme_override_font_sizes/font_size",40) + newlabel.text=str(place)+": "+str(round(finalTime*1000)/1000.0)+"s" + newlabel.set("theme_override_colors/font_color",Gamestate.getPlayers()[playerid].color) + diff --git a/scripts/gamestate.gd b/scripts/gamestate.gd index e3ba2bd..3f406ab 100644 --- a/scripts/gamestate.gd +++ b/scripts/gamestate.gd @@ -6,6 +6,8 @@ var players: Array[Player] = [] var userinput_prefix="inputP" +var time_elapsed=0 + func addPlayer(key:int): if not getPlayerkeys().has(key): #playerkeys.append(key) @@ -43,3 +45,12 @@ class Player: print("i is "+str(i)+" h="+str(fmod(0.3*i,1.0))+" assigned color "+str(color)) +func startGame(): + for player in players: + player.setRunning(true) + +func addTimeElapsed(delta): + time_elapsed+=delta + +func getTimeElapsed(): + return time_elapsed