I'm putting together a system for Day and Night for my game, I have a script that makes the day goes normally do not put the night, I thought of creating another copy and put the same script for the night and then the first script calls the second and the second calls the first well be an endless cycle of day and night, was wondering if anyone has any ideas to make it better or am new to the programming world so I have no idea how to do this.
Sorry for my english I'm trying to improve, I'm Brazilian. I appreciate all the help and I await response from someone.
var slider : float;
var slider2 : float;
var Hour : float;
private var Tod: float;
var sun: Light;
var NightFogColor : Color;
var DuskFogColor : Color;
var MorningFogColor : Color;
var MiddayFogColor : Color;
var NightAmbientLight : Color;
var DuskAmbientLight : Color;
var MorningAmbientLight : Color;
var MiddayAmbientLight : Color;
var NightTint : Color;
var DuskTint : Color;
var MorningTint : Color;
var MiddayTint : Color;
var SkyBoxMaterial1 : Material;
var SkyBoxMaterial2 : Material;
var SunNight : Color;
var SunDay : Color;
function OnGUI () {
slider= GUI.HorizontalSlider( Rect(20,20,200,30), slider, 0,1.0);
Hour= slider*24;
Tod= slider2*24;
sun.transform.localEulerAngles.x= (slider*360)-90;
slider = slider +Time.deltaTime/900;
sun.color = Color.Lerp (SunNight, SunDay, slider*2);
if(slider<0.5){
slider2= slider;
}
if(slider>0.5){
slider2= (1-slider);
}
sun.intensity = (slider2-0.2)*2;
if(Tod<4){
//it is Night
RenderSettings.skybox=SkyBoxMaterial1;
RenderSettings.skybox.SetFloat("_Blend", 0);
SkyBoxMaterial1.SetColor ("_Tint", NightTint);
RenderSettings.ambientLight = NightAmbientLight;
RenderSettings.fogColor = NightFogColor;
}
if(Tod>4&&Tod<6){
RenderSettings.skybox=SkyBoxMaterial1;
RenderSettings.skybox.SetFloat("_Blend", 0);
RenderSettings.skybox.SetFloat("_Blend", (Tod/2)-2);
SkyBoxMaterial1.SetColor ("_Tint", Color.Lerp (NightTint, DuskTint, (Tod/2)-2) );
RenderSettings.ambientLight = Color.Lerp (NightAmbientLight, DuskAmbientLight, (Tod/2)-2);
RenderSettings.fogColor = Color.Lerp (NightFogColor,DuskFogColor, (Tod/2)-2);
//it is Dusk
}
if(Tod>6&&Tod<8){
RenderSettings.skybox=SkyBoxMaterial2;
RenderSettings.skybox.SetFloat("_Blend", 0);
RenderSettings.skybox.SetFloat("_Blend", (Tod/2)-3);
SkyBoxMaterial2.SetColor ("_Tint", Color.Lerp (DuskTint,MorningTint, (Tod/2)-3) );
RenderSettings.ambientLight = Color.Lerp (DuskAmbientLight, MorningAmbientLight, (Tod/2)-3);
RenderSettings.fogColor = Color.Lerp (DuskFogColor,MorningFogColor, (Tod/2)-3);
//it is Morning
}
if(Tod>8&&Tod<10){
RenderSettings.ambientLight = MiddayAmbientLight;
RenderSettings.skybox=SkyBoxMaterial2;
RenderSettings.skybox.SetFloat("_Blend", 1);
SkyBoxMaterial2.SetColor ("_Tint", Color.Lerp (MorningTint,MiddayTint, (Tod/2)-4) );
RenderSettings.ambientLight = Color.Lerp (MorningAmbientLight, MiddayAmbientLight, (Tod/2)-4);
RenderSettings.fogColor = Color.Lerp (MorningFogColor,MiddayFogColor, (Tod/2)-4);
}
}
//it is getting Midday
If you are just looking for code to activate and deactivate script you can do it this way.
Assuming both script are in the same object
GetComponent(scriptName).enabled = true; (or false to deactive)
Related
I've imported a GLTF file with two different meshes. My goal is to give each mesh a material with a unique custom fragment shader using onBeforeCompile. Each mesh has the same type of material (MeshNormalMaterial).
When I try to apply one fragment shader to one material and the other fragment shader to the other material, both materials wind up with the same fragment shader. The fragment shader each material has depends on which material I setup first.
Here's a few pictures showing what I'm talking about:
Below is all the relevant code.
Main code: This is the general structure of my code. I've enclosed the important part between "PRIMARY AREA OF INTEREST" comments. For simplicity, I've replaced my shader code with "..." or a comment describing what it does. They do work as shown in the pictures above.
// Three.JS Canvas
const threeDisplay = document.getElementById("threeDisplay");
// Globals
var displayDimensions = getElemDimensions(threeDisplay); // Uniform
var currentTime = 0; // Uniform
var helix = null; // Mesh
var innerHelix = null; // Mesh
var horseshoe = null; // Mesh
// Set the scene and camera up
const scene = new THREE.Scene();
const camera = initCamera();
// Setup a directional light
const light = new THREE.DirectionalLight( 0xffffff, 1.0 );
light.position.set(-0.2, 1, -0.6);
scene.add(light);
// Setup WebGL renderer
const renderer = initRenderer();
threeDisplay.appendChild( renderer.domElement );
// Load the gltf model
new GLTFLoader().load( "./spiral_pillar_hq_horseshoe.glb", function (object) {
const helixFragmentShaderReplacements = [
{
from: ' ... ',
to: ' // rainbow '
}
];
const horseshoeFragmentShaderReplacements = [
{
from: ' ... ',
to: ' // white '
}
];
//////////////////////////////////////
// PRIMARY AREA OF INTEREST - START //
//////////////////////////////////////
// Turn the horseshoe into a shader.
horseshoe = object.scene.children[1];
var horseshoeGeometry = horseshoe.geometry;
var horseshoeMaterial = shaderMeshMaterial(new THREE.MeshNormalMaterial(), horseshoeGeometry, horseshoeFragmentShaderReplacements);
var horseshoeMesh = new THREE.Mesh(horseshoeGeometry, horseshoeMaterial);
horseshoe = horseshoeMesh;
horseshoe.rotation.z = deg2rad(180); // Re-orient the horseshoe to the correct position and rotation.
horseshoe.position.y = 13;
scene.add(horseshoe);
// Turn the inner helix into a colorful, wiggly shader.
helix = object.scene.children[0];
var helixGeometry = helix.geometry;
var helixMaterial = shaderMeshMaterial(new THREE.MeshNormalMaterial(), helixGeometry, helixFragmentShaderReplacements);
var helixMesh = new THREE.Mesh(helixGeometry, helixMaterial);
helix = helixMesh;
scene.add(innerHelix);
animate();
////////////////////////////////////
// PRIMARY AREA OF INTEREST - END //
////////////////////////////////////
}, undefined, function (error) {
console.error(error);
});
Below are functions which are relevant.
shaderMeshMaterial: Constructs a new material based on the supplied materialType that supports editing the default shader. If it's not initProcessing, then the problem may stem from this function.
// Globals used: displayDimensions
function shaderMeshMaterial(materialType, geometry, fragmentShaderReplacements) {
var material = materialType;
material.onBeforeCompile = function ( shader ) {
// Uniforms
shader.uniforms.time = { value: 0 };
shader.uniforms.resolution = { value: new THREE.Vector2(displayDimensions.width, displayDimensions.height) };
shader.uniforms.bboxMin = { value: geometry.boundingBox.min };
shader.uniforms.bboxMax = { value: geometry.boundingBox.max };
fragmentShaderReplacements.forEach((rep) => {
shader.fragmentShader = shader.fragmentShader.replace(rep.from, rep.to);
});
console.log(shader);
material.userData.shader = shader;
}
return material;
}
initRenderer: Sets up the renderer. Just showing you guys the renderer setup I have in case that's important.
// Globals used: displayDimensions
function initRenderer() {
var renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true,
precision: "mediump"
});
renderer.setClearColor( 0x000000, 0);
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( displayDimensions.width, displayDimensions.height );
renderer.shadowMap.enabled = true;
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.25;
return renderer;
}
animate: Handles the animation frames.
// Globals used: renderer, currentTime, postprocessing
function animate (timestamp = 0) {
requestAnimationFrame(animate);
resizeRendererToDisplaySize(renderer);
currentTime = timestamp/1000; // Current time in seconds.
scene.traverse( function ( child ) {
if ( child.isMesh ) {
const shader = child.material.userData.shader;
if ( shader ) {
shader.uniforms.time.value = currentTime;
}
}
} );
renderer.render( scene, camera );
postprocessing.composer.render( 0.1 );
};
One last thing to note is that when I inspected the console log of shader from the shaderMeshMaterial function, I can see that the fragment shaders are indeed different as they should be for each material. Also not sure why there are 4 console logs when there should only be 2.
Sorry for all the code, but I did condense it to where all irrelevant code was stripped out. I'm fairly new to Three.JS, so any possible explanations as to why this is happening are much appreciated!
EDIT: Removed vertex shader parameter from shaderMeshMaterial function to keep this question focused on just the fragment shaders. Though this problem does apply to both the vertex and fragment shaders, I figure if you fix one then you'll fix the other.
EDIT 2: Added language identifiers to code snippets. Also I removed the postprocessing function and the problem still persists, so I know the problem isn't caused by that. I've updated the code above to reflect this change. As a happy side effect of removing the postprocessing function, the console.log of the shader variable from shaderMeshMaterial new appears twice in the log (as it should).
EDIT 3: (Implementing WestLangley's suggestion) I tweaked the shaderMeshMaterial function by adding the customProgramCacheKey function. I had to condense the four parameters of shaderMeshMaterial into one for the sake of the customProgramCacheKey function. I believe I implemented the function correctly, but I'm still getting the same result as before where both materials display the same fragment shader.
New "PRIMARY AREA OF INTEREST" code:
horseshoe = object.scene.children[1];
var horseshoeGeometry = horseshoe.geometry;
var meshData = {
materialType: new THREE.MeshNormalMaterial(),
geometry: horseshoeGeometry,
fragmentShaderReplacements: horseshoeFragmentShaderReplacements
}
var horseshoeMaterial = shaderMeshMaterial(meshData);
var horseshoeMesh = new THREE.Mesh(horseshoeGeometry, horseshoeMaterial);
horseshoe = horseshoeMesh;
horseshoe.rotation.z = deg2rad(180); // Re-orient the horseshoe to the correct position and rotation.
horseshoe.position.y = 13;
scene.add(horseshoe);
// Turn the inner helix into a colorful, wiggly shader.
helix = object.scene.children[0];
var helixGeometry = helix.geometry;
var meshData2 = {
materialType: new THREE.MeshNormalMaterial(),
geometry: helixGeometry,
fragmentShaderReplacements: helixFragmentShaderReplacements
}
var helixMaterial = shaderMeshMaterial(meshData2);
var helixMesh = new THREE.Mesh(helixGeometry, helixMaterial);
helix = helixMesh;
scene.add(innerHelix);
animate();
New shaderMeshMaterial code:
// Globals used: displayDimensions
function shaderMeshMaterial(meshData) {
var material = meshData.materialType;
material.onBeforeCompile = function ( shader ) {
// Uniforms
shader.uniforms.time = { value: 0 };
shader.uniforms.resolution = { value: new THREE.Vector2(displayDimensions.width, displayDimensions.height) };
shader.uniforms.bboxMin = { value: meshData.geometry.boundingBox.min };
shader.uniforms.bboxMax = { value: meshData.geometry.boundingBox.max };
meshData.fragmentShaderReplacements.forEach((rep) => {
shader.fragmentShader = shader.fragmentShader.replace(rep.from, rep.to);
});
material.customProgramCacheKey = function () {
return meshData;
};
console.log(shader);
material.userData.shader = shader;
}
return material;
}
WestLangley suggestion worked for me!
material.onBeforeCompile = ...
// Make sure WebGLRenderer doesnt reuse a single program
material.customProgramCacheKey = function () {
return UNIQUE_PER_MATERIAL_ID;
};
I believe your mistake is returning meshData from customProgramCacheKey.
I think customProgramCacheKey need concrete identifier like a number or string.
It would be nice to understand what exactly happening and why do we need to specify customProgramCacheKey.
EDIT: I discover that default value for customProgramCacheKey calculated as follow in Threejs source.
customProgramCacheKey() {
return this.onBeforeCompile.toString();
}
Perhaps this is explains this default caching behavior because calling toString on function returns that function body literally as string.
For example consider function const myFunc = () => { return 1 }. Calling myFunc.toString() returns "() => { return 1 }"
So if your calling onBeforeCompile in a for loop you function body as string never change.
I am trying to add a simple countdown timer to a Phaser game. When the timer ends I want the game to restart. After adding the relevant code there are no errors in the console but I can't get the timer to appear on the screen. I am new to Phaser and am still learning Javascript. Where I am going wrong please? I have posted only the relevant code below, and the code used for already existing text in the game that is working fine (text to count coins collected).
PlayState = {};
PlayState.init = function () {
//....
};
PlayState.preload = function () {
this.game.load.image('font:numbers', 'images/numbers.png'); //for the
//HUD coin count - not the timer
};
PlayState.create = function () {
//TIMER CODE:
this.timeInSeconds = 120;
this.timeText = this.game.add.text(this.game.world.centerX,
this.game.world.centerY, "0:00",{font: '15px Arial', fill: '#FFFFFF', align:
'center'});
this.timeText.anchor.set(0.5, 0.5);
this.timer = this.game.time.events.loop(Phaser.Timer.SECOND,
this.updateTimer, this);
};
PlayState.update = function () {
this.coinFont.text = `x${this.coinPickupCount}`; //for HUD coin count not
//the timer
};
//TIMER CODE:
PlayState.updateTimer = function() {
this.timeInSeconds--;
var minutes = Math.floor(this.timeInSeconds / 60);
var seconds = this.timeInSeconds - (minutes * 60);
var timeString = this.addZeros(minutes) + ":" + this.addZeros(seconds);
this.timeText.text = timeString;
if (this.timeInSeconds == 0) {
this.game.state.restart();
}
};
//add leading zeros to any number less than 10
//for example turn 1 to 01
PlayState.addZeros = function(num) {
if (num < 10) {
num = "0" + num;
}
return num;
};
//BELOW IS CODE FOR THE COIN COUNT NOT THE TIMER
PlayState._createHud = function () {
this.keyIcon = this.game.make.image(0, 30, 'icon:key');
this.keyIcon.anchor.set(0, 0.5);
const NUMBERS_STR = '0123456789X ';
this.coinFont = this.game.add.retroFont('font:numbers', 20,
26,NUMBERS_STR, 6);
let coinIcon = this.game.make.image(this.keyIcon.width + 7,
0, 'icon:coin');
let coinScoreImg = this.game.make.image(coinIcon.x +
coinIcon.width, coinIcon.height / 2, this.coinFont);
coinScoreImg.anchor.set(0, 0.5);
this.hud = this.game.add.group();
this.hud.add(coinIcon);
this.hud.position.set(10, 10);
this.hud.add(coinScoreImg);
this.hud.add(this.keyIcon);
this.hud.fixedToCamera = true;
};
window.onload = function () {
let game = new Phaser.Game(1280, 800, Phaser.CANVAS, 'game');
game.state.add('play', PlayState);
game.state.start('play');
};
I have finally solved the issue. The text was not showing because it was being rendered AFTER the background image in create. So it was there but being hidden by the background image. I simply moved the timer code to the end of create and it now works.
PlayState.create = function () {
this.game.world.setBounds(0, 0, 2560, 800);
background1 = this.game.add.sprite(0, 0, 'background');
background2 = this.game.add.sprite(1280, 0, 'background2');
this.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
this.game.scale.setMinMax(480,320,1280,800);
this.game.scale.windowConstraints.bottom = 'visual';
this.game.add.image(0, 0, 'background');
this._loadLevel(this.game.cache.getJSON('level:1'));
this._createHud();
//TIMER CODE SHOULD GO HERE AND NOT AT THE BEGINNING OF CREATE
this.timeInSeconds = 120;
this.timeText = this.game.add.text(220, 30, "0:00",{font: '30px Arial', fill:
'#FFFFFF', align: 'center'});
this.timeText.anchor.set(0.5, 0.5);
this.timer = this.game.time.events.loop(Phaser.Timer.SECOND, this.updateTimer,
this);
};
You set the initial text to "0:00" and even that doesn't show on screen? First thing I would do is look at the coordinates where the text is located, maybe it's not visible off screen. Instead of this.game.world.centerX, this.game.world.centerY try something like 100,100, does it show up then? Also try to set very long initial text, so something like "blah test ABC 123" instead of "0:00" maybe makes some difference.
Secondly, maybe the Arial font is not available for some reason. If you leave out the {font: '15px..'center'} part it will use a default font, does that change anything?
Thirdly, you say you didn't post all your code here, but maybe you accidentally overwrite the variable this.timeText somewhere in you code? So check that you don't set that variable to be something else.
Finally, I would add a console.log to the updateTimer function, just to see if it is being called. so:
PlayState.updateTimer = function() {
console.log('updateTimer was called: ' + this.timeInSeconds);
this.timeInSeconds--;
// etc.
am using urhosharp game engine from xamarim to develop a cross-platform game .... it was really good choice and compatible with WPF but I did not know how to draw shapes , I went through the guide and documentation and did not find a way maybe to draw circles,Rounded Shapes,annulus or any geometric type anyone knows or could help me . I would be very grateful .
Thanks in advance
I tried this piece of code but no circle appeared in the screen:
DebugRenderer debug = new DebugRenderer();
debug.AddCircle(new Vector3(50,50,0),new Vector3(100,25,0),50,Color.Magenta,2 ,true );
for (int i = 0; i < 512; ++i)
{
var start = new Vector3(i, 0, 0);
var end = new Vector3(i, 100, 0);
debug.AddLine(start, end, Color.White, false);
debug.AddCircle(start, end, 50f, Color.Red, i, false);
}
scene.AddComponent(debug);
Just want to note that DebugRenderRender is intended for debugging purposes. If you want to make DebugRenderer work you will need to subscribe to PostRenderUpdate like this:
Engine.SubscribeToPostRenderUpdate(args => YourMethodHandler);
Usually you will do that in your setup. And then YourMethodHandler is like:
protected void YourMethodHandler()
{
// this requires that you have already added a DebugRenderer
// component in your scene object
var debugRenderer = scene.GetComponent<DebugRenderer>();
if (debugRenderer != null)
{
// do your drawing code here
// to draw a rectangle for example:
var upperBound = new Vector3(-4.0f, 2.0f, 0.0f);
var lowerBound = new Vector3(4.0f, -2.0f, 0.0f);
debugRenderer.AddBoundingBox(
new BoundingBox(upperBound, lowerBound),
Color.White,
false);
}
}
To be more precise, it works only when implemented like this:
var dr = app.Scene.GetOrCreateComponent<DebugRenderer>();
app.Engine.PostRenderUpdate += (arg4) => {
app.Renderer.DrawDebugGeometry(false);
};
app.Renderer.BeginViewRender += (arg5) => {
dr.AddBoundingBox(new BoundingBox(-1000, 1000), Color.Blue);
dr.LineAntiAlias = true;
dr.AddTriangle(new Vector3(2,0,0), new Vector3(2,1,0), new Vector3(2,0,1), Color.Magenta, false);
dr.AddCircle(new Vector3(2,0,0), new Vector3(1,1,1), 5.0f, Color.Red);
};
This is my script:
var ctexture : Texture2D;
function Update() {
var ray = Camera.main.ScreenPointToRay (Vector3(Screen.width/2,Screen.height/2,0));
var hit : RaycastHit;
if (Physics.Raycast (ray, hit, 100)) {
var pointVec=Camera.main.WorldToScreenPoint(hit.point);
GUI.Label(Rect(pointVec.x,pointVec.y,145,93),ctexture);
Debug.DrawRay (ray.origin, ray.direction * 10, Color.yellow);
Debug.Log(hit.point);}}
I can see Debug.DrawRay ray and it's just how i wanted it to be. The problem is that i can't see result of GUI.Label. The ctexture is assigned and Debug.Log prints out correct info.
Thanks in advance.
Put the code in the OnGUI() function:
var ctexture : Texture2D;
function OnGUI() {
var ray = Camera.main.ScreenPointToRay (Vector3(Screen.width/2,Screen.height/2,0));
var hit : RaycastHit;
if (Physics.Raycast (ray, hit, 100)) {
var pointVec=Camera.main.WorldToScreenPoint(hit.point);
GUI.Label(Rect(pointVec.x,pointVec.y,145,93),ctexture);
Debug.DrawRay (ray.origin, ray.direction * 10, Color.yellow);
Debug.Log(hit.point);
}
}
Created layout after setting the height and width of child elements based on current device screen width and height,as you can see the code snippet which calculates the width and height based on screen size for each child element.
How to do the same or similar settings using Xml mark up to create view in alloy project if not using '%',or 'dp'
function Cal_width(size) {
var width;
try {
width = size * Titanium.Platform.displayCaps.platformWidth / 100;
} catch(e) {
warn("Error accessing display caps for screen density calculation: " + e);
}
return width;
}
function Cal_height(size) {
var height;
try {
height = size * Titanium.Platform.displayCaps.platformHeight / 100;
} catch(e) {
warn("Error accessing display caps for screen density calculation: " + e);
}
return height;
}
const topOffset = Cal_height(1);
const topOffset_label = Cal_height(5);
//const leftOffsetLabel = Cal_width(30);
const leftOffset = Cal_width(5);
const rightOffset = Cal_width(5);
const textFieldHeight = Cal_height(8);
const textFieldWidth = Cal_width(90);
const txtFieldEmailTopOffset = Cal_height(5);
const btnLogin_width = Cal_width(90);
const btnHeight = Cal_height(10);
const topOffsetCreateBtn = Cal_height(6);
const btnCreate_Width = Cal_width(100);
const font_Size = Cal_height(3);
const logo_height = Cal_height(10);
const logo_width = Cal_width(80);
const logoTopOffSet = Cal_height(5);
const leftForgotPswd = Cal_width(40);
// specify visual assets' heights
var win = Titanium.UI.createView({
layout : 'vertical'
});
var applogo = Titanium.UI.createLabel({
width : logo_width,
top : logoTopOffSet,
height : logo_height,
backgroundImage : 'android/_logo.png'
});
win.add(applogo);
//create label to show error in email textfield
var lbemail_error = Titanium.UI.createLabel({
top : topOffset_label,
color : 'red',
textAlign:'center',
font : {
fontFamily : 'Arial',
fontSize : Cal_height(3)
}
});
win.add(lbemail_error);
//create textfield for email input and set its position with respect the screen
var tfemailInput = Titanium.UI.createTextField({
top : Cal_height(5),
left : leftOffset,
right : rightOffset,
width : textFieldWidth,
height : textFieldHeight,
hintText : 'Email',
keyboardType : Titanium.UI.KEYBOARD_EMAIL,
returnKeyType : Titanium.UI.RETURNKEY_NEXT,
borderStyle : Titanium.UI.INPUT_BORDERSTYLE_ROUNDED,
font : {
fontFamily : 'Arial',
fontSize : font_Size
}
});
win.add(tfemailInput);
In alloy you'd ideally use tss files for styling instead of throwing everything into XML attributes. Alloy's tss files can access variables in Alloy.CFG, which you can define. So you can do something like this:
alloy.js
Alloy.CFG.Cal_width = function (size) { /* your code here*/ };
Alloy.CFG.Cal_height = function (size) { /* your code here*/ };
Alloy.CFG.topOffset_label = Alloy.CFG.Cal_height(5)
screen.xml
<Label id="lbemail_error"></Label>
screen.tss
"#lbemail_error": {
top : Alloy.CFG.topOffset_label,
color : 'red',
textAlign:'center',
font : {
fontFamily : 'Arial',
fontSize : Alloy.CFG.Cal_height(3)
}
}