DanisRace/Scripts/LEGACY_Car_controll.py

1770 lines
65 KiB
Python
Raw Normal View History

2024-07-13 15:15:50 +02:00
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