Recently, I am learning Phaser 3 to build a game, and using Typescript to write the code.
besides, I am trying to create different objects by using Object-oriented programming inside Phaser class.
The code I wrote is below:
class DifferentGraphics extends Phaser.Scene {
constructor() {
super({
key: "DifferentGraphics"
});
}
create() {
class Graphic {
graphic: Phaser.GameObjects.Graphics;
graphicAdd() {
this.graphic.fillRect(100, 100, 200, 200);
this.graphic.fillStyle(0xffffff);
}
}
let GraphicA = new Graphic();
GraphicA.graphicAdd();
}
}
Compiler didn’t show any Typescript error, but the browser displayed “Uncaught TypeError: Cannot read property ’ fillRect ’ of undefined” after running the code.
I don’t know what’s wrong with my code?
If anyone can share your ideas or solutions, I will appreciate it.
The target I wanna achieve is to make 3 different objects, and these objects have different colors, sizes, positions, and methods that can tween the size separately by using Object-oriented programming.
How can I do to make it happen?
I need a direction or suggestion
Thank you
this.graphic is not initialized
You must initialize this.graphic in constructor, e.g
class Graphic {
graphic: Phaser.GameObjects.Graphics;
constructor(scene){
this.graphic = scene.add.graphics(0,0);
}
graphicAdd() {
this.graphic.fillRect(100, 100, 200, 200);
this.graphic.fillStyle(0xffffff);
}
}
then let GraphicA = new Graphic(this);
Related
Yes, still going with this. My impression is that there's this powerful facility in Raku, which is not really easy to use, and there's so little documentation for that. I'd like to kind of mitigate that.
In this case, I'm trying to force attributes to be read-only by default, to make immutable classes. Here's my attempt:
my class MetamodelX::Frozen is Metamodel::ClassHOW {
method compose_attributes($the-obj, :$compiler_services) {
my $attribute-container = callsame;
my $new-container = Perl6::Metamodel::AttributeContainer.new(
:attributes($attribute-container.attributes),
:attribute_lookup($attribute-container.attribute_table),
:0attr_rw_by_default
);
$new-container.compose_attributes($the-obj, $compiler_services);
}
}
my package EXPORTHOW {
package DECLARE {
constant frozen = MetamodelX::Frozen;
}
}
I'm calling that from a main function that looks like this:
use Frozen;
frozen Foo {
has $.bar;
method gist() {
return "→ $!bar";
}
}
my $foo = Foo.new(:3bar);
say $foo.bar;
$foo.bar(33);
I'm trying to follow the source, that does not really give a lot of facilities to change attribute stuff, so there seems to be no other way that creating a new instance of the container. And that might fail in impredictable ways, and that's what it does:
Type check failed in binding to parameter '$the-obj'; expected Any but got Foo (Foo)
at /home/jmerelo/Code/raku/my-raku-examples/frozen.raku:7
Not clear if this is the first the-obj or the second one, but any way, some help is appreciated.
I'm attempting to follow the guide to try to persist multiple choices from two lists to config. (https://edvin.gitbooks.io/tornadofx-guide/part2/Config%20Settings%20and%20State.html). The guide only discusses SimpleStringProperty in this context. I can see that I should be using SimpleListProperty, but I don't see the right way to associate it with config.
My rough attempt so far:
data class Devices(val receivers: List<String>, val transmitters: List<String>)
// XXX I'd like to just persist Devices, but I'm exposing separate properties for the constituents of Devices
class DevicesModel: ItemViewModel<Devices>() {
// XXX type ends up as Property<ObservableList<JsonValue>>, which seems wrong
val receivers = bind { SimpleListProperty(this, "receivers", config.jsonArray("receivers")!!.toObservable()) }
val transmitters = bind { SimpleListProperty(this, "transmitters", config.jsonArray("transmitters")!!.toObservable()) }
}
class FooView: View() {
val devicesModel = DevicesModel()
// XXX this wants a ReadOnlyListProperty, rather than what it's getting
fun receivers() = listview<String>(devicesModel.receivers) {
selectionModel.selectionMode = SelectionMode.MULTIPLE
}
fun transmitters() = listview<String>(devicesModel.transmitters) {
selectionModel.selectionMode = SelectionMode.MULTIPLE
}
}
Obviously I haven't tackled commit etc, which I will. My question is about the binding/association specifically -- where have I gone wrong? My lack of JavaFX / UI programming background is probably hurting me here.
I have three questions marked with XXX in code, specifically:
I have a mismatch between the properties I'm exposing and the data class. I suppose this could be dealt with in the commit, but that seems messy.
The typing on the properties themselves (particularly JsonValue being exposed) seems wrong, but I don't see a way to expose what I'm looking for.
Why does listview() want a ReadOnlyListProperty? How do I make this accept an Observable?
I will post a PR to the guide with an example, and some clarifying explanation, once I get this working.
I'm just trying to get a basic box rendered with LibGDX (using Kotlin & LibKTX) but am running into some issues.
If I call the ModelBuilder createBox function without the specified begin() and end() functions my box is not rendered. I checked the materials, camera position, the bounding box, added a light source, etc. but it's just.. not there. I figured the issue was with the way I was building the nodes, as I can't find an issue with the Material.
This is how I am trying to render my box:
class HomeView(private val baseUI: BaseUI) : KtxScreen {
private val cam by lazy { PerspectiveCamera(67f, baseUI.aWidth, baseUI.aHeight) }
private val boxInstance: ModelInstance
private val modelBatch: ModelBatch
private val modelBuilder: ModelBuilder by lazy { ModelBuilder() }
private val vertexAttributes =
VertexAttributes.Usage.Position.toLong() or
VertexAttributes.Usage.Normal.toLong() or
VertexAttributes.Usage.TextureCoordinates.toLong()
private val greenMat by lazy { Material(ColorAttribute.createDiffuse(Color.GREEN)) }
private val environment by lazy { Environment() }
//------ end global
init {
cam.position.set(vec3(-10f, -10f, 10f))
cam.lookAt(0f, 0f, 0f)
cam.near = .1f
cam.far = 10f
cam.update()
modelBatch = ModelBatch()
modelBuilder.begin()
modelBuilder.createBox(5f, 5f, 5f, greenMat, vertexAttributes)
boxInstance = ModelInstance(modelBuilder.end())
environment.set(ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f))
environment.add(DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f))
}
override fun render(delta: Float) {
Gdx.gl.glViewport(0, 0, baseUI.aWidth.toInt(), baseUI.aHeight.toInt())
//this is working, screen appears grey
clearScreen(.3f, .3f, .3f, 1f)
modelBatch.begin(cam)
modelBatch.render(boxInstance, environment)
modelBatch.end()
}
//rest omitted
}
and here is my BaseUI class that I'm using to add the screen (I'm just trying to test screens out, this is all just for testing purposes so ignore the inefficiency please)
class BaseUI : KtxGame<KtxScreen>(), KtxApplicationAdapter {
val aWidth by lazy { Gdx.graphics.width.toFloat() }
val aHeight by lazy { Gdx.graphics.height.toFloat() }
override fun create() {
addScreen(HomeView(this))
setScreen<HomeView>()
}
override fun render() {
super<KtxGame>.render()
}
//rest ommitted
}
When I run this I get the following error:
Exception in thread "LWJGL Application" com.badlogic.gdx.utils.GdxRuntimeException: Call end() first
which makes it seem like I need to call modelBatch.end() before I even create the nodes, which is confusing. I feel like I am doing something very basic wrong here, as I was able to get the basic 3D examples working back when I was trying this with Java a few years back.
So, two questions:
Why is LibGDX saying that I need to call end() before I create the nodes with ModelBuilder?
Is using modelBuilder.begin() and modelBuilder.end() actually the best way to use the ModelBuilder? I've yet to see a 3D example do this. Admittedly, all the 3D examples I have found have been from like 2013 so this might just be something that's been added. The LibGDX 3D section says to use this set of tutorials that do not use the begin() and end() functions, so I'm a bit confused as to what is the "best practice".
Thanks for any help!
edit: I tried it with a loaded model and it's having the same issue. Hmm..
edit2: Thank you Xoppa for helping me figure out what was wrong. The LibKTX specific function clearScreen() did not incorporate the GL20.GL_COLOR_BUFFER_BIT clear function as expected, which was my bad from reading their documentation. Adding this to my render function displayed the green box as expected:
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT or GL20.GL_DEPTH_BUFFER_BIT)
LibGDX is not saying to call end() before you create a node, but that there is already an existing model that was created. Therefore, before creating another one you need to call end().
From your code sample, the reason why GdxRuntimeException is being thrown is that you call begin() and then createBox(). createBox() actually calls begin() in the function. (take a look here: https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g3d/utils/ModelBuilder.java) Therefore, the next begin() call the model is not null and the exception is thrown.
For best practices, if createBox() can satisfy your request than just use that. If you need something more complicated, such that createSphere(), createCapsule() don't work for you, then you need to call begin(), part(...), and end().
Hope this helps!
I want to write something like this inside my src/core/Chessman.js file:
import King from './chessmen/King'
class Chessman {
static factory(side, quality) {
switch(quality) {
case 'king' : return new King(side) break
// ... other qualities
}
constructor(side) { this.side = side }
cast(position, ref) { }
run(position, startRef, endRef) {}
}
and inside my src/core/chessmen/King.js file:
import Chessman from '../Chessman'
class King extends Chessman {
constructor(side) {
super(side)
this.iterative = false // true for Queens, Rooks and Bishop
this.directions = [
'up', 'up+right', 'right', 'right+down',
'down', 'down+left', 'left', 'left+top'
]
}
// overrides parent behavior
cast(position, ref) {}
run(position, startRef, endRef) {}
}
But sadly I get the error (while testing) with Karma, jasmine and babel
TypeError: Super expression must either be null or a function, not undefined
at src/core/chessmen/King.js:57
And there's no line 57 for the moment in King.js !
You have a circular dependency error. Given what you've shown us, consider the following steps:
Chessman.js starts loading
It pauses execution so its dependencies can load.
King.js starts loading since it is a dependency.
King.js throws because class King extends Chessman runs, but Chessman has not been set yet, because it paused on step #2
You'd be much better off moving your factory function to its own file, to avoid cyclical dependencies. The only safe circular dependencies in JS are ones that are not needed when the module itself is initialized. Since class extends X runs at module initialization time, it is not safe for cycles.
If this was literally your only class, you could write your app such that King.js was imported before Chessman.js, but given your usage of a factory, and your naming scheme, I assume there are other chess pieces. Since every single chess piece class will trigger this issue, there is no way to import them in the correct order. Avoiding the issue by moving the factory function out of Chessman.js is the only solution to this.
If you want to have a factory, instead of saving it directly in the base class module, move it to it's own module - chessman.factory.js. There, do whatever Chessman.factory does in a method or something. This way the chessman.js module wouldn't have to know about modules that need itself,
Typescript 0.9.5 I now catching errors which were not reported in 0.9.1. From dojo.d.ts:
declare module Dojo {
class Color {
constructor();
constructor(colors: any[]);
}
}
usage:
var Color: Dojo.Color;
new Color([1,2,3]);
The error:
Invalid 'new' expression.
This error makes sense. The solution seems to be to change the class to an interface. This works:
declare module Dojo {
interface Color {
new();
new(colors: any[]);
}
}
var Color: Dojo.Color;
new Color([1, 2, 3]);
So my actual question is this...what is a good pattern to follow for AMD style typescript coding? Here is what I have come up with to handle this particular example:
declare module Dojo {
class Color {
}
interface IColor {
new(): Color;
new (colors: any[]): Color;
}
}
Usage:
require(["dojo/_base/Color", function (Color: Dojo.IColor) {
new Color([1, 2, 3]);
}
Or maybe there's a way to use the existing definition in dojo.d.ts?
TypeScript is even friendlier for working with AMD than you think. Assuming you're working with the d.ts file available here, this is what your code should look like:
/// <reference path="./dojo.d.ts"/>
import Color = require("dojo/_base/Color");
var c = new Color([1, 2, 3]);
and this is what that compiles to:
define(["require", "exports", "dojo/_base/Color"], function(require, exports, Color) {
var c = new Color([1, 2, 3]);
});
You can use multiple import statements in your code and the compiler will organize them for you.
You'll need to tell the compiler that it's the AMD module system you're using (and not commonjs) with the -m AMD command line switch or the <TypeScriptModuleKind>amd</TypeScriptModuleKind> property in your Visual Studio csproj.
Edit: Alternately you can use the typeof type operator to refer to the shape of a module.
/// <reference path="./dojo.d.ts"/>
declare function require(name: string): any;
var Color: typeof Dojo.Color = require("dojo/_base/Color");
var c = new Color([1, 2, 3]);
This doesn't provide as much type safety as the above solution.
This usage
var Color: Dojo.Color;
new Color([1,2,3]);
throws an error because you are declaring the variable Color without assigning a value it, which means that Color will be undefined. undefined does not have a constructor. I believe that you are wanting to do this instead:
new Dojo.Color([1,2,3]);
Note that this
var c: Dojo.IColor;
new c([1, 2, 3]);
will compile but will fail at runtime. You've told the compiler that c has a constructor by giving it a type that says it has a constructor, but it is really undefined so it will fail during runtime.
To answer your question: classes and interfaces have completely different roles. All an interface does is specify typing information. A class is something that you can call a constructor on.