Making a highly customizable method, or a specific method that does a task? - structure

I'm not really sure how I would phrase the title right, so I apologize for the initial confusion.
This is just a small question I had about how to structure code and such and I have no idea on what to call it so I will explain it with this example:
Say I am writing a Call of Duty type game where the player can customize their weapons with certain attachment.
I have a class that defines each gun. It looks something like this:
class Gun {
int clip = 30;
int ammo = 100;
float reloadTime = 5f;
float damage = 10f;
Attachment[] attachments;
//Plus some not included attachments.
void shoot() {
//...
}
void reload() {
//...
}
void applyAllAttachments() {
//Apply the list of attachments' effects
}
}
class Attachment {
void effect() {
//change the gun in some way.
}
}
Now I would like to add 4 attachments, Fast Mags (increase reload speed), Hollow Point (increase damage), Grenade Launcher (Secondary Gun) and Minigun (Replace the barrel with a minigun or something).
For the Fast Mags and the Hollow Point, it should be simple, all I have to do is change a number or a value, but for the Grenade Launcher and Minigun, which have custom, extra functions (like Unity Delegates), would it be wiser to add a function that handles external custom firing types, or would it be better to just have separate methods inside the Gun class that specifically handle to extra minigun functions?
TL;DR
If I want to add a grenade launcher attachment to a gun, should I do this:
class Gun {
int clip = 30;
int ammo = 100;
float reloadTime = 5f;
float damage = 10f;
Attachment[] attachments = Attachment[10];
//Plus some not included attachments.
void shoot() {
//...
customShoot();
}
void customShoot() {
//Apply attachments custom attachment shoot methods.
}
void reload() {
//...
}
void applyAllAttachments() {
//Apply the list of attachments' effects
}
}
class GrenadeLauncher extends Attachment {
#Override
public void effect() {
//Spawn new grenade
}
}
Or This:
class Gun {
int clip = 30;
int ammo = 100;
float reloadTime = 5f;
float damage = 10f;
Attachment[] attachments = Attachment[10];
//Plus some not included attachments.
void shoot() {
//...
if (attachments.GetType() == GrenadeLauncher) {
grenadeLauncherShoot();
}
}
void grenadeLauncherShoot() {
}
void reload() {
//...
}
void applyAllAttachments() {
//Apply the list of attachments' effects
}
}
Sorry for my pseudo/java code, hope it's comprehensible.

The first way is better: You can create new attachments without having to modify the Gun class.
In a general manner, you shouldn't need to check for type, and your code will be cleaner if you don't.
Here, your Attachment class should be abstract (I suppose it already is), and force children to implements some functions.
public abstract class Attachment
{
protected abstract void shoot();
}
Then the gun calls it for all Attachements:
class Gun {
int clip = 30;
int ammo = 100;
float reloadTime = 5f;
float damage = 10f;
Attachment[] attachments = Attachment[10];
//Plus some not included attachments.
void shoot() {
//...
for(int i = 0; i < attachments.length(); ++i) {
attachments[i].shoot();
}
}
void reload() {
//...
}
}
class GrenadeLauncher extends Attachment {
#Override
public void shoot()
{
//Spawn new grenade
}
}
By the way, why did you tag java and Unity? If you work with unity your code should be c# or javascript

Related

Trying to make Unending Boundaries In a Runner Game

Trying to make a runner game. I don't want my character to fall off the edge of the map. How do I make the character always center of the path? I want to make so that my character is always center of the path as it is being instantiated and to never fall off the map.
public class GroundTile : MonoBehaviour
{
GroundSpawner groundSpawner;
// Start is called before the first frame update
private void Start()
{
groundSpawner = GameObject.FindObjectOfType<GroundSpawner>();
}
private void OnTriggerExit (Collider other)
{
groundSpawner.SpawnTile();
Destroy(gameObject, 2);
}
// Update is called once per frame
void Update()
{
}
}
public class GroundSpawner : MonoBehaviour
{
public GameObject groundTile;
Vector3 nextSpawnPoint;
// Start is called before the first frame update
public void SpawnTile()
{
GameObject temp = Instantiate(groundTile, nextSpawnPoint, Quaternion.identity);
nextSpawnPoint = temp.transform.GetChild(1).transform.position;
}
private void Start()
{
for (int i = 0; i < 10; i++)
{
SpawnTile();
}
}
}
I tried so many methods.

