1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
|
#!/usr/bin/python
__author__ = "Fireclaw the Fox"
__license__ = """
Simplified BSD (BSD 2-Clause) License.
See License.txt or http://opensource.org/licenses/BSD-2-Clause for more info
"""
# Python imports
import os
# Panda3D imoprts
from direct.showbase.ShowBase import ShowBase
from direct.fsm.FSM import FSM
from direct.gui.DirectGui import DGG
from panda3d.core import (
AntialiasAttrib,
ConfigPageManager,
ConfigVariableInt,
ConfigVariableBool,
ConfigVariableString,
OFileStream,
WindowProperties,
loadPrcFileData,
loadPrcFile,
Filename)
# Game imports
#TODO: Put your game imports here
#
# PATHS AND CONFIGS
#
# set company and application details
companyName = "Your Companies Name"
appName = "Game Name"
versionstring = "19.07"
# build the path from the details we have
home = os.path.expanduser("~")
basedir = os.path.join(
home,
companyName,
appName)
if not os.path.exists(basedir):
os.makedirs(basedir)
# look for a config file
prcFile = os.path.join(basedir, "{}.prc".format(appName))
if os.path.exists(prcFile):
mainConfig = loadPrcFile(Filename.fromOsSpecific(prcFile))
# set configurations that should not be changed from a config file
loadPrcFileData("",
"""
#
# Model loading
#
model-path $MAIN_DIR/assets/
#
# Window and graphics
#
window-title {}
#show-frame-rate-meter 1
#
# Logging
#
#notify-level info
notify-timestamp 1
""".format(appName))
#
# MAIN GAME CLASS
#
class Main(ShowBase, FSM):
"""Main function of the application
initialise the engine (ShowBase)"""
def __init__(self):
"""initialise the engine"""
ShowBase.__init__(self)
base.notify.info("Version {}".format(versionstring))
FSM.__init__(self, "FSM-Game")
#
# BASIC APPLICATION CONFIGURATIONS
#
# disable pandas default camera driver
self.disableMouse()
# set antialias for the complete sceen to automatic
self.render.setAntialias(AntialiasAttrib.MAuto)
# shader generator
render.setShaderAuto()
# Enhance font readability
DGG.getDefaultFont().setPixelsPerUnit(100)
# get the displays width and height for later usage
self.dispWidth = self.pipe.getDisplayWidth()
self.dispHeight = self.pipe.getDisplayHeight()
#
# CONFIGURATION LOADING
#
# load given variables or set defaults
# check if particles should be enabled
# NOTE: If you use the internal physics engine, this always has
# to be enabled!
particles = ConfigVariableBool("particles-enabled", True).getValue()
if particles:
self.enableParticles()
def setFullscreen():
"""Helper function to set the window fullscreen
with width and height set to the screens size"""
# set window properties
# clear all properties not previously set
base.win.clearRejectedProperties()
# setup new window properties
props = WindowProperties()
# Fullscreen
props.setFullscreen(True)
# set the window size to the screen resolution
props.setSize(self.dispWidth, self.dispHeight)
# request the new properties
base.win.requestProperties(props)
# Set the config variables so we correctly store the
# new size and fullscreen setting later
winSize = ConfigVariableString("win-size")
winSize.setValue("{} {}".format(self.dispWidth, self.dispHeight))
fullscreen = ConfigVariableBool("fullscreen")
fullscreen.setValue(True)
# Render a frame to make sure the fullscreen is applied
# before we do anything else
self.taskMgr.step()
# make sure to propagate the new aspect ratio properly so
# the GUI and other things will be scaled appropriately
aspectRatio = self.dispWidth / self.dispHeight
self.adjustWindowAspectRatio(aspectRatio)
# check if the config file hasn't been created
if not os.path.exists(prcFile):
setFullscreen()
# automatically safe configuration at application exit
base.exitFunc = self.__writeConfig
#
# INITIALIZE GAME CONTENT
#
#TODO: put game content initialization here
#
# EVENT HANDLING
#
# By default we accept the escape key
self.accept("escape", self.__escape)
#
# ENTER GAMES INITIAL FSM STATE
#
#TODO: Change this to any state you want the game to start with
self.request("Game")
#
# FSM PART
#
def enterGame(self):
# main game logic should be started here
pass
def exitGame(self):
# cleanup for game code
pass
#
# FSM PART END
#
#
# BASIC FUNCTIONS
#
def __escape(self):
"""Handle user escape key klicks"""
if self.state == "Game":
# In this state, we will stop the application
self.userExit()
else:
# In every other state, we switch back to the Game state
self.request("Game")
def __writeConfig(self):
"""Save current config in the prc file or if no prc file exists
create one. The prc file is set in the prcFile variable"""
page = None
#
#TODO: add any configuration variable names that you have added
# to the dictionaries in the next lines. Set the current
# configurations value as value in this dictionary and it's
# name as key.
configVariables = {
# set the window size in the config file
"win-size": ConfigVariableString("win-size", "{} {}".format(self.dispWidth, self.dispHeight)).getValue(),
# set the default to fullscreen in the config file
"fullscreen": "#t" if ConfigVariableBool("fullscreen", True).getValue() else "#f",
# particles
"particles-enabled": "#t" if self.particleMgrEnabled else "#f",
# audio
"audio-volume": str(round(self.musicManager.getVolume(), 2)),
"audio-music-active": "#t" if ConfigVariableBool("audio-music-active").getValue() else "#f",
"audio-sfx-active": "#t" if ConfigVariableBool("audio-sfx-active").getValue() else "#f",
# logging
"notify-output": os.path.join(basedir, "game.log"),
# window
"framebuffer-multisample": "#t" if ConfigVariableBool("framebuffer-multisample").getValue() else "#f",
"multisamples": str(ConfigVariableInt("multisamples", 8).getValue()),
"texture-anisotropic-degree": str(ConfigVariableInt("texture-anisotropic-degree").getValue()),
"textures-auto-power-2": "#t" if ConfigVariableBool("textures-auto-power-2", True).getValue() else "#f",
}
page = None
# Check if we have an existing configuration file
if os.path.exists(prcFile):
# open the config file and change values according to current
# application settings
page = loadPrcFile(Filename.fromOsSpecific(prcFile))
removeDecls = []
for dec in range(page.getNumDeclarations()):
# Check if our variables are given.
# NOTE: This check has to be done to not loose our base
# or other manual config changes by the user
if page.getVariableName(dec) in configVariables.keys():
removeDecls.append(page.modifyDeclaration(dec))
for dec in removeDecls:
page.deleteDeclaration(dec)
else:
# Create a config file and set default values
cpMgr = ConfigPageManager.getGlobalPtr()
page = cpMgr.makeExplicitPage("Application Config")
# always write custom configurations
for key, value in configVariables.items():
page.makeDeclaration(key, value)
# create a stream to the specified config file
configfile = OFileStream(prcFile)
# and now write it out
page.write(configfile)
# close the stream
configfile.close()
#
# BASIC END
#
# CLASS Main END
#
# START GAME
#
Game = Main()
Game.run()
|