/* built with Studio Sketchpad:
* https://sketchpad.cc
*
* observe the evolution of this sketch:
* https://studio.sketchpad.cc/sp/pad/view/ro.xvjqNbay51Z/rev.7338
*
* authors:
* unnamed
* The Awesome TNT
* Ewen
*
* license (unless otherwise specified):
* creative commons attribution-share alike 3.0 license.
* https://creativecommons.org/licenses/by-sa/3.0/
*/
/* @pjs preload="/static/uploaded_resources/p.13415/sky.jpg"; */
import processing.core.*;
import processing.opengl.*;
import java.util.*;
import java.io.*;
int oldMouseX=200, oldMouseY=200;
final static int R = 1000; // scale
PMatrix3D cam; // the cam
PFont font; // the font
HashMap<String, Object> settings;
int tickSpeed = 1000/60; // 60 fps
int delta = 0;
long lastUpdateTime;
Sky sky;
double camXRot=0, camYRot=0;
double camX=0, camY=0, camZ=0;
PVector x, y, d, d2, d3;
// x = x direction (relative to cam)
// y = y direction (relative to cam)
// d = cam directon * 100
// d2 = forward move vector
// d3 = strafe vector
double moveSpeed=10; // the cam move speed
boolean wpress=false, apress=false, spress=false, dpress=false;
// extra
int tx=100, ty=200, tvx=0.3, tvy=0.7;
int extraFrame=0;
Node root; // the root node, this is where to put all the stuff
Node bulletNode;
Node particlesNode;
// BEGIN NATIVE JS CODE, COMMENT OUT IN REAL PROCESSING
// Don't use these functions, use the non __ wrappers
int __lastX=200, __lastY=200;
boolean allowLocking=true;
s=null;
boolean __hasPointerLock(){
return ('pointerLockElement' in document ||
'mozPointerLockElement' in document ||
'webkitPointerLockElement' in document);
}
void __requestPointerLock(){
if(!allowLocking)return;
s.requestPointerLock();
}
void __releasePointerLock(){
if(!allowLocking)return;
document.exitPointerLock();
}
boolean __isPointerLocked(){
document.pointerLockElement = document.pointerLockElement ||
document.mozPointerLockElement ||
document.webkitPointerLockElement;
return !!document.pointerLockElement;
}
void __initLocking(){
var havePointerLock = __hasPointerLock();
if(!havePointerLock){
allowLocking=false;
println("no pointer lock");
return;
}
s=document.getElementById("pjsCanvas");
s.requestPointerLock = s.requestPointerLock ||
s.mozRequestPointerLock ||
s.webkitRequestPointerLock;
document.exitPointerLock = document.exitPointerLock ||
document.mozExitPointerLock ||
document.webkitExitPointerLock;
document.addEventListener("mousemove", function(e) {
var movementX = e.movementX ||
e.mozMovementX ||
e.webkitMovementX ||
0,
movementY = e.movementY ||
e.mozMovementY ||
e.webkitMovementY ||
0;
__lastX+=movementX;
__lastY+=movementY;
mouseX=__lastX;
mouseY=__lastY;
}, false);
}
// END NATIVE JS CODE
// PROCESSING NATIVE WRAPPER
// wraps the native __ functions so it won't crash if they don't exist
// may slow stuff down with all the try/catch
void requestPointerLock(){
try {
__requestPointerLock();
} catch(Exception e){}
}
void releasePointerLock(){
try {
__releasePointerLock();
} catch(Exception e){}
}
boolean isPointerLocked(){
try {
return __isPointerLocked();
} catch(Exception e){
return false;
}
}
void initLocking(){
try {
__initLocking();
} catch(Exception e){}
}
// END NATIVE WRAPPER
void setup() { // set it up
size(400, 400, OPENGL);
frameRate(120);
cam = new PMatrix3D();
hint(ENABLE_OPENGL_4X_SMOOTH);
///////// ENABLE FOR ERROR REPORTING AND WORSE PERFORMANCE
hint(DISABLE_OPENGL_ERROR_REPORT);
settings=new HashMap<String, Object>();
sky=new Sky();
sky.init();
root=new Node(null);
bulletNode=new Node(root);
bulletNode.type="bulletnode";
root.shapes.add(bulletNode);
particlesNode=new Node(root);
particlesNode.type="particlesnode";
root.shapes.add(particlesNode);
//root.shapes.add(new EpicTestPlane(root));
root.shapes.add(new EpicTestBox(root));
//root.shapes.add(new MapRendererNode(root, mapShape));
initLocking();
extraFrame=random(300);
tx=random(-50, 50);
ty=random(-50, 50);
tvx=random(-1.0, 1.0);
tvy=random(-1.0, 1.0);
lastUpdateTime=millis();
}
void draw() {
if(!focused && frameCount!=1){
long currentTime=millis();
delta+=(currentTime-lastUpdateTime);
lastUpdateTime=currentTime;
if(delta>0){
delta-=1000/25;
extraFrame++;
if(extraFrame>300){
extraFrame=0;
}
pushMatrix();
tx+=tvx;
ty+=tvy;
if(tx<-50 || tx>50){tvx=-tvx;}
if(ty<-50 || ty>50){tvy=-tvy;}
translate(200+tx, 200+ty);
rotateY((extraFrame)*(TWO_PI/300));
rotateX((extraFrame%150)*(TWO_PI/150));
background(0);
stroke(255);
if(extraFrame<100){
fill(lerpColor(color(255, 0, 0), color(0, 255, 0), extraFrame/100));
} else if(extraFrame<200){
fill(lerpColor(color(0, 255, 0), color(0, 0, 255), (extraFrame-100)/100));
} else {
fill(lerpColor(color(0, 0, 255), color(255, 0, 0), (extraFrame-200)/100));
}
textSize(20);
text("Epic FPS Game\nClick to focus", -50, -20);
popMatrix();
}
return;
}
// draw it
noLights();
// BACKGROUND / CAM
background(0);
int deltaX=oldMouseX-mouseX;
int deltaY=oldMouseY-mouseY;
oldMouseX=mouseX;
oldMouseY=mouseY;
camXRot+=deltaX/100.0;
camYRot+=deltaY/100.0;
camXRot=camXRot%TWO_PI;
if(camYRot>HALF_PI){camYRot=HALF_PI;}
if(camYRot<-HALF_PI){camYRot=-HALF_PI;}
cam.reset();
cam.rotateY(camXRot);
cam.rotateX(camYRot);
x = cam.mult(new PVector(1, 0, 0), new PVector(0, 0, 0));
y = cam.mult(new PVector(0, 1, 0), new PVector(0, 0, 0));
d = x.cross(y);
d.normalize();
d2 = new PVector();
d2.set(d);
d.mult(R);
d2.mult(moveSpeed);
d3=new PVector();
d3.set(x);
d3.normalize();
d3.mult(moveSpeed);
// update
long currentTime=millis();
delta+=(currentTime-lastUpdateTime);
lastUpdateTime=currentTime;
while(delta>0){
delta-=tickSpeed;
updateWorld(d);
}
// -- set up perspective
float fov = PI/3.0;
float cameraZ = (height/2.0) / tan(fov/2.0);
perspective(fov, float(width)/float(height), cameraZ/10.0, cameraZ*1000.0);
camera(0, 0, 0, d.x, d.y, d.z, y.x, y.y, y.z);
// RENDER SKYBOX
noStroke();
hint(DISABLE_DEPTH_TEST);
sky.render();
hint(ENABLE_DEPTH_TEST);
// TRANSLATE to player's position here
translate(camX, camY, camZ);
// LIGHTS
lightSpecular(200, 30, 30);
directionalLight(249, 250, 91, -3, 4, -4);
ambientLight(255, 255, 255);
shininess(5);
specular(200, 200, 200);
emissive(20,20,20);
// RENDER WORLD
root.render();
// RENDER HUD
hint(DISABLE_DEPTH_TEST); // disable z-buffering (causes stuff to go in front of hud)
renderHud(d);
hint(ENABLE_DEPTH_TEST); // enable it again for the next render
}
void renderHud(PVector d){
camera(); // CROSSHAIR & text
stroke(255);
fill(255);
textSize(16);
text("HINT: hold right click for epicness\ndebug stuff: \nbullets:"+bulletNode.shapes.size()+",\nd="+d+"\nfps:"+frameRate+"\nrot:\n"+camXRot+"\n"+camYRot+"\npos:\n"+camX+"\n"+camY+"\n"+camZ, 0, 0);
line(width / 2 - 9, height / 2 - 0, width / 2 + 8, height / 2 + 0);
line(width / 2 - 0, height / 2 - 9, width / 2 + 0, height / 2 + 8);
if(frameCount==1){
background(0);
}
}
void updateWorld(PVector d){
if(Bullet.count>0){
Bullet.count--;
}
if(wpress){
camX-=d2.x;
camY-=d2.y;
camZ-=d2.z;
}
if(apress){
camX-=d3.x;
camY-=d3.y;
camZ-=d3.z;
}
if(spress){
camX+=d2.x;
camY+=d2.y;
camZ+=d2.z;
}
if(dpress){
camX+=d3.x;
camY+=d3.y;
camZ+=d3.z;
}
root.update();
if((Bullet.fireGun) && Bullet.count==0){
Bullet.count=10;
bulletNode.shapes.add(new Bullet(d, bulletNode));
for(int i=0;i<30;i++){
particlesNode.shapes.add(new FireParticle(d.x+random(-80,80),d.y+random(-80,80),d.z+random(-80,80),5,particlesNode));
}
if(Bullet.shotGun){
for(int i=0;i<10;i++)bulletNode.shapes.add(new Bullet(new PVector(random(-R, R), random(-R, R), random(-R, R)), bulletNode));
}
}
for(int i=0;i<bulletNode.shapes.size();i++) {
if(bulletNode.shapes.get(i).v.dist(d)>1000)
bulletNode.shapes.remove(i);
}
for(int i=0;i<particlesNode.shapes.size();i++) {
if(particlesNode.shapes.get(i).age<=0)
particlesNode.shapes.remove(i);
// eventually, make this into a generalized particle system
// where all particles have ages
}
}
void mousePressed() {
requestPointerLock();
Bullet.fireGun=true;
if(mouseButton==RIGHT) {
Bullet.shotGun=true;
}
}
void mouseReleased() {
Bullet.fireGun=false;
Bullet.shotGun=false;
}
void keyPressed(){
if(key=='r'){
camXRot=0;
camYRot=0;
camX=0;
camY=0;
camZ=0;
}
if(key=='w'){
wpress=true;
}
if(key=='a'){
apress=true;
}
if(key=='s'){
spress=true;
}
if(key=='d'){
dpress=true;
}
}
void keyReleased(){
if(key=='w'){
wpress=false;
}
if(key=='a'){
apress=false;
}
if(key=='s'){
spress=false;
}
if(key=='d'){
dpress=false;
}
}
class Object3D { // extend
Node parent;
String type="object3d"; // USE ME TO CHECK OBJECT TYPE
float x=0, y=0, z=0, rx=0, ry=0, rz=0;
float sc=1;
Object3D(Node p){
this.parent=p;
}
// put stuffs here
void render(){
pushMatrix();
__transform();
renderObject();
popMatrix();
}
void renderObject(){} // extend me
void update(){} // me too
void __transform() { // __ = private inner function
translate(x, y, z);
rotateX(rx);
rotateY(ry);
rotateZ(rz);
scale(sc);
}
}
class Node extends Object3D {
ArrayList<Node> shapes;
Node(Node p){
super(p);
type="node";
shapes=new ArrayList<Node>();
}
void render() {
pushMatrix();
__transform();
for(int i=0;i<shapes.size();i++)shapes.get(i).render();
popMatrix();
}
void update(){
for(int i=0;i<shapes.size();i++)shapes.get(i).update(delta);
}
}
class Bullet extends Object3D {
static int count=0;
static boolean fireGun=false, shotGun=false;
PVector v;
Bullet(PVector d, Node p){
super(p);
v = d;
x=-camX;
y=-camY;
z=-camZ;
type="bullet";
}
void update() {
x+=v.x;
y+=v.y;
z+=v.z;
}
void renderObject(){
fill(50);
noStroke();
sphere(30);
}
}
class EpicTestPlane extends Object3D {
EpicTestPlane(Node p){
super(p);
type="epictestplane";
y=100;
sc=10000;
}
void renderObject(){
fill(0, 100, 0);
stroke(0);
beginShape(QUADS);
vertex(-0.5, 0.5, 0.5);
vertex( 0.5, 0.5, 0.5);
vertex( 0.5, 0.5, -0.5);
vertex(-0.5, 0.5, -0.5);
endShape();
}
}
class EpicTestBox extends Object3D {
EpicTestBox(Node p){
super(p);
type="epictestplane";
y=100;
x=100;
rx=1;
rz=0.44;
sc=100;
}
void renderObject(){
fill(255, 0, 0);
stroke(0);
box(1);
}
}
class MapRendererNode extends Object3D {
PShape map;
MapRendererNode(Node p, PShape s){
super(p);
type="maprenderernode";
y=100;
sc=100;
map=s;
}
void renderObject(){
shape(map, 0, 0);
}
}
class FireParticle extends Object3D {
int age, vx, vy;
int r, g, b;
FireParticle(int x, int y, int z, int age, Node p){
super(p);
this.age = age;
this.x=x-camX;
this.y=y-camY;
this.z=z-camZ;
this.vx= random(-20,20);
this.vy = random(-20,20);
this.r=random(160, 255);
this.g=random(50, 150);
this.b=random(100);
type="fireparticle";
}
void update(){
age--;
x+=vx;
y+=vy;
y++;
}
void renderObject(){
fill(r, g, b);
sphere(5);
}
}
class Sky {
PImage skytex;
void init(){
skytex = loadImage("/static/uploaded_resources/p.13415/sky.jpg");
}
void render(){
pushMatrix();
textureMode(NORMALIZED);
scale(100);
fill(255);
beginShape(QUADS);
texture(skytex);
// +Z "front" face
vertex(-1, -1, 1, 0, 0);
vertex( 1, -1, 1, 1, 0);
vertex( 1, 1, 1, 1, 1);
vertex(-1, 1, 1, 0, 1);
// -Z "back" face
vertex( 1, -1, -1, 0, 0);
vertex(-1, -1, -1, 1, 0);
vertex(-1, 1, -1, 1, 1);
vertex( 1, 1, -1, 0, 1);
// +Y "bottom" face
vertex(-1, 1, 1, 0, 0);
vertex( 1, 1, 1, 1, 0);
vertex( 1, 1, -1, 1, 1);
vertex(-1, 1, -1, 0, 1);
// -Y "top" face
vertex(-1, -1, -1, 0, 0);
vertex( 1, -1, -1, 1, 0);
vertex( 1, -1, 1, 1, 1);
vertex(-1, -1, 1, 0, 1);
// +X "right" face
vertex( 1, -1, 1, 0, 0);
vertex( 1, -1, -1, 1, 0);
vertex( 1, 1, -1, 1, 1);
vertex( 1, 1, 1, 0, 1);
// -X "left" face
vertex(-1, -1, -1, 0, 0);
vertex(-1, -1, 1, 1, 0);
vertex(-1, 1, 1, 1, 1);
vertex(-1, 1, -1, 0, 1);
endShape();
popMatrix();
}
}