DanisRace/Scripts/LEGACY_Car_controll.py
Victorious Children Studios 594e088a83 07-07-24
2024-07-13 16:15:50 +03:00

1770 lines
65 KiB
Python

import bge
import time
import math
import bpy
import random
import numpy
import aud
import mathutils
import inspect
import Reuse
import Distraction
import Opt
import Character_Controll
deleteAtDistance = 500
fixGaragePosition = [-754.61, -1043.9, 409.32]
raceNames = {"RedKissBox":"Tali",
"NeonSpeedsterBox":"Jack"}
def start_car():
# This function runs when the car is created.
# It creates the Bullet Physics RayCast Vehicle
# wrapper for the car.
# Getting basic things
cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
car = cont.owner
# Creating the vehicle constraint itself
vehicle = bge.constraints.createVehicle(car.getPhysicsId())
# Saving the ID of the constraint so we could access it later.
car["cid"] = vehicle.getConstraintId()
bge.logic.globalDict[car["cid"]] = {"wheels":[]}
###### SETTING UP WHEELS #####
# LEFT BACK
wheel0 = car.children[car.get("wheelsname", "Wheel")+""]
bge.logic.globalDict[car["cid"]]["wheels"].append(wheel0)
wheel0.removeParent()
vehicle.addWheel(wheel0,
[car.get("wheelswidth", 0.89), car.get("wheelsback", 1.65), car.get("wheelsdown", -0.1)], # Pos Local
[0, 0, -1], # Dir Local
[-1, 0, 0], # Axl Local
0.2, # Suspention length
car.get("wheelradius", 0.42), # Wheel Radius
1
)
# RIGHT BACK
wheel1 = car.children[car.get("wheelsname", "Wheel")+".001"]
bge.logic.globalDict[car["cid"]]["wheels"].append(wheel1)
wheel1.removeParent()
vehicle.addWheel(wheel1,
[-car.get("wheelswidth", 0.89), car.get("wheelsback", 1.65), car.get("wheelsdown", -0.1)], # Pos Local
[0, 0, -1], # Dir Local
[-1, 0, 0], # Axl Local
0.2, # Suspention length
car.get("wheelradius", 0.42), # Wheel Radius
1
)
# LEFT FRONT
wheel2 = car.children[car.get("wheelsname", "Wheel")+".002"]
bge.logic.globalDict[car["cid"]]["wheels"].append(wheel2)
wheel2.removeParent()
vehicle.addWheel(wheel2,
[car.get("wheelswidth", 0.89), car.get("wheelsfront", -1.25), car.get("wheelsdown", -0.1)], # Pos Local
[0, 0, -1], # Dir Local
[-1, 0, 0], # Axl Local
0.2, # Suspention length
car.get("wheelradius", 0.42), # Wheel Radius
1
)
# RIGHT FRONT
wheel3 = car.children[car.get("wheelsname", "Wheel")+".003"]
bge.logic.globalDict[car["cid"]]["wheels"].append(wheel3)
wheel3.removeParent()
vehicle.addWheel(wheel3,
[-car.get("wheelswidth", 0.89), car.get("wheelsfront", -1.25), car.get("wheelsdown", -0.1)], # Pos Local
[0, 0, -1], # Dir Local
[-1, 0, 0], # Axl Local
0.2, # Suspention length
car.get("wheelradius", 0.42), # Wheel Radius
1
)
# Setting up wheel physics characteristics.
# ( NOTE: ) This is not the only place where those are set.
# Damage and Rescue functions update those values.
car["suspensions"] = []
for i in range(4):
vehicle.setSuspensionStiffness(car.get("suspension", 200), i)
car["suspensions"].append(car.get("suspension", 200))
vehicle.setTyreFriction(car.get("friction", 1), i)
vehicle.setRollInfluence(car.get("roll", 0), i)
##### SETTING UP THE DAMAGE MODEL #####
def collision_callback(object, point, normal):
# This function will run whenever the car colides with anything.
# Dani object ( main human character )
dani = scene.objects["Dani_Box"]
toFPS = Opt.ToFPS()
# Near misses - when the player drives quickly
# near a different vehicle. If colision happens,
# near misses are canceled.
car["veryclose"] = None
# If anywhere within the proximity of the car,
# an explosion was set off ( car colided with the shockwave sphere ).
# we want to setup a timer, to blow car up in a few ticks after that.
# Doing it immediately makes the second explosion almost inconciaveable.
if object.get("explosion"):
car["blowuptimer"] = 20
# Canceling the rest of the calculation if we can't see it, or it is too far from the camera.
cam = scene.active_camera
if car.getDistanceTo("Dani_Box") > 20 or cam.pointInsideFrustum(car.worldPosition) == cam.OUTSIDE:
return
# If human pushes the car, there is no damage
if dani == object:
return
# Separation is an invisible object that bots see to navigate.
# We don't want it to cause damage.
if "Separation" in object.name:
return
#### WATER INTERACTIONS ####
if object.name == "Water":
car["underwater"] = True
if car["active"]:
dani["underwater"] = True
# Sound
device = bge.logic.globalDict["SoundDevice"]
s = "//sfx/splash.ogg"
code = s+str(car["cid"])
if code not in bge.logic.globalDict["sounds"]:
bge.logic.globalDict["sounds"][code] = {"sound":aud.Sound(bge.logic.expandPath(s)),
"play":None}
sound = bge.logic.globalDict["sounds"][code]
if not sound["play"] or not sound["play"].status:
sound["play"] = device.play(sound["sound"])
sound["play"].location = point
sound["play"].velocity = car.getLinearVelocity()
sound["play"].relative = False
sound["play"].distance_maximum = 100
sound["play"].distance_reference = 1
sound["play"].attenuation = 1
return
# Returning if performance is not good
if not Opt.GoodFPS("Car Collisions", 0.9) and not car.get("active"):
return
# Velocity of the car
cv = car.getLinearVelocity()
# Averagin the values
av = sum(cv) / 3
if av < 0: av *= -1
av /= (toFPS ** 2)
# Setting off sparks if the velocity is beyond a certain amount
if av > 0.1:
Distraction.particles("Sparkle", point,
despawn = random.randint(30, 100),
amount = random.randint(0, 3),
max = 50,
spread = 0,
normal = 0.04,
velocity = cv * 0.015)
# Restricting all the rest of the calculations based on a timer
# between the colisions.
if car.get("lastdamage"):
return
car["lastdamage"] = random.randint(10, 60)
# Adding nitro on colision ( based on the speed of the car )
car["nitro"] += av*20
#### ENEMY VOICES ####
# NPC cars might get angry and start attacking you if you hit them.
# When they get angry they swear at you. This is the logic of the
# swearing sounds. And the getting angry logic.
if object.get("engine") and car.get("npc") and car.get("npc") != "racer" and object.get("enemy") != car:
device = bge.logic.globalDict["SoundDevice"]
if not car["npc"] == "enemy":
sound = random.choice(bge.logic.globalDict["sounds_angry_start"])
sound = bge.logic.globalDict["sounds"][sound]
sound["play"] = device.play(sound["sound"])
sound["play"].location = car.position
sound["play"].relative = False
sound["play"].distance_maximum = 50
sound["play"].distance_reference = 5
sound["play"].attenuation = 1
sound["play"].volume = 1.5
car["enemysound"] = sound["play"]
if object.get("active"):
scene.objects["Angry_pusuit"]["pusuit"] = True
if not dani.get("active_sound"):
dani["active_sound"] = device.play(bge.logic.globalDict["sounds"]["dani_ohno"]["sound"])
bge.logic.globalDict["sounds"]["dani_ohno"]["play"] = dani["active_sound"]
dani["active_sound_is"] = "dani_ohno"
elif car["enemy"] == object and ( not car.get("enemysound") or not car["enemysound"].status ):
sound = random.choice(bge.logic.globalDict["sounds_angry_hit"])
sound = bge.logic.globalDict["sounds"][sound]
sound["play"] = device.play(sound["sound"])
sound["play"].location = car.position
sound["play"].relative = False
sound["play"].distance_maximum = 50
sound["play"].distance_reference = 5
sound["play"].attenuation = 1
sound["play"].volume = 1.5
car["enemysound"] = sound["play"]
if object.get("active") and not dani.get("active_sound_is") == "dani_ohnoindeed" and not dani.get("active_sound"):
dani["active_sound"] = device.play(bge.logic.globalDict["sounds"]["dani_ohnoindeed"]["sound"])
bge.logic.globalDict["sounds"]["dani_ohnoindeed"]["play"] = dani["active_sound"]
dani["active_sound_is"] = "dani_ohnoindeed"
# Getting angry
car["npc"] = "enemy"
car["enemy"] = object
object["chased"] = True
# Getting car's body.
rig = car.children[car.get("rig","RIG")]
body = rig.children["Car_body"]
# Getting the velocity of the colision ( comparing to the valocity of the object we are coliding with )
ov = object.getLinearVelocity()
ov /= (toFPS ** 2)
sp = cv - ov
# We can't simply average the velocity since it could be negative.
sm = 0
for i in sp:
if i > 0:
sm += i
else:
sm += i*-1
sp = sm / 3
# Adding the mass of both objects to the calculation
obmass = object.mass
if not obmass: obmass = 1
breakMultiply = max(0, min(1, 1-(sp * obmass)/55)) ** 0.05
breakMultiply *= (toFPS ** 2)
# Blow up when getting a 0 breakMultiply
if not breakMultiply:
car["blowuptimer"] = 10
####### BREAKING THE CAR #######
if breakMultiply < 0.999 or object.get("explosion"):
# Hit sound
device = bge.logic.globalDict["SoundDevice"]
# Hit versus scrape sound
if breakMultiply < 0.98:
s = "//sfx/hit.ogg"
else:
s = "//sfx/scrape.ogg"
code = s+str(car["cid"])
if code not in bge.logic.globalDict["sounds"]:
bge.logic.globalDict["sounds"][code] = {"sound":aud.Sound(bge.logic.expandPath(s)),
"play":None}
sound = bge.logic.globalDict["sounds"][code]
sound["play"] = device.play(sound["sound"])
sound["play"].location = point
sound["play"].relative = False
sound["play"].distance_maximum = 100
sound["play"].distance_reference = 1
sound["play"].attenuation = 1
sound["play"].pitch = random.choice([1, 0.8, 1.2, 0.6, 1.4])
sound["play"].volume = 1 / max(0.1, breakMultiply )
# slecting what area of the car to effect
areas = {"Front_Left" : normal[0] < 0.1 and normal[1] < 0.1,
"Front_Right": normal[0] < 0.1 and normal[1] > -0.1,
"Back_Left" : normal[0] > -0.1 and normal[1] < 0.1,
"Back_Right" : normal[0] > -0.1 and normal[1] < 0.1}
wheels = {"Front_Left" : 2,
"Front_Right": 3,
"Back_Left" : 0,
"Back_Right" : 1}
for area in areas:
if ( areas[area] and car[area] > 0 ) or object.get("explosion"):
# Reducing health
car[area] *= breakMultiply
# If broken toally we pop a wheel
if car[area] <= 0.01:
# We can't simply undo the wheel from the constraint. But
# we can do the next best thing.
bge.logic.globalDict[car["cid"]]["wheels"][wheels[area]].setVisible(False)
vehicle.applyBraking(10, wheels[area])
vehicle.setSuspensionStiffness(0,wheels[area])
# If it is an npc, we make him give up trying to drive.
if not car.get("racing"):
car["npc"] = ""
# Tire Pop
sound = bge.logic.globalDict["sounds"]["tire_pop"]
sound["play"] = device.play(sound["sound"])
sound["play"].location = point
sound["play"].relative = False
sound["play"].distance_maximum = 100
sound["play"].distance_reference = 1
sound["play"].attenuation = 1
sound["play"].volume = 2
# If we are not totally broken, make the wheel worse handeling-wise.
elif car["Front_Left"] < 0.7:
vehicle.setSuspensionStiffness(car.get("suspension", 200)*car["Front_Left"],wheels[area])
vehicle.setRollInfluence(1-car[area], wheels[area])
# If below a certain health, we make the car body look borked
if car[area] < 0.7:
body.replaceMesh(car.get("borked", "Borked"))
# If the heal even lower.
if car[area] < 0.3:
# Removing left door.
if "Left" in area:
try:
door = rig.children["Door_Pease.001"]
door.visible = False
except:
pass
# Removing right door.
elif "Right" in area:
try:
door = rig.children["Door_Pease"]
door.visible = False
except:
pass
# Adding the collision function to the car's collision functions.
car.collisionCallbacks.append(collision_callback)
def update():
# This function is called on ever game logic tick for every car
# in the scene. This is the logic of the car.
# BGE logic stuff
cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
car = cont.owner
toFPS = Opt.ToFPS()
carRacing = car.get("racing")
carEnemy = car.get("enemy")
carBehaviour = car.get("npc")
carActive = car.get("active")
carSpeed = car.get("speed")
rig = car.children[car.get("rig","RIG")]
cam = scene.active_camera
camtarget = car.children["CarCamTarget"]
# Is the car in view
distanceToCam = car.getDistanceTo(cam)
inview = ( cam.pointInsideFrustum(car.worldPosition) == cam.INSIDE and distanceToCam < deleteAtDistance / 2 ) or distanceToCam < deleteAtDistance / 3 or distanceToCam > deleteAtDistance
# Dani related things
dani = scene.objects["Dani_Box"]
# Delete vehicle ( at distance, usually done for NPC cars ).
if car.getDistanceTo(cam) > deleteAtDistance and not carRacing and car in bge.logic.globalDict["allcars"]:
def RemovingTheCar(car, dani):
# If car is waiting for a race to start, we don't delete it
if carBehaviour == "racer":
racename = car["race"]
race = bge.logic.globalDict["races"][racename]
starter = race["starters"][0]
if dani.getDistanceTo(starter["location"]) < deleteAtDistance or car["racing"]:
return
print("Removing Car:", car)
# Making sure it can be respawned
if car.get("spawnPoint"):
car["spawnPoint"]["to_spawn"] = True
# Removing the car from races
for racename in bge.logic.globalDict["races"]:
race = bge.logic.globalDict["races"][racename]
try:
race["racers"].remove(car)
except:
pass
if car in bge.logic.globalDict["allcars"]:
bge.logic.globalDict["allcars"].remove(car)
# Removing from cache if too many cars in cache
if Reuse.reuse.get(car.name):# or len(bge.logic.globalDict["allcars"]) > bge.logic.globalDict["maxCars"]:
for i in bge.logic.globalDict[car["cid"]]["wheels"]:
i.endObject()
Reuse.EndObject(car)
# Otherwise storing it for later.
else:
Reuse.Delete(car, inactive=True)
# Undoing angry pursuit
try:
if car["enemy"]["active"]:
scene.objects["Angry_pusuit"]["pusuit"] = False
except:
pass
if Reuse.reuse.get(car.name) or len(bge.logic.globalDict["allcars"]) > bge.logic.globalDict["maxCars"]:
Opt.ScheduleTask("Removing Car ["+car.name+"]", 1.0, RemovingTheCar, car, dani)
else: RemovingTheCar(car, dani)
# Cutting down on unnesesary running of the script
if ( not carRacing and not carActive ) and ( not inview ):
car["deactivated"] = True
car.suspendPhysics()
return
elif car.get("deactivated"):
car.restorePhysics()
car["deactivated"] = False
# Physics constraint for the vehicle
vehicle = bge.constraints.getVehicleConstraint(car["cid"])
# Sound device for sounds.
device = bge.logic.globalDict["SoundDevice"]
# Car's health
health = sum([car["Front_Left"], car["Front_Right"], car["Back_Left"], car["Back_Right"]])/4
engineHealth = ( car["Front_Left"] + car["Front_Right"] ) / 2
car["health"] = health
# Fixing the car ( when in the garage)
if distanceToCam < 30 and car.getDistanceTo(fixGaragePosition) < 2 and health < 1:
bge.logic.globalDict["print"] = "Press F to fix the car."
# Fix car if F is pressed
if 28 in bge.logic.globalDict["keys"]:
body = rig.children["Car_body"]
body.replaceMesh( body["good"] )
for i in range(4):
vehicle.setSuspensionStiffness(car.get("suspension", 200), i)
vehicle.applyBraking(0, i)
vehicle.setTyreFriction(car.get("friction", 1), i)
vehicle.setRollInfluence(car.get("roll", 0), i)
bge.logic.globalDict[car["cid"]]["wheels"][i].setVisible(True)
for i in ["Front_Right", "Front_Left", "Back_Left", "Back_Right"]:
car[i] = 1
# Doors ( some cars have them falling )
try:
rig.children["Door_Pease.001"].visible = True
rig.children["Door_Pease"].visible = True
except:
pass
elif carActive and health < 0.98:
toprint = "You can fix the car in the garage at home."
if toprint not in bge.logic.globalDict["done-prints"]:
bge.logic.globalDict["print"] = toprint
# Whether the car is on graound.
graypos = car.position.copy()
graypos[2] -= 1.5
onGround = car.rayCastTo(graypos)
# Car's rotation
rot = car.localOrientation.to_euler()
upsideDown = not ( -2.5 < rot[0] < 2.5 and -2.5 < rot[1] < 2.5 )
# Colision timer
if car.get("lastdamage"):
car["lastdamage"] -= 1
# Lauchtime timer
if "launchtime" not in car:
car["launchtime"] = 300
car["launchtime"] -= 1
# Water boyancy
if car.position[2] < -9.5 and car.get("underwater"):
car.applyForce([0,0,-5*(car.position[2]+9.5)])
if car["speed"] < -1.5:
car.applyForce([0,-80,0], True)
car.orientation = [0,0,rot[2]]
elif car.position[2] > -9.5:
car["underwater"] = False
# Speed calculation
psp = vehicle.getWheelRotation(0)+vehicle.getWheelRotation(1)
sp = psp - car["prevwheelrot"]
car["prevwheelrot"] = psp
car["speed"] = sp
# sp will be speed normalized
if sp < 0: sp *= -1
# Down Force
dforce = -5*sp*car.get("downforce", 1)
if onGround:
dforce = min(-5, dforce)
car.applyForce([0,0, Opt.Force(dforce)], True)
# Gage
if carActive:
gagerotation = sp * 0.214 # 400 km/h == 4.27 radiance on the gage
gage = scene.objects["Gage_Arrow"]
gage.orientation = [0,0,-gagerotation]
gage_health = scene.objects["Gage_Health"]
gage_health["Health"] = int(( (health ** 2 ** 3) / (1 ** 2 ** 3 ) )*100)
###### NITRO ######
# Making sure that nitro isn't overboard.
car["nitro"] = max(0,min(10000, car.get("nitro", 0.0)))
if carActive:
gage_nitro = scene.objects["Gage_Nitro"]
gage_nitro["Nitro"] = car["nitro"]/100
# Function activated when Nitro is used
def nitro():
if car["nitro"] <= 0:
stopNitro()
return
# Actual Nitro Effect on the car
#if car["engine"] < car.get("maxengine", 2)-0.1:
car["engine"] += car.get("maxaccel",0.003)* 5 * toFPS
#else:
# car["engine"] = car.get("maxengine", 2)*1.5
car["nitro"] -= 20
# Anti bank
if car.get("roll",0):
car.applyRotation([0.05*car.get("roll",0),0,0], True)
car.applyForce([0,0, -20*car.get("roll",0)], True)
# Nitro Sound
s = "//sfx/nitro.ogg"
code = s+str(car["cid"])
if code not in bge.logic.globalDict["sounds"]:
bge.logic.globalDict["sounds"][code] = {"sound":aud.Sound(bge.logic.expandPath(s)),
"play":None}
sound = bge.logic.globalDict["sounds"][code]
if not sound["play"] or not sound["play"].status:
sound["play"] = device.play(sound["sound"])
sound["play"].location = car.position
sound["play"].relative = False
sound["play"].distance_maximum = 100
sound["play"].distance_reference = 1
sound["play"].attenuation = 1
sound["play"].pitch = 1
sound["play"].volume = 5
car["nitroing"] = True
if not carActive and not Opt.GoodFPS("Nitro", 0.9):
return
for nitroObject in car.children:
if "nitro" in nitroObject.name:
if not nitroObject.get("nitroCone"):
nitroCone = Reuse.Create("NitroCone")
nitroObject["nitroCone"] = nitroCone
nitroCone.position = nitroObject.worldPosition
nitroCone.orientation = nitroObject.worldOrientation
nitroCone.setParent(nitroObject)
# Camera effect
if carActive:
camtarget = car.children["CarCamTarget"]
if not car.get("zoom"):
car["zoom"] = camtarget.scaling[0]
camtarget.scaling *= 1.02
# Unction activated when nitro isn't used.
def stopNitro():
# Grpaphics stop
for nitroObject in car.children:
if "nitro" in nitroObject.name:
if nitroObject.get("nitroCone"):
nitroObject["nitroCone"].removeParent()
Reuse.Delete(nitroObject["nitroCone"])
nitroObject["nitroCone"] = None
# Sound stop
s = "//sfx/nitro.ogg"
code = s+str(car["cid"])
if code in bge.logic.globalDict["sounds"]:
sound = bge.logic.globalDict["sounds"][code]
try:
if sound["play"].volume > 0:
sound["play"].volume -= 0.5
else:
sound["play"].stop()
except:
pass
# Activating nitro
if carActive and 48 in bge.logic.globalDict["keys"]:
# 48 is Z
nitro()
else:
stopNitro()
if not onGround:
car["nitro"] += 5
# Telling the player that the car is availble
if dani.get("doesntknowhowtositintocars", True) and not dani["driving"] and distanceToCam < 7:
bge.logic.globalDict["print"] = "Press E to sit into the car."
dani["doesntknowhowtositintocars"] = False
# Camera changes ( help camera show you where you are going ).
if carActive and not upsideDown and sp > 0.1:
dontseecar = cam.rayCastTo(car) != car
if dontseecar and camtarget.scaling[0] > 0.1:
if not car.get("zoom"):
car["zoom"] = camtarget.scaling[0]
camtarget.scaling *= 0.97
elif car.get("zoom") and scene.objects["SecondaryCamSensor"].rayCastTo(car) == car:
newzoom = camtarget.scaling[0] + (( car["zoom"] - camtarget.scaling[0] ) / ( 30 / toFPS ) )
camtarget.scaling = [ newzoom, newzoom, newzoom ]
if camtarget.scaling[0] == car["zoom"]:
car["zoom"] = False
camrot = mathutils.Vector(camtarget.localOrientation.to_euler())
reference = car.getVectTo(car.position + car.getLinearVelocity())[2]
rotref = car.localAngularVelocity
backorfoth = ((reference[1]+1)/2)
if backorfoth > 0.6: backorforth = 1
else: backorforth = 0
if camtarget["back"] and backorforth: backorforth = 0
elif camtarget["back"]: backorforth = 1
camnewrot = mathutils.Vector( [ 0.3 - max(-0.1, min(0.2, rotref[0]/2)),# - (car["engine"]*0.005),
0 - (rotref[2]/10) - (rotref[1]/6),
( math.pi * backorforth ) - (rotref[2]/4)] )
if backorforth and camrot[2] < 0:
camnewrot[2] -= math.pi * 2
camnewrot = mathutils.Vector(camnewrot)
camrot = camrot + (( camnewrot - camrot ) / 10 )
camtarget.localOrientation = camrot
elif carActive and cam.rayCastTo(car) != car:
camrot = camtarget.localOrientation.to_euler()
camrot[0] -= 0.02
#camrot[2] += 0.01
camtarget.localOrientation= camrot
# Smoke ( if health too low )
if not car["underwater"] and inview:
smokeCoefitient = max(0, 1-engineHealth*1.1)*0.2
fireCoefitient = max(0, 1-engineHealth*2)*0.2
smokeemiter = car.children["SmokeEmmiter"]
Distraction.Smoke(smokeemiter.position, smokeCoefitient)
Distraction.Fire(smokeemiter.position, fireCoefitient)
# Exposion
if engineHealth < 0.2 and not car.get("blown"):
boompos = smokeemiter.position.copy()
boompos[2] -= 2
Distraction.Explosion(boompos, mass=0.5, size=2)
car["blown"] = True
# Blowuptimer
if car.get("blowuptimer") != None:
if car["blowuptimer"] == 0 and not car.get("blown"):
Distraction.Explosion(car.children["SmokeEmmiter"].position.copy(), mass=0.5, size=2)
car["blown"] = True
else:
car["blowuptimer"] -= 1
######### SOUND ########
if carActive:
# Dani yelling when in air
if not onGround and not car["underwater"] and not dani.get("active_sound"):
dani["active_sound"] = device.play(bge.logic.globalDict["sounds"]["dani_yelling"]["sound"])
bge.logic.globalDict["sounds"]["dani_yelling"]["play"] = dani["active_sound"]
dani["active_sound_is"] = "dani_yelling"
elif onGround and dani["active_sound"] and dani["active_sound_is"] == "dani_yelling":
dani["active_sound"].stop()
dani["active_sound"] = None
# Sinking
if car.get("underwater") and not dani.get("active_sound") and not dani.get("active_sound_is") == "dani_wearesinking" and dani.get("sinking_timer", 0) < time.time():
dani["active_sound"] = device.play(bge.logic.globalDict["sounds"]["dani_wearesinking"]["sound"])
bge.logic.globalDict["sounds"]["dani_wearesinking"]["play"] = dani["active_sound"]
dani["active_sound_is"] = "dani_wearesinking"
dani["sinking_timer"] = time.time() + 40
# Very close to another car
try:
for i in bge.logic.globalDict["allcars"]:
if i != car and i.getDistanceTo(car) < 6:
car["veryclose"] = i
break
except:
pass
if sp < 0.3:
car["veryclose"] = None
elif car.get("veryclose") and car["veryclose"].getDistanceTo(car) > 7:
if not dani.get("active_sound"):
dani["active_sound"] = device.play(bge.logic.globalDict["sounds"]["dani_ohgod"]["sound"])
bge.logic.globalDict["sounds"]["dani_ohgod"]["play"] = dani["active_sound"]
dani["active_sound_is"] = "dani_ohgod"
car["nitro"] += 200
car["veryclose"] = None
if not dani.get("active_sound") or not dani["active_sound"].status:
dani["active_sound"] = None
# Engine sound
s = car.get("engine_sound","//sfx/engines/neonspeedster.ogg")
code = s+str(car["cid"])
if code not in bge.logic.globalDict["sounds"]:
bge.logic.globalDict["sounds"][code] = {"sound":aud.Sound(bge.logic.expandPath(s)),
"play":None}
sound = bge.logic.globalDict["sounds"][code]
esp = car["engine"]
if esp < 0: esp *= -1
esp = math.log1p(esp) * 5
if 0.01 < esp or car.get("engineStarted"):
car["engineStarted"] = True
if not sound["play"] or not sound["play"].status:
sound["play"] = device.play(sound["sound"])
sound["play"].location = car.worldPosition
sound["play"].velocity = car.getLinearVelocity()
sound["play"].relative = False
sound["play"].distance_maximum = 200
sound["play"].distance_reference = 1
sound["play"].attenuation = 1
revs = ( esp + ( esp % 1.5 ) ) * 0.5
sound["play"].pitch = max(0.4, revs )
sound["play"].volume = engineHealth * 1
if carActive:
scene.objects["Gage_Tachometer"]["Health"] = revs * 30
else:
try:
bge.logic.globalDict["sounds"][code]["play"].stop()
except:
pass
# Grind sound
s = "//sfx/grind.ogg"
code = s+str(car["cid"])
if code not in bge.logic.globalDict["sounds"]:
bge.logic.globalDict["sounds"][code] = {"sound":aud.Sound(bge.logic.expandPath(s)),
"play":None}
sound = bge.logic.globalDict["sounds"][code]
if 0.01 < sp:
if not sound["play"] or not sound["play"].status:
sound["play"] = device.play(sound["sound"])
sound["play"].location = car.worldPosition
sound["play"].velocity = car.getLinearVelocity()
sound["play"].relative = False
sound["play"].distance_maximum = 200
sound["play"].distance_reference = 1
sound["play"].attenuation = 1
sound["play"].pitch = max(0.3, engineHealth) * 2
sound["play"].volume = (1-engineHealth) * min(1.5, sp *8) * 1
else:
try:
bge.logic.globalDict["sounds"][code]["play"].stop()
except:
pass
# Drift sound
s = "//sfx/drift.ogg"
code = s+str(car["cid"])
if code not in bge.logic.globalDict["sounds"]:
bge.logic.globalDict["sounds"][code] = {"sound":aud.Sound(bge.logic.expandPath(s)),
"play":None}
slide = car.localLinearVelocity[0]
if car.get("deccelerating"):
slide = car.localLinearVelocity[1]
if slide < 0:
slide *= -1
sound = bge.logic.globalDict["sounds"][code]
if slide > 1 and -0.5 < rot[0] < 0.5 and -0.5 < rot[1] < 0.5 and onGround:
car["nitro"] += 2
if not sound["play"] or not sound["play"].status:
sound["play"] = device.play(sound["sound"])
sound["play"].location = car.worldPosition
sound["play"].velocity = car.getLinearVelocity()
sound["play"].relative = False
sound["play"].distance_maximum = 200
sound["play"].distance_reference = 1
sound["play"].attenuation = 1
#sound["play"].pitch = 0.8
sound["play"].volume = min(2, slide / 5) / 5
else:
try:
bge.logic.globalDict["sounds"][code]["play"].stop()
except:
pass
#### RACE RESCUE FUNCTION ####
def rescue():
if car.get("launchtime", 0) > 0:
return
# Sparkles on disappearing positiong
Distraction.particles("Sparkle", car.position.copy(),
despawn = random.randint(30, 100),
amount = 30,
max = 30,
spread = 2,
normal = 0.05,
scale = 7)
# Camera
if carActive:
def resetCarZoom():
car["zoom"] = False
Character_Controll.ChangeCameraTarget(car.children["CarCamTarget"], 100, [3,3,3],callable=resetCarZoom)
car.children["CarCamTarget"].orientation = [0.2,0,0]
# Teleportation
car.position = car["rescue"]
car.localLinearVelocity = [0,0,0]
car["checkpoint"] = ( car.get("rescueTo", car["checkpoint"]-1) + 1 ) % len(bge.logic.globalDict["races"][car.get("race")]["checkpoints"])
nextcheckpointn = car["checkpoint"]
nextcheckpoint = bge.logic.globalDict["races"][car.get("race")]["checkpoints"][ nextcheckpointn ]["location"]
prevcheckpoint = ( car["checkpoint"]-2 ) % len(bge.logic.globalDict["races"][car.get("race")]["checkpoints"])
car["prevrescue"] = bge.logic.globalDict["races"][car.get("race")]["checkpoints"][ prevcheckpoint ]["location"]
print("Rescue at: Car:", car, "Checkpoint:", car["checkpoint"])
# Sparkles on the new position
Distraction.particles("Sparkle", car.position,
despawn = random.randint(30, 100),
amount = 50,
max = 100,
spread = 2,
normal = 0.05,
scale = 5)
# Rotation the car based on the locations of checkpoints.
tocheck = car.getVectTo(nextcheckpoint)
car.alignAxisToVect(tocheck[1], 1, 1.0)
car.alignAxisToVect( (0,0,1), 2, 1.0 )
# Rotating the car 180 degrees since forward it -Y not Y.
rot = car.worldOrientation.to_euler()
car.worldOrientation = [rot[0], rot[1], rot[2]+math.pi]
# Adding the rotation of the previous checkpoint.
# if car.get("prevrescue"):
# tocheck = car.getVectTo(car.get("prevrescue"))
# car.alignAxisToVect(tocheck[1], 1, 0.7)
# car.alignAxisToVect( (0,0,1), 2, 1.0 )
# Putting the car a bit higher than the road.
car.position[2] += 2
car["launchtime"] = 200
car["nitro"] = max(1000, car["nitro"])
car["underwater"] = False
car["engine"] = 0
# Restoring the wheels.
for i in range(4):
#vehicle.setSuspensionStiffness(car.get("suspension", 200), i)
car["suspensions"][i] = car.get("suspension", 200)
vehicle.applyBraking(0, i)
vehicle.setTyreFriction(car.get("friction", 1), i)
vehicle.setRollInfluence(car.get("roll", 0), i)
bge.logic.globalDict[car["cid"]]["wheels"][i].setVisible(True)
for i in ["Front_Right", "Front_Left", "Back_Left", "Back_Right"]:
car[i] = max(0.8, car[i])
# Rescuing the active car in the race when pressing Backspace ( code 59 )
if carActive and dani.get("race") and dani.get("rescue") and ( ( car["speed"] > -0.02 and car["engine"] > 0.5 ) or engineHealth <= 0.2 or car["underwater"]):
#if carActive and dani.get("race") and dani.get("rescue") and 59 in bge.logic.globalDict["keys"] and car["launchtime"] <=0:
if not car.get("toresquetimer", 50):
nextcheckpoint = bge.logic.globalDict["races"][dani.get("race")]["checkpoints"][ ( dani.get("checkpoint") + 1 ) % len(bge.logic.globalDict["races"][dani.get("race")]["checkpoints"]) ]["location"]
car["rescue"] = dani["rescue"]
car["race"] = dani["race"]
car["checkpoint"] = dani["checkpoint"]
car["rescueTo"] = dani["rescueTo"]
car["prevrescue"] = dani["prevrescue"]
rescue()
car["toresquetimer"] = 50
else:
car["toresquetimer"] = car.get("toresquetimer", 50) -1
bge.logic.globalDict["cheat"] = [0]
###### NPC LOGIC #######
if car.get("npc") and bge.logic.globalDict["derby-cheat"]:
debryclosest = None
derbydistance = 1000
for i in scene.objects:
if "speed" in i and i != car:
idist = car.getDistanceTo(i)
if idist < derbydistance and car.rayCastTo(i.position) == i:
derbydistance = idist
debryclosest = i
if derbydistance < 10:
break
if debryclosest:
car["npc"] = "enemy"
car["enemy"] = debryclosest
## NPC PREPARATIONS ##
if car.get("npc"):
#### CAR VISION OF THE ROAD AND OBSTACLES ####
# To make the vision work we are going to use Ray Casting
# but instead of doing a whole path tracing thing to see
# everything in front of the car ( which you be slow )
# instead we trace only 5 specifically chosen points.
# Each car model has those 5 points positioned by hand
# in respecive car blend files. Those 5 points are.
left = 50 # To the forward - left diagonal \
# } On the height of the car
right = 50 # To the forward - right diagonal /
leftf = 50 # To the forward - left diagonal \
# } Slightly lower than the car ( to scan road )
rightf = 50 # To the forward - right diagonal /
forward = 50 # Directly in front of the car.
forwardData = None # Data of the ray casting for the forward.
leftm = "" # Material on the left of the car
rightm = "" # Material on the right of the car
# Each ray has it's default value be 50. During ray casting, the value will
# change to the distance of whatever the car "sees". If it sees nothing, the
# values will stay 50.
# Few more things to consider.
road = "Track2" # Material of the road ( to ignore )
separator = "Track_light" # Material of the separator line ( drawn in the middle of the road ).
separator_object = "Separation" # Name of an invisible object sticking out of this separator line.
# Left, slightly lower ray
ray = car.rayCast(car.children["Left"], car, poly=True)
# rayCast returns a list of values [ Hit Object , Hit Location, Hit Angle, Hit Polygon ]
# If we have any hit object ( exluding the road separator line if the car is a racing npc )
if ray[1] and ( not carRacing or not str(ray[0]) == separator_object ):
# Excluding if the Polygon's material is road material
if not ray[3] or road not in str(ray[3].material):
# Getting the distance to the hit location and storing it as both
left = car.getDistanceTo(ray[1]) # left and
leftf = left # leftf
try: leftm = str(ray[3].material)# And storing the material name for later
except: pass
# Doing something similar to the left point on the same heigh as the car
ray = car.rayCast(car.children["Left.001"],car, poly=True)
if ray[1] and ( not carRacing or not str(ray[0]) == separator_object ):
if not ray[3] or road not in str(ray[3].material):
# Only instead of doing the complex appending, we only
# overwrite the left variable, if the distance is lower.
# Basically left will end up the closest visible point from
# the left of the car. And leftf will be the original left.
left = min(car.getDistanceTo(ray[1]), left)
# Doing something similar for the right side as well
ray = car.rayCast(car.children["Right"],car, poly=True)
# Only now we exclude the separator line regardless if it
# is a racer or not. So if the car ends up on the wrong
# side of the road and goes British, it could find its way
# back to the right side of the road.
if ray[1] and not str(ray[0]) == separator_object:
if not ray[3] or road not in str(ray[3].material) :
right = car.getDistanceTo(ray[1])
rightf = right
try: rightm = str(ray[3].material)
except: pass
# And we slightly enfoce it to go to the right side of
# the road. By folling it to think that there is something
# of the left.
elif not carRacing and str(ray[0]) == separator_object:
left = min(car.getDistanceTo(ray[1]), left)
# And now for the slightly higher point on the right.
ray = car.rayCast(car.children["Right.001"],car, poly=True)
if ray[1] and not str(ray[0]) == separator_object:
if not ray[3] or road not in str(ray[3].material):
right = min(car.getDistanceTo(ray[1]), right)
elif not carRacing and str(ray[0]) == separator_object:
left = min(car.getDistanceTo(ray[1]), left)
# And for the forward.
ray = car.rayCast(car.children["Forward"],car, poly=True)
forwardData = ray
if ray[1] and str(ray[0]) == separator_object:
if not ray[3] or road not in str(ray[3].material):
forward = car.getDistanceTo(ray[1])
# Minimum value will be the smallest distance out of all of them
# which is useful for all sorts of things.
minimum = min(left, right, forward)
# And now we calculate how much the car needs to actually turn.
turn = max(-0.8, min(0.8, (( max(0, min(1, (right/12))) - max(0, min(1, (left/12))) ) *-2 )))
## NORMAL NPC CARS ##
if car.get("npc") == "npc":
# Normal NPC cars are those you can see driving around the city
# at a regular speed.
# Activate enemy logic when pursuit cheat is enabled
if distanceToCam < 100 and bge.logic.globalDict["pursuit-cheat"]:
car["npc"] = "enemy"
for i in scene.objects:
if i.get("active"):
car["enemy"] = i
break
# Applying the turn calculated in vision step
car["turn"] = turn
# Accelerating the car, with the target speed based on distance
# to the closest seen point.
targetSpeed = 4 * ((minimum/12)-0.4)
# We also ignore target speed, and make the car drive as fast
# as it can, when it is chased by somebody.
if (sp < targetSpeed or car.get("chased")) and minimum > 2:
accelerate(car)
else:
deccelerate(car)
# To help it avoid obstacles better.
if minimum < 2 and car.get("accelerating"):
car["turn"] = -0.8
# If we about to hit a car head first
if forwardData[0] and forwardData[0].get("speed"):
turn = max(-0.8, min(0.8, turn*10))
car["engine"] = car["speed"]*10
# Cliffs
# turnback = True
# if rot[0] > 0.1 and not car.get("chased"):
# accelerate(car)
# elif rot[0] < -0.9 and sp < 0.9 and onGround:
# car.applyForce([0,-20, 0], True)
# turnback = False
#
#
#
# if minimum < 5:
# deccelerate(car)
# if 0.9 < turn or turn < -0.9:
# car["turn"] = turn *-1
# car.applyTorque([0.0,0.0,turn*-30],1)
#
# elif turnback:
# car["turn"] = 0.3
# car.applyTorque([0.0,0.0,car["turn"]*30],1)
#
# if "launchtime" not in car:
# car["launchtime"] = 300
# car["launchtime"] -= 1
# if 0.03 > sp and ( car["engine"] / max(0.1, engineHealth) > 1 ) and car["launchtime"] < 0:
# if not rot[0] < -0.1 and (leftm or rightm):
# car.applyTorque([0.0,0.0,50],1)
# car.position[2] += 0.05
#
#
# if sp > 2.8 and (0.3 < turn or turn < -0.3):
# for i in range(4):
# vehicle.applyEngineForce(car["speed"]*5* toFPS, i)
# if sp < 0: sp *= -1
# car.applyTorque([0.0,0.0,car["turn"]*sp*5* toFPS],1)
#
#for i in range(4):
# vehicle.applyEngineForce(car["engine"], i)
## ANGRY CARS GUIDED TO A POINT ##
elif car.get("npc") == "enemy" or ( car.get("npc") == "racer" and car.get("racing")):
# If racing
if car.get("npc") == "racer":
checkpoint = bge.logic.globalDict["races"][car.get("race")]["checkpoints"][car.get("checkpoint")].copy()
if "raceData" in bge.logic.globalDict["races"][car.get("race")]:
raceData = bge.logic.globalDict["races"][car.get("race")]["raceData"]
targetTime = raceData["times"][car["checkpoint"]]
try: prevTime = raceData["times"][car["checkpoint"]-1]
except: prevTime = 0
lastCheckPointTime = car.get("last-checkpoint-time", bge.logic.globalDict["races"][car.get("race")]["start-time"])
currentTime = bge.logic.getRealTime() - bge.logic.globalDict["races"][car.get("race")]["start-time"]
targetTimeToCheckpoint = targetTime - prevTime
currentTimeToCheckpoint = currentTime - lastCheckPointTime
else:
targetTimeToCheckpoint = 1
currentTimeToCheckpoint = 1
car["enemy"] = checkpoint["location"]
# If the racing bot is following the player, it will mimic the player
#racePositions = bge.logic.globalDict["races"][car.get("race")].get("positions", [dani, car])
#if dani in racePositions and dani.get("driving") != car and racePositions.index(dani) < racePositions.index(car):
# car["enemy"] = dani["driving"]
# If reached checkpoint
if car.getDistanceTo(car["enemy"]) < checkpoint["radius"]:
if not checkpoint.get("OnLoop"):
car["prevrescue"] = car["rescue"]
car["rescue"] = checkpoint["location"]
car["rescueTo"] = car["checkpoint"]
# Printing if the bot is on time
if "raceData" in bge.logic.globalDict["races"][car.get("race")]:
car["last-checkpoint-time"] = currentTime
print("Race Time of [", car, "]:", round(currentTimeToCheckpoint, 2), round(targetTimeToCheckpoint - currentTimeToCheckpoint, 2))
# Calibrating the stopping distance
if checkpoint.get("Uturn"):
targetSpeed = -checkpoint.get("Uturn") * toFPS
car["stopdistance"] = car.get("stopdistance", -18) * ( car["speed"] / targetSpeed )
print("Race Stopping Calibration [", car, "]:", car.get("stopdistance", -18), int( ( car["speed"] / targetSpeed ) * 100), "%")
car["checkpoint"] = car["checkpoint"]+1
car["launchtime"] = 50
try:
car["distanceBetweenCheckpoints"] = car.getDistanceTo(bge.logic.globalDict["races"][car.get("race")]["checkpoints"][car.get("checkpoint")]["location"])
except:
pass
# If finished lap
if car.get("checkpoint") == len(bge.logic.globalDict["races"][car.get("race")]["checkpoints"]):
print(car, "LAP")
car["checkpoint"] = 0
car["lap"] += 1
# If finished race
if car["lap"] == bge.logic.globalDict["races"][car.get("race")]["laps"]:
car["racing"] = False
car["npc"] = ""
bge.logic.globalDict["print"] = raceNames.get(car.name, car.name) + " finished race!"
# Making rescuing less sensitive when passing a Uturn
if bge.logic.globalDict["races"][car.get("race")]["checkpoints"][car.get("checkpoint")].get("Uturn"):
car["launchtime"] = 500
nextcheckpoint = bge.logic.globalDict["races"][car.get("race")]["checkpoints"][ ( car.get("checkpoint") + 1 ) % len(bge.logic.globalDict["races"][car.get("race")]["checkpoints"]) ]["location"]
tonextcheckpoint = car.getVectTo(nextcheckpoint)
# Moving the indicator
car["beam"].position = car.position
car["beam"].position[2] += 1
tocam = car["beam"].getVectTo(cam)
car["beam"].alignAxisToVect(tocam[1], 1, 1.0)
car["beam"].alignAxisToVect( (0,0,1), 2, 1.0 )
beamscale = max( 0.2, car.getDistanceTo(dani) / 100 )
car["beam"].scaling = [beamscale, beamscale, beamscale]
try:
toenemy = car.getVectTo(car.get("enemy", dani))
if car.get("npc") == "enemy" and sum([car["enemy"].get("Front_Right"), car["enemy"].get("Front_Left"), car["enemy"].get("Back_Right"), car["enemy"].get("Back_Left")])/4 < 0.2:
car["npc"] = "npc"
car["enemy"] = ""
except:
car["npc"] = "npc"
car["enemy"] = ""
return
enemyturn = min(0.8, toenemy[2][0]*2)
onenemy = toenemy[2][1] *-1
oldenemyturn = enemyturn
onoldenemy = onenemy
# If we are too slow. NITRO
if car.get("npc") == "racer":
betweencheckpoints = car.get("distanceBetweenCheckpoints", toenemy[0]) - checkpoint["radius"]
fractionDistance = 1 - (toenemy[0] / betweencheckpoints)
if ( currentTimeToCheckpoint * 1.2 > targetTimeToCheckpoint * fractionDistance or onenemy > 0.6 ) and not car.get("deccelerating") and onGround:
nitro()
else:
stopNitro()
try:
tonext = 1-min(1, toenemy[0]/(car["speed"]*-50) ) ** 0.2
except:
tonext = 0
if type(tonext) == complex:
tonext = float(tonext.real)
targetSpeed = 0
if car.get("npc") == "racer":
if "raceData" in bge.logic.globalDict["races"][car.get("race")]:
raceData = bge.logic.globalDict["races"][car.get("race")]["raceData"]
checkpoint["Uturn"] = raceData["targetSpeed"][car.get("checkpoint")]
if checkpoint.get("Uturn"):
# At current configuration car looses 1 speed at about 12.2 units of distance
targetSpeed = -checkpoint.get("Uturn") * toFPS
brakingDistance = ( car["speed"] - targetSpeed ) * -18# car.get("stopdistance", -18)
if toenemy[0] <= brakingDistance and car["speed"] < targetSpeed:
deccelerate(car)
# We want to record the stopdistance
# if targetSpeed <= car["speed"]:
# car["stopdistance"] = car.get("stopdistance", -18) + toenemy[0]
# print(car, "stopdistance Calibrated at:", car["stopdistance"])
# elif car["speed"] > targetSpeed and onenemy > 0.8:
# nitro()
if onenemy > 0.7 and minimum > 7:
nextenemyturn = min(0.8, tonextcheckpoint[2][0]*2)
nextonenemy = tonextcheckpoint[2][1] *-1
enemyturn = enemyturn + ( ( nextenemyturn - enemyturn ) * tonext )
onenemy = onenemy + ( ( nextonenemy - onenemy ) * tonext )
if type(onenemy) == complex:
onenemy = float(onenemy.real)
enemyturn = float(enemyturn.real)
if car["speed"] > -0.2 or engineHealth <= 0.2 or car["underwater"]:# or onenemy < 0.4:
rescue()
smartturn = ( turn * onoldenemy ) + ( oldenemyturn * onenemy) + ( enemyturn ) / ( onoldenemy + onenemy + 1)
#if onenemy < 0.6:
# smartturn = oldenemyturn
#if toenemy[0] < 60:
#smartturn = enemyturn
#if onenemy < 0.9:
# smartturn = enemyturn
#if onoldenemy < 0.7:
# smartturn = oldenemyturn
# If we about to hit a car head first
#if forwardData[0] and forwardData[0].get("speed"):
# handbreak(car)
# turn = max(-0.8, min(0.8, turn*-1000))
# smartturn = turn
if (( minimum < 10 and onenemy > 0.3 ) or ( minimum < 5 and onenemy > 0.1 )) and toenemy[0] > 50:
smartturn = turn
if minimum < 7:
car["turn"] = max(-0.5, min( 0.8 , car["turn"] * 1.5 ))
if carRacing: angleAt = -0.7
else: angleAt = 0
if onenemy > angleAt:
car["turn"] = smartturn
t = car["turn"]
if t < 0: t *= -1
# If we turning, turn harder
if t > 0.3 and car["speed"] < -1:
car["turn"] *= 3
# If we are turning hard enough, drift
#if t > 0.4 and car["speed"] < -2 and car["speed"] < targetSpeed / 2:
# handbreak(car)
# If we are turning very hard, use breaks
if t > 0.4 and car["speed"] < -1.5 and car["speed"] < targetSpeed:
deccelerate(car)
if not car.get("deccelerating"):
accelerate(car)
else:
if car.get("npc") == "racer":
rescue()
car["turn"] = enemyturn *-1
deccelerate(car)
#for i in range(4):
# vehicle.applyEngineForce(car["engine"], i)
################### APPLYING ##########################
# This is here to trigger an error for if car's object
# has been deleted from the game during the execution
# of this script. Otherwise, applying things to the vehicle
# constraints might result in Segmentation Fault ( the engine
# crashing ).
car.position
# Auto deceleration
if not car.get("accelerating") and car["engine"] > 0:
car["engine"] -= car.get("maxaccel",2) * toFPS
elif not car.get("accelerating") and car["engine"] < 0:
car["engine"] += car.get("maxaccel",2) * toFPS
else:
car["accelerating"] = False
# Auto going straiter
if not car.get("turning"):
car["turn"] *= 0.5 ** toFPS
else:
car["turning"] = False
ApplyEnginePower(car, vehicle)
# if not car.get("deccelerating"):
# minusfrac = 1
# if car["engine"] < 0: minusfrac = -1
# applyforce = math.log1p(car["engine"]*minusfrac) / 4
# if -0.05 < applyforce < 0.05:
# applyforce = 0
# else:
# #applyforce = Opt.Force(applyforce**0.1*3*minusfrac)
# applyforce = Opt.Force(HorsePowerToNewton(applyforce))*minusfrac
#
# if car.get("nitroing"):
# applyforce *= Opt.Force(0.3)
#
# vehicle.applyEngineForce(applyforce*car["Back_Left"], 0)
# vehicle.applyEngineForce(applyforce*car["Back_Right"], 1)
# vehicle.applyEngineForce(0, 2)
# vehicle.applyEngineForce(0, 3)
if not car.get("nitroing"):
car["engine"] = min( car.get("maxengine", 800)*engineHealth, max( -car.get("maxengine", 800)*engineHealth, car["engine"]))
else:
car["nitroing"] = False
if car.get("deccelerating"):
car["deccelerating"] = False
# Making sure the car is not turning more than it is possible.
car["turn"] = max(-0.8, min(0.8, car["turn"]))
# Suspension updates ( important due to FPS flactuations )
ApplySuspension(car, vehicle)
# Turning Force Update
vehicle.setSteeringValue(car["turn"]*car["Front_Left"] , 2)
vehicle.setSteeringValue(car["turn"]*car["Front_Left"] , 3)
# Adding fake torque to the car, to make it easier to turn
#if carSpeed < -0.05 and onGround:
# car.applyTorque([0.0,0.0,Opt.Force(car["turn"]*10)],1)
#elif carSpeed > 0.05 and onGround:
# car.applyTorque([0.0,0.0,Opt.Force(car["turn"]*-10)],1)
def ApplySuspension(car, vehicle):
for i in range(4):
suspension = car["suspensions"][i] / 100
suspense = Opt.Force(suspension*car.mass)
damping = 0.3
vehicle.setSuspensionCompression(1, i)
vehicle.setSuspensionStiffness(suspense, i)
vehicle.setSuspensionDamping(1, i)
def ApplyEnginePower(car, vehicle):
if not car.get("deccelerating"):
# minusfrac = 1
# if car["engine"] < 0: minusfrac = -1
# applyforce = math.log1p(car["engine"]*minusfrac) / 4
# if -0.05 < applyforce < 0.05:
# applyforce = 0
# else:
# #applyforce = Opt.Force(applyforce**0.1*3*minusfrac)
# applyforce = Opt.Force(HorsePowerToNewton(applyforce))*minusfrac
#
# if car.get("nitroing"):
# applyforce *= Opt.Force(0.3)
# Getting car's horse power
horses = car.get("horses", 750)
rpm = car["engine"]
maxrpm = car.get("maxengine", 800)
horses = EngineCurve(rpm, maxrpm, horses)
if car["active"]:
print(horses)
applyforce = Opt.Force(HorsePowerToNewton(horses / 2000))
vehicle.applyEngineForce(0, 0)
vehicle.applyEngineForce(0, 1)
vehicle.applyEngineForce(applyforce*car["Front_Left"], 2)
vehicle.applyEngineForce(applyforce*car["Front_Left"], 3)
def HorsePowerToNewton(value):
return value * 745.6998715823
def EngineCurve(rpm, maxrpm, horses):
# This function draws a simulated
# Engine RPM curve and outputs
# house power.
return math.sin(rpm/maxrpm*(math.pi/4*3))*horses
def accelerate(car):
if type(car) == bge.types.SCA_PythonController:
cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
car = cont.owner
if not car["active"]:
return
toFPS = Opt.ToFPS()
vehicle = bge.constraints.getVehicleConstraint(car["cid"])
car["engine"] += car.get("maxaccel",2) * toFPS
if car["engine"] > 0 and car["speed"] <= 0.2:
car["accelerating"]= True
else:
car["engine"] *= 0.95 ** toFPS
car["deccelerating"]= True
for i in range(4):
vehicle.applyEngineForce(Opt.Force(car["speed"]*5*car.mass), i)
def deccelerate(car):
if type(car) == bge.types.SCA_PythonController:
cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
car = cont.owner
if not car["active"]:
return
toFPS = Opt.ToFPS()
vehicle = bge.constraints.getVehicleConstraint(car["cid"])
car["engine"] -= car.get("maxaccel",0.003) * toFPS
if car["engine"] < 0 and car["speed"] >= -0.2:
car["accelerating"]= True
else:
car["engine"] *= 0.95 ** toFPS
car["deccelerating"]= True
for i in range(4):
vehicle.applyEngineForce(Opt.Force(car["speed"]*5*car.mass), i)
def turn():
cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
car = cont.owner
if not car["active"]:
return
toFPS = Opt.ToFPS()
if car["turn"] < 0: car["turn"] = 0
car["turn"] += 0.005 * toFPS
car["turning"]= True
def unturn():
cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
car = cont.owner
if not car["active"]:
return
toFPS = Opt.ToFPS()
if car["turn"] > 0: car["turn"] = 0
car["turn"] -= 0.005 * toFPS
car["turning"]= True
def handbreak(car):
if type(car) == bge.types.SCA_PythonController:
cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
car = cont.owner
if not car["active"]:
return
toFPS = Opt.ToFPS()
vehicle = bge.constraints.getVehicleConstraint(car["cid"])
for i in range(4):
vehicle.applyEngineForce(Opt.Force(car["speed"]*2*car.mass), i)
car["deccelerating"]= True
sp = car["speed"]
if sp < 0: sp *= -1
car.applyTorque([0.0,0.0,Opt.Force(car["turn"]*sp*2*car.mass)],1)
def get_in():
return
# This function has been moved to Character Controlls