Unable to identify where a NullPointerException is coming from

so I am getting the following error:
Exception in thread "Thread-0" java.lang.NullPointerException
at dev.tamir.firstgame.entities.creatures.Player.getInput(Player.java:19)
at dev.tamir.firstgame.entities.creatures.Player.tick(Player.java:31)
at dev.tamir.firstgame.states.GameState.tick(GameState.java:25)
at dev.tamir.firstgame.Game.tick(Game.java:65)
at dev.tamir.firstgame.Game.run(Game.java:110)
at java.lang.Thread.run(Unknown Source)
And I've checked all the lines Java had marked me and I can not find what is producing the null.
Player:
package dev.tamir.firstgame.entities.creatures;
import java.awt.Graphics;
import dev.tamir.firstgame.Game;
import dev.tamir.firstgame.gfx.Assets;
public class Player extends Creature {
private Game game;
public Player(Game game, float x, float y) {
super(game, x, y, Creature.DEFAULT_CREATURE_WIDTH, Creature.DEFAULT_CREATURE_HEIGHT);
}
#Override
public void tick() {
getInput();
move();
game.getGameCamera().centerOnEntity(this);
}
private void getInput() {
xMove = 0;
yMove = 0;
if(game.getKeyManager().up)
yMove = -speed;
if(game.getKeyManager().down)
yMove = speed;
if(game.getKeyManager().left)
xMove = -speed;
if(game.getKeyManager().right)
xMove = speed;
}
#Override
public void render(Graphics g) {
g.drawImage(Assets.robro[7], (int) (x - game.getGameCamera().getxOffset()), (int) (y - game.getGameCamera().getyOffset()), width, height, null);
}
}
Gamestate:
package dev.tamir.firstgame.states;
import java.awt.Graphics;
import dev.tamir.firstgame.Game;
import dev.tamir.firstgame.entities.creatures.Player;
import dev.tamir.firstgame.tiles.Tile;
import dev.tamir.firstgame.worlds.World;
public class GameState extends State {
private Player player;
private World world;
public GameState(Game game) {
super(game);
player = new Player(game, 0, 0);
world = new World(game, "res/worlds/world1.txt");
}
#Override
public void tick() {
world.tick();
player.tick();
}
#Override
public void render(Graphics g) {
world.render(g);
player.render(g);
}
}
Game:
package dev.tamir.firstgame;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import dev.tamir.firstgame.Display.Display;
import dev.tamir.firstgame.gfx.Assets;
import dev.tamir.firstgame.gfx.GameCamera;
import dev.tamir.firstgame.input.KeyManager;
import dev.tamir.firstgame.states.GameState;
import dev.tamir.firstgame.states.MenuState;
import dev.tamir.firstgame.states.State;
public class Game implements Runnable {
private Display display;
private Thread thread;
private BufferStrategy bs;
private Graphics g;
//States
private State gameState;
private State menuState;
//Input
private KeyManager keyManager;
//Camera
private GameCamera gameCamera;
private boolean running = false;
private int width, height;
public String title;
public Game(String title, int width, int height) {
this.width = width;
this.height = height;
this.title = title;
keyManager = new KeyManager();
}
private void init() {
display = new Display(title, width, height);
display.getFrame().addKeyListener(keyManager);
Assets.init();
gameCamera = new GameCamera(this, 0,0);
gameState = new GameState(this);
menuState = new MenuState(this);
State.setState(gameState);
}
private void tick() {
keyManager.tick();
if(State.getState() != null)
State.getState().tick();
}
private void render() {
bs = display.getCanvas().getBufferStrategy();
if(bs == null) {
display.getCanvas().createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
//Clear
g.clearRect(0, 0, width, height);
//Draw
if(State.getState() != null)
State.getState().render(g);
//End of Draw
bs.show();
g.dispose();
}
public void run() {
init();
int fps = 60;
double timePerTick = 1000000000 / fps;
double delta = 0;
long now;
long lastTime = System.nanoTime();
long timer = 0;
int ticks = 0;
while (running) {
now = System.nanoTime();
delta += (now - lastTime) / timePerTick;
timer += now - lastTime;
lastTime = now;
if(delta >= 1) {
tick();
render();
ticks++;
delta--;
}
if(timer >= 1000000000) {
System.out.println("FPS: " + ticks );
ticks = 0;
timer = 0;
}
}
stop();
}
public KeyManager getKeyManager() {
return keyManager;
}
public GameCamera getGameCamera() {
return gameCamera;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public synchronized void start() {
if (running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop() {
if (!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
help would be very appreciated, as I've been looking for hours now and I don't know what is causing the null and I am suspecting the error log may even be misleading me.
My guess would be you have a private Game in your creature class. When you call super() in Player, you pass a Game object to Creature. The Creature constructor most likely has a line like this.game = game;
Of course, I can't say for sure because the Creature class is not included in your post, but that's the most likely code setup. Because game would then be private to Creature, Player cannot see it. That means the private Game game that you declare in Player is never set.
After you call super, do this.game = game;
This will almost certainly take care of your issue.
Just for future reference, the message you got when the error resulted is the call stack; basically it tells you what methods called what, the most recent being at the top. The error took place at line 19 in Player.getInput(), which was called by tick() in that same class.
The only object you use in getInput() is game, and so that must be the source of the null pointer. From there, it's a quick check to see that game is a private field of Player, and since it is null that's a huge clue that it was never initialized (though that is not always the case). Private fields most often are initialized in the class constuctor (but they don't have to be... your Player class is pretty sparse so it wouldn't take that long to look through all of it if you absolutly had to. Looking at the Player constructor, we see a Game object named game is passed in, which suggests that it was intended to be used to initialize game and yet never is. VoilĂ , we found the problem!
I'm sorry if that last paragraph felt a little condecending; it wasn't meant to be. I just wanted to walk you through how I found your issue. Hopefully knowing how I found it will help you find later errors on your own.

How to replace / remove text from a PDF file

How would I go about replacing / removing text from a PDF file?
I have a PDF file that I obtained somewhere, and I want to be able to replace some text within it.
Or, I have a PDF file that I want to obscure (redact) some of the text within it so that it's no longer visible [and so that it looks cool, like the CIA files].
Or, I have a PDF that contains global Javascript that I want to stop from interrupting my use of the PDF.
This is possible in a limited fashion with the use of iText / iTextSharp.
It will only work with Tj/TJ opcodes (i.e. standard text, not text embedded in images, or drawn with shapes).
You need to override the default PdfContentStreamProcessor to act on the page content streams, as presented by Mkl here Removing Watermark from PDF iTextSharp. Inherit from this class, and in your new class look for the Tj/TJ opcodes, the operand(s) will generally be the text element(s) (for a TJ this may not be straightforward text, and may require further parsing of all the operands).
A pretty basic example of some of the flexibility around iTextSharp is available from this github repository https://github.com/bevanweiss/PdfEditor (code excerpts below also)
NOTE: This utilises the AGPL version of iTextSharp (and is hence also AGPL), so if you will be distributing executables derived from this code or allowing others to interact with those executables in any way then you must also provide your modified source code. There is also no warranty, implied or expressed, related to this code. Use at your own peril.
PdfContentStreamEditor
using System.Collections.Generic;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
namespace PDFCleaner
{
public class PdfContentStreamEditor : PdfContentStreamProcessor
{
/**
* This method edits the immediate contents of a page, i.e. its content stream.
* It explicitly does not descent into form xobjects, patterns, or annotations.
*/
public void EditPage(PdfStamper pdfStamper, int pageNum)
{
var pdfReader = pdfStamper.Reader;
var page = pdfReader.GetPageN(pageNum);
var pageContentInput = ContentByteUtils.GetContentBytesForPage(pdfReader, pageNum);
page.Remove(PdfName.CONTENTS);
EditContent(pageContentInput, page.GetAsDict(PdfName.RESOURCES), pdfStamper.GetUnderContent(pageNum));
}
/**
* This method processes the content bytes and outputs to the given canvas.
* It explicitly does not descent into form xobjects, patterns, or annotations.
*/
public virtual void EditContent(byte[] contentBytes, PdfDictionary resources, PdfContentByte canvas)
{
this.Canvas = canvas;
ProcessContent(contentBytes, resources);
this.Canvas = null;
}
/**
* This method writes content stream operations to the target canvas. The default
* implementation writes them as they come, so it essentially generates identical
* copies of the original instructions the {#link ContentOperatorWrapper} instances
* forward to it.
*
* Override this method to achieve some fancy editing effect.
*/
protected virtual void Write(PdfContentStreamProcessor processor, PdfLiteral operatorLit, List<PdfObject> operands)
{
var index = 0;
foreach (var pdfObject in operands)
{
pdfObject.ToPdf(null, Canvas.InternalBuffer);
Canvas.InternalBuffer.Append(operands.Count > ++index ? (byte) ' ' : (byte) '\n');
}
}
//
// constructor giving the parent a dummy listener to talk to
//
public PdfContentStreamEditor() : base(new DummyRenderListener())
{
}
//
// constructor giving the parent a dummy listener to talk to
//
public PdfContentStreamEditor(IRenderListener renderListener) : base(renderListener)
{
}
//
// Overrides of PdfContentStreamProcessor methods
//
public override IContentOperator RegisterContentOperator(string operatorString, IContentOperator newOperator)
{
var wrapper = new ContentOperatorWrapper();
wrapper.SetOriginalOperator(newOperator);
var formerOperator = base.RegisterContentOperator(operatorString, wrapper);
return (formerOperator is ContentOperatorWrapper operatorWrapper ? operatorWrapper.GetOriginalOperator() : formerOperator);
}
public override void ProcessContent(byte[] contentBytes, PdfDictionary resources)
{
this.Resources = resources;
base.ProcessContent(contentBytes, resources);
this.Resources = null;
}
//
// members holding the output canvas and the resources
//
protected PdfContentByte Canvas = null;
protected PdfDictionary Resources = null;
//
// A content operator class to wrap all content operators to forward the invocation to the editor
//
class ContentOperatorWrapper : IContentOperator
{
public IContentOperator GetOriginalOperator()
{
return _originalOperator;
}
public void SetOriginalOperator(IContentOperator op)
{
this._originalOperator = op;
}
public void Invoke(PdfContentStreamProcessor processor, PdfLiteral oper, List<PdfObject> operands)
{
if (_originalOperator != null && !"Do".Equals(oper.ToString()))
{
_originalOperator.Invoke(processor, oper, operands);
}
((PdfContentStreamEditor)processor).Write(processor, oper, operands);
}
private IContentOperator _originalOperator = null;
}
//
// A dummy render listener to give to the underlying content stream processor to feed events to
//
class DummyRenderListener : IRenderListener
{
public void BeginTextBlock() { }
public void RenderText(TextRenderInfo renderInfo) { }
public void EndTextBlock() { }
public void RenderImage(ImageRenderInfo renderInfo) { }
}
}
}
TextReplaceStreamEditor
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
namespace PDFCleaner
{
public class TextReplaceStreamEditor : PdfContentStreamEditor
{
public TextReplaceStreamEditor(string MatchPattern, string ReplacePattern)
{
_matchPattern = MatchPattern;
_replacePattern = ReplacePattern;
}
private string _matchPattern;
private string _replacePattern;
protected override void Write(PdfContentStreamProcessor processor, PdfLiteral oper, List<PdfObject> operands)
{
var operatorString = oper.ToString();
if ("Tj".Equals(operatorString) || "TJ".Equals(operatorString))
{
for(var i = 0; i < operands.Count; i++)
{
if(!operands[i].IsString())
continue;
var text = operands[i].ToString();
if(Regex.IsMatch(text, _matchPattern))
{
operands[i] = new PdfString(Regex.Replace(text, _matchPattern, _replacePattern));
}
}
}
base.Write(processor, oper, operands);
}
}
}
TextRedactStreamEditor
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
namespace PDFCleaner
{
public class TextRedactStreamEditor : PdfContentStreamEditor
{
public TextRedactStreamEditor(string MatchPattern) : base(new RedactRenderListener(MatchPattern))
{
_matchPattern = MatchPattern;
}
private string _matchPattern;
protected override void Write(PdfContentStreamProcessor processor, PdfLiteral oper, List<PdfObject> operands)
{
base.Write(processor, oper, operands);
}
public override void EditContent(byte[] contentBytes, PdfDictionary resources, PdfContentByte canvas)
{
((RedactRenderListener)base.RenderListener).SetCanvas(canvas);
base.EditContent(contentBytes, resources, canvas);
}
}
//
// A pretty simple render listener, all we care about it text stuff.
// We listen out for text blocks, look for our text, and then put a
// black box over it.. text 'redacted'
//
class RedactRenderListener : IRenderListener
{
private PdfContentByte _canvas;
private string _matchPattern;
public RedactRenderListener(string MatchPattern)
{
_matchPattern = MatchPattern;
}
public RedactRenderListener(PdfContentByte Canvas, string MatchPattern)
{
_canvas = Canvas;
_matchPattern = MatchPattern;
}
public void SetCanvas(PdfContentByte Canvas)
{
_canvas = Canvas;
}
public void BeginTextBlock() { }
public void RenderText(TextRenderInfo renderInfo)
{
var text = renderInfo.GetText();
var match = Regex.Match(text, _matchPattern);
if(match.Success)
{
var p1 = renderInfo.GetCharacterRenderInfos()[match.Index].GetAscentLine().GetStartPoint();
var p2 = renderInfo.GetCharacterRenderInfos()[match.Index+match.Length].GetAscentLine().GetEndPoint();
var p3 = renderInfo.GetCharacterRenderInfos()[match.Index+match.Length].GetDescentLine().GetEndPoint();
var p4 = renderInfo.GetCharacterRenderInfos()[match.Index].GetDescentLine().GetStartPoint();
_canvas.SaveState();
_canvas.SetColorStroke(BaseColor.BLACK);
_canvas.SetColorFill(BaseColor.BLACK);
_canvas.MoveTo(p1[Vector.I1], p1[Vector.I2]);
_canvas.LineTo(p2[Vector.I1], p2[Vector.I2]);
_canvas.LineTo(p3[Vector.I1], p3[Vector.I2]);
_canvas.LineTo(p4[Vector.I1], p4[Vector.I2]);
_canvas.ClosePathFillStroke();
_canvas.RestoreState();
}
}
public void EndTextBlock() { }
public void RenderImage(ImageRenderInfo renderInfo) { }
}
}
Using them with iTextSharp
var reader = new PdfReader("SRC FILE PATH GOES HERE");
var dstFile = File.Open("DST FILE PATH GOES HERE", FileMode.Create);
pdfStamper = new PdfStamper(reader, output, reader.PdfVersion, false);
// We don't need to auto-rotate, as the PdfContentStreamEditor will already deal with pre-rotated space..
// if we enable this we will inadvertently rotate the content.
pdfStamper.RotateContents = false;
// This is for the Text Replace
var replaceTextProcessor = new TextReplaceStreamEditor(
"TEXT TO REPLACE HERE",
"TEXT TO SUBSTITUTE IN HERE");
for(int i=1; i <= reader.NumberOfPages; i++)
replaceTextProcessor.EditPage(pdfStamper, i);
// This is for the Text Redact
var redactTextProcessor = new TextRedactStreamEditor(
"TEXT TO REDACT HERE");
for(int i=1; i <= reader.NumberOfPages; i++)
redactTextProcessor.EditPage(pdfStamper, i);
// Since our redacting just puts a box over the top, we should secure the document a bit... just to prevent people copying/pasting the text behind the box.. we also prevent text to speech processing of the file, otherwise the 'hidden' text will be spoken
pdfStamper.Writer.SetEncryption(null,
Encoding.UTF8.GetBytes("ownerPassword"),
PdfWriter.AllowDegradedPrinting | PdfWriter.AllowPrinting,
PdfWriter.ENCRYPTION_AES_256);
// hey, lets get rid of Javascript too, because it's annoying
pdfStamper.Javascript = "";
// and then finally we close our files (saving it in the process)
pdfStamper.Close();
reader.Close();
You can use GroupDocs.Redaction (available for .NET) for replacing or removing the text from PDF documents. You can perform the exact phrase, case-sensitive and regular expression redaction (removal) of the text. The following code snippet replaces the word "candy" with "[redacted]" in the loaded PDF document.
C#:
using (Document doc = Redactor.Load("D:\\candy.pdf"))
{
doc.RedactWith(new ExactPhraseRedaction("candy", new ReplacementOptions("[redacted]")));
// Save the document to "*_Redacted.*" file.
doc.Save(new SaveOptions() { AddSuffix = true, RasterizeToPDF = false });
}
Disclosure: I work as Developer Evangelist at GroupDocs.

Why is this subclass' parent method call not polymorphic?

I've been dabbling in Dlang recently as C++ just wasn't quite sitting right with me after having used Python for so long. While dabbling, I came across what I thought would be a very simple exercise in polymorphism. I suppose how you would expect something to work and what it actually does are two entirely different things for reasons an end user probably can't comprehend. That being said, here is the source code of my "sandbox.D":
import std.stdio;
class Animal {
string voice = "--silence--";
void speak() {
writeln(this.voice);
}
}
class Dog : Animal {
string voice = "Whoof!";
}
int main() {
auto a = new Animal();
auto d = new Dog();
writeln(a.voice); // Prints "--silence--"
writeln(d.voice); // Prints "Whoof!"
a.speak(); // Prints "--silence--"
d.speak(); // Prints "--silence--" NOT "Whoof!"
return 0;
}
I guess my issue is why the "this" keyword just doesn't seem to be functioning how you would expect it to in the C++ successor language.
Methods are polymorphic, variables aren't. So instead of making the voice a variable, you want to override speak in the child.
Also, the auto return type doesn't work with polymorphism, you need to actually specify the types. (The reason is that auto return makes a function template in the compiler, which in theory could have multiple overridable slots in the function table, so it just doesn't try to put it in.)
So try this out:
import std.stdio;
class Animal {
void speak() { // changed to void instead of auto
writeln("--silence--");
}
}
class Dog : Animal {
override void speak() { // the override tells it to override the base method
writeln("woof");
}
}
int main() {
auto d = new Dog();
d.speak();
return 0;
}
If you have a lot of shared functionality and want to reuse one function with slight changes in child classes, you might make a method instead of a variable that just returns something.
Like string voice() { return "woof"; }, then it can be overridden in children.
Another way is to use template this parameter:
import std.stdio;
class Animal {
string voice;
void speak(this C)() {
writeln((cast(C)this).voice);
}
}
class Dog : Animal {
string voice = "Whoof!";
}
int main() {
auto a = new Animal();
auto d = new Dog();
a.speak(); // Prints ""
d.speak(); // Prints "Whoof!"
return 0;
}
Or when you do not need to have voice as a member:
import std.stdio;
class Animal {
static immutable voice = "";
void speak(this C)() {
writeln(C.voice);
}
}
class Dog : Animal {
static immutable voice = "Whoof!";
}
int main() {
auto a = new Animal();
auto d = new Dog();
a.speak(); // Prints ""
d.speak(); // Prints "Whoof!"
return 0;
}

Static Initialization and Use of a Class in a Separate Module in D

In my program, I have a class that I want to be allocated before entering main(). I'd like to tuck these away in a separate module to keep the clutter out of my code; However, as soon as the module goes out of scope (before main() is entered), the objects are deallocated, leaving me trying to use a null reference in main. A short example:
// main.d
import SceneData;
int main(string[] argv)
{
start.onSceneEnter();
readln();
return 0;
}
// SceneData.d
import Scene;
public
{
Scene start;
}
static this()
{
Scene start = new Scene("start", "test", "test";
}
// Scene.d
import std.stdio;
class Scene
{
public
{
this(string name)
{
this.name = name;
}
this(string name, string descriptionOnEnter, string descriptionOnConnect)
{
this.name = name;
this.descriptionOnEnter = descriptionOnEnter;
this.descriptionOnConnect = descriptionOnConnect;
}
void onSceneEnter()
{
writeln(name);
writeln(descriptionOnEnter);
}
}
private
{
string name;
string descriptionOnEnter;
string descriptionOnConnect;
}
}
I'm still getting used to the concept of modules being the basic unit of encapsulation, as opposed to the class in C++ and Java. Is this possible to do in D, or must I move my initializations to the main module?
Here:
static this()
{
Scene start = new Scene("start", "test", "test");
}
"start" is a local scope variable that shadows global one. Global one is not initialized.
After I have changed this to:
static this()
{
start = new Scene("start", "test", "test");
}
Program crashed no more.